v1.11.0: CCS811 en daemon + fix filtrage + I2C 10kHz requis

Vérif terrain sur pro100 : à 100 kHz le CCS811 renvoie des valeurs corrompues
0x8000 (32768) par clock-stretching, et le modèle oneshot-reset-toutes-les-10s
ne donne que le 1er échantillon post-init (garbage). Refonte :

- CCS811/daemon.py: service long-running (Type=simple, Restart=always). Init 1x,
  boucle lecture/écriture 10s, filtre eCO2 dans [400,8192], re-init auto sur
  erreurs I2C répétées. Remplace write_data.py (supprimé).
- CCS811/get_data.py: lit la dernière ligne data_CCS811 au lieu du capteur
  (évite la collision I2C avec le daemon -> corruption observée).
- setup_services.sh: service daemon + self-heal suppression de l'ancien .timer;
  activation hors boucle timers.
- launcher.php: .timer -> .service (map statut + allowedServices x2).
- update_firmware.sh: redémarre le daemon à l'OTA.
- doc: README (archi daemon + I2C 10kHz confirmé requis), CLAUDE.md, changelog.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
PaulVua
2026-06-02 16:08:03 +02:00
parent 46c73acb7e
commit 13c266d694
10 changed files with 240 additions and 211 deletions

View File

@@ -26,8 +26,12 @@ mitigation, les lectures échouent typiquement en `OSError` / `Remote I/O error`
dtparam=i2c_arm_baudrate=10000
```
(10 kHz au lieu de 100 kHz par défaut.) Reboot ensuite. À valider au bench — sur
certains modules/CM4 ça passe à 100 kHz, sur d'autres non.
(10 kHz au lieu de 100 kHz par défaut.) Reboot ensuite.
**Confirmé nécessaire sur le terrain** (nebuleair-pro100, juin 2026) : à 100 kHz le
CCS811 renvoie des valeurs corrompues 0x8000+ (32768) par intermittence et finit en
état d'erreur. À 10 kHz c'est stable. Ce réglage n'est pas géré par le repo (fichier
hors `/var/www`), il doit être posé à la main sur chaque capteur équipé d'un CCS811.
Vérifier la présence du capteur :
@@ -64,20 +68,34 @@ sans level-shifter sauf si le module embarque son propre régulateur + shifter.
## Implémentation NebuleAir
- `CCS811/get_data.py` — lecture live (bouton "Get Data" du web). Affiche
`{"eCO2": <ppm>, "TVOC": <ppb>}` ou `{"error": "..."}`.
- `CCS811/write_data.py` — lecture périodique (timer systemd, toutes les 10 s),
écrit dans la table `data_CCS811 (timestamp, eCO2, TVOC)`.
**Architecture : daemon, PAS un timer oneshot** (contrairement aux autres capteurs).
Le CCS811 doit être initialisé **une seule fois** puis lu en continu :
Librairie Python : `adafruit-circuitpython-ccs811` (installée par
`installation_part1.sh`). La table est créée par `sqlite/create_db.py` et
self-healée par `write_data.py` (CREATE TABLE IF NOT EXISTS) — garder les deux
schémas synchro.
- chaque (ré)init fait un reset + app_start, et les premiers échantillons juste après
sont du garbage (eCO2 = 0, ou valeurs 0x8000+ = 32768 dues au clock-stretching) ;
- un cycle reset toutes les 10 s empêche l'algorithme de baseline de se construire.
Composants :
- `CCS811/daemon.py` — service long-running (`nebuleair-ccs811-data.service`,
`Type=simple`, `Restart=always`). Init une fois, puis boucle : toutes les 10 s,
lit un échantillon **valide** (eCO2 ∈ [400, 8192], le reste est jeté) et l'écrit
dans `data_CCS811 (timestamp, eCO2, TVOC)`. Re-init automatique du capteur après
plusieurs erreurs I2C consécutives.
- `CCS811/get_data.py` — bouton "Get Data" du web. **Ne lit PAS le capteur** (ça
entrerait en collision I2C avec le daemon et corromprait la sonde) : renvoie la
**dernière ligne** de `data_CCS811`. Affiche `{"eCO2","TVOC","timestamp"}` ou
`{"error": "..."}`.
Librairie Python : `adafruit-circuitpython-ccs811` (dans `requirements.txt`,
installée par `installation_part1.sh` ET par `update_firmware.sh`). La table est
créée par `sqlite/create_db.py` et self-healée par `daemon.py`
(CREATE TABLE IF NOT EXISTS) — garder les deux schémas synchro.
Activation : `admin.html` → case "Send VOC sensor data (CCS811)".
### Pistes d'amélioration (non implémentées)
Le CCS811 supporte une compensation température/humidité (`SET_ENV_DATA`). Comme le
boîtier embarque déjà un BME280, on pourrait lui pousser temp/hum à chaque lecture
pour améliorer la précision. Non fait en v1 pour garder le script simple et autonome.
boîtier embarque déjà un BME280, on pourrait lui pousser temp/hum périodiquement
pour améliorer la précision. Non fait pour garder le daemon simple.