diff --git a/formats/json-payload.md b/formats/json-payload.md index 5ec3d4e..5782dca 100644 --- a/formats/json-payload.md +++ b/formats/json-payload.md @@ -173,6 +173,8 @@ Reconstitution : `f"{version_major}.{version_minor}.{version_patch}"` → ex. `" | 5 | Mesure en vélo | | 6 | Mesure en transport en commun | +Enum extensible — de nouvelles valeurs peuvent être ajoutées (7, 8, …) sans casser l'encodage 1 octet. Un consommateur qui rencontre une valeur inconnue doit la traiter comme *contexte non renseigné* (équivalent à `0`), pas rejeter la trame. + ## Exemple complet (NebuleAir_Pro) ```json diff --git a/formats/udp-miotiq.md b/formats/udp-miotiq.md index 19f6fd7..d7e6d51 100644 --- a/formats/udp-miotiq.md +++ b/formats/udp-miotiq.md @@ -99,9 +99,23 @@ Descripteur de référence : 2|version_major|hex2dec||| 2|version_minor|hex2dec||| 2|version_patch|hex2dec||| -22|reserved|skip||| +8|latitude|hex2dec|degrees|x/1000000-90| +8|longitude|hex2dec|degrees|x/1000000-180| +2|misc|hex2dec||| +4|reserved|skip||| ``` +**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 : + +- `raw_lat = round((lat_deg + 90) * 1_000_000)` — range attendue `[0, 180_000_000]`, tient dans uint32. +- `raw_lon = round((lon_deg + 180) * 1_000_000)` — range `[0, 360_000_000]`, tient dans uint32. + +Miotiq applique l'équation inverse (`x/1000000-90`, `x/1000000-180`) et exporte directement des degrés WGS84 signés dans le JSON. Précision ~11 cm (6 décimales), conforme à [`CONVENTIONS.md`](../CONVENTIONS.md). + +**Pas de sentinelle numérique pour « no fix »** : quand le GPS n'a pas de fix, le firmware positionne le bit `GPS_NO_FIX` dans `device_status` (voir [`json-payload.md`](json-payload.md#device_status--bitfield-boîtier-1-octet)). Le backend ignore `latitude`/`longitude` quand ce bit est levé, indépendamment de leur valeur brute. + +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 ». + Layout octet par octet : | Offset | Taille | Champ | Unité | Scale | Notes | @@ -143,11 +157,12 @@ Layout octet par octet : | 69 | 1 | `version_major` | | | Version firmware `X.y.z` | | 70 | 1 | `version_minor` | | | `x.Y.z` | | 71 | 1 | `version_patch` | | | `x.y.Z` | -| 72 | 11 | `reserved` | | | À ignorer (évolution future du descripteur) | +| 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) | | **83** | total | | | | | -> Les champs `latitude`, `longitude`, `misc` présents dans le JSON final (voir [`json-payload.md`](json-payload.md#géolocalisation--contexte)) **ne sont pas** dans ce descripteur 83B. **À intégrer** : voir la section [À faire](#à-faire) — l'emplacement naturel est le bloc `reserved` de 11 octets (4+4+1 = 9 octets suffisent). - ### MobileAir (17 octets — legacy, pré-descripteur) > Ce capteur envoie encore un format binaire packé **sans descripteur Miotiq formel**. Migration prévue vers la même approche descripteur que NebuleAir Pro 4G. @@ -266,23 +281,8 @@ Côté PHP (cf. implémentations existantes `udp_miotiq_byte.php` / `udp_miotiq_ ## À faire -- [ ] **Intégrer `latitude` et `longitude` dans le descripteur NebuleAir Pro 4G** — aujourd'hui absents du descripteur 83B mais attendus dans le JSON final. Emplacement proposé : dans le bloc `reserved` de 11 octets. Encodage suggéré (à valider) — `hex2dec` signé sur 4 octets chacun, équation `x/1000000` pour obtenir des degrés WGS84 avec précision ~10 cm : - - ``` - 8|latitude|hex2dec|degrees|x/1000000| - 8|longitude|hex2dec|degrees|x/1000000| - ``` - - > À confirmer : Miotiq supporte-t-il les entiers **signés** sur `hex2dec` ? Si non, décaler les coordonnées (ex. `(x - 2^31) / 1000000`) via la colonne equation, ou passer en représentation non-signée avec un offset. - -- [ ] **Trouver un emplacement pour `misc`** (contexte de mesure 0–6) — 1 octet `hex2dec` sans unité ni équation. Placement proposé : à la suite de `longitude` dans l'ancien bloc `reserved`. - - ``` - 2|misc|hex2dec||| - ``` - -- [ ] Une fois les trois champs ajoutés : il reste **2 octets** sur les 11 du `reserved` initial (4+4+1 = 9). Garder une ligne `4|reserved|skip|||` (2 octets) pour évolutions futures, ou les réallouer. - +- [ ] **Côté firmware NebuleAir Pro 4G** : implémenter l'encodage offset de `latitude`/`longitude` (`raw = round((deg + 90|180) * 1_000_000)`) et positionner `device_status.GPS_NO_FIX` quand il n'y a pas de fix. +- [ ] **Valider en test réel** que l'équation Miotiq `x/1000000-90` est acceptée telle quelle dans la colonne equation (soustraction littérale). Fallback si refusée : firmware envoie `raw / 1000` (millidegrés + 90000 pour lat, + 180000 pour lon) et équation devient `x/1000-90`. À tester une fois, valable à vie. - [ ] Confirmer l'endianness des champs multi-octets (big-endian supposé). - [ ] Confirmer le caractère signé/non-signé de `battery_current` (décharge = négatif ?). - [ ] Migrer MobileAir du format binaire 17B vers un descripteur Miotiq formel. @@ -297,3 +297,4 @@ Côté PHP (cf. implémentations existantes `udp_miotiq_byte.php` / `udp_miotiq_ | 2026-04-23 | v3 | Format descripteur aligné sur doc officielle Miotiq : 6e colonne = export JSON (W/Y/N), ajout base functions `hex2bin` et `userdef`, colonne `equation` (expression en x). | | 2026-04-23 | v4 | Correction : `string` produit du hex (pas ASCII). Correction ISO_39=PM2.5 et ISO_24=PM10 (inversion). Gaz confirmés (NO₂/CO/H₂S/NH₃/O₃). Lien vers JSON canonique AirCarto 2026. | | 2026-04-23 | v5 | Extension prévue du descripteur NebuleAir Pro 4G avec `latitude`, `longitude`, `misc` dans le bloc `reserved` — proposition d'encodage dans la section À faire. | +| 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`. |