Skip to content

Commit 4329a90

Browse files
committed
Documentation and type hinting
1 parent d77e625 commit 4329a90

File tree

1 file changed

+64
-13
lines changed

1 file changed

+64
-13
lines changed

adafruit_ags02ma.py

Lines changed: 64 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,12 @@
2727
2828
"""
2929

30+
try:
31+
from busio import I2C
32+
from typing_extensions import NoReturn
33+
except ImportError:
34+
pass
35+
3036
import time
3137
import struct
3238
from micropython import const
@@ -44,7 +50,7 @@
4450
_AGS02MA_CRC8_POLYNOMIAL = const(0x31)
4551

4652

47-
def _generate_crc(data):
53+
def _generate_crc(data: int) -> int:
4854
"""8-bit CRC algorithm for checking data
4955
5056
:param bytearray data: The data to generate a CRC for
@@ -64,13 +70,45 @@ def _generate_crc(data):
6470

6571

6672
class AGS02MA:
67-
"""Driver for the AGS02MA air quality sensor
73+
"""Driver for the AGS02MA air quality sensor.
74+
75+
.. warning::
76+
I2C communication rate cannot be higher than 30KHZ
6877
6978
:param ~busio.I2C i2c_bus: The I2C bus the AGS02MA is connected to.
7079
:param int address: The I2C device address. Defaults to :const:`0x1A`
80+
81+
:raises RunTimeError: When the sensor could not be found
82+
83+
84+
**Quickstart: Importing and using the device**
85+
86+
Here is an example of using the :class:`AGS02MA` class.
87+
First you will need to import the libraries to use the sensor
88+
89+
.. code-block:: python
90+
91+
import board
92+
import busio
93+
from adafruit_ags02ma import AGS02MA
94+
95+
Once this is done you can define your `busio.I2C` object and define your sensor object
96+
97+
.. code-block:: python
98+
99+
i2c = busio.I2C(board.SCL, board.SDA, frequency=20_000)
100+
ags = AGS02MA(i2c, address=0x1A)
101+
102+
Now you have access to the :attr:`gas_resistance` and :attr:`TVOC` attributes
103+
104+
.. code-block:: python
105+
106+
res = ags.gas_resistance
107+
tvoc = ags.TVOC
108+
71109
"""
72110

73-
def __init__(self, i2c_bus, address=AGS02MA_I2CADDR_DEFAULT):
111+
def __init__(self, i2c_bus: I2C, address: int = AGS02MA_I2CADDR_DEFAULT) -> None:
74112
self.i2c_device = i2c_device.I2CDevice(i2c_bus, address)
75113

76114
self._buf = bytearray(5)
@@ -80,30 +118,40 @@ def __init__(self, i2c_bus, address=AGS02MA_I2CADDR_DEFAULT):
80118
except RuntimeError as exc: # a CRC error or something!
81119
raise RuntimeError("Failed to find AGS02MA - check your wiring!") from exc
82120

83-
def firmware_version(self):
121+
def firmware_version(self) -> int:
84122
"""Return 24-bit value which contains the firmware version"""
85123
return self._read_reg(_AGS02MA_VERSION_REG, 30)
86124

87125
@property
88-
def gas_resistance(self):
126+
def gas_resistance(self) -> float:
89127
"""The resistance of the MEMS gas sensor"""
90128
return self._read_reg(_AGS02MA_GASRES_REG, 1500) * 100 # in 0.1Kohm
91129

92130
@property
93-
def TVOC(self): # pylint: disable=invalid-name
94-
"""The calculated Total Volatile Organic Compound measurement, in ppb"""
131+
def TVOC(self) -> int: # pylint: disable=invalid-name
132+
"""The calculated Total Volatile Organic Compound measurement, in ppb
133+
134+
:raises RunTimeError: When the sensor still preheating
135+
"""
95136
val = self._read_reg(_AGS02MA_TVOCSTAT_REG, 1500)
96137
status = val >> 24
97-
# print(hex(status))
138+
98139
if status & 0x1:
99140
raise RuntimeError("Sensor still preheating")
100141
return val & 0xFFFFFF
101142

102-
def set_address(self, new_addr):
143+
def set_address(self, new_addr: int) -> NoReturn:
103144
"""Set the address for the I2C interface, from 0x0 to 0x7F
145+
The sensor supports modifying the I2C address. After sending
146+
this command, the new address will take effect immediately,
147+
New address will remain after powering the sensor off.
104148
105-
:param int new_addr: THe new address
149+
:param int new_addr: The new address
150+
151+
:raises: ValueError: When selected address is not in the range 0x00-0x7F
106152
"""
153+
if new_addr not in range(1, 128):
154+
raise ValueError("Selected address must be between 0x00 and 0x7F")
107155

108156
_buf = bytearray(
109157
[
@@ -119,21 +167,24 @@ def set_address(self, new_addr):
119167
with self.i2c_device as i2c:
120168
i2c.write(_buf)
121169

122-
def _read_reg(self, addr, delayms):
170+
def _read_reg(self, addr: int, delayms: int) -> int:
123171
"""Read a register
124172
125173
:param int addr: The address to read
126174
:param int delayms: The delay between writes and reads, in milliseconds
175+
176+
:raises RunTimeError: When CRC check have failed.
177+
127178
"""
128179

129180
with self.i2c_device as i2c:
130181
self._addr[0] = addr
131182
i2c.write(self._addr)
132183
time.sleep(delayms / 1000)
133184
i2c.readinto(self._buf)
134-
# print([hex(x) for x in self._buf])
185+
135186
if _generate_crc(self._buf) != 0:
136187
raise RuntimeError("CRC check failed")
137188
val, crc = struct.unpack(">IB", self._buf) # pylint: disable=unused-variable
138-
# print(hex(val), hex(crc))
189+
139190
return val

0 commit comments

Comments
 (0)