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.jsonem 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
Stringem 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
snprintfou 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
- 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. - Resets aleatórios (
wdt reset): algo está bloqueando por tempo demais. Nunca coloque chamadas longas dedelay()no callback do MQTT e chameyield()em loops longos. - A placa nunca entra no Wi-Fi: rede somente 5 GHz, senha errada ou captive portal em uma rede de convidados.
- 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.
- Mensagens com mais de algumas centenas de bytes somem: é o buffer padrão de 256 bytes do PubSubClient. Aumente-o com moderação.
- 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.



