import time from machine import I2C, Pin class SHTC3: """Utility class for Sensirion SHTC3 Temperature and Humidity Sensor.""" ADDR = 0x70 # Commands WAKE = b'\x35\x17' SLEEP = b'\xB0\x98' MEASURE = b'\x78\x66' # High precision, T first, clock stretching disabled def __init__(self, i2c=None): if i2c is None: # Default to ESP32-S3-RLCD-4.2 onboard I2C pins self.i2c = I2C(0, sda=Pin(13), scl=Pin(14)) else: self.i2c = i2c def _crc8(self, data): """Sensirion CRC-8 checksum calculation (polynom 0x31, init 0xFF).""" 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): """Wakes up the sensor, reads temp and humidity, validates CRC, and sleeps. Returns: tuple: (temperature_c, relative_humidity_pct) or (None, None) on error. """ try: # 1. Wakeup self.i2c.writeto(self.ADDR, self.WAKE) time.sleep_ms(1) # 2. Trigger Measurement self.i2c.writeto(self.ADDR, self.MEASURE) time.sleep_ms(15) # High precision measurement takes up to 12.1ms # 3. Read 6 bytes of data # bytes 0, 1: Temp, byte 2: Temp CRC # bytes 3, 4: Hum, byte 5: Hum CRC data = self.i2c.readfrom(self.ADDR, 6) # 4. Enter low-power sleep mode self.i2c.writeto(self.ADDR, self.SLEEP) # Verify CRC t_data = data[0:2] t_crc = data[2] h_data = data[3:5] h_crc = data[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 = (data[0] << 8) | data[1] raw_h = (data[3] << 8) | data[4] # Formula from datasheet 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 to send sleep command anyway to save power try: self.i2c.writeto(self.ADDR, self.SLEEP) except: pass return None, None