ESP32 e Arduino

Tutorial ESP8266 MQTT: Conecte um NodeMCU a um Broker na Nuvem (Sem e Com TLS)

Conecte um ESP8266 NodeMCU a um broker MQTT com PubSubClient, publique telemetria em JSON, controle o LED da placa e depois adicione TLS com BearSSL mantendo o heap limitado sob controle.

Placa NodeMCU ESP8266 em uma protoboard enviando mensagens MQTT do ESP8266 para um broker na nuvem
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 ESP8266 continua sendo uma das formas mais baratas de colocar um sensor no Wi-Fi, de uma estufa em uma fazenda a um quadro de bombas de saneamento, e projetos de ESP8266 com MQTT combinam naturalmente com o seu tamanho reduzido. Neste tutorial, você vai conectar um NodeMCU ou Wemos D1 mini a um broker com PubSubClient, publicar telemetria em JSON, acionar o LED da placa a partir do seu computador e depois migrar para TLS sem ficar sem memória.

O Que Você Precisa

  • Um NodeMCU v2/v3, Wemos D1 mini ou qualquer placa ESP8266 com USB.
  • Arduino IDE 2.x com o pacote de placas "esp8266 by ESP8266 Community" (adicione https://arduino.esp8266.com/stable/package_esp8266com_index.json em File → Preferences → Additional boards manager URLs).
  • A biblioteca PubSubClient, de Nick O'Leary, pelo Gerenciador de Bibliotecas.
  • As ferramentas de linha de comando do Mosquitto no seu computador, para testes.
  • Uma rede Wi-Fi de 2,4 GHz. O ESP8266 não suporta 5 GHz.

Nos primeiros passos, você vai usar o broker.connectmq.com, o servidor MQTT público (gratuito) operado pelo ConnectMQ. Ele aceita clientes anônimos na porta 1883 com qualquer client ID único e não vazio. Trate-o como um mural público: tudo o que você publica ali pode ser lido por outras pessoas, então use-o para testes e protótipos, não para dados de produção.

Configurações da Placa Que Importam

Antes de escrever código, ajuste estes itens no menu Tools:

Configuração Valor recomendado Por quê
Board NodeMCU 1.0 (ESP-12E Module) ou LOLIN(WEMOS) D1 mini Layout de flash e nomes de pinos corretos
CPU Frequency 160 MHz para TLS, 80 MHz nos demais casos Os handshakes TLS ficam muito mais rápidos a 160 MHz
SSL Support All SSL ciphers (padrão) ou Basic SSL ciphers O Basic economiza flash e ainda funciona com brokers modernos
lwIP Variant v2 Lower Memory Deixa mais heap para o seu sketch
Upload Speed 921600 (reduza para 115200 se o upload falhar) Iterações mais rápidas

Passo 1: Seu Primeiro Sketch ESP8266 MQTT

O sketch abaixo usa o LED da placa no GPIO2 (LED_BUILTIN), que é ativo em nível baixo na maioria dos módulos. Ele publica o uptime, a intensidade do sinal e o heap livre a cada cinco segundos e escuta os comandos ON ou OFF.

#include <ESP8266WiFi.h>
#include <PubSubClient.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;

char deviceId[24];
char topicTelemetry[64];
char topicLedSet[64];
char topicLedState[64];

WiFiClient netClient;
PubSubClient mqtt(netClient);

unsigned long lastPublish = 0;
unsigned long lastAttempt = 0;

void setLed(bool on) {
  digitalWrite(LED_BUILTIN, on ? LOW : HIGH);   // ativo em nível baixo
  mqtt.publish(topicLedState, on ? "ON" : "OFF", true);
}

void onMessage(char* topic, byte* payload, unsigned int length) {
  char msg[16];
  unsigned int n = length < sizeof(msg) - 1 ? length : sizeof(msg) - 1;
  memcpy(msg, payload, n);
  msg[n] = '\0';
  Serial.printf("[%s] %s\n", topic, msg);

  if (strcmp(msg, "ON") == 0)  setLed(true);
  if (strcmp(msg, "OFF") == 0) setLed(false);
}

void connectWifi() {
  WiFi.mode(WIFI_STA);
  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
  Serial.print("Wi-Fi");
  while (WiFi.status() != WL_CONNECTED) {
    delay(300);
    Serial.print(".");
  }
  Serial.printf(" connected, IP %s\n", WiFi.localIP().toString().c_str());
}

bool connectMqtt() {
  if (mqtt.connect(deviceId, nullptr, nullptr, topicLedState, 1, true, "offline")) {
    Serial.println("MQTT connected");
    mqtt.subscribe(topicLedSet, 1);
    setLed(false);
    return true;
  }
  Serial.printf("MQTT failed, rc=%d\n", mqtt.state());
  return false;
}

void setup() {
  Serial.begin(115200);
  pinMode(LED_BUILTIN, OUTPUT);

  // ID único a partir do chip ID, por exemplo esp8266-3f2a1b
  snprintf(deviceId, sizeof(deviceId), "esp8266-%06x", ESP.getChipId());
  snprintf(topicTelemetry, sizeof(topicTelemetry), "connectmq/demo/%s/telemetry", deviceId);
  snprintf(topicLedSet,    sizeof(topicLedSet),    "connectmq/demo/%s/led/set", deviceId);
  snprintf(topicLedState,  sizeof(topicLedState),  "connectmq/demo/%s/led/state", deviceId);
  Serial.printf("\nDevice ID: %s\n", deviceId);

  connectWifi();
  mqtt.setServer(MQTT_HOST, MQTT_PORT);
  mqtt.setCallback(onMessage);
  mqtt.setKeepAlive(30);
}

void loop() {
  if (WiFi.status() != WL_CONNECTED) connectWifi();

  if (!mqtt.connected()) {
    if (millis() - lastAttempt > 5000) {
      lastAttempt = millis();
      connectMqtt();
    }
    return;
  }
  mqtt.loop();

  if (millis() - lastPublish > 5000) {
    lastPublish = millis();
    char payload[96];
    snprintf(payload, sizeof(payload), "{\"uptime\":%lu,\"rssi\":%d,\"heap\":%u}",
             millis() / 1000, WiFi.RSSI(), ESP.getFreeHeap());
    mqtt.publish(topicTelemetry, payload);
  }
}

Abra o monitor serial a 115200 baud, anote o device ID e depois se inscreva a partir do seu computador (substitua o ID pelo seu):

mosquitto_sub -h broker.connectmq.com -p 1883 -i laptop-3f2a1b -t "connectmq/demo/esp8266-3f2a1b/#" -v

Acione o LED:

mosquitto_pub -h broker.connectmq.com -p 1883 -i ctl-3f2a1b -t "connectmq/demo/esp8266-3f2a1b/led/set" -m ON

O topic led/state é retido, então qualquer novo assinante descobre imediatamente se o LED está aceso, e o Last Will o define como offline se a placa perder a alimentação.

Passo 2: Entenda o Orçamento de Memória do ESP8266

Depois que o sketch sem TLS funcionar, observe o valor de heap que ele publica. Um sketch simples normalmente deixa uma boa quantidade de heap livre, mas o TLS muda o cenário. Uma sessão BearSSL com buffers padrão precisa de um bloco de memória contíguo grande para os buffers de recepção e transmissão, além do trabalho de validação do certificado, e o ESP8266 tem apenas uma fração da RAM de um ESP32.

Consequências práticas:

  • Mantenha o buffer do PubSubClient tão pequeno quanto suas mensagens permitirem. Chamar setBufferSize(4096) "por via das dúvidas" pode ser a diferença entre um handshake que funciona e um que falha.
  • Evite o uso intenso da classe String em sketches que rodam por muito tempo; alocações repetidas fragmentam o heap, e o handshake TLS pode falhar dias depois, mesmo com o heap livre parecendo adequado. ESP.getMaxFreeBlockSize() mostra o maior bloco contíguo, que é o número que importa.
  • Monte o JSON com snprintf ou com um documento ArduinoJson de tamanho fixo, em vez de concatenar strings.

Se você precisa de payloads grandes com frequência, leia tamanho do buffer do PubSubClient para conhecer técnicas de streaming que evitam buffers grandes.

Passo 3: ESP8266 MQTT sobre TLS

Em produção, o seu dispositivo deve se conectar a um broker privado via TLS na porta 8883, com credenciais próprias. Com um broker MQTT gerenciado como o ConnectMQ, você recebe usuário, senha e client ID pelo portal. O certificado do servidor é emitido pela Let's Encrypt, então você confia no certificado raiz ISRG Root X1.

O core do ESP8266 usa BearSSL. Diferentemente do ESP32, ele verifica as datas de validade do certificado, então o relógio precisa estar correto antes do handshake.

#include <ESP8266WiFi.h>
#include <WiFiClientSecure.h>
#include <PubSubClient.h>
#include <time.h>

// ISRG Root X1 (raiz da Let's Encrypt), cole o PEM completo
static const char ROOT_CA[] PROGMEM = R"EOF(
-----BEGIN CERTIFICATE-----
...ISRG Root X1...
-----END CERTIFICATE-----
)EOF";

BearSSL::X509List trustAnchors(ROOT_CA);
BearSSL::WiFiClientSecure tlsClient;
PubSubClient mqtt(tlsClient);

void syncClock() {
  configTime(0, 0, "pool.ntp.org", "time.nist.gov");
  Serial.print("Waiting for NTP");
  time_t now = time(nullptr);
  while (now < 1700000000) {      // qualquer timestamp bem no passado
    delay(250);
    Serial.print(".");
    now = time(nullptr);
  }
  Serial.println(" done");
}

void setupTls() {
  syncClock();
  tlsClient.setTrustAnchors(&trustAnchors);
  // Opcional: buffers menores se o servidor suportar max fragment length
  if (tlsClient.probeMaxFragmentLength("broker.connectmq.com", 8883, 1024)) {
    tlsClient.setBufferSizes(1024, 1024);
  }
  mqtt.setServer("broker.connectmq.com", 8883);
}

bool connectMqtt() {
  return mqtt.connect("YOUR_CLIENT_ID", "YOUR_USERNAME", "YOUR_PASSWORD");
}

Chame setupTls() em setup() depois que o Wi-Fi conectar. Ajuste a frequência da CPU para 160 MHz; o primeiro handshake pode demorar um tempo perceptível a 80 MHz, e o watchdog não vai gostar de um connect() lento dentro de um loop ocupado.

Passo 4: ESP8266 MQTT a Bateria com Deep Sleep

Muitos sensores com ESP8266 funcionam a bateria e só precisam reportar a cada poucos minutos. O rádio é de longe o maior consumidor de energia, então o padrão vencedor é: acordar, conectar, publicar, desconectar, dormir. O deep sleep no ESP8266 exige uma ligação física entre o GPIO16 (D0 no NodeMCU e no D1 mini) e o pino RST, porque o chip acorda reiniciando a si mesmo. Desconecte esse fio durante o upload se a placa se comportar mal na gravação.

void publishAndSleep() {
  connectWifi();
  mqtt.setServer(MQTT_HOST, MQTT_PORT);
  if (mqtt.connect(deviceId)) {
    char payload[64];
    snprintf(payload, sizeof(payload), "{\"a0\":%d,\"rssi\":%d}", analogRead(A0), WiFi.RSSI());
    mqtt.publish(topicTelemetry, payload);
    // dá um instante para a pilha enviar o pacote antes de cortarmos a energia do rádio
    for (int i = 0; i < 10; i++) { mqtt.loop(); delay(10); }
    mqtt.disconnect();
  }
  ESP.deepSleep(5 * 60 * 1000000ULL);   // 5 minutos, em microssegundos
}

Chame publishAndSleep() no final de setup() e deixe loop() vazio. Algumas observações práticas: um handshake TLS a cada despertar custa bem mais tempo e energia do que MQTT sem criptografia, então pese a exigência de segurança contra a autonomia da bateria e considere intervalos de sono mais longos com TLS. Use uma retained message para a leitura mais recente, para que dashboards abertos entre os despertares ainda vejam um valor. E não use Last Will para indicar presença em dispositivos que dormem; um disconnect() limpo nunca o dispara, e um status "offline" seria enganoso de qualquer forma.

Solução de Problemas de ESP8266 MQTT

  1. rc=-2 com TLS, mas tudo certo na 1883: relógio não sincronizado, certificado raiz errado ou heap contíguo insuficiente. Imprima tlsClient.getLastSSLError() para ver o motivo informado pelo BearSSL. Nosso guia do PubSubClient rc=-2 cobre todos os códigos.
  2. Resets aleatórios (wdt reset): algo está bloqueando por tempo demais. Nunca coloque chamadas longas de delay() no callback do MQTT e chame yield() em loops longos.
  3. A placa nunca entra no Wi-Fi: rede somente 5 GHz, senha errada ou captive portal em uma rede de convidados.
  4. A placa desconecta sempre que uma segunda placa se conecta: as duas usam o mesmo client ID. A abordagem com o chip ID mostrada acima evita isso.
  5. Mensagens com mais de algumas centenas de bytes somem: é o buffer padrão de 256 bytes do PubSubClient. Aumente-o com moderação.
  6. As mensagens param de chegar depois de horas: fragmentação do heap. Acompanhe getMaxFreeBlockSize() ao longo do tempo.

ESP8266 ou ESP32?

O ESP8266 é perfeitamente capaz para nós com um único sensor, relés e displays pequenos, especialmente com MQTT sem criptografia ou conexões TLS ocasionais. Se você precisa de muitas sessões TLS simultâneas, Bluetooth, mais GPIOs ou espaço para atualizações OTA somadas a payloads grandes, passe para o ESP32. Nossa comparação ESP32 vs ESP8266 analisa essas escolhas, e o tutorial IoT com ESP32 é o próximo passo quando esta placa ficar pequena para você.

Rode Sua Frota de ESP8266 no ConnectMQ

Quando o protótipo funcionar, mova-o para um broker MQTT na nuvem com credenciais privadas e TLS. O ConnectMQ, um broker MQTT gerenciado, suporta MQTT 3.1.1 e 5.0 em TCP 1883 e TLS 8883, e o portal inclui um cliente MQTT no navegador e um explorador de topics ao vivo para conferir o que suas placas publicam. Crie um broker Serverless gratuito em app.connectmq.com, sem precisar de cartão de crédito.

Perguntas frequentes

O ESP8266 pode usar MQTT sobre TLS?

Sim. O core do ESP8266 inclui o BearSSL, e o PubSubClient funciona com BearSSL::WiFiClientSecure. Sincronize o relógio primeiro, confie no certificado raiz do broker e mantenha moderado o restante do uso de memória.

Qual pino o LED da placa NodeMCU usa?

Na maioria das placas NodeMCU e Wemos D1 mini é o GPIO2 (LED_BUILTIN, também marcado como D4), e ele é ativo em nível baixo, ou seja, escrever LOW o acende.

Posso usar o ESP8266 com MQTT 5?

O PubSubClient suporta apenas MQTT 3.1.1, o que basta para a maioria dos sensores. O broker ainda pode atender clientes MQTT 5, como dashboards e backends, nos mesmos topics.

Por que meu ESP8266 precisa da hora para usar TLS?

O BearSSL verifica se o certificado do servidor está dentro do período de validade. Sem um relógio correto, o dispositivo acha que está em 1970 e rejeita o certificado.

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.