from time import sleep from typing import Dict, Final from minimalmodbus import NoResponseError from .generic import ModbusRTUDevice class SensorWiredIAQ(ModbusRTUDevice): """ Wired sensor measuring temperature, relative humidity, carbon dioxide and VOC, optionally particulate matter """ IDENTIFIER: int = 0xBEEF input_registers: Dict[str, int] = { 'T': 30003, # deg C 'T_F': 30004, # deg F 'RH': 30005, # %, from SHT4x 'CO2': 30006, # ppm 'VOC_INDEX': 30007, # VOC index as calculated by Sensirion library (1 to 500, average 100) 'VOC_TICKS': 30008, # raw VOC ticks 'PMC_MASS_1_0': 30009, # ug / m^3 'PMC_MASS_2_5': 30010, # ug / m^3 'PMC_MASS_4_0': 30011, # ug / m^3 'PMC_MASS_10_0': 30012, # ug / m^3 'PMC_NUMBER_0_5': 30013, # 1 / m^3 'PMC_NUMBER_1_0': 30014, # 1 / m^3 'PMC_NUMBER_2_5': 30015, # 1 / m^3 'PMC_NUMBER_4_0': 30016, # 1 / m^3 'PMC_NUMBER_10_0': 30017, # 1 / m^3 'TYPICAL_PARTICLE_SIZE': 30018, # nm 'T_SCD4x': 30019, # deg C 'T_SCD4x_F': 30020, # deg F 'RH_SCD4x': 30021 # % } | ModbusRTUDevice.input_registers # TODO use super, but __class__ not defined holding_registers: Dict[str, int] = { 'MODBUS_ADDR': 40001, 'BAUDRATE': 40002, 'LED_ON': 40003, 'LED_BRIGHTNESS': 40004, 'LED_SMOOTH': 40005, 'CO2_ALERT_LIMIT1': 40006, 'CO2_ALERT_LIMIT2': 40007, 'SCD4x_T_OFFSET': 40008 } | ModbusRTUDevice.holding_registers RESET_MAGIC_NUMBER: Final[int] = 0xABCD @property def CO2(self) -> int: return int(self.read_register(self.input_registers["CO2"])) @property def T(self) -> float: # TODO maybe use signed version? return self.read_register(self.input_registers["T"], signed=True) / 10 @property def RH(self) -> float: return self.read_register(self.input_registers["RH"]) @property def LED(self) -> int: return int(self.read_register(self.holding_registers["LED_brightness"])) @LED.setter def LED(self, value: int): if value == 0: self.write_register(self.holding_registers["LED_on"], 0) else: self.write_register(self.holding_registers["LED_brightness"], value) sleep(0.1) self.write_register(self.holding_registers["LED_on"], 1)