Files
aircarto-protocols/sensors/nextpm.md
Your Name a27af69f27 docs(nextpm): rewrite around Modbus RTU mode
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>
2026-05-04 13:52:50 +02:00

12 KiB
Raw Blame History

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 (ModbusMaster Arduino, 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
5657 0x0038 PM1 — moyenne 10 s 2 registres (uint32) value / 1000 µg/m³
5859 0x003A PM2.5 — moyenne 10 s 2 registres (uint32) value / 1000 µg/m³
6061 0x003C PM10 — moyenne 10 s 2 registres (uint32) value / 1000 µg/m³
6869 0x0044 PM1 — moyenne 60 s 2 registres (uint32) value / 1000 µg/m³
7071 0x0046 PM2.5 — moyenne 60 s 2 registres (uint32) value / 1000 µg/m³
7273 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
128129 0x0080 Canal 1 — particules 0.20.5 µm 2 registres (uint32) comptage brut #
130131 0x0082 Canal 2 — particules 0.51.0 µm 2 registres (uint32) comptage brut #
132133 0x0084 Canal 3 — particules 1.02.5 µm 2 registres (uint32) comptage brut #
134135 0x0086 Canal 4 — particules 2.55.0 µm 2 registres (uint32) comptage brut #
136137 0x0088 Canal 5 — particules 5.010 µ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 en 0x38..0x8C la couvre probablement entre 0x4A et 0x55, 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
57 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

  1. 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).
  2. 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.
  3. Cycle de lecture aligné sur le rafraîchissement interne du capteur (10 s) — il est inutile d'interroger plus vite.
  4. Ignorer les 2 premières minutes après mise sous tension : le ventilateur monte en régime et les concentrations sont sous-estimées.
  5. 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.
  6. 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 / 0x13 lecture concentrations 10/60/900 s, 0x14 lecture T/HR, 0x15 sleep, 0x16 wake, 0x17 set fan speed, 0x21 set clock, 0x41 firmware version.
  • L'octet STATE est 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.py sur gitea.aircarto.fr.
    • Lecture par registre (C++/Arduino, ESP32) : moduleair_light/src/sensors.cpp sur github.com/aircarto.

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).