-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathaht.py
129 lines (111 loc) · 4.95 KB
/
aht.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
"""Driver for AHT2x sensors (humidity and temperature):
Models: AHT20 and AHT21
Adresse i2c: 56 (0x3b)
Official website of the manufacturer: http://www.aosong.com
"""
import time
from micropython import const
__author__ = "Jonathan Fromentin"
__credits__ = ["Jonathan Fromentin"]
__license__ = "CeCILL version 2.1"
__version__ = "2.0.0"
__maintainer__ = "Jonathan Fromentin"
AHT_I2C_ADDR = const(0x38) # Default I2C address
AHT_STATUS_BUSY = const(0x01) # Status bit for busy
AHT_STATUS_CALIBRATED = const(0x10) # status bit for calibrated
AHT_CMD_INIT = const(0xBE) # command for initialization
AHT_CMD_TRIGGER = const(0xAC) # command for trigger measurement
AHT_CMD_RESET = const(0xBA) # command for soft reset
AHT_CRC_POLYNOMIAL = const(0x31) # Polynomial representation
AHT_CRC_MSB = const(0x80) # Most significant bit
AHT_CRC_INIT = const(0xFF) # Initial value of CRC
class AHT2x:
"""Class based on AHT20 and AHT21 documentation."""
def __init__(self, i2c, address=AHT_I2C_ADDR, crc=False):
"""Parameters:
i2c: instance of machine.I2C
address: i2c address of sensor
crc: Boolean for CRC control. True to active the CRC control."""
time.sleep(0.04) # Wait 40ms after power-on.
self.i2c = i2c
self.address = address
self.active_crc = crc
self._buf = bytearray(6 + crc) # Request the CRC byte only if necessary
self.humidity = None
self.temperature = None
while not self.is_calibrated:
self._calibrate()
@property
def is_ready(self):
"""The sensor is busy until the measurement is complete."""
if bool(self._status() & AHT_STATUS_BUSY):
return False
return self._measure()
@property
def is_calibrated(self):
"""The activation of the calibration must be done before any
measurement. If not, do a soft reset."""
return bool(self._status() & AHT_STATUS_CALIBRATED)
def _status(self):
"""The status byte initially returned from the sensor.
Bit Definition Description
[0:2] Remained Remained
[3] CAL Enable 0:Uncalibrated,1:Calibrated
[4] Remained Remained
[5:6] Remained Remained
[7] Busy 0:Free in dormant state, 1:Busy in measurement"""
self.i2c.readfrom_into(self.address, self._buf)
if not self.active_crc or (self._crc8() == self._buf[6]):
return self._buf[0]
return AHT_STATUS_BUSY # Return the status busy and uncalibrated
def reset(self):
"""The soft reset command is used to restart the sensor system without
turning the power off and on again. After receiving this command, the
sensor system begins to re-initialize and restore the default setting
state"""
self._buf[0] = AHT_CMD_RESET
self.i2c.writeto(self.address, self._buf[:1])
time.sleep(0.02) # The time required for reset does not exceed 20 ms
# The soft reset is badly documented. It is therefore possible that it
# is necessary to calibrate the sensor after a soft reset.
while not self.is_calibrated:
self._calibrate()
def _calibrate(self):
"""Internal function to send initialization command.
Note: The calibration status check in the first step
only needs to be checked at power-on. No operation is
required during the normal acquisition process."""
self._buf[0] = AHT_CMD_INIT
self._buf[1] = 0x08
self._buf[2] = 0x00
self.i2c.writeto(self.address, self._buf[:3])
time.sleep(0.01) # Wait initialization process
def _crc8(self):
"""Internal function to calcule the CRC-8-Dallas/Maxim of current
message. The initial value of CRC is 0xFF, and the CRC8 check
polynomial is: CRC [7:0] = 1+X^4 +X^5 +X^8"""
crc = bytearray(1)
crc[0] = AHT_CRC_INIT
for byte in self._buf[:6]:
crc[0] ^= byte
for _ in range(8):
if crc[0] & AHT_CRC_MSB:
crc[0] = (crc[0] << 1) ^ AHT_CRC_POLYNOMIAL
else:
crc[0] = crc[0] << 1
return crc[0]
def _measure(self):
"""Internal function for triggering the AHT to read temp/humidity"""
self._buf[0] = AHT_CMD_TRIGGER
self._buf[1] = 0x33
self._buf[2] = 0x00
self.i2c.writeto(self.address, self._buf[:3])
time.sleep(0.08) # Wait 80ms for the measurement to be completed.
self.i2c.readfrom_into(self.address, self._buf)
if not self.active_crc or (self._crc8() == self._buf[6]):
hum = self._buf[1] << 12 | self._buf[2] << 4 | self._buf[3] >> 4
self.humidity = hum * 100 / 0x100000
temp = (self._buf[3] & 0xF) << 16 | self._buf[4] << 8 | self._buf[5]
self.temperature = temp * 200.0 / 0x100000 - 50
return True
return False