diff --git a/scd4x.py b/scd4x.py index f4fc409..aa37227 100644 --- a/scd4x.py +++ b/scd4x.py @@ -4,8 +4,8 @@ # # SPDX-License-Identifier: MIT # -# this version: also Copyright (c) 2022-2024 peter-l5 -# build version: v103 +# this version: also Copyright (c) 2022-2026 peter-l5, khaylenko +# build version: v107 """ `micropython_scd4x` @@ -14,7 +14,7 @@ Driver for Sensirion SCD4X CO2 sensor -* Author(s): ladyada, peter-l5 +* Author(s): ladyada, peter-l5, khaylenko Implementation Notes -------------------- @@ -34,7 +34,7 @@ from micropython import const import struct -__version__ = "v103" +__version__ = "v107" __repo__ = "https://github.com/peter-l5/MicroPython_SCD4X" SCD4X_DEFAULT_ADDR = 0x62 @@ -56,6 +56,7 @@ _SCD4X_PERSISTSETTINGS = const(0x3615) _SCD4X_GETASCE = const(0x2313) _SCD4X_SETASCE = const(0x2416) +_SCD4X_SENSORVARIANT = const(0x202F) class SCD4X: @@ -94,12 +95,13 @@ class SCD4X: """ - def __init__(self, i2c_bus: I2C, address: int = SCD4X_DEFAULT_ADDR) -> None: - print("__init__ :", dir()) - print("address : %x" % address) - print("i2c_bus : ", i2c_bus) + def __init__(self, i2c_bus: I2C, address: int = SCD4X_DEFAULT_ADDR, debug_info: bool = True) -> None: + if debug_info: + print("__init__ :", dir()) + print("address : %x" % address) + print("i2c_bus : ", i2c_bus) + print(i2c_bus) self.address = address - print(i2c_bus) self.i2c_device = i2c_bus self._buffer = bytearray(18) self._cmd = bytearray(2) @@ -191,14 +193,27 @@ def self_calibration_enabled(self) -> bool: def self_calibration_enabled(self, enabled: bool) -> None: self._set_command_value(_SCD4X_SETASCE, enabled) - def self_test(self) -> None: + def self_test(self) -> dict: """Performs a self test, takes up to 10 seconds""" self.stop_periodic_measurement() self._send_command(_SCD4X_SELFTEST, cmd_delay=10) self._read_reply(self._buffer, 3) - if (self._buffer[0] != 0) or (self._buffer[1] != 0): - raise RuntimeError("Self test failed") - + + code = (self._buffer[0] << 8) | self._buffer[1] + + if code == 0: + result = 'Test passed' + elif code == 512: + result = 'Sensor Element Failure' + elif code == 1024: + result = 'Heater Failure' + elif code == 2048: + result = 'Measurement Circuit / Out of Range' + else: + result = 'Unknown' + + return {'result': result, 'code': code} + def _read_data(self) -> None: """Reads the temp/hum/co2 from the sensor and caches it""" self._send_command(_SCD4X_READMEASUREMENT, cmd_delay=0.001) @@ -217,18 +232,36 @@ def data_ready(self) -> bool: return not ((self._buffer[0] & 0x07 == 0) and (self._buffer[1] == 0)) @property - def serial_number(self) -> Tuple[int, int, int, int, int, int]: - """Request a 6-tuple containing the unique serial number for this sensor""" + def serial_number(self) -> int: + """Request the unique serial number for this sensor.""" self._send_command(_SCD4X_SERIALNUMBER, cmd_delay=0.001) self._read_reply(self._buffer, 9) - return ( - self._buffer[0], - self._buffer[1], - self._buffer[3], - self._buffer[4], - self._buffer[6], - self._buffer[7], - ) + + word0 = (self._buffer[0] << 8) | self._buffer[1] + word1 = (self._buffer[3] << 8) | self._buffer[4] + word2 = (self._buffer[6] << 8) | self._buffer[7] + + return word0 << 32 | word1 << 16 | word2 + + @property + def sensor_variant(self) -> dict: + """Request a string containing the sensor variant""" + self._send_command(_SCD4X_SENSORVARIANT, cmd_delay=0.001) + self._read_reply(self._buffer, 3) + + raw = (self._buffer[0] << 8) | self._buffer[1] + extracted = (raw & 0xF000) >> 12 + + if extracted == 0: + variant = 'SCD40' + elif extracted == 1: + variant = 'SCD41' + elif extracted == 5: + variant = 'SCD43' + else: + variant = 'Unknown' + + return {'variant': variant, 'raw': raw} def stop_periodic_measurement(self) -> None: """Stop measurement mode"""