Notions de base

MQTT Last Will and Testament (LWT) expliqué

Fonctionnement du Last Will and Testament MQTT : quand le broker le publie, le will delay de MQTT 5 et le pattern de présence online/offline retenu, avec exemples.

Mis à jour · 6 min de lecture

Les appareils sur des réseaux peu fiables ont rarement l’occasion de dire au revoir. Les batteries se vident, le Wi-Fi décroche, les processus plantent. Le Last Will and Testament (LWT, « dernières volontés ») de MQTT permet à un client d’enregistrer à l’avance un message que le broker publiera en son nom s’il disparaît de façon inattendue. C’est la brique standard de la détection de présence et des alertes dans les systèmes MQTT.

Comment fonctionne le Last Will

Le will est déclaré dans le paquet CONNECT. Il comporte les mêmes éléments qu’une publication classique :

ChampSignification
Will TopicLe topic sur lequel le broker publiera, par ex. acme/sensor-17/status
Will PayloadLe corps du message, par ex. offline
Will QoS0, 1 ou 2 — voir les niveaux de QoS
Will RetainIndique si le will est stocké comme message retenu (retained)
Will Properties (MQTT 5)Will Delay Interval, Message Expiry, Content Type, User Properties…

Le broker conserve le will avec la session et n’en fait rien tant que le client est connecté. La suite dépend de la façon dont la connexion se termine.

Quand le will est-il publié ?

Le broker publie le will lorsque la connexion réseau se ferme sans déconnexion normale, notamment quand :

  • le broker détecte une erreur d’E/S ou une panne réseau ;
  • le client ne communique pas pendant la période de keep-alive — le broker attend jusqu’à 1,5 × l’intervalle de keep-alive avant de considérer la connexion comme morte ;
  • le client ferme la connexion TCP/WebSocket sans envoyer de DISCONNECT ;
  • le broker ferme la connexion à cause d’une erreur de protocole.

Le will n’est pas publié lorsque le client envoie un DISCONNECT normal ; un arrêt propre le supprime. MQTT 5 ajoute une exception : un client peut se déconnecter avec le reason code 0x04 (Disconnect with Will Message) pour fermer proprement tout en faisant envoyer le will.

Will Delay Interval (MQTT 5)

En MQTT 3.1.1, le will se déclenche immédiatement. C’est bruyant pour les appareils qui se reconnectent vite après une brève coupure réseau : les abonnés voient offline suivi une seconde plus tard de online. MQTT 5 ajoute la propriété Will Delay Interval (en secondes) :

  • Le broker attend la durée indiquée avant de publier le will.
  • Si le client se reconnecte avec le même client ID pendant ce délai, le will n’est pas envoyé.
  • Le will est publié à l’expiration du délai ou à la fin de la session, selon ce qui arrive en premier — un will delay plus long que le Session Expiry Interval est donc de fait plafonné par celui-ci.
Will MQTT 5 avec un délai de 30 secondes (MQTT.js)
const client = mqtt.connect('wss://broker.emqx.io:8084/mqtt', {
  protocolVersion: 5,
  clientId: 'sensor-17',
  properties: { sessionExpiryInterval: 300 },
  will: {
    topic: 'acme/sensor-17/status',
    payload: 'offline',
    qos: 1,
    retain: true,
    properties: { willDelayInterval: 30 },
  },
});

Le pattern de présence : statut online/offline

L’usage le plus courant du LWT le combine aux messages retenus (retained) pour que n’importe quel client puisse savoir à tout moment si un appareil est en ligne :

  1. Connectez-vous avec un will : topic acme/sensor-17/status, payload offline, QoS 1, retain = true.
  2. Juste après le CONNACK, publiez online sur le même topic, QoS 1, retain = true. Cela écrase tout offline périmé resté de la fois précédente.
  3. Lors d’un arrêt propre, publiez vous-même offline (retenu), puis envoyez DISCONNECT. Comme le will est supprimé lors d’une déconnexion propre, c’est cette publication explicite qui maintient un statut exact.
  4. En cas de plantage, le broker publie pour vous le will offline retenu.

Les tableaux de bord s’abonnent alors à acme/+/status et reçoivent immédiatement le statut courant de chaque appareil, grâce à la rétention.

presence.mjs (MQTT.js)
import mqtt from 'mqtt';

const statusTopic = 'acme/sensor-17/status';

const client = mqtt.connect('wss://broker.hivemq.com:8884/mqtt', {
  clientId: 'sensor-17',
  keepalive: 30,
  will: { topic: statusTopic, payload: 'offline', qos: 1, retain: true },
});

client.on('connect', () => {
  client.publish(statusTopic, 'online', { qos: 1, retain: true });
});

process.on('SIGINT', () => {
  client.publish(statusTopic, 'offline', { qos: 1, retain: true }, () => client.end());
});

Pièges courants

  • Collisions de client ID. Si un second client se connecte avec le même client ID, le broker déconnecte le premier — et publie son will. Deux instances qui se disputent un même ID produisent un statut online/offline qui clignote.
  • Les bibliothèques qui se déconnectent toujours proprement. Certains SDK envoient un DISCONNECT à la sortie du processus, si bien que le will ne se déclenche jamais. Testez en tuant le processus ou en coupant le réseau.
  • Oublier le retain. Un will non retenu n’est vu que par les clients abonnés à ce moment-là.
  • Les autorisations. Le will est publié avec les permissions du client. Si le client n’a pas le droit de publier sur le topic du will, le broker peut refuser la connexion ou ignorer silencieusement le will. Voir les erreurs de connexion MQTT.

Définir un will en ligne de commande

Les clients Mosquitto acceptent directement les options de will, ce qui facilite les expériences rapides. Lancez un abonné dans un terminal, puis connectez un second client avec un will et tuez-le avec Ctrl+C ou en fermant le terminal :

bash
# terminal 1 — watch the status topic
mosquitto_sub -h test.mosquitto.org -t 'testmqtt/lwt-demo/#' -v

# terminal 2 — connect with a retained will and a 10 s keep-alive
mosquitto_sub -h test.mosquitto.org -t 'testmqtt/lwt-demo/cmd' -k 10 \
  --will-topic 'testmqtt/lwt-demo/status' --will-payload 'offline' \
  --will-qos 1 --will-retain

Selon la façon dont le processus se termine, le client aura ou non le temps d’envoyer un DISCONNECT. Le moyen le plus fiable de voir le will est de couper le réseau (par exemple en désactivant le Wi-Fi) et d’attendre l’expiration du keep-alive — exactement la panne pour laquelle le LWT a été conçu.

Comment tester le Last Will

  1. Dans un onglet du client MQTT en ligne, abonnez-vous à testmqtt/lwt-demo/#.
  2. Dans un second onglet, connectez-vous avec un will sur testmqtt/lwt-demo/status et un keep-alive court.
  3. Fermez le second onglet sans vous déconnecter. Dans la fenêtre du keep-alive, le premier onglet reçoit le will.

Essayez-le dans le client MQTT en ligne

Questions fréquentes

Pourquoi mon Last Will MQTT n’est-il pas envoyé ?

Le broker ne publie le will que lorsqu’un client se déconnecte de façon non propre. Si votre bibliothèque cliente envoie un paquet DISCONNECT à la fermeture, le will est supprimé. Vérifiez aussi le keep-alive : le broker peut attendre jusqu’à 1,5 fois l’intervalle de keep-alive avant de détecter une connexion morte.

Peut-on modifier le Last Will après la connexion ?

Non. Le will fait partie du paquet CONNECT et ne peut pas être modifié pendant la session. Pour le changer, déconnectez-vous puis reconnectez-vous avec un nouveau will.

Le message Last Will doit-il être retenu ?

Pour les topics de présence et de statut, oui. Un will offline retenu garantit que les clients qui s’abonnent plus tard voient toujours l’appareil hors ligne, au lieu de ne rien voir ou de voir un ancien message online.