Skip to content

Working code library for SHT4x #1

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Jan 18, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 23 additions & 6 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,6 @@ This is easily achieved by downloading

Installing from PyPI
=====================
.. note:: This library is not available on PyPI yet. Install documentation is included
as a standard element. Stay tuned for PyPI availability!

.. todo:: Remove the above note if PyPI version is/will be available at time of release.
If the library is not planned for PyPI, remove the entire 'Installing from PyPI' section.

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

.. todo:: Add a quick, simple example. It and other examples should live in the examples folder and be included in docs/examples.rst.
.. code-block:: python

import time
import busio
import board
import adafruit_sht4x

i2c = busio.I2C(board.SCL, board.SDA)
sht = adafruit_sht4x.SHT4x(i2c)
print("Found SHT4x with serial number", hex(sht.serial_number))

sht.mode = adafruit_sht4x.Mode.NOHEAT_HIGHPRECISION
# Can also set the mode to enable heater
# sht.mode = adafruit_sht4x.Mode.LOWHEAT_100MS
print("Current mode is: ", adafruit_sht4x.Mode.string[sht.mode])

while True:
temperature, relative_humidity = sht.measurements
print("Temperature: %0.1f C" % temperature)
print("Humidity: %0.1f %%" % relative_humidity)
print("")
time.sleep(1)


Contributing
============
Expand Down
172 changes: 171 additions & 1 deletion adafruit_sht4x.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,177 @@

"""

# imports
import time
import struct
import adafruit_bus_device.i2c_device as i2c_device
from micropython import const

__version__ = "0.0.0-auto.0"
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_SHT4x.git"


_SHT4X_DEFAULT_ADDR = const(0x44) # SHT4X I2C Address
_SHT4X_READSERIAL = const(0x89) # Read Out of Serial Register
_SHT4X_SOFTRESET = const(0x94) # Soft Reset


class CV:
"""struct helper"""

@classmethod
def add_values(cls, value_tuples):
"""Add CV values to the class"""
cls.string = {}
cls.delay = {}

for value_tuple in value_tuples:
name, value, string, delay = value_tuple
setattr(cls, name, value)
cls.string[value] = string
cls.delay[value] = delay

@classmethod
def is_valid(cls, value):
"""Validate that a given value is a member"""
return value in cls.string


class Mode(CV):
"""Options for ``power_mode``"""

pass # pylint: disable=unnecessary-pass


Mode.add_values(
(
("NOHEAT_HIGHPRECISION", 0xFD, "No heater, high precision", 0.01),
("NOHEAT_MEDPRECISION", 0xF6, "No heater, med precision", 0.005),
("NOHEAT_LOWPRECISION", 0xE0, "No heater, low precision", 0.002),
("HIGHHEAT_1S", 0x39, "High heat, 1 second", 1.1),
("HIGHHEAT_100MS", 0x32, "High heat, 0.1 second", 0.11),
("MEDHEAT_1S", 0x2F, "Med heat, 1 second", 1.1),
("MEDHEAT_100MS", 0x24, "Med heat, 0.1 second", 0.11),
("LOWHEAT_1S", 0x1E, "Low heat, 1 second", 1.1),
("LOWHEAT_100MS", 0x15, "Low heat, 0.1 second", 0.11),
)
)


class SHT4x:
"""
A driver for the SHT4x temperature and humidity sensor.

:param ~busio.I2C i2c_bus: The `busio.I2C` object to use. This is the only required parameter.

"""

def __init__(self, i2c_bus):
self.i2c_device = i2c_device.I2CDevice(i2c_bus, _SHT4X_DEFAULT_ADDR)
self._buffer = bytearray(6)
self.reset()
self._mode = Mode.NOHEAT_HIGHPRECISION # pylint: disable=no-member

@property
def serial_number(self):
"""The unique 32-bit serial number"""
self._buffer[0] = _SHT4X_READSERIAL
with self.i2c_device as i2c:
i2c.write(self._buffer, end=1)
time.sleep(0.01)
i2c.readinto(self._buffer)

ser1 = self._buffer[0:2]
ser1_crc = self._buffer[2]
ser2 = self._buffer[3:5]
ser2_crc = self._buffer[5]

# check CRC of bytes
if ser1_crc != self._crc8(ser1) or ser2_crc != self._crc8(ser2):
raise RuntimeError("Invalid CRC calculated")

serial = (ser1[0] << 24) + (ser1[1] << 16) + (ser2[0] << 8) + ser2[1]
return serial

def reset(self):
"""Perform a soft reset of the sensor, resetting all settings to their power-on defaults"""
self._buffer[0] = _SHT4X_SOFTRESET
with self.i2c_device as i2c:
i2c.write(self._buffer, end=1)
time.sleep(0.001)

@property
def mode(self):
"""The current sensor reading mode (heater and precision)"""
return self._mode

@mode.setter
def mode(self, new_mode):
print(new_mode)
if not Mode.is_valid(new_mode):
raise AttributeError("mode must be a Mode")
self._mode = new_mode

@property
def relative_humidity(self):
"""The current relative humidity in % rH"""
return self.measurements[1]

@property
def temperature(self):
"""The current temperature in degrees celsius"""
return self.measurements[0]

@property
def measurements(self):
"""both `temperature` and `relative_humidity`, read simultaneously"""

temperature = None
humidity = None
command = self._mode

with self.i2c_device as i2c:
self._buffer[0] = command
i2c.write(self._buffer, end=1)
time.sleep(Mode.delay[self._mode])
i2c.readinto(self._buffer)

# separate the read data
temp_data = self._buffer[0:2]
temp_crc = self._buffer[2]
humidity_data = self._buffer[3:5]
humidity_crc = self._buffer[5]

# check CRC of bytes
if temp_crc != self._crc8(temp_data) or humidity_crc != self._crc8(
humidity_data
):
raise RuntimeError("Invalid CRC calculated")

# decode data into human values:
# convert bytes into 16-bit signed integer
# convert the LSB value to a human value according to the datasheet
temperature = struct.unpack_from(">H", temp_data)[0]
temperature = -45.0 + 175.0 * temperature / 65535.0

# repeat above steps for humidity data
humidity = struct.unpack_from(">H", humidity_data)[0]
humidity = -6.0 + 125.0 * humidity / 65535.0
humidity = max(min(humidity, 100), 0)

return (temperature, humidity)

## CRC-8 formula from page 14 of SHTC3 datasheet
# https://media.digikey.com/pdf/Data%20Sheets/Sensirion%20PDFs/HT_DS_SHTC3_D1.pdf
# Test data [0xBE, 0xEF] should yield 0x92

@staticmethod
def _crc8(buffer):
crc = 0xFF
for byte in buffer:
crc ^= byte
for _ in range(8):
if crc & 0x80:
crc = (crc << 1) ^ 0x31
else:
crc = crc << 1
return crc & 0xFF # return the bottom 8 bits
7 changes: 5 additions & 2 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,11 @@


intersphinx_mapping = {
"python": ("https://docs.python.org/3.4", None),"BusDevice": ("https://circuitpython.readthedocs.io/projects/busdevice/en/latest/", None),

"python": ("https://docs.python.org/3.4", None),
"BusDevice": (
"https://circuitpython.readthedocs.io/projects/busdevice/en/latest/",
None,
),
"CircuitPython": ("https://circuitpython.readthedocs.io/en/latest/", None),
}

Expand Down
6 changes: 1 addition & 5 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,10 @@ Table of Contents
.. toctree::
:caption: Tutorials

.. todo:: Add any Learn guide links here. If there are none, then simply delete this todo and leave
the toctree above for use later.

.. toctree::
:caption: Related Products

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

.. toctree::
:caption: Other Links
Expand Down
25 changes: 23 additions & 2 deletions examples/sht4x_simpletest.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,24 @@
# SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries
# SPDX-FileCopyrightText: Copyright (c) 2020 ladyada for Adafruit Industries
#
# SPDX-License-Identifier: Unlicense
# SPDX-License-Identifier: MIT

import time
import busio
import board
import adafruit_sht4x

i2c = busio.I2C(board.SCL, board.SDA)
sht = adafruit_sht4x.SHT4x(i2c)
print("Found SHT4x with serial number", hex(sht.serial_number))

sht.mode = adafruit_sht4x.Mode.NOHEAT_HIGHPRECISION
# Can also set the mode to enable heater
# sht.mode = adafruit_sht4x.Mode.LOWHEAT_100MS
print("Current mode is: ", adafruit_sht4x.Mode.string[sht.mode])

while True:
temperature, relative_humidity = sht.measurements
print("Temperature: %0.1f C" % temperature)
print("Humidity: %0.1f %%" % relative_humidity)
print("")
time.sleep(1)
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@
],
# What does your project relate to?
keywords="adafruit blinka circuitpython micropython sht4x temperature humidity sensor "
"sht40 sensirion",
"sht40 sensirion",
# You can just specify the packages manually here if your project is
# simple. Or you can use find_packages().
# TODO: IF LIBRARY FILES ARE A PACKAGE FOLDER,
Expand Down