1
0
mirror of https://github.com/osmarks/random-stuff synced 2024-10-18 06:00:39 +00:00
random-stuff/scd4x_prometheus.py
2024-10-09 20:46:32 +01:00

85 lines
2.8 KiB
Python

# refer to https://sensirion.com/media/documents/48C4B7FB/64C134E7/Sensirion_SCD4x_Datasheet.pdf
import smbus3
import struct
import time
from prometheus_client import start_http_server, Gauge
import sys
location = sys.argv[1]
def sensiron_bad_crc8(data):
crc = 0xFF
POLY = 0x31
for byte in data:
crc ^= byte
for _ in range(8):
if crc & 0x80:
crc = (crc << 1) ^ POLY
else:
crc = (crc << 1)
crc &= 0xFF
return crc
bus = smbus3.SMBus(1)
ADDR = 0x62
def encode_word_crc(hi, lo):
return [hi, lo, sensiron_bad_crc8([hi, lo])]
def setup():
stop_measurement = smbus3.i2c_msg.write(ADDR, [0x3f, 0x86])
bus.i2c_rdwr(stop_measurement)
time.sleep(0.5)
serial_cmd = smbus3.i2c_msg.write(ADDR, [0x36, 0x82]) # serial number
serial_read = smbus3.i2c_msg.read(ADDR, 9)
bus.i2c_rdwr(serial_cmd, serial_read)
serial = bytes(serial_read)
print((serial[0:2] + serial[3:5] + serial[6:8]).hex())
time.sleep(0.1)
# automatic self-calibration breaks badly if CO2 never below 400ppm, which is not guaranteed
disable_asc = smbus3.i2c_msg.write(ADDR, [0x24, 0x16] + encode_word_crc(0x00, 0x00))
bus.i2c_rdwr(disable_asc)
time.sleep(0.1)
# default offset of 4 degrees C is "probably right" but I don't have the equipment to test this
#real_offset = 4.0
#offset_bytes = struct.pack(">H", int(real_offset * 65535.0 / 175.0))
#set_temp_offset = smbus3.i2c_msg.write(ADDR, [0x24, 0x1d] + encode_word_crc(*offset_bytes))
#bus.i2c_rdwr(set_temp_offset)
#time.sleep(0.1)
start_measurement = smbus3.i2c_msg.write(ADDR, [0x21, 0xb1])
bus.i2c_rdwr(start_measurement)
setup()
temperature = Gauge("scd4x_temperature", "Temperature in Celsius", ("location",))
co2_ppm = Gauge("scd4x_co2_ppm", "CO2 parts per million", ("location",))
rh = Gauge("scd4x_relative_humidity_percent", "Relative humidity in percent", ("location",))
def read_temperature_pressure():
measurement_read_write = smbus3.i2c_msg.write(ADDR, [0xec, 0x05])
measurement_read_read = smbus3.i2c_msg.read(ADDR, 9)
bus.i2c_rdwr(measurement_read_write, measurement_read_read)
measurement_read_read = bytes(measurement_read_read)
print(measurement_read_read)
co2 = struct.unpack(">H", measurement_read_read[0:2])[0]
raw_temperature = struct.unpack(">H", measurement_read_read[3:5])[0]
raw_humidity = struct.unpack(">H", measurement_read_read[6:8])[0]
temperature_celsius = -45 + 175 * (raw_temperature / 65535.0)
relative_humidity = raw_humidity / 65535.0 * 100
temperature.labels(location=location).set(temperature_celsius)
rh.labels(location=location).set(relative_humidity)
co2_ppm.labels(location=location).set(co2)
start_http_server(9091)
while True:
time.sleep(5)
read_temperature_pressure()