SHT4X
/
sht4xmod.py
152 строки · 7.8 Кб
1"""SHT4x Sensirion module"""
2import time3
4from sensor_pack_2 import bus_service5from sensor_pack_2.base_sensor import BaseSensorEx, IBaseSensorEx, check_value6from sensor_pack_2.crc_mod import crc87
8def _calc_crc(sequence) -> int:9"""Обертка для короткого вызова."""10return crc8(sequence, polynomial=0x31, init_value=0xFF)11
12class SHT4xSensirion(BaseSensorEx, IBaseSensorEx):13"""Class for work with Sensirion SHT4x sensor"""14cmd_get_id = 0x8915cmd_soft_reset = 0x9416magic = -1 + 2 ** 1617
18def __init__(self, adapter: bus_service.BusAdapter, address=0x44, check_crc: bool = True):19"""Если check_crc в Истина, то каждый, принятый от датчика пакет данных, проверяется на правильность путем20расчета контрольной суммы."""
21check_value(address, range(0x44, 0x47), f"Неверный адрес устройства: {address}")22super().__init__(adapter, address, True)23self._check_crc = check_crc24self._last_cmd_code = None25#26self._with_heater = None27self._value = None28self._long_pulse = None29#30self._buf_1 = bytearray(1)31self._buf_6 = bytearray(6)32
33#@staticmethod34#def get_answer_len(command_code: int) -> int:35# """Возвращает количество байт в ответе датчика"""36# if SHT4xSensirion.cmd_soft_reset == command_code:37# return 038# return 639
40def get_last_cmd_code(self) -> int:41"""Возвращает последний код команды, переданный по шине данных в датчик"""42return self._last_cmd_code43
44def _send_command(self, command_code: int):45"""Передает команду датчику по шине"""46check_value(command_code, range(0x100), f"Неверный код команды: {command_code}")47_local = self._buf_148_local[0] = command_code49self.write(_local)50self._last_cmd_code = command_code51
52def _read_answer(self) -> [bytes, None]:53"""Читает ответ на команду, переданную методом _send_command.54Возвращает ссылку на буфер с принятыми данными.
55Проверяет CRC"""
56_cmd = self.get_last_cmd_code()57if SHT4xSensirion.cmd_soft_reset == _cmd:58return None59_buf = self._buf_660self.read_to_buf(_buf)61# ответ считан62if self._check_crc:63crc_from_buf = [_buf[i] for i in (2, 5)] # список со значениями CRC64calculated_crc = [_calc_crc(_buf[rng.start:rng.stop]) for rng in (range(2), range(3, 5))]65if crc_from_buf != calculated_crc:66raise ValueError(f"Неверная CRC! Вычислено: {calculated_crc}. Из буфера: {crc_from_buf};")67return _buf68
69def get_id(self) -> tuple[int, int]:70_cmd = SHT4xSensirion.cmd_get_id71self._send_command(_cmd)72# этот 'чудо-датчик' не может сразу отдать прошитый в нем номер! Приходится вызывать sleep_us!73time.sleep_us(110)74_buf = self._read_answer()75t = self.unpack("HBH", _buf)76# отбрасываю CRC77return t[0], t[2]78
79def soft_reset(self):80"""Программный сброс датчика. После сброса датчик переходит в состояние простоя, idle state!"""81self._send_command(SHT4xSensirion.cmd_soft_reset)82
83def get_conversion_cycle_time(self) -> int:84"""Возвращает время в мкс(!) преобразования сигнала в цифровой код и готовности его для чтения по шине!85Для текущих настроек датчика. При изменении настроек следует заново вызвать этот метод!"""
86if not self._with_heater: # работа без нагрева!87_val = self._value # 0..2; 0 - низкая, 1 - средняя, 2 - высокая повторяемость/точность88_ms = 1_600, 4_500, 8_30089return _ms[_val]90
91if self._long_pulse: # работа с нагревом!92return 1_100_00093# короткий импульс нагрева94return 110_00095
96def start_measurement(self, with_heater: bool = False, value: int = 0, long_pulse: bool = False):97"""Настраивает параметры датчика и запускает процесс измерения.98with_heater - если Истина, то измерение будет проходить c нагревом (НЕ обычный режим)
99value - повторяемость, если with_heater is False:
1000 - низкая (самая низкая точность)
1011 - средняя (средняя точность)
1022 - высокая (высокая точность)
103value - мощность нагрева, если with_heater is True:
1040 - 20 мВт
1051 - 110 мВт
1062 - 200 мВт
107long_pulse - продолжительность нагрева, используется если with_heater is True:
108False - 0.1 сек
109True - 1.0 сек"""
110check_value(value, range(3), f"Неверное значение value: {value}")111
112_cmd = None113if not with_heater:114# нагреватель НЕ используется! 0xE0, 0xF6, 0xFD115_t = 0xE0, 0xF6, 0xFD116_cmd = _t[value]117
118if with_heater:119# используется нагреватель! (0x15, 0x1E), (0x24, 0x2F), (0x32, 0x39)120_t = (0x15, 0x1E), (0x24, 0x2F), (0x32, 0x39)121_cmd = _t[value][long_pulse]122
123# передаю в датчик код команды124self._send_command(_cmd)125# запоминаю для get_conversion_cycle_time126self._with_heater = with_heater127self._value = value128self._long_pulse = long_pulse129
130def get_measurement_value(self) -> [None, tuple[float, float]]:131"""Возвращает измеренное датчиком значение/значения"""132_cmd = self.get_last_cmd_code()133if SHT4xSensirion.cmd_get_id == _cmd:134return135_buf = self._read_answer()136_t = self.unpack("HBH", _buf)137t = 175.0 * _t[0] / SHT4xSensirion.magic - 45.0 # температура в градусах Цельсия!138rh = 125.0 * _t[2] / SHT4xSensirion.magic - 6.0 # относительная влажность в процентах!139return t, rh140
141def is_single_shot_mode(self) -> bool:142"""Возвращает Истина, когда датчик находится в режиме однократных измерений,143каждое из которых запускается методом start_measurement"""
144return True145
146def is_continuously_mode(self) -> bool:147"""Возвращает Истина, когда датчик находится в режиме многократных измерений,148производимых автоматически. Процесс запускается методом start_measurement"""
149return False150
151# Iterator152# Поскольку разработчики не завезли автоматический режим работы датчика, у меня нет для вас итератора :-)