Fundamentos de MQTT

MQTT Last Will and Testament (LWT): Como Detectar Dispositivos Offline

O Last Will and Testament permite que o broker anuncie que um client sumiu sem se despedir. Conheça os campos do will, as regras exatas de disparo e como testar o LWT derrubando um client em um broker real.

Broker publicando um aviso de offline depois que um sensor se desconecta, ilustrando o MQTT Last Will and Testament
Rode isso no seu próprio broker MQTTTenha um broker MQTT privado e gerenciado no plano Free e comece com exemplos de código prontos.
Teste grátis Exemplos de código Sem cartão de crédito

O MQTT Last Will and Testament (LWT) é o recurso que permite a um broker falar em nome de um client que já não consegue falar por si mesmo. Um dispositivo registra uma mensagem de "will" (testamento) ao se conectar, e o broker a publica se esse dispositivo desaparecer sem uma desconexão limpa. Ao final deste artigo você conhecerá cada campo do will, as condições exatas que o disparam e como testá-lo você mesmo derrubando um client conectado a um broker real.

Por Que o MQTT Precisa de um Last Will

O MQTT foi projetado para redes pouco confiáveis. Dispositivos perdem energia, firmwares travam, links celulares caem por minutos. Em um sistema publish/subscribe puro, publicador e assinante nunca falam diretamente entre si, então ninguém perceberia que um sensor ficou em silêncio até que uma pessoa olhasse um dashboard desatualizado.

O broker MQTT é a única parte que vê todas as conexões. O LWT transforma essa posição em um recurso: o client diz ao broker de antemão "se eu sumir, publique isto por mim". Os assinantes então ficam sabendo da falha pelos mesmos topics que já acompanham.

Os Campos do MQTT Last Will and Testament

O will é definido dentro do pacote CONNECT, então precisa ser configurado antes de o client se conectar. Ele não pode ser alterado durante uma sessão; para mudá-lo, reconecte.

Campo Finalidade Valor típico
Will topic Onde o broker publica o will site/line1/pump-07/status
Will payload Corpo da mensagem offline ou {"state":"offline"}
Will QoS Garantia de entrega do will 1
Will retain Se o will se torna o valor retido true
Will delay interval (MQTT 5) Segundos de espera antes de publicar De 0 a alguns segundos
Will properties (MQTT 5) Expiração da mensagem, content type, user properties Opcional

A maioria das configurações de produção usa QoS 1 e retain true. O retain é o que torna o status útil para clients que se conectam depois; sem ele, um dashboard aberto após a falha nunca descobre que o dispositivo caiu. O comportamento de retenção é explicado em detalhes em mensagens retidas no MQTT.

Quando o Broker Publica o Will

O broker publica o will quando a conexão de rede se fecha sem um pacote DISCONNECT. Na prática, isso cobre:

  1. A conexão TCP é fechada ou reiniciada pelo sistema operacional do client, por exemplo quando um processo é morto.
  2. O timer de keepalive expira. O broker espera cerca de 1,5 vez o intervalo de keepalive sem pacotes antes de declarar o client morto.
  3. O client viola o protocolo e o broker fecha a conexão.
  4. Uma falha de rede que o broker detecta por meio de um erro de I/O.

Ele não publica o will quando:

  • O client envia um DISCONNECT normal. O will é descartado.
  • No MQTT 5, o client se reconecta antes de o will delay interval expirar, retomando sua sessão.

Esse ponto é importante: um desligamento limpo não gera will. Se você quer "offline" também no desligamento planejado, publique-o você mesmo antes de desconectar. O MQTT 5 também permite que um client envie DISCONNECT com o reason code 0x04 (disconnect with will message) para pedir que o broker publique o will mesmo assim.

Testando o LWT Derrubando um Client

A maneira mais rápida de ganhar intuição é ver um will disparar. Usamos o servidor MQTT público (gratuito), pensado para testes, em broker.connectmq.com com um prefixo de topic único.

Terminal 1, o observador:

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

Terminal 2, o "dispositivo". Ele registra um will retido, usa um keepalive de 10 segundos e permanece inscrito para que o processo continue rodando:

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: anuncie o dispositivo como online com uma mensagem de nascimento (birth message) retida:

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

Agora mate o dispositivo de forma abrupta. No Linux ou macOS:

pkill -9 -f lwt-device-q81m

O terminal 1 imprime connectmq/demo/q81m/device1/status offline quase imediatamente, porque o sistema operacional fechou o socket e o broker viu a conexão cair sem DISCONNECT. Se, em vez disso, você desconectar o cabo de rede ou suspender um notebook, o will só chega depois que a janela de keepalive passa, cerca de 15 segundos com -k 10.

Faça mais um experimento: reinicie o processo do dispositivo e pare-o com Ctrl+C. As ferramentas do Mosquitto enviam um DISCONNECT adequado no Ctrl+C, então nenhum will é publicado e o status retido continua como estava. Essa é a lacuna que você fecha com uma publicação explícita de offline no desligamento.

LWT em Python com paho-mqtt

Aqui está um esqueleto completo de dispositivo usando paho-mqtt 2.x. Ele define o will antes de conectar, publica uma birth message retida em on_connect (para que ela se repita após cada reconexão) e publica "offline" na saída planejada:

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)

Rode o script, veja "online" aparecer no terminal observador e depois mate-o com kill -9 para ver o will publicado pelo broker, ou pressione Ctrl+C para ver a mensagem de offline do próprio script.

Dicas de Design para uma Detecção de Offline Confiável

Escolha um keepalive sensato. O keepalive define o pior tempo de detecção para falhas silenciosas. De 15 a 60 segundos é comum para dispositivos ligados à rede elétrica. Valores muito curtos custam bateria e banda; valores muito longos atrasam os alertas. Nosso guia sobre o intervalo de keep alive do MQTT aborda os trade-offs.

Sempre combine o LWT com uma birth message. O will só diz "offline". Algo precisa dizer "online" de novo depois da reconexão, e isso precisa ser retido para sobrescrever o will retido.

Use o mesmo topic e a mesma flag retain para os dois. Se o will é retido e a birth message não, novos assinantes veem "offline" para sempre.

Cuidado com client IDs duplicados. Se dois dispositivos compartilham um client ID, o broker desconecta um quando o outro se conecta, e eles se derrubam mutuamente em loop. O status fica oscilando entre online e offline. Torne cada client ID único.

Considere um will delay no MQTT 5. Um pequeno atraso evita um "offline" momentâneo quando um dispositivo se reconecta rapidamente após uma oscilação de rede. Veja o will delay interval do MQTT para os detalhes.

Inclua contexto em payloads JSON. Um payload como {"state":"offline","reason":"lwt"} permite que os consumidores diferenciem uma falha de um desligamento planejado.

Last Will and Testament no ConnectMQ

O ConnectMQ suporta LWT em conexões MQTT 3.1.1 e 5.0, incluindo wills retidos. Em um broker de produção, você se conecta com as credenciais do portal (YOUR_USERNAME, YOUR_PASSWORD, YOUR_CLIENT_ID) via TLS na porta 8883, e o will funciona exatamente como nos exemplos acima. Como os client IDs no ConnectMQ são vinculados às credenciais emitidas, fica mais fácil evitar o problema de oscilação por ID duplicado.

Para ter visibilidade do lado do broker além do LWT, o ConnectMQ também expõe o estado das conexões em $SYS/broker/connection/{clientId}/state, o que é útil para ferramentas de monitoramento que não devem depender de cada dispositivo configurar seu will corretamente. Se você está decidindo onde hospedar isso, compare as opções na nossa visão geral de broker MQTT gerenciado e, para os fundamentos do protocolo, veja o tutorial de MQTT completo.

Comece com o ConnectMQ

Cadastre-se em app.connectmq.com e crie um broker no plano Serverless gratuito, sem cartão de crédito. Aponte seus dispositivos para ele com um Last Will retido e uma birth message, e você terá status online/offline confiável desde o primeiro dia.

Perguntas frequentes

O Last Will é publicado quando um client se desconecta normalmente?

Não. Um DISCONNECT normal diz ao broker para descartar o will. Publique sua própria mensagem de offline antes de desconectar se precisar dela em desligamentos planejados.

Quanto tempo o broker leva para publicar o will?

Se o socket se fecha, é quase imediato. Se o dispositivo desaparece silenciosamente, o broker espera cerca de 1,5 vez o intervalo de keepalive, mais qualquer will delay interval do MQTT 5.

A mensagem de will deve ser retida?

Normalmente sim. Um will retido garante que clients que se conectam depois da falha ainda vejam o dispositivo como offline.

Posso alterar o will depois de conectar?

Não. O will faz parte do pacote CONNECT. Para alterá-lo, desconecte e conecte novamente com novas configurações de will.

Artigos relacionados

Por que Seu Cliente MQTT Fica Desconectando (e Como Corrigir)

Loops de reconexão estão entre os problemas mais comuns do MQTT. Conheça as cinco causas habituais, de client IDs duplicados a timeouts de keep alive e pacotes grandes demais, e siga um fluxo de diagnóstico que identifica a sua.

9 min de leitura

Quem Inventou o MQTT? A História dos Oleodutos à IoT

O MQTT foi inventado em 1999 por Andy Stanford-Clark, da IBM, e Arlen Nipper, da Arcom, para monitorar oleodutos via satélite. Acompanhe sua trajetória até o open source, a OASIS, a ISO e os brokers MQTT gerenciados na nuvem de hoje.

8 min de leitura

Todos os artigos →

Seu broker MQTT privado está a poucos cliques de distância

Crie uma conta, receba as credenciais do seu broker e conecte seu primeiro dispositivo — sem servidores para instalar, atualizar ou escalar.