Skip to content

Commit fe91231

Browse files
authored
Merge pull request #1 from ladyada/master
Working code library for SHT4x
2 parents 8f5e77a + fd8b7e6 commit fe91231

File tree

6 files changed

+224
-17
lines changed

6 files changed

+224
-17
lines changed

README.rst

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,6 @@ This is easily achieved by downloading
3333

3434
Installing from PyPI
3535
=====================
36-
.. note:: This library is not available on PyPI yet. Install documentation is included
37-
as a standard element. Stay tuned for PyPI availability!
38-
39-
.. todo:: Remove the above note if PyPI version is/will be available at time of release.
40-
If the library is not planned for PyPI, remove the entire 'Installing from PyPI' section.
4136

4237
On supported GNU/Linux systems like the Raspberry Pi, you can install the driver locally `from
4338
PyPI <https://pypi.org/project/adafruit-circuitpython-sht4x/>`_. To install for current user:
@@ -64,7 +59,29 @@ To install in a virtual environment in your current project:
6459
Usage Example
6560
=============
6661

67-
.. todo:: Add a quick, simple example. It and other examples should live in the examples folder and be included in docs/examples.rst.
62+
.. code-block:: python
63+
64+
import time
65+
import busio
66+
import board
67+
import adafruit_sht4x
68+
69+
i2c = busio.I2C(board.SCL, board.SDA)
70+
sht = adafruit_sht4x.SHT4x(i2c)
71+
print("Found SHT4x with serial number", hex(sht.serial_number))
72+
73+
sht.mode = adafruit_sht4x.Mode.NOHEAT_HIGHPRECISION
74+
# Can also set the mode to enable heater
75+
# sht.mode = adafruit_sht4x.Mode.LOWHEAT_100MS
76+
print("Current mode is: ", adafruit_sht4x.Mode.string[sht.mode])
77+
78+
while True:
79+
temperature, relative_humidity = sht.measurements
80+
print("Temperature: %0.1f C" % temperature)
81+
print("Humidity: %0.1f %%" % relative_humidity)
82+
print("")
83+
time.sleep(1)
84+
6885
6986
Contributing
7087
============

adafruit_sht4x.py

Lines changed: 171 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,177 @@
2626
2727
"""
2828

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

3134
__version__ = "0.0.0-auto.0"
3235
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_SHT4x.git"
36+
37+
38+
_SHT4X_DEFAULT_ADDR = const(0x44) # SHT4X I2C Address
39+
_SHT4X_READSERIAL = const(0x89) # Read Out of Serial Register
40+
_SHT4X_SOFTRESET = const(0x94) # Soft Reset
41+
42+
43+
class CV:
44+
"""struct helper"""
45+
46+
@classmethod
47+
def add_values(cls, value_tuples):
48+
"""Add CV values to the class"""
49+
cls.string = {}
50+
cls.delay = {}
51+
52+
for value_tuple in value_tuples:
53+
name, value, string, delay = value_tuple
54+
setattr(cls, name, value)
55+
cls.string[value] = string
56+
cls.delay[value] = delay
57+
58+
@classmethod
59+
def is_valid(cls, value):
60+
"""Validate that a given value is a member"""
61+
return value in cls.string
62+
63+
64+
class Mode(CV):
65+
"""Options for ``power_mode``"""
66+
67+
pass # pylint: disable=unnecessary-pass
68+
69+
70+
Mode.add_values(
71+
(
72+
("NOHEAT_HIGHPRECISION", 0xFD, "No heater, high precision", 0.01),
73+
("NOHEAT_MEDPRECISION", 0xF6, "No heater, med precision", 0.005),
74+
("NOHEAT_LOWPRECISION", 0xE0, "No heater, low precision", 0.002),
75+
("HIGHHEAT_1S", 0x39, "High heat, 1 second", 1.1),
76+
("HIGHHEAT_100MS", 0x32, "High heat, 0.1 second", 0.11),
77+
("MEDHEAT_1S", 0x2F, "Med heat, 1 second", 1.1),
78+
("MEDHEAT_100MS", 0x24, "Med heat, 0.1 second", 0.11),
79+
("LOWHEAT_1S", 0x1E, "Low heat, 1 second", 1.1),
80+
("LOWHEAT_100MS", 0x15, "Low heat, 0.1 second", 0.11),
81+
)
82+
)
83+
84+
85+
class SHT4x:
86+
"""
87+
A driver for the SHT4x temperature and humidity sensor.
88+
89+
:param ~busio.I2C i2c_bus: The `busio.I2C` object to use. This is the only required parameter.
90+
91+
"""
92+
93+
def __init__(self, i2c_bus):
94+
self.i2c_device = i2c_device.I2CDevice(i2c_bus, _SHT4X_DEFAULT_ADDR)
95+
self._buffer = bytearray(6)
96+
self.reset()
97+
self._mode = Mode.NOHEAT_HIGHPRECISION # pylint: disable=no-member
98+
99+
@property
100+
def serial_number(self):
101+
"""The unique 32-bit serial number"""
102+
self._buffer[0] = _SHT4X_READSERIAL
103+
with self.i2c_device as i2c:
104+
i2c.write(self._buffer, end=1)
105+
time.sleep(0.01)
106+
i2c.readinto(self._buffer)
107+
108+
ser1 = self._buffer[0:2]
109+
ser1_crc = self._buffer[2]
110+
ser2 = self._buffer[3:5]
111+
ser2_crc = self._buffer[5]
112+
113+
# check CRC of bytes
114+
if ser1_crc != self._crc8(ser1) or ser2_crc != self._crc8(ser2):
115+
raise RuntimeError("Invalid CRC calculated")
116+
117+
serial = (ser1[0] << 24) + (ser1[1] << 16) + (ser2[0] << 8) + ser2[1]
118+
return serial
119+
120+
def reset(self):
121+
"""Perform a soft reset of the sensor, resetting all settings to their power-on defaults"""
122+
self._buffer[0] = _SHT4X_SOFTRESET
123+
with self.i2c_device as i2c:
124+
i2c.write(self._buffer, end=1)
125+
time.sleep(0.001)
126+
127+
@property
128+
def mode(self):
129+
"""The current sensor reading mode (heater and precision)"""
130+
return self._mode
131+
132+
@mode.setter
133+
def mode(self, new_mode):
134+
print(new_mode)
135+
if not Mode.is_valid(new_mode):
136+
raise AttributeError("mode must be a Mode")
137+
self._mode = new_mode
138+
139+
@property
140+
def relative_humidity(self):
141+
"""The current relative humidity in % rH"""
142+
return self.measurements[1]
143+
144+
@property
145+
def temperature(self):
146+
"""The current temperature in degrees celsius"""
147+
return self.measurements[0]
148+
149+
@property
150+
def measurements(self):
151+
"""both `temperature` and `relative_humidity`, read simultaneously"""
152+
153+
temperature = None
154+
humidity = None
155+
command = self._mode
156+
157+
with self.i2c_device as i2c:
158+
self._buffer[0] = command
159+
i2c.write(self._buffer, end=1)
160+
time.sleep(Mode.delay[self._mode])
161+
i2c.readinto(self._buffer)
162+
163+
# separate the read data
164+
temp_data = self._buffer[0:2]
165+
temp_crc = self._buffer[2]
166+
humidity_data = self._buffer[3:5]
167+
humidity_crc = self._buffer[5]
168+
169+
# check CRC of bytes
170+
if temp_crc != self._crc8(temp_data) or humidity_crc != self._crc8(
171+
humidity_data
172+
):
173+
raise RuntimeError("Invalid CRC calculated")
174+
175+
# decode data into human values:
176+
# convert bytes into 16-bit signed integer
177+
# convert the LSB value to a human value according to the datasheet
178+
temperature = struct.unpack_from(">H", temp_data)[0]
179+
temperature = -45.0 + 175.0 * temperature / 65535.0
180+
181+
# repeat above steps for humidity data
182+
humidity = struct.unpack_from(">H", humidity_data)[0]
183+
humidity = -6.0 + 125.0 * humidity / 65535.0
184+
humidity = max(min(humidity, 100), 0)
185+
186+
return (temperature, humidity)
187+
188+
## CRC-8 formula from page 14 of SHTC3 datasheet
189+
# https://media.digikey.com/pdf/Data%20Sheets/Sensirion%20PDFs/HT_DS_SHTC3_D1.pdf
190+
# Test data [0xBE, 0xEF] should yield 0x92
191+
192+
@staticmethod
193+
def _crc8(buffer):
194+
crc = 0xFF
195+
for byte in buffer:
196+
crc ^= byte
197+
for _ in range(8):
198+
if crc & 0x80:
199+
crc = (crc << 1) ^ 0x31
200+
else:
201+
crc = crc << 1
202+
return crc & 0xFF # return the bottom 8 bits

docs/conf.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,11 @@
2929

3030

3131
intersphinx_mapping = {
32-
"python": ("https://docs.python.org/3.4", None),"BusDevice": ("https://circuitpython.readthedocs.io/projects/busdevice/en/latest/", None),
33-
32+
"python": ("https://docs.python.org/3.4", None),
33+
"BusDevice": (
34+
"https://circuitpython.readthedocs.io/projects/busdevice/en/latest/",
35+
None,
36+
),
3437
"CircuitPython": ("https://circuitpython.readthedocs.io/en/latest/", None),
3538
}
3639

docs/index.rst

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,10 @@ Table of Contents
2323
.. toctree::
2424
:caption: Tutorials
2525

26-
.. todo:: Add any Learn guide links here. If there are none, then simply delete this todo and leave
27-
the toctree above for use later.
28-
2926
.. toctree::
3027
:caption: Related Products
3128

32-
.. todo:: Add any product links here. If there are none, then simply delete this todo and leave
33-
the toctree above for use later.
29+
Purchase SHT40 breakout <https://www.adafruit.com/products/4885>
3430

3531
.. toctree::
3632
:caption: Other Links

examples/sht4x_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_sht4x
9+
10+
i2c = busio.I2C(board.SCL, board.SDA)
11+
sht = adafruit_sht4x.SHT4x(i2c)
12+
print("Found SHT4x with serial number", hex(sht.serial_number))
13+
14+
sht.mode = adafruit_sht4x.Mode.NOHEAT_HIGHPRECISION
15+
# Can also set the mode to enable heater
16+
# sht.mode = adafruit_sht4x.Mode.LOWHEAT_100MS
17+
print("Current mode is: ", adafruit_sht4x.Mode.string[sht.mode])
18+
19+
while True:
20+
temperature, relative_humidity = sht.measurements
21+
print("Temperature: %0.1f C" % temperature)
22+
print("Humidity: %0.1f %%" % relative_humidity)
23+
print("")
24+
time.sleep(1)

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@
5353
],
5454
# What does your project relate to?
5555
keywords="adafruit blinka circuitpython micropython sht4x temperature humidity sensor "
56-
"sht40 sensirion",
56+
"sht40 sensirion",
5757
# You can just specify the packages manually here if your project is
5858
# simple. Or you can use find_packages().
5959
# TODO: IF LIBRARY FILES ARE A PACKAGE FOLDER,

0 commit comments

Comments
 (0)