102 lines
2.7 KiB
Python
102 lines
2.7 KiB
Python
"""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
|