docs(co2): ajouter ISO_17 (CO2, ppm) au protocole NebuleAir Pro 4G

- iso-pollutant-codes.md: code ISO_17 = CO2 (ppm), sentinelle 0xFFFF
- udp-miotiq.md: ISO_17 consomme les 2 octets reserved (offset 81),
  trame inchangee a 83 octets, retrocompat (0 = anciens fw)
- json-payload.md: tableau polluants, note sentinelle, exemple

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Your Name
2026-06-01 17:44:25 +02:00
parent a27af69f27
commit ace447c933
3 changed files with 12 additions and 3 deletions

View File

@@ -27,7 +27,7 @@ Un descripteur est une suite de lignes, une par champ. **Format officiel Miotiq*
| `length` | Taille du champ en **caractères hexadécimaux** (2 chars = 1 octet). |
| `variable name` | Identifiant logique du champ. Les codes polluants suivent [ISO 7168 AirCarto](iso-pollutant-codes.md). |
| `base function` | Fonction de décodage appliquée aux octets bruts. Voir tableau ci-dessous. |
| `units` | Unité physique finale (`ugm3`, `degC`, `%`, `hPa`, `ppb`, `dB`, `V`, `A`, `W`, `m/s`, `degrees`, `count`). Vide pour les champs d'état / versions. |
| `units` | Unité physique finale (`ugm3`, `degC`, `%`, `hPa`, `ppb`, `ppm`, `dB`, `V`, `A`, `W`, `m/s`, `degrees`, `count`). Vide pour les champs d'état / versions. |
| `equation` | Expression de transformation appliquée à la valeur décodée, où `x` est la valeur. Ex. `x/10`, `x/100`, `(x-32)*5/9`. Vide = pas de transformation. |
| `export to JSON` | Contrôle la sortie JSON côté Miotiq (voir ci-dessous). Valeurs : `Y` (défaut), `W`, `N`. |
@@ -102,7 +102,7 @@ Descripteur de référence :
8|latitude|hex2dec|degrees|x/1000000-90|
8|longitude|hex2dec|degrees|x/1000000-180|
2|misc|hex2dec|||
4|reserved|skip|||
4|ISO_17|hex2dec|ppm||
```
**Encodage `latitude` / `longitude`**`hex2dec` est **non-signé** côté Miotiq. Pour transmettre des coordonnées négatives sans ambiguïté, le firmware encode avec un offset fixe :
@@ -116,6 +116,8 @@ Miotiq applique l'équation inverse (`x/1000000-90`, `x/1000000-180`) et exporte
Les firmwares antérieurs à cette extension envoyaient déjà 83 octets (bloc `reserved` = 11 zéros), qui décodent désormais comme `lat=-90, lon=-180, misc=0`. Sur ces firmwares `device_status = 0xFF` (= champ non supporté — cf. [`json-payload.md`](json-payload.md#error_flags--bitfield-système-1-octet)) : un backend prudent traite donc la combinaison `device_status == 0xFF && (lat, lon) == (-90, -180)` comme « coords non disponibles ».
**CO₂ (`ISO_17`, offset 81)** — ce champ réutilise les 2 octets jadis `reserved` : la trame reste à **83 octets** (aucune trame déployée n'est rejetée). Le CO₂ est encodé en **ppm bruts** (`uint16`, pas d'équation, ambiant ≈ 420 ppm). Comme `reserved` était émis à `0x0000`, les firmwares sans capteur CO₂ décodent `ISO_17 = 0` ; les firmwares CO₂ utilisent la sentinelle `0xFFFF` (65535) quand le capteur est absent ou en défaut. Le backend traite donc `ISO_17 ∈ {0, 0xFFFF}` comme « CO₂ non disponible ».
Layout octet par octet :
| Offset | Taille | Champ | Unité | Scale | Notes |
@@ -160,7 +162,7 @@ Layout octet par octet :
| 72 | 4 | `latitude` | degrés | /1e6 90 | WGS84, offset unsigned. Voir encodage ci-dessus. Ignoré si `device_status.GPS_NO_FIX`. |
| 76 | 4 | `longitude` | degrés | /1e6 180 | WGS84, offset unsigned. Idem. |
| 80 | 1 | `misc` | | | Contexte de mesure 06 (voir [`json-payload.md`](json-payload.md#géolocalisation--contexte)) |
| 81 | 2 | `reserved` | | | À ignorer (évolution future du descripteur) |
| 81 | 2 | `ISO_17` | ppm | | CO₂. `uint16` ppm (pas d'équation). `0xFFFF` = capteur CO₂ absent ; `0` (anciens fw, ex-`reserved`) = non mesuré. |
| **83** | total | | | | |
### MobileAir (17 octets — legacy, pré-descripteur)
@@ -221,3 +223,4 @@ Valeurs manquantes codées `-1` (sentinelle legacy). À **ne pas reproduire** po
| 2026-04-24 | v6 | Intégration effective de `latitude` (4B), `longitude` (4B), `misc` (1B) dans le descripteur NebuleAir Pro 4G. Encodage offset unsigned (`raw = (deg + 90|180) * 1e6`, équation `x/1000000-90|180`) pour contourner l'absence de signed sur `hex2dec` Miotiq. « No fix » géré par le bit `GPS_NO_FIX` de `device_status`. Reste 2B `reserved`. |
| 2026-04-27 | v7 | Octet 9 renommé `version``command`. Ce champ était hardcodé `0x01` côté firmware (jamais une vraie version de protocole). Réaffecté à un type de trame : `0x00` = données mesure, `0x01` = ping test. Permet au firmware de déclencher une trame de bout en bout (capteur → Miotiq → backend) sans envoyer de mesures réelles. Versioning protocole assuré par `version_major/minor/patch` (offsets 69-71). |
| 2026-04-27 | v8 | Rétrocompatibilité : ping test déplacé de `0x01` vers `0x02`. Les firmwares déployés émettent déjà `0x01` (héritage du champ `version` hardcodé) ; les traiter comme ping aurait fait passer toutes leurs trames pour des diagnostics. `0x00` et `0x01` restent donc des trames de mesure normales, `0x02` devient le déclencheur explicite du ping. |
| 2026-06-01 | v9 | Ajout du CO₂ (`ISO_17`, ppm, `uint16`) sur NebuleAir Pro 4G, en consommant les 2 octets `reserved` (offset 81). Trame inchangée à 83 octets — aucune trame déployée rejetée. Plus de bloc `reserved`. Sentinelle `0xFFFF` = capteur absent ; `0` (ex-`reserved` des anciens fw) = non mesuré. `ISO_17` ajouté à [`iso-pollutant-codes.md`](iso-pollutant-codes.md). |