''' Live read of the Senseair S88 CO2 sensor (used by the web "Get Data" button). Prints a JSON object: {"CO2": } or {"error": ""}. Usage: /usr/bin/python3 /var/www/nebuleair_pro_4g/S88/get_data.py [port] If no port is given, the script reads S88_port from config_table. ''' import json import sqlite3 import sys import serial DB_PATH = "/var/www/nebuleair_pro_4g/sqlite/sensors.db" DEFAULT_PORT = "/dev/ttyAMA5" BAUDRATE = 9600 def get_port_from_config(): try: conn = sqlite3.connect(DB_PATH) cursor = conn.cursor() cursor.execute("SELECT value FROM config_table WHERE key = ?", ("S88_port",)) row = cursor.fetchone() conn.close() return row[0] if row else DEFAULT_PORT except Exception: return DEFAULT_PORT def read_co2(ser): # TODO: implement the Senseair S88 read protocol once the datasheet is provided. # Expected return: integer CO2 concentration in ppm, or None on failure. raise NotImplementedError("Senseair S88 read protocol not implemented yet") def main(): port = sys.argv[1] if len(sys.argv) > 1 else get_port_from_config() try: ser = serial.Serial( port=port, baudrate=BAUDRATE, parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_ONE, bytesize=serial.EIGHTBITS, timeout=1, ) except Exception as e: print(json.dumps({"error": f"Cannot open {port}: {e}"})) return try: co2 = read_co2(ser) if co2 is None: print(json.dumps({"error": "No data from S88"})) return print(json.dumps({"CO2": int(round(co2))})) except NotImplementedError as e: print(json.dumps({"error": str(e)})) except Exception as e: print(json.dumps({"error": f"S88 read error: {e}"})) finally: try: ser.close() except Exception: pass if __name__ == "__main__": main()