''' Script to get air-quality values from the AMS CCS811 sensor and write to database. /usr/bin/python3 /var/www/nebuleair_pro_4g/CCS811/write_data.py CCS811 is a MOX gas sensor: eCO2 (equivalent CO2 in ppm, derived from VOCs) and TVOC (Total VOC in ppb). TVOC is the primary measurement of interest. I2C, library adafruit-circuitpython-ccs811. Address from config_table (key CCS811_address, e.g. "0x5A" / "0x5B"), default 0x5A. ''' import sqlite3 import sys import time DB_PATH = "/var/www/nebuleair_pro_4g/sqlite/sensors.db" DEFAULT_ADDRESS = 0x5A DATA_READY_RETRIES = 30 DATA_READY_DELAY = 0.2 # seconds def get_config(cursor, key, default): cursor.execute("SELECT value FROM config_table WHERE key = ?", (key,)) row = cursor.fetchone() return row[0] if row else default def main(): conn = sqlite3.connect(DB_PATH) cursor = conn.cursor() # Self-heal: ensure the table exists even if create_db.py was skipped during OTA. # Duplicates the canonical schema from sqlite/create_db.py — keep them in sync. cursor.execute(""" CREATE TABLE IF NOT EXISTS data_CCS811 ( timestamp TEXT, eCO2 INTEGER, TVOC INTEGER ) """) conn.commit() addr_str = get_config(cursor, "CCS811_address", "0x5A") try: address = int(str(addr_str), 16) except ValueError: address = DEFAULT_ADDRESS try: import board import busio import adafruit_ccs811 except Exception as e: print(f"CCS811: library import failed: {e}") conn.close() sys.exit(1) try: i2c = busio.I2C(board.SCL, board.SDA) ccs811 = adafruit_ccs811.CCS811(i2c, address=address) except Exception as e: print(f"CCS811: cannot init at {hex(address)}: {e}") conn.close() sys.exit(1) try: ready = False for _ in range(DATA_READY_RETRIES): if ccs811.data_ready: ready = True break time.sleep(DATA_READY_DELAY) if not ready: print("CCS811: data not ready (warming up?), skipping.") return eco2 = int(ccs811.eco2) tvoc = int(ccs811.tvoc) cursor.execute("SELECT last_updated FROM timestamp_table LIMIT 1") row = cursor.fetchone() rtc_time_str = row[0] cursor.execute( "INSERT INTO data_CCS811 (timestamp, eCO2, TVOC) VALUES (?, ?, ?)", (rtc_time_str, eco2, tvoc), ) conn.commit() print(f"eCO2: {eco2} ppm, TVOC: {tvoc} ppb (saved at {rtc_time_str})") except Exception as e: print(f"CCS811 error: {e}") finally: conn.close() if __name__ == "__main__": main()