Reference
at42qt2120.AT42QT2120
An AT42QT2120 capacitive touch sensing chip.
This interfaces with the AT42QT2120 to read touch inputs from its 12 channels. Each channel's touch state can be accessed and queried to determine if it is activated or not. The class encapsulates low-level I2C communication and provides higher-level abstractions for working with the chip.
Source code in at42qt2120.py
class AT42QT2120:
"""An AT42QT2120 capacitive touch sensing chip.
This interfaces with the AT42QT2120 to read touch inputs from its 12
channels. Each channel's touch state can be accessed and queried to
determine if it is activated or not. The class encapsulates low-level I2C
communication and provides higher-level abstractions for working with the
chip.
"""
_i2c: i2c_device.I2CDevice
_channels: list[AT42QT2120Channel | None]
def __init__(self, i2c: busio.I2C, address: int = AT42QT2120_I2CADDR_DEFAULT) -> None:
"""Creates a new ``AT42QT2120`` instance.
Args:
i2c: The I2C bus to use.
address: The I2C address of the sensor.
"""
self._i2c = i2c_device.I2CDevice(i2c, address)
self._channels = [None] * 12
def __getitem__(self, key: int) -> AT42QT2120Channel:
"""Gets the channel at the specified key.
Args:
key: The index of the channel to retrieve.
Raises:
IndexError: If the specified key is out of range.
Returns:
The channel corresponding to the specified key.
"""
if key < 0 or key > 11:
raise IndexError("pin must be a value 0-11")
if self._channels[key] is None:
self._channels[key] = AT42QT2120Channel(self, key)
return self._channels[key]
@property
def touched_pins(self) -> tuple[bool, ...]:
"""Get a tuple of the touched state for all pins.
Returns:
A tuple of boolean values, where each value indicates whether the corresponding pin is
touched (True) or not (False).
"""
return tuple_of_bits(self.touched(), 12)
def write_register_byte(self, register: int, value: int) -> None:
"""Write a single byte to a specified register.
Args:
register: The register to write to.
value: The value to write to the register.
"""
with self._i2c:
self._i2c.write(bytes([register, value]))
def read_register_byte(self, register: int) -> int:
"""Read a single byte from a specified register.
Args:
register: The register to read from.
Returns:
The value read from the register.
"""
with self._i2c:
request = bytes([register])
response = bytearray(1)
self._i2c.write_then_readinto(request, response)
return response[0]
# If anything goes wrong, return 0. Our code should handle this.
return 0
def touched(self) -> int:
"""Get the touch state of all pins as a 12-bit value.
Returns: A 12-bit value representing the touch state of each pin. Each state in the value
is represented by either a 1 or 0; touched or not.
"""
high = self.read_register_byte(AT42QT2120_KEY_STATUS + 1)
low = self.read_register_byte(AT42QT2120_KEY_STATUS)
return two_byte_int(high, low)
def is_touched(self, pin: int) -> bool:
"""Get if ``pin`` is being touched.
Args:
pin: The pin to check.
Raises:
IndexError: If ``pin`` is out of range.
Returns:
True if ``pin`` is being touched; otherwise False.
"""
if pin < 0 or pin > 11:
raise IndexError("Pin must be a value 0-11.")
return bit_on(self.touched(), pin)
def reset(self) -> None:
"""Reset the AT42QT2120 to its default state.
For now, this is really just about undoing changes to thresholds.
"""
self.write_register_byte(AT42QT2120_RESET, 1)
# From the datasheet:
# "This soft reset triggers the internal watchdog timer on a 125 ms
# interval. After 125 ms the device executes a full reset. The device
# NACKs any attempts to communicate with it for approximately 200 ms
# after the soft reset command."
time.sleep(0.125 + 0.200)
touched_pins
property
Get a tuple of the touched state for all pins.
| Returns: |
|
|---|
__getitem__(key)
Gets the channel at the specified key.
| Parameters: |
|
|---|
| Raises: |
|
|---|
| Returns: |
|
|---|
Source code in at42qt2120.py
def __getitem__(self, key: int) -> AT42QT2120Channel:
"""Gets the channel at the specified key.
Args:
key: The index of the channel to retrieve.
Raises:
IndexError: If the specified key is out of range.
Returns:
The channel corresponding to the specified key.
"""
if key < 0 or key > 11:
raise IndexError("pin must be a value 0-11")
if self._channels[key] is None:
self._channels[key] = AT42QT2120Channel(self, key)
return self._channels[key]
__init__(i2c, address=AT42QT2120_I2CADDR_DEFAULT)
Creates a new AT42QT2120 instance.
| Parameters: |
|
|---|
Source code in at42qt2120.py
def __init__(self, i2c: busio.I2C, address: int = AT42QT2120_I2CADDR_DEFAULT) -> None:
"""Creates a new ``AT42QT2120`` instance.
Args:
i2c: The I2C bus to use.
address: The I2C address of the sensor.
"""
self._i2c = i2c_device.I2CDevice(i2c, address)
self._channels = [None] * 12
is_touched(pin)
Get if pin is being touched.
| Parameters: |
|
|---|
| Raises: |
|
|---|
| Returns: |
|
|---|
Source code in at42qt2120.py
def is_touched(self, pin: int) -> bool:
"""Get if ``pin`` is being touched.
Args:
pin: The pin to check.
Raises:
IndexError: If ``pin`` is out of range.
Returns:
True if ``pin`` is being touched; otherwise False.
"""
if pin < 0 or pin > 11:
raise IndexError("Pin must be a value 0-11.")
return bit_on(self.touched(), pin)
read_register_byte(register)
Read a single byte from a specified register.
| Parameters: |
|
|---|
| Returns: |
|
|---|
Source code in at42qt2120.py
def read_register_byte(self, register: int) -> int:
"""Read a single byte from a specified register.
Args:
register: The register to read from.
Returns:
The value read from the register.
"""
with self._i2c:
request = bytes([register])
response = bytearray(1)
self._i2c.write_then_readinto(request, response)
return response[0]
# If anything goes wrong, return 0. Our code should handle this.
return 0
reset()
Reset the AT42QT2120 to its default state.
For now, this is really just about undoing changes to thresholds.
Source code in at42qt2120.py
def reset(self) -> None:
"""Reset the AT42QT2120 to its default state.
For now, this is really just about undoing changes to thresholds.
"""
self.write_register_byte(AT42QT2120_RESET, 1)
# From the datasheet:
# "This soft reset triggers the internal watchdog timer on a 125 ms
# interval. After 125 ms the device executes a full reset. The device
# NACKs any attempts to communicate with it for approximately 200 ms
# after the soft reset command."
time.sleep(0.125 + 0.200)
touched()
Get the touch state of all pins as a 12-bit value.
| A 12-bit value representing the touch state of each pin. Each state in the value |
|
|---|
Source code in at42qt2120.py
def touched(self) -> int:
"""Get the touch state of all pins as a 12-bit value.
Returns: A 12-bit value representing the touch state of each pin. Each state in the value
is represented by either a 1 or 0; touched or not.
"""
high = self.read_register_byte(AT42QT2120_KEY_STATUS + 1)
low = self.read_register_byte(AT42QT2120_KEY_STATUS)
return two_byte_int(high, low)
write_register_byte(register, value)
Write a single byte to a specified register.
| Parameters: |
|
|---|
Source code in at42qt2120.py
def write_register_byte(self, register: int, value: int) -> None:
"""Write a single byte to a specified register.
Args:
register: The register to write to.
value: The value to write to the register.
"""
with self._i2c:
self._i2c.write(bytes([register, value]))
at42qt2120.AT42QT2120Channel
A specific channel of an AT42QT2120 capacitive touch sensor.
This provides access to the state and raw measurement of a specified channel on the AT42QT2120 sensor. The channel can be checked to determine whether it is being touched or to retrieve its raw measurement data.
Source code in at42qt2120.py
class AT42QT2120Channel:
"""A specific channel of an AT42QT2120 capacitive touch sensor.
This provides access to the state and raw measurement of a specified
channel on the AT42QT2120 sensor. The channel can be checked to determine
whether it is being touched or to retrieve its raw measurement data.
"""
_at42qt2120: "AT42QT2120"
_channel: int
def __init__(self, at42qt2120: "AT42QT2120", channel: int) -> None:
"""Creates a new ``AT42QT2120Channel`` instance.
Args:
at42qt2120: An instance of the touch sensor driver.
channel: The channel this instance represents (0-11).
"""
self._at42qt2120 = at42qt2120
self._channel = channel
@property
def value(self) -> bool:
"""The current touch state of the sensor.
Returns:
True if the sensor is touched, False otherwise
"""
return bit_on(self._at42qt2120.touched(), self._channel)
@property
def raw_value(self) -> int:
"""The raw signal measurement value for the specified channel.
Returns:
The raw signal measurement as an integer.
"""
high = self._at42qt2120.read_register_byte(AT42QT2120_KEY_SIGNAL_0 + self._channel * 2 + 1)
low = self._at42qt2120.read_register_byte(AT42QT2120_KEY_SIGNAL_0 + self._channel * 2)
return two_byte_int(high, low)
@property
def threshold(self) -> int:
"""The threshold value for the specified channel.
Returns:
The threshold value as an integer.
"""
return self._at42qt2120.read_register_byte(AT42QT2120_DETECT_THRESHOLD_0 + self._channel)
@threshold.setter
def threshold(self, value: int) -> None:
"""Sets the threshold value for the specified channel.
Args:
value: The 8-bit threshold value to set.
Raises:
ValueError: If the threshold value is not an integer between 0 and 255.
"""
if value < 0 or value > 255:
raise ValueError("Threshold must be an integer between 0 and 255.")
self._at42qt2120.write_register_byte(AT42QT2120_DETECT_THRESHOLD_0 + self._channel, value)
raw_value
property
The raw signal measurement value for the specified channel.
| Returns: |
|
|---|
threshold
property
writable
The threshold value for the specified channel.
| Returns: |
|
|---|
value
property
The current touch state of the sensor.
| Returns: |
|
|---|
__init__(at42qt2120, channel)
Creates a new AT42QT2120Channel instance.
| Parameters: |
|
|---|
Source code in at42qt2120.py
def __init__(self, at42qt2120: "AT42QT2120", channel: int) -> None:
"""Creates a new ``AT42QT2120Channel`` instance.
Args:
at42qt2120: An instance of the touch sensor driver.
channel: The channel this instance represents (0-11).
"""
self._at42qt2120 = at42qt2120
self._channel = channel
Helper functions
two_byte_int(high, low)
Combine two separate bytes (high and low) into a single 16-bit integer.
This function takes two integers representing the high and low bytes of a 16-bit integer and combines them to produce the resulting integer. Both bytes are masked to ensure only the least significant 8 bits of each are used. The result is also masked to fit within 16 bits.
| Parameters: |
|
|---|
| Returns: |
|
|---|
Examples:
Build a 16-bit integer from two 8-bit integers:
>>> two_byte_int(0xFF, 0x00) == 0xFF00
True
Build a 16-bit integer from two incorrect 16-bit integers, losing their upper bytes:
>>> two_byte_int(0xFF11, 0xFF22) == 0x1122
True
Source code in at42qt2120.py
def two_byte_int(high: int, low: int) -> int:
"""Combine two separate bytes (high and low) into a single 16-bit integer.
This function takes two integers representing the high and low bytes of
a 16-bit integer and combines them to produce the resulting integer. Both
bytes are masked to ensure only the least significant 8 bits of each are
used. The result is also masked to fit within 16 bits.
Args:
high: The high byte of the 16-bit integer.
low: The low byte of the 16-bit integer.
Returns:
The resulting 16-bit integer combined from the high and low bytes.
Examples:
Build a 16-bit integer from two 8-bit integers:
>>> two_byte_int(0xFF, 0x00) == 0xFF00
True
Build a 16-bit integer from two incorrect 16-bit integers, losing
their upper bytes:
>>> two_byte_int(0xFF11, 0xFF22) == 0x1122
True
"""
return ((high & 0xFF) << 8 | (low & 0xFF)) & 0xFFFF
bit_on(value, bit)
Determines whether a specific bit is set in the binary representation of a given integer value.
This function checks if the bit at the specified position is set to 1 in the binary representation of the provided integer. The bit position is zero-indexed, where the least significant bit is at position 0.
| Parameters: |
|
|---|
| Returns: |
|
|---|
Examples:
The 0th bit of 0b1010 is off.
>>> bit_on(0b1010, 0)
False
The 4th bit of 0x15 is on.
>>> bit_on(0x15, 4)
True
Source code in at42qt2120.py
def bit_on(value: int, bit: int) -> bool:
"""Determines whether a specific bit is set in the binary representation of
a given integer value.
This function checks if the bit at the specified position is set to 1
in the binary representation of the provided integer. The bit position
is zero-indexed, where the least significant bit is at position 0.
Args:
value: An integer in which the bit is to be checked.
bit: The zero-indexed position of the bit to check.
Returns:
True if the bit at the specified position is set (1), otherwise False.
Examples:
The 0th bit of 0b1010 is off.
>>> bit_on(0b1010, 0)
False
The 4th bit of 0x15 is on.
>>> bit_on(0x15, 4)
True
"""
return bool(value & (1 << bit))
tuple_of_bits(value, bits)
Generates a tuple of boolean values representing the binary state of each bit in an integer, from the least significant bit to the most significant bit, for a specified number of bits.
Each position in the tuple corresponds to whether the bit at that position is set (True) or not (False).
| Parameters: |
|
|---|
| Returns: |
|
|---|
Examples:
The 4 bits of 0xF are all on.
>>> tuple_of_bits(0xF,4)
(True, True, True, True)
The 5 bits of 0x15 are alternatingly on or off.
>>> tuple_of_bits(0x15,5)
(True, False, True, False, True)
Source code in at42qt2120.py
def tuple_of_bits(value: int, bits: int) -> tuple[bool, ...]:
"""Generates a tuple of boolean values representing the binary state of each bit
in an integer, from the least significant bit to the most significant bit, for
a specified number of bits.
Each position in the tuple corresponds to whether the bit at that position is set (True) or not
(False).
Args:
value: The integer value whose bits are to be represented as a tuple.
bits: The number of bits to consider starting from the least
significant bit.
Returns:
A tuple of boolean values, where each value indicates whether the corresponding bit is set
(True) or not (False).
Examples:
The 4 bits of 0xF are all on.
>>> tuple_of_bits(0xF,4)
(True, True, True, True)
The 5 bits of 0x15 are alternatingly on or off.
>>> tuple_of_bits(0x15,5)
(True, False, True, False, True)
"""
return tuple(bit_on(value, i) for i in range(bits))