"""CircuitPython SHTC3 temperature and humidity sensor driver. Uses standard I2C transactions with bus locking. """ import time class SHTC3: ADDR = 0x70 WAKE = b'\x35\x17' SLEEP = b'\xB0\x98' MEASURE = b'\x78\x66' # High precision, T first, clock stretching disabled def __init__(self, i2c): self.i2c = i2c def _crc8(self, data): crc = 0xFF for byte in data: crc ^= byte for _ in range(8): if crc & 0x80: crc = (crc << 1) ^ 0x31 else: crc <<= 1 crc &= 0xFF return crc def read_sensor(self): try: # 1. Wakeup while not self.i2c.try_lock(): pass try: self.i2c.writeto(self.ADDR, self.WAKE) finally: self.i2c.unlock() time.sleep(0.001) # 2. Trigger Measurement while not self.i2c.try_lock(): pass try: self.i2c.writeto(self.ADDR, self.MEASURE) finally: self.i2c.unlock() time.sleep(0.015) # 3. Read 6 bytes of data # bytes 0, 1: Temp, byte 2: Temp CRC # bytes 3, 4: Hum, byte 5: Hum CRC buf = bytearray(6) while not self.i2c.try_lock(): pass try: self.i2c.readfrom_into(self.ADDR, buf) finally: self.i2c.unlock() # 4. Enter sleep mode while not self.i2c.try_lock(): pass try: self.i2c.writeto(self.ADDR, self.SLEEP) finally: self.i2c.unlock() # Verify CRC t_data = buf[0:2] t_crc = buf[2] h_data = buf[3:5] h_crc = buf[5] if self._crc8(t_data) != t_crc: print("SHTC3 Temp CRC error") return None, None if self._crc8(h_data) != h_crc: print("SHTC3 Hum CRC error") return None, None raw_t = (buf[0] << 8) | buf[1] raw_h = (buf[3] << 8) | buf[4] temp = -45.0 + 175.0 * (raw_t / 65536.0) hum = 100.0 * (raw_h / 65536.0) return round(temp, 2), round(hum, 2) except Exception as e: print(f"Error reading SHTC3 sensor: {e}") try: while not self.i2c.try_lock(): pass try: self.i2c.writeto(self.ADDR, self.SLEEP) finally: self.i2c.unlock() except: pass return None, None