Fondamentaux MQTT

MQTT Last Will and Testament (LWT) : détecter les appareils hors ligne

Le Last Will and Testament permet au broker d'annoncer qu'un client a disparu sans dire au revoir. Découvrez les champs du will, les règles exactes de déclenchement et comment tester le LWT en tuant un client connecté à un broker réel.

Broker publiant un avis hors ligne après la déconnexion d'un capteur, illustrant le MQTT Last Will and Testament
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 MQTT Last Will and Testament (LWT) est la fonctionnalité qui permet à un broker de parler au nom d'un client qui ne peut plus le faire lui-même. Un appareil enregistre un message « will » lors de sa connexion, et le broker le publie si cet appareil disparaît sans déconnexion propre. À la fin de cet article, vous connaîtrez chaque champ du will, les conditions précises qui le déclenchent, et comment le tester vous-même en tuant un client connecté à un broker réel.

Pourquoi MQTT a besoin d'un Last Will

MQTT est conçu pour des réseaux peu fiables. Les appareils perdent leur alimentation, les firmwares se bloquent, les liaisons cellulaires tombent pendant des minutes. Dans un système publish/subscribe pur, éditeur et abonné ne se parlent jamais directement : personne ne remarquerait qu'un capteur s'est tu avant qu'un humain ne regarde un tableau de bord figé.

Le broker MQTT est le seul acteur qui voit toutes les connexions. Le LWT transforme cette position en fonctionnalité : le client dit à l'avance au broker « si je disparais, publie ceci pour moi ». Les abonnés apprennent alors la panne par les topics qu'ils surveillent déjà.

Les champs du MQTT Last Will and Testament

Le will est défini dans le paquet CONNECT : il doit donc être configuré avant la connexion du client. Il ne peut pas être modifié pendant une session ; pour le changer, il faut se reconnecter.

Champ Rôle Valeur typique
Will topic Où le broker publie le will site/line1/pump-07/status
Will payload Corps du message offline ou {"state":"offline"}
Will QoS Garantie de livraison du will 1
Will retain Si le will devient la valeur retained true
Will delay interval (MQTT 5) Secondes d'attente avant publication De 0 à quelques secondes
Will properties (MQTT 5) Message expiry, content type, user properties Optionnelles

La plupart des configurations de production utilisent la QoS 1 et retain à true. C'est le retain qui rend le statut utile aux clients qui se connectent plus tard ; sans lui, un tableau de bord ouvert après la panne n'apprend jamais que l'appareil est tombé. Le comportement retained est expliqué en détail dans les retained messages MQTT.

Quand le broker publie le will

Le broker publie le will lorsque la connexion réseau se ferme sans paquet DISCONNECT. En pratique, cela couvre :

  1. La connexion TCP fermée ou réinitialisée par l'OS du client, par exemple lorsqu'un processus est tué.
  2. L'expiration du minuteur keepalive. Le broker attend environ 1,5 fois l'intervalle de keepalive sans aucun paquet avant de déclarer le client mort.
  3. Une violation du protocole par le client, qui amène le broker à fermer la connexion.
  4. Une panne réseau que le broker détecte via une erreur d'E/S.

Il ne publie pas le will lorsque :

  • Le client envoie un DISCONNECT normal. Le will est alors abandonné.
  • En MQTT 5, le client se reconnecte avant l'expiration du will delay interval et reprend sa session.

La première règle est importante : un arrêt propre ne produit aucun will. Si vous voulez aussi « offline » lors d'un arrêt planifié, publiez-le vous-même avant de vous déconnecter. MQTT 5 permet également à un client d'envoyer un DISCONNECT avec le reason code 0x04 (déconnexion avec message will) pour demander au broker de publier le will malgré tout.

Tester le LWT en tuant un client

Le moyen le plus rapide de se forger une intuition est de voir un will se déclencher. Nous utilisons le serveur MQTT public gratuit broker.connectmq.com, réservé aux tests et aux prototypes, avec un préfixe de topic unique.

Terminal 1, l'observateur :

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

Terminal 2, l'« appareil ». Il enregistre un will retained, utilise un keepalive de 10 secondes et reste abonné pour que le processus continue de tourner :

mosquitto_sub -h broker.connectmq.com -p 1883 -i lwt-device-q81m -k 10 \
  --will-topic connectmq/demo/q81m/device1/status \
  --will-payload offline --will-qos 1 --will-retain \
  -t connectmq/demo/q81m/device1/cmd

Terminal 3, annoncez l'appareil en ligne avec un message de naissance retained :

mosquitto_pub -h broker.connectmq.com -p 1883 -i lwt-birth-q81m \
  -t connectmq/demo/q81m/device1/status -m online -q 1 -r

Tuez maintenant l'appareil brutalement. Sous Linux ou macOS :

pkill -9 -f lwt-device-q81m

Le terminal 1 affiche connectmq/demo/q81m/device1/status offline presque immédiatement, car le système d'exploitation a fermé le socket et le broker l'a vu tomber sans DISCONNECT. Si vous débranchez plutôt le câble réseau ou mettez un portable en veille, le will n'arrive qu'après la fenêtre de keepalive, soit environ 15 secondes avec -k 10.

Tentez une dernière expérience : relancez le processus de l'appareil et arrêtez-le avec Ctrl+C. Les outils Mosquitto envoient un véritable DISCONNECT sur Ctrl+C : aucun will n'est publié et le statut retained reste ce qu'il était. C'est ce manque que vous comblez avec une publication explicite de « offline » à l'arrêt.

Le LWT en Python avec paho-mqtt

Voici un squelette d'appareil complet avec paho-mqtt 2.x. Il définit le will avant de se connecter, publie un message de naissance retained dans on_connect (pour qu'il soit répété après chaque reconnexion) et publie « offline » lors d'une sortie propre :

import signal
import sys
import time
import paho.mqtt.client as mqtt

BROKER = "broker.connectmq.com"
CLIENT_ID = "lwt-py-device-q81m"
STATUS = "connectmq/demo/q81m/device2/status"

client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id=CLIENT_ID)
client.will_set(STATUS, payload="offline", qos=1, retain=True)

def on_connect(client, userdata, flags, reason_code, properties):
    if reason_code.is_failure:
        print("connect failed:", reason_code)
        return
    client.publish(STATUS, "online", qos=1, retain=True)
    print("online")

def shutdown(signum, frame):
    client.publish(STATUS, "offline", qos=1, retain=True).wait_for_publish(timeout=5)
    client.disconnect()
    client.loop_stop()
    sys.exit(0)

client.on_connect = on_connect
signal.signal(signal.SIGINT, shutdown)
signal.signal(signal.SIGTERM, shutdown)

client.connect(BROKER, 1883, keepalive=15)
client.loop_start()
while True:
    time.sleep(1)

Lancez-le, regardez « online » apparaître dans le terminal d'observation, puis tuez-le avec kill -9 pour voir le will publié par le broker, ou appuyez sur Ctrl+C pour voir le message offline publié par le script lui-même.

Conseils de conception pour une détection fiable

Choisissez un keepalive raisonnable. Le keepalive fixe le délai de détection dans le pire cas pour les pannes silencieuses. De 15 à 60 secondes est courant pour les appareils alimentés sur secteur. Des valeurs très courtes coûtent batterie et bande passante ; des valeurs très longues retardent les alertes. Notre guide sur l'intervalle keep alive MQTT détaille les compromis.

Associez toujours le LWT à un message de naissance. Le will dit seulement « offline ». Quelque chose doit redire « online » après la reconnexion, et ce message doit être retained pour écraser le will retained.

Utilisez le même topic et le même flag retain pour les deux. Si le will est retained mais pas le message de naissance, les nouveaux abonnés verront « offline » pour toujours.

Méfiez-vous des client IDs en double. Si deux appareils partagent un client ID, le broker déconnecte l'un quand l'autre se connecte, et ils s'éjectent mutuellement en boucle. Le statut oscille entre online et offline. Rendez chaque client ID unique.

Envisagez un will delay en MQTT 5. Un court délai évite un « offline » fugace lorsqu'un appareil se reconnecte rapidement après une micro-coupure réseau. Consultez le will delay interval MQTT pour les détails.

Ajoutez du contexte dans des payloads JSON. Un payload comme {"state":"offline","reason":"lwt"} permet aux consommateurs de distinguer un plantage d'un arrêt planifié.

Le Last Will and Testament sur ConnectMQ

ConnectMQ prend en charge le LWT sur les connexions MQTT 3.1.1 et 5.0, y compris les wills retained. Sur un broker de production, vous vous connectez avec les identifiants du portail (YOUR_USERNAME, YOUR_PASSWORD, YOUR_CLIENT_ID) via TLS sur le port 8883, et le will fonctionne exactement comme dans les exemples ci-dessus. Comme les client IDs sur ConnectMQ sont liés aux identifiants émis, le problème d'oscillation dû aux IDs en double est plus facile à éviter.

Pour une visibilité côté broker en complément du LWT, ConnectMQ expose aussi l'état des connexions sur $SYS/broker/connection/{clientId}/state, ce qui est pratique pour les outils de supervision qui ne doivent pas dépendre de la bonne configuration du will par chaque appareil. Si vous hésitez sur l'hébergement, comparez les options dans notre présentation du broker MQTT managé, et pour les fondamentaux du protocole, consultez le tutoriel MQTT complet.

Démarrer avec ConnectMQ

Inscrivez-vous sur app.connectmq.com et créez un broker sur le plan Serverless gratuit, sans carte bancaire. Faites pointer vos appareils vers lui avec un Last Will retained et un message de naissance, et vous disposez dès le premier jour d'un statut en ligne/hors ligne fiable.

Questions fréquentes

Le Last Will est-il publié lorsqu'un client se déconnecte normalement ?

Non. Un DISCONNECT normal indique au broker d'abandonner le will. Publiez votre propre message offline avant de vous déconnecter si vous en avez besoin pour les arrêts planifiés.

Combien de temps le broker met-il à publier le will ?

Si le socket se ferme, c'est presque immédiat. Si l'appareil disparaît silencieusement, le broker attend environ 1,5 fois l'intervalle de keepalive, plus un éventuel will delay interval MQTT 5.

Le message will doit-il être retained ?

En général, oui. Un will retained garantit que les clients qui se connectent après la panne voient toujours l'appareil comme hors ligne.

Puis-je modifier le will après la connexion ?

Non. Le will fait partie du paquet CONNECT. Pour le modifier, déconnectez-vous puis reconnectez-vous avec de nouveaux paramètres de will.

Articles liés

Qui a inventé MQTT ? L'histoire, des oléoducs à l'IoT

MQTT a été inventé en 1999 par Andy Stanford-Clark (IBM) et Arlen Nipper (Arcom) pour surveiller des oléoducs par satellite. Suivez son parcours vers l'open source, OASIS, l'ISO et les brokers MQTT managés d'aujourd'hui.

8 min de lecture

Pourquoi votre client MQTT se déconnecte sans cesse (et comment y remédier)

Les boucles de reconnexion sont l'un des problèmes MQTT les plus courants. Découvrez les cinq causes habituelles, des client ID en double aux timeouts de keep alive et aux paquets trop volumineux, et suivez une méthode de diagnostic qui identifie la vôtre.

9 min de lecture

Taille maximale d'un message MQTT : limites et stratégies pour les gros payloads

MQTT peut techniquement transporter un paquet de 256 Mo, mais les brokers, les bibliothèques clientes et les appareils imposent des limites bien plus basses. Découvrez où se trouvent les vraies limites, ce qui se passe quand on les dépasse et comment envoyer de gros payloads.

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.