Automatisation IoT

Intégration MQTT de The Things Network : relayer les uplinks LoRaWAN vers votre broker

Abonnez-vous au serveur MQTT de The Things Network, décodez les uplinks LoRaWAN avec un payload formatter et republiez un JSON de capteur propre dans votre propre arborescence de topics grâce à un court pont Python.

Pont The Things Network MQTT acheminant les uplinks de capteurs LoRaWAN depuis une passerelle vers l'arborescence de topics d'un broker MQTT cloud
Essayez-le sur votre propre broker MQTTObtenez un broker MQTT privé et managé avec l’offre Free et partez d’exemples de code prêts à l’emploi.
Essayer gratuitement Exemples de code Aucune carte bancaire requise

Le serveur The Things Network MQTT fournit à chaque application un flux en direct de ses uplinks LoRaWAN, ce qui facilite l'intégration de données de capteurs longue portée dans vos propres systèmes. Dans ce tutoriel, vous allez écrire un payload formatter, vous connecter au serveur MQTT de TTN avec une clé d'API et exécuter un petit pont Python qui republie les mesures décodées en JSON propre dans l'arborescence de topics de votre propre broker, où tableaux de bord, Node-RED et automatisations peuvent les exploiter aux côtés de vos autres appareils.

Pourquoi relayer TTN vers votre propre broker

The Things Network (TTN) gère la partie radio de LoRaWAN : passerelles, activation des appareils, déduplication et déchiffrement. Son serveur MQTT publie chaque uplink sous la forme d'un volumineux document JSON contenant les métadonnées de chaque passerelle ayant capté le paquet. C'est excellent pour le débogage, mais peu pratique comme modèle de données à long terme :

  • les topics sont ceux de TTN (v3/<app>@ttn/devices/<device>/up), pas la hiérarchie de votre site ;
  • les payloads sont gros et imbriqués, alors que la plupart des consommateurs ne veulent que trois ou quatre valeurs ;
  • vos appareils Wi-Fi, automates et contrôleurs se trouvent déjà sur un autre broker.

Un pont résout ces trois problèmes. Il s'abonne à TTN, extrait l'essentiel et publie des messages compacts dans la même arborescence de topics que tout le reste. Les consommateurs n'ont jamais besoin des identifiants TTN, et si vous passez plus tard à un serveur de réseau privé, seul le pont change. Le guide agriculture intelligente IoT explique où cela s'inscrit dans une conception à l'échelle de l'exploitation.

Étape 1 : décoder le payload dans TTN

Les appareils LoRaWAN envoient des octets compacts. Ajoutez un payload formatter dans la console TTN sous Applications > votre application > Payload formatters > Uplink, type Custom Javascript formatter. Cet exemple décode un nœud de sol qui envoie l'humidité (uint16, en dixièmes de pour cent), la température du sol (int16, en dixièmes de degré) et la batterie (uint16, en millivolts) :

function decodeUplink(input) {
  var b = input.bytes;
  if (input.fPort !== 1 || b.length < 6) {
    return { errors: ["unexpected port or length"] };
  }
  var moisture = ((b[0] << 8) | b[1]) / 10;
  var tRaw = (b[2] << 8) | b[3];
  if (tRaw & 0x8000) tRaw -= 0x10000;
  var battery = ((b[4] << 8) | b[5]) / 1000;
  return {
    data: {
      moisture_pct: moisture,
      soil_temp_c: tRaw / 10,
      battery_v: battery
    },
    warnings: [],
    errors: []
  };
}

Utilisez le panneau Test avec un payload hexadécimal comme 0136 008C 0E74 pour vérifier le résultat avant de déployer le moindre appareil. L'objet décodé apparaît dans chaque uplink sous uplink_message.decoded_payload.

Étape 2 : obtenir les identifiants MQTT auprès de TTN

Dans la console, ouvrez Integrations > MQTT. Vous y verrez :

Paramètre Valeur
Serveur Votre cluster, par exemple eu1.cloud.thethings.network
Ports 1883 (en clair) et 8883 (TLS)
Nom d'utilisateur <application-id>@ttn
Mot de passe Une clé d'API ; cliquez sur Generate new API key

Copiez immédiatement la clé d'API ; TTN ne l'affiche qu'une seule fois. Utilisez toujours le port 8883 vers TTN, car la clé donne accès aux données de votre application. La section consacrée au serveur MQTT dans la documentation officielle de The Things Stack liste l'ensemble des topics, y compris les événements de join, de downlink et de service.

Le topic d'uplink d'une application est :

v3/<application-id>@ttn/devices/<device-id>/up

Vous pouvez vérifier le flux avant d'écrire la moindre ligne de code :

mosquitto_sub -h eu1.cloud.thethings.network -p 8883 --capath /etc/ssl/certs \
  -u 'my-farm-app@ttn' -P 'NNSXS.YOUR_TTN_API_KEY' \
  -t 'v3/my-farm-app@ttn/devices/+/up' -v

Étape 3 : le pont The Things Network MQTT en Python

Le pont utilise deux clients paho-mqtt 2.x : l'un abonné à TTN, l'autre publiant vers votre broker. Exécutez-le d'abord avec le serveur MQTT public gratuit broker.connectmq.com, réservé aux tests, en remplaçant t6n1b4 par votre propre chaîne aléatoire, car l'espace public est lisible par tous.

import json
import os
import ssl

import paho.mqtt.client as mqtt

TTN_HOST = "eu1.cloud.thethings.network"
TTN_APP = os.environ.get("TTN_APP", "my-farm-app")
TTN_KEY = os.environ["TTN_API_KEY"]

OUT_HOST = os.environ.get("OUT_HOST", "broker.connectmq.com")
OUT_PORT = int(os.environ.get("OUT_PORT", "1883"))
OUT_USER = os.environ.get("OUT_USER")          # à définir en production
OUT_PASS = os.environ.get("OUT_PASS")
OUT_CLIENT_ID = os.environ.get("OUT_CLIENT_ID", "ttn-bridge-out-t6n1b4")
OUT_PREFIX = os.environ.get("OUT_PREFIX", "connectmq/demo/t6n1b4/farm")

# --- broker de sortie --------------------------------------------------------
out = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id=OUT_CLIENT_ID)
if OUT_USER:
    out.username_pw_set(OUT_USER, OUT_PASS)
if OUT_PORT == 8883:
    out.tls_set(cert_reqs=ssl.CERT_REQUIRED)
out.will_set(f"{OUT_PREFIX}/bridge/status", "offline", qos=1, retain=True)

def out_on_connect(client, userdata, flags, reason_code, properties):
    print("out broker:", reason_code)
    client.publish(f"{OUT_PREFIX}/bridge/status", "online", qos=1, retain=True)

out.on_connect = out_on_connect
out.connect(OUT_HOST, OUT_PORT, keepalive=60)
out.loop_start()

# --- TTN ---------------------------------------------------------------------
def ttn_on_connect(client, userdata, flags, reason_code, properties):
    print("ttn:", reason_code)
    client.subscribe(f"v3/{TTN_APP}@ttn/devices/+/up", qos=1)

def ttn_on_message(client, userdata, msg):
    try:
        up = json.loads(msg.payload)
        device = up["end_device_ids"]["device_id"]
        um = up["uplink_message"]
        decoded = um.get("decoded_payload")
    except (ValueError, KeyError) as exc:
        print("skipping malformed uplink:", exc)
        return
    if not decoded:
        print(f"{device}: no decoded payload (check the formatter)")
        return

    rx = um.get("rx_metadata", [])
    best = max(rx, key=lambda g: g.get("rssi", -999)) if rx else {}
    record = {
        "ts": up.get("received_at"),
        **decoded,
        "rssi": best.get("rssi"),
        "snr": best.get("snr"),
        "gateways": len(rx),
        "f_cnt": um.get("f_cnt"),
    }
    topic = f"{OUT_PREFIX}/{device}/telemetry"
    out.publish(topic, json.dumps(record), qos=1, retain=True)
    print(topic, record)

ttn = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2,
                  client_id=f"ttn-bridge-in-{TTN_APP}")
ttn.username_pw_set(f"{TTN_APP}@ttn", TTN_KEY)
ttn.tls_set(cert_reqs=ssl.CERT_REQUIRED)
ttn.on_connect = ttn_on_connect
ttn.on_message = ttn_on_message
ttn.connect(TTN_HOST, 8883, keepalive=60)
ttn.loop_forever()

Exécutez-le :

pip install paho-mqtt
export TTN_API_KEY='NNSXS.YOUR_TTN_API_KEY'
python ttn_bridge.py

Et observez la sortie propre depuis un autre terminal :

mosquitto_sub -h broker.connectmq.com -p 1883 -i watch-t6n1b4 \
  -t 'connectmq/demo/t6n1b4/farm/#' -v

Chaque uplink devient un retained message comme {"ts":"2026-10-16T06:15:02Z","moisture_pct":31.0,"soil_temp_c":14.0,"battery_v":3.7,"rssi":-108,"snr":4.5,"gateways":2,"f_cnt":412}. Comme il est retained, un tableau de bord qui démarre plus tard voit immédiatement la dernière mesure de chaque capteur, ce qui compte pour des appareils qui n'émettent que toutes les 15 minutes.

Notes de conception

Pourquoi inclure le RSSI, le SNR et le nombre de passerelles ? Ce sont les premiers signes d'une antenne défaillante, d'une passerelle déplacée ou d'un capteur qui s'enfonce dans la boue. Les stocker ne coûte presque rien.

Pourquoi des retained messages ? Les appareils LoRaWAN sont silencieux la plupart du temps. Sans retain, tout consommateur qui se connecte entre deux uplinks ne voit rien jusqu'au suivant.

Pourquoi la QoS 1 des deux côtés ? Le pont peut redémarrer pendant que TTN livre des messages ; la QoS 1 associée à un client qui se reconnecte réduit les trous. Pour les compromis, consultez les niveaux de QoS MQTT expliqués.

Profondeur des topics. connectmq/demo/t6n1b4/farm/<device>/telemetry compte six niveaux, bien en deçà de la limite de huit niveaux du serveur MQTT public gratuit. En production, utilisez votre propre hiérarchie, comme farm1/north/<device>/telemetry.

Taille des messages. Un uplink TTN brut avec les métadonnées de plusieurs passerelles peut atteindre quelques kilo-octets. L'enregistrement republié pèse quelques centaines d'octets, bien en dessous de la limite de 64 Ko de l'espace public de test et de celle de 256 Ko du plan gratuit de ConnectMQ, et il est beaucoup moins coûteux à traiter pour les tableaux de bord et les clients mobiles sur batterie.

Gérer les trous et les doublons

LoRaWAN est par conception une liaison radio avec pertes : les appareils émettent sans accusé de réception, et un paquet qu'aucune passerelle ne capte est tout simplement perdu. Le compteur de trames (f_cnt) inclus dans chaque enregistrement permet aux consommateurs de détecter les trous. Si le compteur passe de 410 à 413, deux uplinks ont été perdus côté radio, pas dans MQTT. Cette distinction fait gagner du temps lorsque quelqu'un signale des données manquantes.

Le pont peut aussi voir deux fois le même uplink s'il se reconnecte à TTN pendant qu'un message QoS 1 est en transit. Les consommateurs qui stockent les données doivent traiter la combinaison identifiant d'appareil et compteur de trames comme une clé unique et ignorer les répétitions. Notez que le compteur est réinitialisé lorsqu'un appareil rejoint à nouveau le réseau : utilisez-le donc pour détecter les trous sur de courtes périodes plutôt que comme identifiant permanent.

Pour envoyer une commande à un appareil (par exemple un nouvel intervalle d'émission), le pont peut s'abonner à un topic de commande sur votre broker et la transmettre au topic de downlink de TTN :

import base64

def forward_downlink(device_id, port, raw_bytes):
    body = {"downlinks": [{
        "f_port": port,
        "frm_payload": base64.b64encode(raw_bytes).decode(),
        "priority": "NORMAL",
    }]}
    ttn.publish(f"v3/{TTN_APP}@ttn/devices/{device_id}/down/push",
                json.dumps(body), qos=1)

# exemple : régler l'intervalle à 30 minutes (un octet) sur le port 2
# forward_downlink("soil-node-07", 2, bytes([30]))

Les appareils de classe A ne reçoivent les downlinks qu'après leur prochain uplink : les commandes arrivent donc avec un délai égal à l'intervalle d'émission. Limitez les downlinks ; le temps d'antenne LoRaWAN et les règles de rapport cyclique les rendent coûteux.

Le faire fonctionner de manière fiable

  1. Exécutez le pont comme service systemd ou conteneur avec redémarrage automatique.
  2. Conservez la clé d'API TTN dans une variable d'environnement ou un coffre de secrets, jamais dans le script.
  3. N'accordez à la clé d'API que les droits nécessaires (lecture du trafic de l'application et, le cas échéant, écriture des downlinks).
  4. Surveillez bridge/status : le last will le passe à offline si le processus meurt.
  5. Gardez à l'esprit la politique d'utilisation équitable de TTN pour le réseau communautaire ; il est conçu pour des capteurs à faible fréquence, pas pour des appareils bavards.

Production sur un broker privé

Définissez OUT_HOST=broker.connectmq.com, OUT_PORT=8883, OUT_USER, OUT_PASS et OUT_CLIENT_ID avec les identifiants délivrés pour votre broker privé, et remplacez OUT_PREFIX par votre propre hiérarchie. Le reste du script ne change pas. Un broker MQTT managé offre à vos données LoRaWAN, capteurs Wi-Fi et contrôleurs un emplacement commun et chiffré que vous n'avez pas à maintenir. Si vous exploitez votre propre serveur de réseau au lieu de TTN, le tutoriel ChirpStack MQTT présente le pont équivalent, et le montage capteur d'humidité du sol MQTT est une alternative Wi-Fi pour les parcelles proches des bâtiments. D'autres modèles sont réunis dans le guide de l'automatisation IoT, et les bases sur le rôle d'un broker MQTT vous aideront si MQTT est nouveau pour vous.

Amenez vos données LoRaWAN sur ConnectMQ

ConnectMQ offre à vos données TTN relayées un broker MQTT privé avec TLS, un explorateur de topics en direct, un tableau de bord et des règles d'alerte à seuil pour des valeurs comme une batterie faible ou un sol sec. Créez un broker Serverless gratuit sur app.connectmq.com, sans carte bancaire, et dirigez-y la sortie du pont.

Questions fréquentes

Quels sont le nom d'utilisateur et le mot de passe MQTT de TTN ?

Le nom d'utilisateur est l'identifiant de votre application suivi de @ttn (pour l'édition communautaire de The Things Network), et le mot de passe est une clé d'API générée sous Integrations > MQTT.

Aucun payload formatter d'uplink n'est configuré, ou il a levé une erreur. Testez-le dans le panneau du formatter de la console avec un vrai payload hexadécimal.

Puis-je connecter TTN directement à un autre broker sans code ?

TTN propose des webhooks et d'autres intégrations, mais pour publier dans votre propre broker MQTT selon votre propre structure de topics, un petit pont comme celui-ci reste l'option la plus simple et la plus transparente.

Le pont doit-il tourner à proximité de la passerelle ?

Non. Les deux connexions passent par internet : il peut donc tourner sur n'importe quel serveur, un Raspberry Pi ou un conteneur.

Articles liés

Guide d'installation de Zigbee2MQTT : du coordinateur au tableau de bord

Installez Zigbee2MQTT avec Docker, configurez le coordinateur et la connexion MQTT, appairez et renommez les appareils, pilotez-les via MQTT et affichez leurs états sur un tableau de bord, en testant d'abord sur le serveur MQTT public gratuit.

8 min de lecture

Tous les articles →

Votre broker MQTT privé, à quelques clics

Créez un compte, récupérez les identifiants de votre broker et connectez votre premier appareil — aucun serveur à installer, mettre à jour ou dimensionner.