87 lines
2.7 KiB
Python
87 lines
2.7 KiB
Python
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
|
|
from machine import SoftI2C
|
|
self.i2c = SoftI2C(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
|