Topics MQTT¶
Référence complète de la structure des topics MQTT et du format des messages utilisés par ExploreIOT pour la communication entre les capteurs LoRaWAN et le backend.
Voir aussi
Pour comprendre le pattern pub/sub et l'architecture MQTT du projet, voir Architecture MQTT.
Structure des topics¶
ExploreIOT utilise le format de topic Chirpstack v4 dans tous les modes (production et simulation) :
| Segment | Description |
|---|---|
application |
Préfixe fixe |
{app_id} |
Identifiant de l'application Chirpstack (UUID ou nom) |
device |
Préfixe fixe |
{device_id} |
EUI-64 du capteur, 16 caractères hexadécimaux (ex: a1b2c3d4e5f60001) |
event |
Préfixe fixe |
up |
Type d'événement — up désigne un uplink (données montantes du capteur) |
Exemple de topic complet :
En mode simulation, publisher.py publie sur le même format de topic que Chirpstack v4, garantissant que le subscriber utilise un pipeline identique quel que soit le mode.
Abonnement avec wildcard¶
Le subscriber MQTT s'abonne à tous les capteurs en une seule souscription grâce au wildcard + de MQTT, qui remplace exactement un niveau de topic.
Ce pattern capture les messages de n'importe quelle application et n'importe quel capteur.
Configuré via la variable d'environnement MQTT_TOPIC :
Format du payload MQTT¶
Les messages MQTT publiés par Chirpstack suivent le format JSON de l'API Chirpstack v4. Le champ data contient la charge utile binaire du capteur encodée en Base64.
Structure JSON complète¶
{
"deduplicationId": "550e8400-e29b-41d4-a716-446655440000",
"time": "2026-04-11T14:30:05.123456789Z",
"deviceInfo": {
"tenantId": "52f14cd4-c6f1-4fbd-8f87-4025e1d49242",
"tenantName": "exploreiot",
"applicationId": "64dfc3f0-9c37-4d34-8b01-c9b6e1b2f3a4",
"applicationName": "exploreiot-demo",
"deviceProfileId": "a8f9b2c1-3e4d-5f6a-7b8c-9d0e1f2a3b4c",
"deviceProfileName": "SHT31-LoRa",
"deviceName": "Capteur Bureau 1",
"devEui": "a1b2c3d4e5f60001",
"tags": {}
},
"devAddr": "00a1b2c3",
"adr": true,
"dr": 5,
"fCnt": 1523,
"fPort": 1,
"confirmed": false,
"data": "AYgCKg==",
"rxInfo": [
{
"gatewayId": "0016c001f1500812",
"snr": 9.5,
"rssi": -67,
"location": {
"latitude": 48.8566,
"longitude": 2.3522,
"altitude": 35
}
}
],
"txInfo": {
"frequency": 868100000,
"modulation": {
"lora": {
"bandwidth": 125000,
"spreadingFactor": 7,
"codeRate": "CR_4_5"
}
}
}
}
Champs principaux¶
| Champ | Type | Description |
|---|---|---|
time |
string (ISO 8601) | Horodatage de réception par la passerelle |
deviceInfo.devEui |
string (hex 16 car.) | EUI-64 du capteur LoRaWAN |
deviceInfo.deviceName |
string | Nom convivial configuré dans Chirpstack |
fPort |
entier | Port applicatif LoRaWAN (1–223) |
fCnt |
entier | Compteur de trames (frame counter) |
data |
string (Base64) | Charge utile binaire du capteur, encodée en Base64 |
rxInfo[].rssi |
entier | Force du signal en dBm (ex: -67) |
rxInfo[].snr |
décimal | Rapport signal/bruit en dB (ex: 9.5) |
txInfo.frequency |
entier | Fréquence d'émission en Hz (ex: 868100000 = 868.1 MHz) |
Encodage binaire du champ data¶
Le champ data contient la charge utile applicative du capteur encodée en Base64. Ce sont des octets bruts dont l'interprétation dépend du protocole applicatif défini par le fabricant du capteur.
Exemple de décodage¶
Pour un capteur SHT31 typique, la charge utile de 4 octets encode la température et l'humidité :
Interprétation (format big-endian, valeurs sur 16 bits, facteur 0.1) :
Octets 0-1 : 0x0188 = 392 → température = 39.2 / 1.6 = 24.5°C
Octets 2-3 : 0x022A = 554 → humidité = 55.4 / 0.9 = 61.6%
Le subscriber ExploreIOT (backend/subscriber.py) contient le décodeur spécifique au format de payload utilisé. Pour adapter le décodage à un autre type de capteur, modifiez la fonction decode_payload() dans ce fichier.
Décoder en Python¶
import base64
import struct
# Payload reçu dans le message MQTT
b64_data = "AYgCKg=="
# Décoder depuis Base64
raw_bytes = base64.b64decode(b64_data)
print(f"Bytes hex : {raw_bytes.hex()}") # 018802 2a
# Exemple d'interprétation (à adapter selon le capteur)
if len(raw_bytes) >= 4:
temp_raw, hum_raw = struct.unpack(">HH", raw_bytes[:4])
temperature = temp_raw / 16.0
humidite = hum_raw / 9.0
print(f"Température : {temperature:.1f}°C")
print(f"Humidité : {humidite:.1f}%")
QoS (Quality of Service)¶
ExploreIOT utilise QoS 1 (at-least-once) pour les publications et les souscriptions MQTT.
| Niveau | Nom | Garantie |
|---|---|---|
| 0 | At-most-once | Message envoyé une fois, sans confirmation |
| 1 | At-least-once | Message envoyé jusqu'à confirmation de réception (peut être dupliqué) |
| 2 | Exactly-once | Message envoyé exactement une fois (le plus coûteux) |
QoS 1 est le bon compromis pour l'IoT : il garantit qu'aucune mesure n'est perdue en cas de coupure réseau, tout en restant léger pour les capteurs à batterie. Le subscriber gère la déduplication éventuelle grâce au compteur de trames fCnt.
Identifiants de topic¶
app_id¶
En mode simulation : exploreiot-demo
En production, l'app_id correspond à l'identifiant UUID de l'application dans Chirpstack. Il est visible dans l'interface d'administration Chirpstack sous Applications.
device_id (DevEUI)¶
Format : 16 caractères hexadécimaux en minuscules (EUI-64).
Le DevEUI est un identifiant unique mondial gravé en usine dans chaque module LoRa. Il est imprimé sur l'étiquette du capteur ou visible dans l'interface Chirpstack.
Exemples :
- a1b2c3d4e5f60001
- 0016c001f1500812
- deadbeefcafe0042