Skip to content

Commit a512ac1

Browse files
committed
working library & example
1 parent df552f0 commit a512ac1

File tree

2 files changed

+151
-3
lines changed

2 files changed

+151
-3
lines changed

adafruit_htu31d.py

Lines changed: 128 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,134 @@
2727
2828
"""
2929

30-
# imports
30+
import time
31+
import struct
32+
import adafruit_bus_device.i2c_device as i2c_device
33+
from micropython import const
3134

3235
__version__ = "0.0.0-auto.0"
3336
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_HTU31D.git"
37+
38+
_HTU31D_DEFAULT_ADDR = const(0x40) # HTU31D default I2C Address
39+
40+
_HTU31D_READSERIAL = const(0x0A) # Read Out of Serial Register
41+
_HTU31D_SOFTRESET = const(0x1E) # Soft Reset
42+
_HTU31D_HEATERON = const(0x04) # Enable heater
43+
_HTU31D_HEATEROFF = const(0x02) # Disable heater
44+
_HTU31D_CONVERSION = const(0x40) # Start a conversion
45+
_HTU31D_READTEMPHUM = const(0x00) # Read the conversion values
46+
47+
class HTU31D:
48+
"""
49+
A driver for the HTU31D temperature and humidity sensor.
50+
51+
:param ~busio.I2C i2c_bus: The `busio.I2C` object to use. This is the only required parameter.
52+
53+
"""
54+
55+
def __init__(self, i2c_bus):
56+
self.i2c_device = i2c_device.I2CDevice(i2c_bus, _HTU31D_DEFAULT_ADDR)
57+
self._buffer = bytearray(6)
58+
self.reset()
59+
60+
@property
61+
def serial_number(self):
62+
"""The unique 32-bit serial number"""
63+
self._buffer[0] = _HTU31D_READSERIAL
64+
with self.i2c_device as i2c:
65+
i2c.write_then_readinto(self._buffer, self._buffer, out_end=1, in_end=4)
66+
ser = struct.unpack(">I", self._buffer[0:4])
67+
return ser
68+
69+
def reset(self):
70+
"""Perform a soft reset of the sensor, resetting all settings to their power-on defaults"""
71+
self._buffer[0] = _HTU31D_SOFTRESET
72+
with self.i2c_device as i2c:
73+
i2c.write(self._buffer, end=1)
74+
time.sleep(0.015)
75+
76+
@property
77+
def heater(self):
78+
"""The current sensor heater mode"""
79+
return self._heater
80+
81+
@heater.setter
82+
def heater(self, new_mode):
83+
# check its a boolean
84+
if (new_mode != True) and (new_mode != False):
85+
raise AttributeError("Heater mode must be boolean")
86+
# cache the mode
87+
self._heater = new_mode
88+
# decide the command!
89+
if new_mode:
90+
self._buffer[0] = _HTU31D_HEATERON
91+
else:
92+
self._buffer[0] = _HTU31D_HEATEROFF
93+
with self.i2c_device as i2c:
94+
i2c.write(self._buffer, end=1)
95+
96+
@property
97+
def relative_humidity(self):
98+
"""The current relative humidity in % rH"""
99+
return self.measurements[1]
100+
101+
@property
102+
def temperature(self):
103+
"""The current temperature in degrees celsius"""
104+
return self.measurements[0]
105+
106+
@property
107+
def measurements(self):
108+
"""both `temperature` and `relative_humidity`, read simultaneously"""
109+
110+
temperature = None
111+
humidity = None
112+
113+
self._buffer[0] = _HTU31D_CONVERSION
114+
with self.i2c_device as i2c:
115+
i2c.write(self._buffer, end=1)
116+
117+
# wait conversion time
118+
time.sleep(0.02)
119+
120+
self._buffer[0] = _HTU31D_READTEMPHUM
121+
with self.i2c_device as i2c:
122+
i2c.write_then_readinto(self._buffer, self._buffer, out_end=1)
123+
124+
# separate the read data
125+
temperature, temp_crc, humidity, humidity_crc = struct.unpack_from(">HBHB", self._buffer)
126+
127+
# check CRC of bytes
128+
if temp_crc != self._crc(temperature) or humidity_crc != self._crc(
129+
humidity
130+
):
131+
raise RuntimeError("Invalid CRC calculated")
132+
133+
# decode data into human values:
134+
# convert bytes into 16-bit signed integer
135+
# convert the LSB value to a human value according to the datasheet
136+
temperature = -45.0 + 175.0 * temperature / 65535.0
137+
138+
# repeat above steps for humidity data
139+
humidity = -6.0 + 125.0 * humidity / 65535.0
140+
humidity = max(min(humidity, 100), 0)
141+
142+
return (temperature, humidity)
143+
144+
@staticmethod
145+
def _crc(value):
146+
polynom = 0x988000 # x^8 + x^5 + x^4 + 1
147+
msb = 0x800000
148+
mask = 0xFF8000
149+
result = value << 8 # Pad with zeros as specified in spec
150+
151+
while msb != 0x80:
152+
# Check if msb of current value is 1 and apply XOR mask
153+
if result & msb:
154+
result = ((result ^ polynom) & mask) | (result & ~mask)
155+
# Shift by one
156+
msb >>= 1
157+
mask >>= 1
158+
polynom >>= 1
159+
160+
return result

examples/htu31d_simpletest.py

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,24 @@
1-
# SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries
1+
# SPDX-FileCopyrightText: Copyright (c) 2020 ladyada for Adafruit Industries
22
#
3-
# SPDX-License-Identifier: Unlicense
3+
# SPDX-License-Identifier: MIT
4+
5+
import time
6+
import busio
7+
import board
8+
import adafruit_htu31d
9+
10+
i2c = busio.I2C(board.SCL, board.SDA)
11+
htu = adafruit_htu31d.HTU31D(i2c)
12+
print("Found HTU31D with serial number", hex(htu.serial_number))
13+
14+
htu.heater = True
15+
print("Heater is on?", htu.heater)
16+
htu.heater = False
17+
print("Heater is on?", htu.heater)
18+
19+
while True:
20+
temperature, relative_humidity = htu.measurements
21+
print("Temperature: %0.1f C" % temperature)
22+
print("Humidity: %0.1f %%" % relative_humidity)
23+
print("")
24+
time.sleep(1)

0 commit comments

Comments
 (0)