27
27
28
28
"""
29
29
30
+ try :
31
+ from busio import I2C
32
+ except ImportError :
33
+ pass
34
+
30
35
import time
31
36
import struct
32
37
from micropython import const
44
49
_AGS02MA_CRC8_POLYNOMIAL = const (0x31 )
45
50
46
51
47
- def _generate_crc (data ) :
52
+ def _generate_crc (data : int ) -> int :
48
53
"""8-bit CRC algorithm for checking data
49
54
50
- :param bytearray data: The data to generate a CRC for
55
+ :param int data: The data to generate a CRC for
51
56
"""
52
57
53
58
crc = _AGS02MA_CRC8_INIT
@@ -64,13 +69,47 @@ def _generate_crc(data):
64
69
65
70
66
71
class AGS02MA :
67
- """Driver for the AGS02MA air quality sensor
72
+ """Driver for the AGS02MA air quality sensor.
73
+
74
+ .. warning::
75
+ I2C communication rate cannot be higher than 30KHZ. Refer to
76
+ https://cdn-shop.adafruit.com/product-files/5593/datasheet+ags02ma.pdf
77
+ Section 3.
68
78
69
79
:param ~busio.I2C i2c_bus: The I2C bus the AGS02MA is connected to.
70
80
:param int address: The I2C device address. Defaults to :const:`0x1A`
81
+
82
+ :raises RunTimeError: When the sensor could not be found
83
+
84
+
85
+ **Quickstart: Importing and using the device**
86
+
87
+ Here is an example of using the :class:`AGS02MA` class.
88
+ First you will need to import the libraries to use the sensor
89
+
90
+ .. code-block:: python
91
+
92
+ import board
93
+ import busio
94
+ from adafruit_ags02ma import AGS02MA
95
+
96
+ Once this is done you can define your `busio.I2C` object and define your sensor object
97
+
98
+ .. code-block:: python
99
+
100
+ i2c = busio.I2C(board.SCL, board.SDA, frequency=20_000)
101
+ ags = AGS02MA(i2c, address=0x1A)
102
+
103
+ Now you have access to the :attr:`gas_resistance` and :attr:`TVOC` attributes
104
+
105
+ .. code-block:: python
106
+
107
+ res = ags.gas_resistance
108
+ tvoc = ags.TVOC
109
+
71
110
"""
72
111
73
- def __init__ (self , i2c_bus , address = AGS02MA_I2CADDR_DEFAULT ):
112
+ def __init__ (self , i2c_bus : I2C , address : int = AGS02MA_I2CADDR_DEFAULT ) -> None :
74
113
self .i2c_device = i2c_device .I2CDevice (i2c_bus , address )
75
114
76
115
self ._buf = bytearray (5 )
@@ -80,30 +119,40 @@ def __init__(self, i2c_bus, address=AGS02MA_I2CADDR_DEFAULT):
80
119
except RuntimeError as exc : # a CRC error or something!
81
120
raise RuntimeError ("Failed to find AGS02MA - check your wiring!" ) from exc
82
121
83
- def firmware_version (self ):
122
+ def firmware_version (self ) -> int :
84
123
"""Return 24-bit value which contains the firmware version"""
85
124
return self ._read_reg (_AGS02MA_VERSION_REG , 30 )
86
125
87
126
@property
88
- def gas_resistance (self ):
127
+ def gas_resistance (self ) -> int :
89
128
"""The resistance of the MEMS gas sensor"""
90
129
return self ._read_reg (_AGS02MA_GASRES_REG , 1500 ) * 100 # in 0.1Kohm
91
130
92
131
@property
93
- def TVOC (self ): # pylint: disable=invalid-name
94
- """The calculated Total Volatile Organic Compound measurement, in ppb"""
132
+ def TVOC (self ) -> int : # pylint: disable=invalid-name
133
+ """The calculated Total Volatile Organic Compound measurement, in ppb
134
+
135
+ :raises RunTimeError: When the sensor still preheating
136
+ """
95
137
val = self ._read_reg (_AGS02MA_TVOCSTAT_REG , 1500 )
96
138
status = val >> 24
97
- # print(hex(status))
139
+
98
140
if status & 0x1 :
99
141
raise RuntimeError ("Sensor still preheating" )
100
142
return val & 0xFFFFFF
101
143
102
- def set_address (self , new_addr ) :
144
+ def set_address (self , new_addr : int ) -> None :
103
145
"""Set the address for the I2C interface, from 0x0 to 0x7F
146
+ The sensor supports modifying the I2C address. After sending
147
+ this command, the new address will take effect immediately,
148
+ New address will remain after powering the sensor off.
104
149
105
- :param int new_addr: THe new address
150
+ :param int new_addr: The new address
151
+
152
+ :raises: ValueError: When selected address is not in the range 0x00-0x7F
106
153
"""
154
+ if new_addr not in range (1 , 128 ):
155
+ raise ValueError ("Selected address must be between 0x00 and 0x7F" )
107
156
108
157
_buf = bytearray (
109
158
[
@@ -119,21 +168,24 @@ def set_address(self, new_addr):
119
168
with self .i2c_device as i2c :
120
169
i2c .write (_buf )
121
170
122
- def _read_reg (self , addr , delayms ) :
171
+ def _read_reg (self , addr : int , delayms : int ) -> int :
123
172
"""Read a register
124
173
125
174
:param int addr: The address to read
126
175
:param int delayms: The delay between writes and reads, in milliseconds
176
+
177
+ :raises RunTimeError: When CRC check have failed.
178
+
127
179
"""
128
180
129
181
with self .i2c_device as i2c :
130
182
self ._addr [0 ] = addr
131
183
i2c .write (self ._addr )
132
184
time .sleep (delayms / 1000 )
133
185
i2c .readinto (self ._buf )
134
- # print([hex(x) for x in self._buf])
186
+
135
187
if _generate_crc (self ._buf ) != 0 :
136
188
raise RuntimeError ("CRC check failed" )
137
189
val , crc = struct .unpack (">IB" , self ._buf ) # pylint: disable=unused-variable
138
- # print(hex(val), hex(crc))
190
+
139
191
return val
0 commit comments