From ace447c933189ce791a72c9aed10c0d3c89c5e1b Mon Sep 17 00:00:00 2001 From: Your Name Date: Mon, 1 Jun 2026 17:44:25 +0200 Subject: [PATCH] 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) --- formats/iso-pollutant-codes.md | 1 + formats/json-payload.md | 5 +++++ formats/udp-miotiq.md | 9 ++++++--- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/formats/iso-pollutant-codes.md b/formats/iso-pollutant-codes.md index 1a4d439..d599348 100644 --- a/formats/iso-pollutant-codes.md +++ b/formats/iso-pollutant-codes.md @@ -12,6 +12,7 @@ Les codes vont théoriquement de `ISO_01` à `ISO_99`. Seuls ceux effectivement | `ISO_04` | CO — monoxyde de carbone | ppb | | | | `ISO_05` | H₂S — sulfure d'hydrogène | ppb | | | | `ISO_08` | O₃ — ozone | ppb | | | +| `ISO_17` | CO₂ — dioxyde de carbone | ppm | | En **ppm** (et non ppb comme les gaz traces). `uint16`, sentinelle `0xFFFF` = non équipé. | | `ISO_21` | NH₃ — ammoniac | ppb | | | | `ISO_24` | PM10 | µg/m³ | `x/10` | Particules ≤ 10 µm | | `ISO_39` | PM2.5 | µg/m³ | `x/10` | Particules fines ≤ 2.5 µm | diff --git a/formats/json-payload.md b/formats/json-payload.md index 2a73912..223f73d 100644 --- a/formats/json-payload.md +++ b/formats/json-payload.md @@ -65,6 +65,9 @@ Le mapping complet vit dans [`formats/iso-pollutant-codes.md`](iso-pollutant-cod | `ISO_21` | NH₃ | ppb | | `ISO_04` | CO | ppb | | `ISO_08` | O₃ | ppb | +| `ISO_17` | CO₂ | ppm | + +> **CO₂ (`ISO_17`)** : encodé en **ppm bruts** (`uint16`), pas en ppb comme les gaz traces. Comme ce champ vient d'un descripteur Miotiq `hex2dec` (non signé), il ne peut pas porter la sentinelle `-1` : un capteur sans CO₂ envoie `0xFFFF` (65535) — ou `0` sur les firmwares qui émettaient encore l'ancien bloc `reserved`. Le backend traite `ISO_17 ∈ {0, 65535}` comme « CO₂ non disponible ». Voir [`udp-miotiq.md`](udp-miotiq.md). Les codes ISO vont théoriquement de `ISO_01` à `ISO_99`. Seuls les polluants effectivement mesurés par le capteur sont présents dans le JSON. @@ -198,6 +201,7 @@ Enum extensible — de nouvelles valeurs peuvent être ajoutées (7, 8, …) san "signal_quality_unit": "-22 dB", "command": 0, "ISO_68": 0.8, "ISO_68_unit": "0,8 ugm3", + "ISO_17": 437, "ISO_17_unit": "437 ppm", "ISO_54": 25.5, "ISO_54_unit": "25.5 °C", "noise_cur_leq": 25.5, "noise_cur_leq_unit": "25,5 dB", "noise_cur_level": 25.5, "noise_cur_unit": "25,5 dB", @@ -251,3 +255,4 @@ Enum extensible — de nouvelles valeurs peuvent être ajoutées (7, 8, …) san | 2026-04-23 | v2 | **Format officiel AirCarto 2026** : schéma plat, bitfields détaillés, compat firmware ancien. | | 2026-04-27 | v3 | Champ `version` (offset 9 du binaire, hardcodé `0x01` côté firmware) renommé `command` et réaffecté à un type de trame : `0x00` = données, `0x01` = ping test. Ajout de la section « Commande / type de trame ». Versioning protocole reste sur `version_major/minor/patch`. | | 2026-04-27 | v4 | Rétrocompatibilité : ping test déplacé de `0x01` vers `0x02`. Les firmwares déployés émettent déjà `0x01` (héritage de l'ancien champ `version`) ; les compter comme pings aurait masqué toutes leurs mesures. `0x00` et `0x01` sont désormais tous deux des trames de données normales, `0x02` est le déclencheur explicite du ping. | +| 2026-06-01 | v5 | Ajout du CO₂ (`ISO_17`, ppm) au tableau des polluants et à l'exemple NebuleAir_Pro. Sentinelle « non disponible » = `0` ou `65535` (`0xFFFF`) car le champ vient d'un descripteur Miotiq `hex2dec` non signé (pas de `-1` possible). | diff --git a/formats/udp-miotiq.md b/formats/udp-miotiq.md index 9a353ba..03a3a05 100644 --- a/formats/udp-miotiq.md +++ b/formats/udp-miotiq.md @@ -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 0–6 (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). |