v1.10.1: OTA installe les deps pip + filtre lectures parasites CCS811

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) <noreply@anthropic.com>
This commit is contained in:
PaulVua
2026-06-02 15:51:58 +02:00
parent 4f3d273981
commit 46c73acb7e
7 changed files with 65 additions and 5 deletions

View File

@@ -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}"}))

View File

@@ -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]

View File

@@ -1 +1 @@
1.10.0
1.10.1

View File

@@ -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",

View File

@@ -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..."

16
requirements.txt Normal file
View File

@@ -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

View File

@@ -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