The previous doc described only the proprietary 0x81 UART protocol, but all current AirCarto firmwares (NebuleAir Pro 4G, ModuleAir light) talk to the NextPM in Modbus RTU. Document the actual register mapping (PM at 0x38/0x44 for 10s/60s averages, T/HR at 0x6B/0x6A, status at 0x13, 5 granulometric channels at 0x80-0x88), the LSW-MSW word order, and both reading strategies (per-register and bulk read). Move the proprietary 0x81 protocol to an annex; drop Python/C examples (to be published in separate docs). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
12 KiB
NextPM (Tera Sensor)
Capteur de particules Tera Sensor NextPM : mesure PM1, PM2.5, PM10 (µg/m³), 5 canaux de comptage granulométrique, et intègre un capteur de température et d'humidité interne. Communication UART.
Le capteur expose deux modes de communication mutuellement exclusifs :
- Modbus RTU (utilisé par défaut sur les intégrations AirCarto, dont le NebuleAir Pro 4G) — décrit dans le corps de cette doc.
- Protocole propriétaire Tera Sensor (préambule
0x81) — résumé en annexe à la fin.
Caractéristiques
| Paramètre | Valeur |
|---|---|
| Fabricant / modèle | Tera Sensor — NextPM |
| Grandeurs | PM1, PM2.5, PM10 (µg/m³), 5 canaux #, T (°C), HR (%) |
| Plage PM | 0 – 1000 µg/m³ |
| Alimentation | 5 V, ~100 mA pic, ~35 mA en veille |
| Interface | UART 3V3 (logique CMOS 3.3 V tolérante 5 V TX) |
| Vitesse UART | 115200 baud, 8E1 en Modbus (8N1 en propriétaire) |
| Rafraîchissement | 10 s côté capteur |
| Datasheet | https://www.tera-sensor.com/ |
Câblage
Connecteur JST-PH 4 broches du NextPM (vue côté capteur) :
| Pin capteur | Fil usuel | Fonction | MCU (exemple) |
|---|---|---|---|
| 1 | Rouge | VCC 5 V | 5V |
| 2 | Noir | GND | GND |
| 3 | Blanc | RX capteur (← TX MCU) | UART TX du MCU |
| 4 | Vert | TX capteur (→ RX MCU) | UART RX du MCU |
Le NextPM est en 3V3 côté logique : si le MCU est en 3V3 (nRF9151, ESP32, Raspberry Pi…), connecter directement. Pour un MCU 5 V, prévoir un level shifter sur TX→RX.
Protocole Modbus RTU
Paramètres de la liaison
- 115200 baud, 8 bits, parité paire (EVEN), 1 stop.
- Slave address par défaut :
0x01(configurable côté capteur). - Function code utilisé :
0x03(Read Holding Registers). - Checksum : CRC-16 Modbus (poly
0xA001), placé en fin de trame, little-endian (LSB d'abord). - Temps de traitement côté capteur : prévoir un délai de ~200 ms entre l'envoi de la requête et la lecture de la réponse.
Format de trame
Requête (8 octets pour une lecture de registres) :
+--------+--------+----------+----------+--------+
| ADDR | FUNC | REGADDR | QTY | CRC |
| 1B | 1B | 2B | 2B | 2B |
+--------+--------+----------+----------+--------+
big-endian big-endian little-endian
Réponse :
+--------+--------+--------+--------------------+--------+
| ADDR | FUNC | BCNT | DATA | CRC |
| 1B | 1B | 1B | 2 × QTY octets | 2B |
+--------+--------+--------+--------------------+--------+
BCNT = nombre d'octets de données = 2 × QTY. Chaque registre fait 2 octets, big-endian.
En cas d'erreur, le capteur répond avec FUNC | 0x80 suivi d'un code d'exception Modbus standard.
Stratégies de lecture
Deux approches pratiquées sur les firmwares AirCarto, toutes deux valides :
- Lecture par registre (ex. ModuleAir) : une requête Modbus par valeur (PM1, PM2.5, PM10, T, HR, status). Plus simple à implémenter avec une lib Modbus standard (
ModbusMasterArduino,pymodbus…). - Lecture en bloc (ex. NebuleAir Pro 4G) : une seule requête lit 85 registres à partir de
0x0038, et le firmware extrait localement chaque champ. Évite les courses entre mesures et minimise les échanges UART quand on veut tout récupérer (PM + 5 canaux + T/HR) :
Requête bloc complet : 01 03 00 38 00 55 <CRC_lo> <CRC_hi>
Mapping des registres
Le NextPM expose les concentrations PM avec plusieurs fenêtres de moyennage glissant (10 s, 60 s, et — selon firmware — 900 s), chacune occupant un bloc de 6 registres consécutifs (PM1 / PM2.5 / PM10 sur 2 registres uint32 chacun).
| Registre (déc) | Registre (hex) | Champ | Taille | Décodage | Unité |
|---|---|---|---|---|---|
| 19 | 0x0013 | Status capteur | 1 registre | value & 0xFF |
bitfield |
| 56–57 | 0x0038 | PM1 — moyenne 10 s | 2 registres (uint32) | value / 1000 |
µg/m³ |
| 58–59 | 0x003A | PM2.5 — moyenne 10 s | 2 registres (uint32) | value / 1000 |
µg/m³ |
| 60–61 | 0x003C | PM10 — moyenne 10 s | 2 registres (uint32) | value / 1000 |
µg/m³ |
| 68–69 | 0x0044 | PM1 — moyenne 60 s | 2 registres (uint32) | value / 1000 |
µg/m³ |
| 70–71 | 0x0046 | PM2.5 — moyenne 60 s | 2 registres (uint32) | value / 1000 |
µg/m³ |
| 72–73 | 0x0048 | PM10 — moyenne 60 s | 2 registres (uint32) | value / 1000 |
µg/m³ |
| 106 | 0x006A | Humidité relative | 1 registre | value / 100 |
%HR |
| 107 | 0x006B | Température interne | 1 registre | value / 100 (signed) |
°C |
| 128–129 | 0x0080 | Canal 1 — particules 0.2–0.5 µm | 2 registres (uint32) | comptage brut | # |
| 130–131 | 0x0082 | Canal 2 — particules 0.5–1.0 µm | 2 registres (uint32) | comptage brut | # |
| 132–133 | 0x0084 | Canal 3 — particules 1.0–2.5 µm | 2 registres (uint32) | comptage brut | # |
| 134–135 | 0x0086 | Canal 4 — particules 2.5–5.0 µm | 2 registres (uint32) | comptage brut | # |
| 136–137 | 0x0088 | Canal 5 — particules 5.0–10 µm | 2 registres (uint32) | comptage brut | # |
Une fenêtre de moyennage 900 s (15 min) existe sur le mode propriétaire (commande
0x13) ; le bloc lu en0x38..0x8Cla couvre probablement entre0x4Aet0x55, mais l'adresse exacte n'a pas été confirmée par lecture directe — vérifier datasheet avant usage.
Encodage des uint32 sur 2 registres : chaque registre Modbus est big-endian sur ses 2 octets, mais l'ordre des deux registres est LSW d'abord, MSW ensuite (« little-endian word order »). Reconstruction :
value = (MSW << 16) | LSW
avec LSW = registre N et MSW = registre N+1.
Bitfield du registre status (0x0013)
Octet de poids faible :
| Bit | Signification |
|---|---|
| 0 | Fan default (1 = vitesse dégradée / anormale) |
| 1 | Memory error |
| 2 | Sensor laser default |
| 3 | T/RH sensor default |
| 4 | Sleep mode |
| 5–7 | Réservés |
Un status 0x00 indique un fonctionnement nominal. Loguer la valeur à chaque cycle de mesure et la remonter au backend si elle est non nulle.
Les adresses et tailles de registres ci-dessus correspondent aux versions firmware NextPM utilisées par AirCarto en 2026. Toujours recroiser avec la datasheet Tera Sensor la plus récente avant d'intégrer une nouvelle révision hardware/firmware.
Mise en œuvre recommandée
- Choisir la fenêtre de moyennage selon le cas d'usage :
- 10 s (
0x0038) — réactivité, débogage, exposition courte. Cas typique : NebuleAir Pro 4G. - 60 s (
0x0044) — stabilité, transmission réseau périodique. Cas typique : ModuleAir light. - 900 s — historisation longue durée (à confirmer datasheet).
- 10 s (
- Choisir la stratégie de lecture (cf. plus haut) : registre par registre si on n'a besoin que des PM, lecture en bloc si on veut aussi les 5 canaux et T/HR.
- Cycle de lecture aligné sur le rafraîchissement interne du capteur (10 s) — il est inutile d'interroger plus vite.
- Ignorer les 2 premières minutes après mise sous tension : le ventilateur monte en régime et les concentrations sont sous-estimées.
- Toujours valider le CRC-16 (la plupart des libs Modbus le font) avant d'utiliser la trame ; en cas d'échec, écarter la mesure et incrémenter un compteur d'erreurs.
- Si toutes les valeurs lues sont nulles ou si la requête timeout, écrire en base une ligne « erreur » (ex. PM = 0, status =
0xFF) plutôt que sauter le cycle, pour pouvoir distinguer une absence de capteur d'une vraie mesure à 0.
Pièges connus
- Parité Modbus : le NextPM exige du 8E1, alors que la majorité des UART sont configurés en 8N1 par défaut. Une confusion sur la parité produit un silence radio total côté capteur.
- Word order des uint32 :
(MSW << 16) | LSW(LSW d'abord). Inverser donne des valeurs énormes parfois plausibles, à surveiller en intégration. - Masse commune : si le checksum/CRC échoue de manière intermittente, vérifier la masse (GND) entre MCU et NextPM — flottement de GND observé sur câbles longs.
- Démarrage à froid : prévoir 30 s de stabilisation après mise sous tension ou sortie de veille avant la première lecture exploitée.
Annexe : protocole propriétaire 0x81
Le NextPM supporte également un protocole UART propriétaire Tera Sensor, non utilisé par les firmwares AirCarto actuels mais documenté dans la datasheet officielle :
- UART 115200 8N1 (pas de parité).
- Toutes les trames commencent par le préambule
0x81. - Checksum simple sur 1 octet :
(256 − somme(octets précédents)) mod 256. - Commandes (extrait) :
0x11/0x12/0x13lecture concentrations 10/60/900 s,0x14lecture T/HR,0x15sleep,0x16wake,0x17set fan speed,0x21set clock,0x41firmware version. - L'octet
STATEest inclus inline dans la réponse, juste après le code de commande.
Pour une intégration complète dans ce mode, se référer à la datasheet Tera Sensor — ce mode et le mode Modbus RTU s'excluent mutuellement.
Références
- Datasheet Tera Sensor : https://www.tera-sensor.com/ (demander la dernière révision PDF).
- Code de référence AirCarto en mode Modbus :
- Lecture en bloc (Python, Raspberry Pi) :
nebuleair_pro_4g/NPM/get_data_modbus_v3.pysur gitea.aircarto.fr. - Lecture par registre (C++/Arduino, ESP32) :
moduleair_light/src/sensors.cppsur github.com/aircarto.
- Lecture en bloc (Python, Raspberry Pi) :
Historique
| Date | Révision | Changement |
|---|---|---|
| 2026-04-23 | v1 | Création de la doc (mode propriétaire 0x81). |
| 2026-05-04 | v2 | Réécriture autour du mode Modbus RTU effectivement utilisé en prod ; ajout du mapping de registres et des 5 canaux ; mode propriétaire déplacé en annexe ; exemples de code retirés (à publier dans des docs séparées). |
| 2026-05-04 | v2.1 | Ajout de la fenêtre de moyennage 60 s (0x0044/0x0046/0x0048) constatée sur ModuleAir light ; explicite les deux stratégies de lecture (registre par registre vs bloc complet). |