chore: initial skeleton — NextPM sensor, JSON format, Miotiq UDP parser
This commit is contained in:
90
sensors/_TEMPLATE.md
Normal file
90
sensors/_TEMPLATE.md
Normal file
@@ -0,0 +1,90 @@
|
||||
# <Nom du capteur>
|
||||
|
||||
Remplace ce bloc par une ligne de résumé : fabricant, grandeurs mesurées, interface principale.
|
||||
|
||||
> Exemple : « Tera Sensor NextPM — capteur de particules PM1/PM2.5/PM10, interface UART. »
|
||||
|
||||
## Caractéristiques
|
||||
|
||||
| Paramètre | Valeur |
|
||||
|--------------------------|-------------------------------|
|
||||
| Fabricant / modèle | |
|
||||
| Grandeurs mesurées | PM1, PM2.5, PM10 / T / HR / … |
|
||||
| Plage | |
|
||||
| Précision | |
|
||||
| Alimentation | 3V3 / 5V, mA typique |
|
||||
| Interface | UART / I2C / SPI / analogique |
|
||||
| Datasheet | URL |
|
||||
|
||||
## Câblage
|
||||
|
||||
Lister **chaque fil** avec sa couleur, le pin côté capteur et le pin côté MCU de référence.
|
||||
|
||||
| Fil capteur | Pin capteur | Fonction | Pin MCU (exemple nRF9151) |
|
||||
|-------------|-------------|----------|---------------------------|
|
||||
| Rouge | 1 | VCC | 3V3 |
|
||||
| Noir | 2 | GND | GND |
|
||||
| … | | | |
|
||||
|
||||
## Protocole
|
||||
|
||||
- Transport : UART 115200 8N1 / I2C 100 kHz / …
|
||||
- Adresse (si I2C) :
|
||||
- Polarité, endianness :
|
||||
|
||||
### Format de trame
|
||||
|
||||
Décrire exactement la structure : header, champs, checksum, taille.
|
||||
|
||||
```
|
||||
+------+-----+------+------+-----+
|
||||
| HDR | CMD | LEN | DATA | CS |
|
||||
+------+-----+------+------+-----+
|
||||
1B 1B 1B Nb 1B
|
||||
```
|
||||
|
||||
Checksum : algorithme exact (`256 - sum(prev) mod 256`, CRC8, CRC16 poly…).
|
||||
|
||||
### Commandes
|
||||
|
||||
| Commande | Code | Requête | Réponse (taille, champs) |
|
||||
|----------|------|------------------------|-----------------------------------|
|
||||
| Read X | 0x11 | `81 11 …` | `81 11 state <data> cs` |
|
||||
| Sleep | 0x15 | | |
|
||||
|
||||
### Décodage des champs
|
||||
|
||||
Pour chaque donnée retournée, précise :
|
||||
- Position, taille, endianness.
|
||||
- Facteur d'échelle (ex. `val / 10.0` pour obtenir des µg/m³).
|
||||
- Unité finale.
|
||||
|
||||
## Exemple de code
|
||||
|
||||
### Lecture (pseudo-C)
|
||||
|
||||
```c
|
||||
// TODO
|
||||
```
|
||||
|
||||
### Lecture (Python)
|
||||
|
||||
```python
|
||||
# TODO
|
||||
```
|
||||
|
||||
## Spécificités connues / pièges
|
||||
|
||||
- …
|
||||
|
||||
## Références
|
||||
|
||||
- Datasheet : URL
|
||||
- Code de référence utilisé en prod : `<repo>/src/drivers/<fichier>`
|
||||
- Note d'application constructeur : URL
|
||||
|
||||
## Historique
|
||||
|
||||
| Date | Révision | Changement |
|
||||
|------------|----------|-----------------------------------------------|
|
||||
| YYYY-MM-DD | v1 | Création de la doc. |
|
||||
183
sensors/nextpm.md
Normal file
183
sensors/nextpm.md
Normal file
@@ -0,0 +1,183 @@
|
||||
# NextPM (Tera Sensor)
|
||||
|
||||
Capteur de particules **Tera Sensor NextPM** : mesure PM1, PM2.5, PM10 en masse (µg/m³) et en nombre (#/cm³), intègre un capteur de température et d'humidité embarqué. Communication **UART**.
|
||||
|
||||
## Caractéristiques
|
||||
|
||||
| Paramètre | Valeur |
|
||||
|------------------------|--------------------------------------------------|
|
||||
| Fabricant / modèle | Tera Sensor — NextPM |
|
||||
| Grandeurs | PM1, PM2.5, PM10 (µg/m³ et #/cm³), 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 par défaut | 115200 baud, 8N1 |
|
||||
| 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…), connecter directement. Pour un MCU 5 V, prévoir un level shifter sur TX→RX.
|
||||
|
||||
## Protocole UART
|
||||
|
||||
- 115200 bauds, 8 bits, pas de parité, 1 stop.
|
||||
- Toutes les trames commencent par **`0x81`** (préambule).
|
||||
- Checksum = `(256 - somme(octets précédents)) mod 256`, placé en dernier octet.
|
||||
- Délai de traitement côté capteur : 15–30 ms typique ; prévoir timeout de lecture de 200 ms.
|
||||
|
||||
### Structure des trames
|
||||
|
||||
**Requête MCU → capteur** (sans données) :
|
||||
|
||||
```
|
||||
+------+------+------+
|
||||
| 0x81 | CMD | CS |
|
||||
+------+------+------+
|
||||
```
|
||||
|
||||
**Requête MCU → capteur** (avec données) :
|
||||
|
||||
```
|
||||
+------+------+----------+------+
|
||||
| 0x81 | CMD | DATA... | CS |
|
||||
+------+------+----------+------+
|
||||
```
|
||||
|
||||
**Réponse capteur → MCU** :
|
||||
|
||||
```
|
||||
+------+------+-------+------------+------+
|
||||
| 0x81 | CMD | STATE | DATA... | CS |
|
||||
+------+------+-------+------------+------+
|
||||
```
|
||||
|
||||
`STATE` (1 octet) est un bitfield d'état :
|
||||
|
||||
| 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 `STATE == 0x00` indique un fonctionnement nominal.
|
||||
|
||||
### Commandes principales
|
||||
|
||||
| Commande | Code | Taille requête | Taille réponse | Notes |
|
||||
|-------------------------------|-------|----------------|----------------|----------------------------------------------|
|
||||
| Read concentrations 10 s | 0x11 | 3 | 16 | Moyenne glissante 10 s |
|
||||
| Read concentrations 60 s | 0x12 | 3 | 16 | Moyenne glissante 60 s (plus stable) |
|
||||
| Read concentrations 900 s | 0x13 | 3 | 16 | Moyenne glissante 15 min |
|
||||
| Read T/RH | 0x14 | 3 | 10 | Température et humidité |
|
||||
| Sleep (fan off) | 0x15 | 3 | 4 | Passe en veille, ventilateur coupé |
|
||||
| Wake / fan on | 0x16 | 3 | 4 | Sort de veille |
|
||||
| Set fan speed | 0x17 | 4 | 4 | 1 octet supplémentaire (% vitesse) |
|
||||
| Set clock | 0x21 | 9 | 4 | Horodatage interne |
|
||||
| Read firmware version | 0x41 | 3 | variable | Retourne une chaîne ASCII |
|
||||
|
||||
> Les codes et tailles ci-dessus sont issus de l'intégration de référence. **Toujours recroiser avec la datasheet Tera Sensor la plus récente** avant d'implémenter une nouvelle version firmware — certains registres ont changé entre révisions hardware.
|
||||
|
||||
### Format de la réponse `0x11` / `0x12` / `0x13`
|
||||
|
||||
16 octets de DATA, big-endian :
|
||||
|
||||
| Offset | Taille | Champ | Unité | Décodage |
|
||||
|--------|--------|-----------------------|---------------|-------------------------|
|
||||
| 0 | 2 | PM1 number | #/cm³ | valeur brute |
|
||||
| 2 | 2 | PM2.5 number | #/cm³ | valeur brute |
|
||||
| 4 | 2 | PM10 number | #/cm³ | valeur brute |
|
||||
| 6 | 2 | PM1 mass | µg/m³ × 10 | `raw / 10.0` |
|
||||
| 8 | 2 | PM2.5 mass | µg/m³ × 10 | `raw / 10.0` |
|
||||
| 10 | 2 | PM10 mass | µg/m³ × 10 | `raw / 10.0` |
|
||||
|
||||
### Format de la réponse `0x14`
|
||||
|
||||
| Offset | Taille | Champ | Unité | Décodage |
|
||||
|--------|--------|---------------|--------------|---------------------------|
|
||||
| 0 | 2 | Température | °C × 100 | `raw / 100.0` (signed) |
|
||||
| 2 | 2 | Humidité | %HR × 100 | `raw / 100.0` |
|
||||
|
||||
## Exemple de code
|
||||
|
||||
### Construction de la requête (C)
|
||||
|
||||
```c
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
static uint8_t nextpm_checksum(const uint8_t *buf, size_t len) {
|
||||
uint32_t sum = 0;
|
||||
for (size_t i = 0; i < len; i++) sum += buf[i];
|
||||
return (uint8_t)(256 - (sum & 0xFF));
|
||||
}
|
||||
|
||||
// Envoie une commande sans données (0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x41)
|
||||
size_t nextpm_build_cmd(uint8_t cmd, uint8_t *out) {
|
||||
out[0] = 0x81;
|
||||
out[1] = cmd;
|
||||
out[2] = nextpm_checksum(out, 2);
|
||||
return 3;
|
||||
}
|
||||
```
|
||||
|
||||
### Décodage de la réponse 0x11 / 0x12 / 0x13 (Python)
|
||||
|
||||
```python
|
||||
import struct
|
||||
|
||||
def decode_pm(frame: bytes) -> dict:
|
||||
if len(frame) != 16 or frame[0] != 0x81:
|
||||
raise ValueError("trame NextPM invalide")
|
||||
cmd, state = frame[1], frame[2]
|
||||
data = frame[3:15]
|
||||
cs_expected = (256 - sum(frame[:15])) & 0xFF
|
||||
if cs_expected != frame[15]:
|
||||
raise ValueError("checksum NextPM incorrect")
|
||||
|
||||
pm1_n, pm25_n, pm10_n, pm1_m, pm25_m, pm10_m = struct.unpack(">HHHHHH", data)
|
||||
return {
|
||||
"state": state,
|
||||
"pm1_num": pm1_n,
|
||||
"pm25_num": pm25_n,
|
||||
"pm10_num": pm10_n,
|
||||
"pm1": pm1_m / 10.0,
|
||||
"pm25": pm25_m / 10.0,
|
||||
"pm10": pm10_m / 10.0,
|
||||
}
|
||||
```
|
||||
|
||||
## Mise en œuvre recommandée
|
||||
|
||||
1. Au boot : `0x16` (wake) puis laisser 30 s de stabilisation du flux avant de lire.
|
||||
2. Utiliser `0x12` (moyenne 60 s) pour l'envoi réseau standard — meilleur compromis bruit/latence.
|
||||
3. Loguer `STATE` à chaque lecture ; remonter au backend si `STATE != 0`.
|
||||
4. En cas de cycle veille/mesure (ex. applications sur batterie) : `0x15` (sleep), attendre la prochaine fenêtre, `0x16`, 30 s stabilisation, lire, renvoyer en sleep.
|
||||
|
||||
## Pièges connus
|
||||
|
||||
- Les **2 premières minutes** après le wake sont à ignorer (le ventilateur monte en régime, concentrations sous-estimées).
|
||||
- Si le checksum est faux une fois sur deux : vérifier la masse commune (GND) entre MCU et NextPM — flottement du GND observé sur certains câbles longs.
|
||||
- Le NextPM renvoie parfois un octet `0x00` avant le préambule si la ligne UART n'était pas propre au démarrage : implémenter une resynchronisation sur `0x81` côté parser MCU.
|
||||
|
||||
## Références
|
||||
|
||||
- Datasheet : https://www.tera-sensor.com/ (demander la dernière révision PDF)
|
||||
- Code firmware de référence AirCarto : `nebuleair_pro_4g` et `esp32_NPM_only` sur [gitea.aircarto.fr](https://gitea.aircarto.fr/PaulVua).
|
||||
|
||||
## Historique
|
||||
|
||||
| Date | Révision | Changement |
|
||||
|------------|----------|---------------------------------|
|
||||
| 2026-04-23 | v1 | Création de la doc. |
|
||||
Reference in New Issue
Block a user