From 46c73acb7edd240b0f842e69bc836f37020b9c6e Mon Sep 17 00:00:00 2001 From: PaulVua Date: Tue, 2 Jun 2026 15:51:58 +0200 Subject: [PATCH] v1.10.1: OTA installe les deps pip + filtre lectures parasites CCS811 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Découvert en vérif SSH sur nebuleair-pro100 : le timer CCS811 échouait en ModuleNotFoundError car l'OTA fait git pull mais ne réinstallait jamais les dépendances pip (installation_part1.sh ne tourne qu'à l'install neuve). - requirements.txt: source unique de vérité des deps Python - installation_part1.sh: install via requirements.txt (chemin relatif au script, le repo n'est pas encore cloné dans /var/www à cette étape) - update_firmware.sh: nouvelle étape 2a, pip install -r requirements.txt (idempotent) -> les capteurs déjà déployés récupèrent les libs manquantes à l'OTA - CCS811/write_data.py + get_data.py: skip des lectures eCO2 < 400 ppm (échantillon 0/0 parasite juste après init du driver, plancher physique = 400) Co-Authored-By: Claude Opus 4.8 (1M context) --- CCS811/get_data.py | 10 +++++++--- CCS811/write_data.py | 7 +++++++ VERSION | 2 +- changelog.json | 15 +++++++++++++++ installation_part1.sh | 5 ++++- requirements.txt | 16 ++++++++++++++++ update_firmware.sh | 15 +++++++++++++++ 7 files changed, 65 insertions(+), 5 deletions(-) create mode 100644 requirements.txt diff --git a/CCS811/get_data.py b/CCS811/get_data.py index 3efde19..7219c6d 100644 --- a/CCS811/get_data.py +++ b/CCS811/get_data.py @@ -76,9 +76,13 @@ def main(): print(json.dumps({"error": "CCS811 data not ready (warming up?)"})) return - eco2 = ccs811.eco2 - tvoc = ccs811.tvoc - print(json.dumps({"eCO2": int(eco2), "TVOC": int(tvoc)})) + eco2 = int(ccs811.eco2) + tvoc = int(ccs811.tvoc) + # eCO2 floor is 400 ppm; a sub-400 value is a not-yet-settled sample. + if eco2 < 400: + print(json.dumps({"error": "CCS811 reading not settled (warming up?)"})) + return + print(json.dumps({"eCO2": eco2, "TVOC": tvoc})) except Exception as e: print(json.dumps({"error": f"CCS811 read error: {e}"})) diff --git a/CCS811/write_data.py b/CCS811/write_data.py index 2f7bdd8..a8a394d 100644 --- a/CCS811/write_data.py +++ b/CCS811/write_data.py @@ -78,6 +78,13 @@ def main(): eco2 = int(ccs811.eco2) tvoc = int(ccs811.tvoc) + # eCO2 has a physical floor of 400 ppm. Just after the driver (re)inits, + # the CCS811 can return a 0/0 sample before its first valid measurement is + # ready — those are spurious, drop them (next 10 s tick will retry). + if eco2 < 400: + print(f"CCS811: reading not settled (eCO2={eco2}), skipping.") + return + cursor.execute("SELECT last_updated FROM timestamp_table LIMIT 1") row = cursor.fetchone() rtc_time_str = row[0] diff --git a/VERSION b/VERSION index 81c871d..4dae298 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.10.0 +1.10.1 diff --git a/changelog.json b/changelog.json index 9f38337..1a9c7e6 100644 --- a/changelog.json +++ b/changelog.json @@ -1,5 +1,20 @@ { "versions": [ + { + "version": "1.10.1", + "date": "2026-06-02", + "changes": { + "features": [], + "improvements": [ + "OTA installe désormais les dépendances Python. Nouveau requirements.txt (source unique de vérité), installé par installation_part1.sh (install neuve, chemin relatif au script car le repo n'est pas encore cloné) ET par update_firmware.sh (nouvelle étape 2a, idempotent). Corrige le trou découvert sur nebuleair-pro100 : l'OTA faisait git pull sans réinstaller pip, donc la lib adafruit-circuitpython-ccs811 manquait et le timer CCS811 échouait en ModuleNotFoundError. Tous les capteurs récupéreront automatiquement les libs manquantes à la prochaine MAJ." + ], + "fixes": [ + "CCS811: filtrage des lectures parasites eCO2 < 400 ppm (plancher physique du capteur). Juste après l'init du driver, le CCS811 renvoie parfois un échantillon 0/0 avant sa 1ère mesure valide — ces lignes ne sont plus écrites en base (write_data.py) ni affichées (get_data.py), le tick suivant réessaie." + ], + "compatibility": [] + }, + "notes": "Vérifié en SSH sur nebuleair-pro100 : capteur détecté en I2C à 0x5A, lib installée, données eCO2/TVOC qui remontent. Rappel: le CCS811 a besoin de ~20 min de warm-up et ~48h de burn-in initial pour des valeurs stables." + }, { "version": "1.10.0", "date": "2026-06-02", diff --git a/installation_part1.sh b/installation_part1.sh index 1632500..5f6461c 100644 --- a/installation_part1.sh +++ b/installation_part1.sh @@ -26,8 +26,11 @@ info "Updating package list and installing necessary packages..." sudo apt update && sudo apt install -y git gh apache2 sqlite3 php php-sqlite3 python3 python3-pip jq autossh i2c-tools python3-smbus python3-rpi.gpio || error "Failed to install required packages." # Install Python libraries +# requirements.txt lives next to this script (the repo isn't cloned to +# /var/www yet at this point), so resolve it relative to the script location. info "Installing Python libraries..." -sudo pip3 install pyserial requests adafruit-circuitpython-bme280 adafruit-circuitpython-ccs811 crcmod psutil gpiozero ntplib adafruit-circuitpython-ads1x15 nsrt-mk3-dev pytz --break-system-packages || error "Failed to install Python libraries." +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +sudo pip3 install -r "$SCRIPT_DIR/requirements.txt" --break-system-packages || error "Failed to install Python libraries." # Install Tailscale (for remote SSH access via Headscale tailnet) info "Installing Tailscale..." diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..c3c9321 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,16 @@ +# NebuleAir Pro 4G - dépendances Python. +# Source unique de vérité, installée à l'install neuve (installation_part1.sh) +# ET à chaque OTA (update_firmware.sh, étape 2b) pour que les capteurs déjà +# déployés récupèrent toute nouvelle lib lors de la mise à jour. +# pip skippe ce qui est déjà satisfait => idempotent. +pyserial +requests +adafruit-circuitpython-bme280 +adafruit-circuitpython-ccs811 +crcmod +psutil +gpiozero +ntplib +adafruit-circuitpython-ads1x15 +nsrt-mk3-dev +pytz diff --git a/update_firmware.sh b/update_firmware.sh index 12d083f..6da18f4 100755 --- a/update_firmware.sh +++ b/update_firmware.sh @@ -62,6 +62,21 @@ if [ -f "/var/www/nebuleair_pro_4g/VERSION" ]; then print_status "Firmware version: $(cat /var/www/nebuleair_pro_4g/VERSION)" fi +# Step 2a: Install/update Python dependencies (self-heal) +# OTA does a git pull but historically never (re)installed pip deps, so a new +# sensor lib introduced by an update (e.g. adafruit-circuitpython-ccs811) was +# missing on already-deployed sensors and the timer failed with ModuleNotFound. +# requirements.txt is the single source of truth; pip skips already-satisfied +# packages so this is idempotent and only pulls newly-added libs. +print_status "" +print_status "Step 2a: Installing/updating Python dependencies..." +if [ -f "/var/www/nebuleair_pro_4g/requirements.txt" ]; then + sudo pip3 install -r /var/www/nebuleair_pro_4g/requirements.txt --break-system-packages + check_status "Python dependencies install" +else + print_status "⚠ requirements.txt not found, skipping dependency install" +fi + # Step 2: Update database (schema migration + config keys) # create_db.py is idempotent (CREATE TABLE IF NOT EXISTS + ALTER TABLE ADD COLUMN # wrapped in try/except). Required to add tables introduced after the sensor was