diff --git a/README.rst b/README.rst index 7511a0f..96f9c67 100644 --- a/README.rst +++ b/README.rst @@ -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 `_. To install for current user: @@ -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 ============ diff --git a/adafruit_sht4x.py b/adafruit_sht4x.py index a24581a..8b178c5 100644 --- a/adafruit_sht4x.py +++ b/adafruit_sht4x.py @@ -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 diff --git a/docs/conf.py b/docs/conf.py index 74786ce..3c650e1 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -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), } diff --git a/docs/index.rst b/docs/index.rst index 9237618..6455512 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -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 .. toctree:: :caption: Other Links diff --git a/examples/sht4x_simpletest.py b/examples/sht4x_simpletest.py index 0d4a377..3ae2572 100644 --- a/examples/sht4x_simpletest.py +++ b/examples/sht4x_simpletest.py @@ -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) diff --git a/setup.py b/setup.py index 3881f8c..69ef60a 100644 --- a/setup.py +++ b/setup.py @@ -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,