ESP32 e Arduino

ESP32 Deep Sleep MQTT: Sensores a Bateria que Publicam e Voltam a Dormir

Monte um sensor ESP32 econômico que acorda por timer, conecta rapidamente, publica uma leitura retida, confirma que ela chegou ao broker e volta ao deep sleep.

Nó sensor ESP32 alimentado por bateria acordando para publicar em um ciclo de ESP32 deep sleep MQTT
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

ESP32 deep sleep MQTT é o que faz um sensor a bateria durar meses em vez de dias. Neste tutorial você vai construir um nó que acorda por timer, reconecta ao Wi-Fi o mais rápido possível, publica uma leitura retida no broker.connectmq.com, confirma que a mensagem realmente chegou ao broker e volta a dormir. Como a leitura é retida, os dashboards sempre mostram o último valor, mesmo que o dispositivo passe quase todo o tempo offline.

O ciclo acordar, publicar, dormir

Em deep sleep, o ESP32 desliga as CPUs, a maior parte da RAM e o rádio. Só o domínio RTC continua ativo, consumindo uma fração mínima da corrente em atividade. Quando o timer dispara, o chip não continua de onde parou: ele reinicia e executa setup() desde o começo. Neste design, o loop() nunca roda.

Todo ciclo de despertar segue os mesmos passos:

  1. Inicializar e ler o sensor imediatamente, antes que o rádio aqueça a placa.
  2. Conectar ao Wi-Fi reutilizando o canal e o ponto de acesso salvos no ciclo anterior.
  3. Conectar ao broker MQTT e publicar a leitura como mensagem retida.
  4. Confirmar que o broker a recebeu.
  5. Desconectar de forma limpa, desligar o rádio e entrar em deep sleep.

O tempo gasto entre os passos 2 e 5 domina o consumo de energia, porque o rádio Wi-Fi é de longe o que mais puxa corrente. Toda otimização deste artigo busca encurtar essa janela ou pulá-la quando ela falharia de qualquer jeito.

Fase Consumo relativo Como encurtar
Boot e leitura do sensor Baixo a moderado Ler o sensor primeiro, manter o código enxuto
Associação Wi-Fi e DHCP Alto Reutilizar canal e BSSID, IP estático opcional
Conexão MQTT e publicação Alto Conexão simples ou com sessão leve, uma única publicação
Espera pela confirmação Alto Timeout curto, desistir rápido
Deep sleep Muito baixo Projeto da placa: regulador, LEDs, chip USB

A última linha costuma surpreender: muitas placas de desenvolvimento desperdiçam muito mais no regulador de tensão, no LED de alimentação e no chip USB-serial do que o próprio ESP32 consome em deep sleep. Para uma autonomia real, meça a placa, não o chip. O artigo complementar sobre sensores ESP32 alimentados por bateria aprofunda as escolhas de hardware e as medições de corrente.

Por que mensagens retidas são essenciais aqui

Um sensor que dorme publica uma vez e desaparece. Se um dashboard ou um app de celular se inscrever um minuto depois, uma mensagem normal já se foi. Com a flag retain ativada, o broker guarda a última mensagem daquele tópico e a entrega imediatamente a cada novo assinante. O dashboard mostra a leitura mais recente no instante em que abre, não importa quando o dispositivo acordou pela última vez.

Coloque um timestamp ou número de sequência no payload para que os consumidores saibam a idade do valor retido. Uma leitura de quatro horas atrás que parece atual é enganosa, e para um dispositivo que dorme "antigo" é o estado normal. Se mensagens retidas são novidade para você, a visão geral sobre o que um broker MQTT faz explica como o broker as armazena.

Confirmando a entrega sem publicação QoS 1

O PubSubClient só publica com QoS 0, o que significa "enviado", não "recebido". Em um dispositivo sempre ligado isso costuma ser aceitável. Em um dispositivo que dorme é um problema real: se você chamar esp_deep_sleep_start() logo após publish(), o rádio pode desligar com o pacote ainda no buffer, e a mensagem some sem aviso.

O sketch abaixo usa um truque simples e confiável. Ele se inscreve no próprio tópico de estado antes de publicar e depois espera o broker enviar a nova mensagem de volta. Ver a própria mensagem ecoada prova que o broker a recebeu e roteou. Um número de sequência guardado na memória RTC distingue a mensagem nova da antiga mensagem retida, que o broker também entrega na inscrição.

O sketch completo de ESP32 deep sleep MQTT

#include <WiFi.h>
#include <PubSubClient.h>
#include "esp_sleep.h"

const char* WIFI_SSID     = "YOUR_WIFI";
const char* WIFI_PASSWORD = "YOUR_WIFI_PASSWORD";
const char* MQTT_HOST     = "broker.connectmq.com";
const uint16_t MQTT_PORT  = 1883;
const char* CLIENT_ID     = "sleepy-3e7f10";                 // unique
const char* TOPIC_STATE   = "connectmq/demo/sleepy-3e7f10/state";

const uint64_t SLEEP_SECONDS   = 300;                       // 5 minutes
const uint32_t WIFI_TIMEOUT_MS = 8000;
const uint32_t ACK_TIMEOUT_MS  = 3000;

// Survives deep sleep (lost on power-off or reset)
RTC_DATA_ATTR uint32_t seq = 0;
RTC_DATA_ATTR uint32_t failures = 0;
RTC_DATA_ATTR uint8_t savedBssid[6];
RTC_DATA_ATTR int32_t savedChannel = 0;
RTC_DATA_ATTR bool haveSaved = false;

WiFiClient net;
PubSubClient mqtt(net);
volatile bool acked = false;
char expected[24];

void goToSleep() {
  mqtt.disconnect();
  net.stop();
  WiFi.disconnect(true);
  WiFi.mode(WIFI_OFF);
  // Back off when things keep failing, so a dead network does not drain the battery
  uint64_t seconds = SLEEP_SECONDS * (failures > 3 ? 4 : 1);
  Serial.printf("Sleeping %llu s (failures=%lu)\n", seconds, (unsigned long)failures);
  Serial.flush();
  esp_sleep_enable_timer_wakeup(seconds * 1000000ULL);
  esp_deep_sleep_start();
}

float readSensor() {
  // Replace with your sensor; simulated value keeps the example self-contained
  return 20.0 + (esp_random() % 500) / 100.0;
}

void onMessage(char* topic, byte* payload, unsigned int length) {
  // Our payload contains "seq":N; look for the one we just sent
  String msg;
  for (unsigned int i = 0; i < length; i++) msg += (char)payload[i];
  if (msg.indexOf(expected) >= 0) acked = true;
}

bool connectWifi() {
  WiFi.mode(WIFI_STA);
  WiFi.persistent(false);
  if (haveSaved) {
    WiFi.begin(WIFI_SSID, WIFI_PASSWORD, savedChannel, savedBssid, true);   // fast path
  } else {
    WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
  }
  unsigned long start = millis();
  while (WiFi.status() != WL_CONNECTED) {
    if (millis() - start > WIFI_TIMEOUT_MS) {
      haveSaved = false;              // AP may have changed channel: full scan next time
      return false;
    }
    delay(20);
  }
  memcpy(savedBssid, WiFi.BSSID(), 6);
  savedChannel = WiFi.channel();
  haveSaved = true;
  return true;
}

void setup() {
  unsigned long t0 = millis();
  Serial.begin(115200);
  float temperature = readSensor();                 // read before the radio warms the board
  seq++;

  if (!connectWifi()) { failures++; goToSleep(); }

  mqtt.setServer(MQTT_HOST, MQTT_PORT);
  mqtt.setCallback(onMessage);
  mqtt.setSocketTimeout(4);
  if (!mqtt.connect(CLIENT_ID)) { failures++; goToSleep(); }

  mqtt.subscribe(TOPIC_STATE, 0);
  snprintf(expected, sizeof(expected), "\"seq\":%lu,", (unsigned long)seq);

  char payload[128];
  snprintf(payload, sizeof(payload),
           "{\"seq\":%lu,\"temperature\":%.2f,\"rssi\":%d,\"awakeMs\":%lu,\"failures\":%lu}",
           (unsigned long)seq, temperature, WiFi.RSSI(),
           millis() - t0, (unsigned long)failures);
  mqtt.publish(TOPIC_STATE, payload, true);         // retained

  unsigned long start = millis();
  while (!acked && millis() - start < ACK_TIMEOUT_MS) {
    mqtt.loop();
    delay(5);
  }
  if (acked) failures = 0; else failures++;
  Serial.printf("seq=%lu acked=%d awake=%lu ms\n", (unsigned long)seq, acked, millis() - t0);
  goToSleep();
}

void loop() {
  // Never reached: the ESP32 restarts in setup() after every wake-up
}

O que cada otimização faz

Cache de canal e BSSID. Um WiFi.begin() normal varre todos os canais para encontrar o ponto de acesso. Passar o canal e o BSSID salvos na memória RTC pula essa varredura, que costuma ser a maior economia isolada. Se o roteador mudar de canal, o caminho rápido estoura o tempo, o cache é limpo e o próximo despertar faz uma varredura completa.

Ler o sensor primeiro. O rádio aquece a placa de forma perceptível, o que distorce leituras de temperatura. Medir antes de conectar evita isso.

Backoff em caso de falha. Quando a rede está fora, cada despertar queima energia em tentativas que não podem dar certo. Após falhas repetidas, o nó dorme quatro vezes mais até que uma publicação volte a funcionar.

awakeMs no payload. Informar quanto tempo o dispositivo ficou acordado na fase anterior dá uma visão gratuita e contínua do custo de energia. Se esse número subir aos poucos, algo mudou na rede.

Sem Last Will. Um dispositivo que dorme se desconecta de propósito a cada ciclo, então um Last Will offline não teria sentido. Avalie se ele está vivo pela idade da última leitura retida.

Opcionalmente, um IP estático também economiza a troca DHCP. Chame WiFi.config(ip, gateway, subnet, dns) antes de WiFi.begin(), mas apenas em redes onde você controla a atribuição de endereços.

Verifique se funciona

Inscreva-se a partir do seu computador:

mosquitto_sub -h broker.connectmq.com -p 1883 -i watch-3e7f10 -v -t "connectmq/demo/sleepy-3e7f10/#"

Reduza SLEEP_SECONDS para 20 durante os testes. Você deve ver uma mensagem por ciclo:

connectmq/demo/sleepy-3e7f10/state {"seq":7,"temperature":22.81,"rssi":-61,"awakeMs":1180,"failures":0}

Agora pare o assinante e inicie-o de novo enquanto o ESP32 dorme. A última leitura aparece imediatamente, que é exatamente o que um dashboard experimenta. Depois desligue o roteador por alguns ciclos: o monitor serial mostra failures crescendo, e a primeira mensagem após a recuperação informa quantos ciclos foram perdidos.

O broker.connectmq.com é um servidor MQTT público (gratuito) adequado para esse tipo de teste, mas não para dados de produção. As sessões dele expiram em no máximo 30 minutos, o que não importa aqui, porque o sketch conecta com uma sessão nova a cada despertar. Ao migrar para um broker ConnectMQ privado, o sketch só precisa de credenciais (e TLS, se você optar por ele); o único ponto de atenção é o limite de 25 conexões do plano gratuito, que uma frota de sensores que dormem raramente atinge, porque cada um fica conectado só por um instante a cada ciclo.

Checklist de autonomia da bateria

  1. Remova ou desative o LED de alimentação e use uma placa com regulador de baixa corrente quiescente, ou alimente o módulo diretamente.
  2. Meça a corrente em deep sleep com um multímetro em série; em uma placa bem projetada ela deve ficar bem abaixo de um miliampere.
  3. Mantenha a janela acordada curta: Wi-Fi em cache, timeouts curtos, uma publicação.
  4. Escolha um intervalo sensato. Reduzir o intervalo pela metade praticamente dobra a energia gasta com o rádio ligado; a maioria das leituras ambientais não precisa de resolução de minutos.
  5. Alimente o sensor por um GPIO e desligue-o antes de dormir, para que ele não drene a bateria em segundo plano.
  6. Evite TLS a cada despertar se a autonomia for crítica e o modelo de ameaça permitir isso em uma rede privada; quando precisar de criptografia, reserve tempo para o handshake extra e siga ESP32 MQTT SSL com WiFiClientSecure.

Solução de problemas

  • As mensagens chegam só às vezes. Você está dormindo antes de a publicação sair pelo rádio. Mantenha a confirmação por eco e não reduza demais o ACK_TIMEOUT_MS.
  • seq volta para 1 inesperadamente. A memória RTC sobrevive ao deep sleep, mas não a um corte de energia, a um brownout ou ao botão de reset. Uma tensão de bateria em queda causando brownouts é uma causa comum.
  • O dispositivo nunca acorda. Verifique se você chama esp_sleep_enable_timer_wakeup() com microssegundos e um valor de 64 bits; um overflow de 32 bits gera um intervalo muito mais curto ou errado.
  • A saída serial é cortada. Chame Serial.flush() antes de dormir, como o sketch faz.
  • Tempos acordado longos em alguns ciclos. O caminho rápido do Wi-Fi falhou e uma varredura completa foi executada. Verifique se o seu roteador usa um canal fixo.

Sensores que dormem em produção

Valores retidos são tão confiáveis quanto o broker que os guarda. Um broker MQTT gerenciado mantém esse endpoint disponível enquanto seus sensores dormem, e os mesmos tópicos retidos atendem seus dashboards, scripts e apps. Com o ConnectMQ, você cria credenciais por dispositivo no portal, vê o último valor retido de cada sensor no explorador de tópicos ao vivo e define regras de alerta por limite em leituras como temperatura. Um broker MQTT na nuvem também permite que sensores em uma fazenda, em uma adega e em um armazém reportem para um único endpoint sem nenhum servidor local. É novo na placa? Comece pelo tutorial de IoT com ESP32.

Comece com o ConnectMQ

Crie um broker Serverless gratuito em app.connectmq.com, sem cartão de crédito. Aponte seus sensores para ele com credenciais próprias e veja as leituras retidas aparecerem no portal conforme eles acordam.

Perguntas frequentes

Por que meu ESP32 perde mensagens MQTT antes do deep sleep?

A publicação QoS 0 retorna assim que os dados entram na fila, então dormir imediatamente pode cortá-la. Espere uma confirmação, como a técnica de eco deste sketch, e só então desconecte e durma.

Um sensor em deep sleep deve manter uma sessão MQTT?

Normalmente não. Uma conexão nova a cada despertar é mais simples e funciona com qualquer broker. Sessões persistentes só ajudam se o dispositivo precisar receber comandos enfileirados enquanto dormia.

Como um ESP32 que dorme pode receber comandos?

Publique os comandos como mensagens retidas em um tópico no qual o dispositivo se inscreve ao acordar. Ele recebe o comando mais recente imediatamente, executa e depois o limpa publicando uma mensagem retida vazia.

Qual é um bom intervalo de publicação para um sensor a bateria?

Depende da rapidez com que o valor medido muda. Sensores ambientais costumam funcionar bem com intervalos de cinco a quinze minutos; intervalos menores custam proporcionalmente mais energia.

Artigos relacionados

Exemplo de MQTT com ESP-IDF: Monte um Cliente esp-mqtt do Zero

Monte um projeto ESP-IDF a partir de uma pasta vazia com o componente esp-mqtt: configuração do Wi-Fi em modo station, o handler de eventos MQTT, publicação e inscrição, propriedades do MQTT 5 e TLS com o bundle de certificados.

8 min de leitura

Usando os Recursos do MQTT 5 do esp-mqtt no ESP32 com ESP-IDF

Um projeto ESP-IDF prático que ativa o MQTT 5.0 no esp-mqtt e usa user properties, expiração de mensagens, topic aliases, expiração de sessão e response topics com um broker MQTT 5 real.

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.