From e3e34aaadbe64df54d5ef8ff77b335e0e7d18412 Mon Sep 17 00:00:00 2001 From: osmarks Date: Wed, 9 Oct 2024 20:46:32 +0100 Subject: [PATCH] SCD4x metrics script --- scd4x_prometheus.py | 85 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 scd4x_prometheus.py diff --git a/scd4x_prometheus.py b/scd4x_prometheus.py new file mode 100644 index 0000000..4bf2b71 --- /dev/null +++ b/scd4x_prometheus.py @@ -0,0 +1,85 @@ +# 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() \ No newline at end of file