ESP32 e Arduino

Tutorial ESP32 IoT: do Primeiro Sketch a Sensores Conectados à Nuvem

Vá de um ESP32 recém-tirado da caixa a um sensor de temperatura seguro e conectado à nuvem: configuração da Arduino IDE, Wi-Fi, um DHT22, publish e subscribe MQTT, controle remoto de LED e TLS na porta 8883.

Capa do tutorial ESP32 IoT mostrando uma placa ESP32 com um sensor DHT22 enviando leituras para um broker MQTT 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

Este tutorial ESP32 IoT leva você de uma placa recém-tirada da caixa a um sensor conectado à nuvem que publica temperatura e umidade, aceita comandos remotos e se comunica com a nuvem via TLS. Você vai configurar a Arduino IDE, conectar ao Wi-Fi, ler um DHT22, publicar via MQTT no servidor MQTT público gratuito e depois levar o mesmo sketch para um broker privado e criptografado, para uso real.

Por Que o ESP32 É o Microcontrolador Padrão para IoT

A família ESP32 da Espressif combina um processador dual-core rápido (ou single-core RISC-V, dependendo da variante), Wi-Fi e Bluetooth integrados, muitos GPIOs, entradas analógicas e suporte em hardware a TLS em um módulo que custa poucos dólares. Ele roda código Arduino, MicroPython e o framework próprio da Espressif, o ESP-IDF, e tem uma comunidade enorme. Para quem está construindo um sensor conectado, um controlador de relés ou um pequeno gateway, geralmente é a primeira placa a experimentar.

O que você vai construir neste tutorial:

  1. Uma placa que entra na sua rede Wi-Fi e se reconecta automaticamente.
  2. Um sensor DHT22 publicando leituras em JSON a cada dez segundos via MQTT.
  3. Um LED controlado remotamente, acionado publicando ON ou OFF em um topic de comando.
  4. Um topic de status online/offline usando o recurso de Last Will do MQTT.
  5. Uma versão segura usando TLS na porta 8883 com credenciais privadas.

O Que Você Precisa

Item Observações
Placa de desenvolvimento ESP32 Qualquer placa ESP32 DevKit, ESP32-S3 ou ESP32-C3 com USB funciona
Sensor DHT22 (AM2302) Um módulo breakout com resistor de pull-up integrado é o mais fácil
Jumpers e protoboard Três fios para o sensor
Cabo USB Precisa ser um cabo de dados, não apenas de carga
Computador com Arduino IDE 2.x Windows, macOS ou Linux
Clientes de linha de comando do Mosquitto mosquitto_pub e mosquitto_sub para testes

Ainda não tem o sensor? O sketch informa um erro e continua rodando, então você ainda pode acompanhar as partes de MQTT e do LED.

Passo 1: Configure a Arduino IDE para o ESP32

  1. Instale a Arduino IDE 2.x a partir do site do Arduino.
  2. Abra Tools, Board, Boards Manager, pesquise por esp32 e instale esp32 by Espressif Systems. Se não aparecer, adicione https://espressif.github.io/arduino-esp32/package_esp32_index.json em File, Preferences, Additional boards manager URLs e pesquise de novo. O guia oficial de instalação do Arduino-ESP32 tem capturas de tela para cada plataforma.
  3. Abra Tools, Manage Libraries e instale PubSubClient, de Nick O'Leary, e DHT sensor library, da Adafruit (aceite também a sugestão de instalar a Adafruit Unified Sensor).
  4. Conecte a placa, selecione o seu modelo em Tools, Board (para um DevKit genérico, escolha ESP32 Dev Module) e selecione a porta serial em Tools, Port.

Teste o toolchain com um sketch de blink antes de seguir em frente:

#define LED_PIN 2  // LED da placa na maioria dos ESP32 DevKit

void setup() {
  pinMode(LED_PIN, OUTPUT);
}

void loop() {
  digitalWrite(LED_PIN, HIGH);
  delay(500);
  digitalWrite(LED_PIN, LOW);
  delay(500);
}

Se o upload travar em "Connecting...", segure o botão BOOT da placa até o upload começar. Se nenhuma porta aparecer, instale o driver USB-serial do chip da sua placa (geralmente CP210x ou CH340) ou tente outro cabo. Algumas placas não têm LED no GPIO 2; nesse caso, ligue um LED com um resistor de 220 ohms ao GPIO 2.

Passo 2: Ligue o Sensor DHT22

Conecte o módulo DHT22 da seguinte forma:

Pino do DHT22 Pino do ESP32
VCC (+) 3V3
DATA (out) GPIO 4
GND (-) GND

Se você usar um sensor de quatro pinos sem módulo, adicione um resistor de pull-up de 10 kiloohms entre DATA e 3V3 e deixe o terceiro pino desconectado. Evite os GPIOs 6 a 11, reservados para a memória flash nos módulos ESP32 clássicos, e evite pinos de strapping como os GPIOs 0, 2, 12 e 15 para sensores. O DHT22 não deve ser lido com intervalo menor que dois segundos.

Passo 3: Entenda as Peças do MQTT

O MQTT é um protocolo publish/subscribe. O seu ESP32 não envia dados para uma aplicação de servidor específica; ele publica mensagens em topics de um broker, e qualquer cliente que assine esses topics as recebe. Se quiser todo o contexto, leia primeiro o que um broker MQTT faz.

Neste tutorial ESP32 IoT usamos o servidor MQTT público (gratuito) em broker.connectmq.com, pensado para testes e protótipos, não para dados de produção. Ele aceita conexões anônimas na porta 1883, desde que cada cliente use um client ID único e não vazio. Tudo o que é publicado na área pública pode ser lido por qualquer pessoa, então nunca envie senhas ou dados pessoais, e use um prefixo de topic único para que suas mensagens não colidam com as de outras pessoas. A área pública permite 64 KB por mensagem, 10 mensagens por segundo e 10 assinaturas por cliente, muito mais do que um sensor precisa.

Nossos topics, com k3v9 substituído pela sua própria string aleatória:

connectmq/demo/esp32-k3v9/telemetry   JSON readings, published every 10 s
connectmq/demo/esp32-k3v9/status      "online" / "offline" (retained, Last Will)
connectmq/demo/esp32-k3v9/led/set     commands: ON or OFF
connectmq/demo/esp32-k3v9/led/state   current LED state (retained)

Passo 4: O Sketch ESP32 IoT Completo

Crie um novo sketch, cole o código abaixo e defina o nome da sua rede Wi-Fi, a senha e o prefixo dos topics.

#include <WiFi.h>
#include <PubSubClient.h>
#include <DHT.h>

// ---------- configuração ----------
const char* WIFI_SSID     = "YOUR_WIFI_SSID";
const char* WIFI_PASSWORD = "YOUR_WIFI_PASSWORD";

const char* MQTT_HOST = "broker.connectmq.com";
const uint16_t MQTT_PORT = 1883;
const char* TOPIC_PREFIX = "connectmq/demo/esp32-k3v9";  // troque k3v9 pela sua própria string

#define DHT_PIN 4
#define DHT_TYPE DHT22
#define LED_PIN 2
const unsigned long PUBLISH_INTERVAL_MS = 10000;
// -----------------------------------

DHT dht(DHT_PIN, DHT_TYPE);
WiFiClient net;
PubSubClient mqtt(net);

String clientId;
String topicTelemetry, topicStatus, topicLedSet, topicLedState;
unsigned long lastPublish = 0;
unsigned long lastReconnectAttempt = 0;

void connectWiFi() {
  if (WiFi.status() == WL_CONNECTED) return;
  Serial.printf("Connecting to Wi-Fi %s", WIFI_SSID);
  WiFi.mode(WIFI_STA);
  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
  unsigned long start = millis();
  while (WiFi.status() != WL_CONNECTED && millis() - start < 20000) {
    delay(500);
    Serial.print(".");
  }
  if (WiFi.status() == WL_CONNECTED) {
    Serial.printf("\nWi-Fi connected, IP %s\n", WiFi.localIP().toString().c_str());
  } else {
    Serial.println("\nWi-Fi connection failed, will retry");
  }
}

void setLed(bool on) {
  digitalWrite(LED_PIN, on ? HIGH : LOW);
  mqtt.publish(topicLedState.c_str(), on ? "ON" : "OFF", true);  // estado retido
}

void onMessage(char* topic, byte* payload, unsigned int length) {
  String message;
  for (unsigned int i = 0; i < length; i++) message += (char)payload[i];
  message.trim();
  Serial.printf("Received [%s] %s\n", topic, message.c_str());

  if (topicLedSet == topic) {
    if (message == "ON") setLed(true);
    else if (message == "OFF") setLed(false);
  }
}

bool connectMqtt() {
  Serial.printf("Connecting to MQTT %s:%u as %s\n", MQTT_HOST, MQTT_PORT, clientId.c_str());
  // Last Will: o broker publica "offline" (retido) se desaparecermos
  bool ok = mqtt.connect(clientId.c_str(), topicStatus.c_str(), 1, true, "offline");
  if (ok) {
    Serial.println("MQTT connected");
    mqtt.publish(topicStatus.c_str(), "online", true);
    mqtt.subscribe(topicLedSet.c_str(), 1);
  } else {
    Serial.printf("MQTT connect failed, state=%d\n", mqtt.state());
  }
  return ok;
}

void publishReading() {
  float temperature = dht.readTemperature();
  float humidity = dht.readHumidity();
  if (isnan(temperature) || isnan(humidity)) {
    Serial.println("DHT22 read failed, check wiring");
    mqtt.publish(topicTelemetry.c_str(), "{\"error\":\"sensor_read_failed\"}");
    return;
  }
  char payload[128];
  snprintf(payload, sizeof(payload),
           "{\"temperature\":%.2f,\"humidity\":%.1f,\"rssi\":%d,\"uptime\":%lu}",
           temperature, humidity, WiFi.RSSI(), millis() / 1000);
  mqtt.publish(topicTelemetry.c_str(), payload);
  Serial.printf("Published %s\n", payload);
}

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

  // Client ID único derivado do endereço MAC do chip
  uint64_t mac = ESP.getEfuseMac();
  char id[32];
  snprintf(id, sizeof(id), "esp32-%04X%08X", (uint16_t)(mac >> 32), (uint32_t)mac);
  clientId = id;

  topicTelemetry = String(TOPIC_PREFIX) + "/telemetry";
  topicStatus    = String(TOPIC_PREFIX) + "/status";
  topicLedSet    = String(TOPIC_PREFIX) + "/led/set";
  topicLedState  = String(TOPIC_PREFIX) + "/led/state";

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

void loop() {
  if (WiFi.status() != WL_CONNECTED) {
    connectWiFi();
    return;
  }

  if (!mqtt.connected()) {
    unsigned long now = millis();
    if (now - lastReconnectAttempt > 5000) {  // nova tentativa não bloqueante a cada 5 s
      lastReconnectAttempt = now;
      if (connectMqtt()) lastReconnectAttempt = 0;
    }
    return;
  }

  mqtt.loop();

  if (millis() - lastPublish >= PUBLISH_INTERVAL_MS) {
    lastPublish = millis();
    publishReading();
  }
}

Faça o upload do sketch e abra o Serial Monitor a 115200 baud. Você deve ver a conexão Wi-Fi, a conexão MQTT e uma leitura publicada a cada dez segundos.

Como o sketch está estruturado

  • Reconexões não bloqueantes. O loop nunca fica preso em um ciclo de tentativas. Se o Wi-Fi ou o MQTT cair, ele tenta de novo a cada poucos segundos enquanto o restante do código continua respondendo. Loops longos e bloqueantes são uma causa comum de resets por watchdog; o guia de reconexão MQTT no ESP32 explica estratégias mais robustas.
  • Last Will e status retido. O broker armazena online como status retido e o substitui automaticamente por offline se a placa perder energia ou conectividade sem uma desconexão limpa.
  • Estado do LED retido. Qualquer dashboard que assine depois descobre imediatamente se o LED está aceso.
  • Payloads pequenos. O buffer de pacotes padrão do PubSubClient é de 256 bytes, e este payload cabe com folga. Para documentos JSON maiores, chame mqtt.setBufferSize(1024) antes de conectar, como explicado em tamanho do buffer do PubSubClient.

Passo 5: Teste a Partir do Seu Computador

Acompanhe tudo o que sua placa publica:

mosquitto_sub -h broker.connectmq.com -p 1883 -i laptop-k3v9-sub -t "connectmq/demo/esp32-k3v9/#" -v

Você deve ver imediatamente as mensagens retidas de status e led/state e, em seguida, a telemetria a cada dez segundos:

connectmq/demo/esp32-k3v9/status online
connectmq/demo/esp32-k3v9/telemetry {"temperature":23.40,"humidity":48.2,"rssi":-58,"uptime":42}

Agora acione o LED a partir de um segundo terminal:

mosquitto_pub -h broker.connectmq.com -p 1883 -i laptop-k3v9-pub -t "connectmq/demo/esp32-k3v9/led/set" -m ON
mosquitto_pub -h broker.connectmq.com -p 1883 -i laptop-k3v9-pub -t "connectmq/demo/esp32-k3v9/led/set" -m OFF

O LED muda de estado e uma nova mensagem led/state aparece no subscriber. Desconecte a placa, espere cerca de 45 segundos (1,5 vez o keepalive) e o broker publica offline no topic de status. Esse é o seu ciclo de IoT completo: sensoriamento, publicação, controle remoto e detecção de presença.

Não publique comandos com a flag retain (-r). Um comando retido seria entregue de novo toda vez que o ESP32 se reconectasse.

Passo 6: Migre para um Broker Privado com TLS

O servidor MQTT público é perfeito para aprender, mas um dispositivo real precisa de privacidade, autenticação e criptografia. Com a ConnectMQ você tem um broker privado com credenciais geradas e um certificado Let's Encrypt na porta 8883.

  1. Cadastre-se no portal da ConnectMQ, escolha o plano Serverless (Free), crie um broker e copie o nome de usuário, a senha e o client ID gerados.
  2. Baixe o certificado raiz da Let's Encrypt (ISRG Root X1) ao qual o certificado do broker está encadeado:
curl -o isrgrootx1.pem https://letsencrypt.org/certs/isrgrootx1.pem
  1. Altere o início do sketch da seguinte forma. Só mudam os includes, a configuração, o objeto cliente e a chamada de conexão; todo o resto permanece igual.
#include <WiFi.h>
#include <WiFiClientSecure.h>
#include <PubSubClient.h>
#include <DHT.h>

const char* MQTT_HOST = "broker.connectmq.com";
const uint16_t MQTT_PORT = 8883;
const char* MQTT_USERNAME  = "YOUR_USERNAME";
const char* MQTT_PASSWORD  = "YOUR_PASSWORD";
const char* MQTT_CLIENT_ID = "YOUR_CLIENT_ID";
const char* TOPIC_PREFIX = "home/office/esp32-01";

// Cole o conteúdo completo de isrgrootx1.pem entre os marcadores
const char* ROOT_CA = R"EOF(
-----BEGIN CERTIFICATE-----
...paste the certificate body from isrgrootx1.pem here...
-----END CERTIFICATE-----
)EOF";

WiFiClientSecure net;
PubSubClient mqtt(net);

Em setup(), substitua o client ID baseado no MAC pelo fornecido no portal e carregue o certificado antes de conectar:

  clientId = MQTT_CLIENT_ID;  // deve corresponder ao client ID emitido com suas credenciais
  net.setCACert(ROOT_CA);

E em connectMqtt(), passe as credenciais junto com o Last Will:

  bool ok = mqtt.connect(clientId.c_str(), MQTT_USERNAME, MQTT_PASSWORD,
                         topicStatus.c_str(), 1, true, "offline");

Faça o upload de novo. O Serial Monitor deve mostrar uma conexão bem-sucedida na porta 8883. Verifique a partir do seu computador com as mesmas credenciais, ou abra o cliente MQTT no navegador e o explorador de topics em tempo real no portal para ver as leituras chegando. Lembre-se de que a ConnectMQ vincula os client IDs às credenciais que emite, então cada dispositivo precisa do seu próprio conjunto de credenciais; reutilizar um conjunto em duas placas faz com que uma derrube a outra. O tutorial de MQTT sobre SSL no ESP32 aborda o tratamento de certificados com mais profundidade, incluindo por que setInsecure() nunca deve ir para produção.

Passo 7: Prepare o Sensor para o Mundo Real

Um sketch que roda na sua mesa por uma tarde é diferente de um dispositivo que roda sem supervisão por um ano. Antes de instalar a placa em algum lugar de difícil acesso, como o galpão de uma fazenda ou o teto de uma planta industrial, percorra este checklist:

  1. Alimentação estável. Use uma fonte de 5 V de qualidade, de pelo menos 500 mA. A transmissão Wi-Fi causa picos de corrente, e adaptadores baratos provocam resets por brownout que parecem bugs de software.
  2. Posicionamento do sensor. Mantenha o DHT22 longe do próprio ESP32 e dos reguladores de tensão, que esquentam e distorcem as leituras em um grau ou mais. Um cabo curto e uma caixa ventilada ajudam.
  3. Um conjunto de credenciais por dispositivo. Nunca copie o mesmo nome de usuário, senha e client ID em várias placas. Emita um conjunto por dispositivo para poder revogar um sem mexer nos outros.
  4. Timestamps reais. O campo uptime é útil para depuração, mas a análise precisa de horário real. Sincronize o relógio via NTP na inicialização e adicione um timestamp epoch a cada leitura, como mostrado em timestamps NTP no ESP32 para MQTT.
  5. Atualizações remotas. Subir em uma escada para regravar um sensor cansa rápido. Planeje atualizações over-the-air desde o início com atualizações OTA do ESP32 via MQTT.
  6. Configuração sem recompilar. Credenciais de Wi-Fi fixas no código servem para uma placa. Para várias, use uma biblioteca de captive portal para que cada dispositivo possa ser configurado no local.
  7. Relatórios de saúde. Continue publicando RSSI e uptime. Uma intensidade de sinal caindo aos poucos ou reinícios frequentes são avisos antecipados de que um dispositivo logo ficará offline.

Nenhuma dessas etapas altera a lógica MQTT que você já escreveu. Elas fazem a diferença entre uma demo e um sensor do qual você pode esquecer, porque ele simplesmente continua enviando dados.

Solução de Problemas

Se mqtt.state() retornar um valor diferente de zero, esta tabela geralmente aponta a causa:

state() Significado Correção típica
-4 Timeout de conexão Verifique a rede, o firewall, o número da porta e o keepalive
-2 Falha na conexão TCP ou TLS Host ou porta errados, certificado de CA ausente, Wi-Fi não pronto
-3 / -1 Conexão perdida / desconectado Client ID duplicado, Wi-Fi instável, código bloqueante no loop
2 Client ID rejeitado Client ID vazio ou errado; use o emitido com suas credenciais
4 Nome de usuário ou senha incorretos Copie de novo as credenciais do portal e verifique se há espaços
5 Não autorizado As credenciais não correspondem ao client ID ou ao broker

Outros problemas comuns:

  • As leituras dão nan. Verifique a ligação do DHT22, o resistor de pull-up e se você não está lendo com intervalo menor que dois segundos.
  • O publish falha silenciosamente. A mensagem é maior que o buffer do PubSubClient; aumente-o com setBufferSize().
  • A placa reinicia aleatoriamente. Alimentação USB fraca durante a transmissão Wi-Fi; tente outra porta ou um hub com alimentação própria.
  • Funciona na 1883, mas não na 8883. O certificado de CA está ausente ou incompleto, ou a rede bloqueia a porta de saída 8883.

Para um checklist mais longo, veja o ESP32 não conecta ao broker MQTT.

Próximos Passos

Com essa base, você pode construir quase qualquer sensor ou atuador conectado. Bons próximos passos:

  1. Substitua as strings montadas à mão pelo ArduinoJson, como mostrado em ESP32 com ArduinoJson e MQTT.
  2. Troque o DHT22 por um BME280 via MQTT, mais preciso.
  3. Rode com baterias usando deep sleep do ESP32 e MQTT.
  4. Acione cargas reais com segurança com um relé ESP32 controlado via MQTT.
  5. Compare esta abordagem com o tutorial ESP32 MQTT, mais curto e focado no LED, e com o caminho em Python em MicroPython umqtt no ESP32.

Coloque Seu ESP32 Online com a ConnectMQ

Quando o seu protótipo estiver pronto para dados reais, dê a ele um lar privado. Crie uma conta gratuita em app.connectmq.com no plano Serverless (Free), sem cartão de crédito, crie um broker e grave as credenciais geradas no seu sketch. O plano gratuito suporta até 25 conexões, o que cobre uma pequena frota de sensores mais um ou dois dashboards, e quando você precisar de mais, um plano de broker MQTT gerenciado escala para centenas de dispositivos sem alterar o seu código.

Perguntas frequentes

Qual placa ESP32 é melhor para iniciantes?

Um ESP32 DevKit padrão (geralmente identificado como ESP32-WROOM-32 ou ESP32 Dev Module) é o começo mais fácil, porque quase todo tutorial e biblioteca o suporta. Placas ESP32-S3 e ESP32-C3 também funcionam com o código deste tutorial.

Preciso de uma conta para seguir este tutorial ESP32 IoT?

Não. A primeira parte usa a área pública do broker.connectmq.com, que aceita conexões anônimas com qualquer client ID único e não vazio. Você só precisa de uma conta ao migrar para um broker privado com TLS.

Por que meu ESP32 fica se desconectando do broker?

As causas mais comuns são dois dispositivos usando o mesmo client ID, código bloqueante que impede a execução de mqtt.loop() e sinal Wi-Fi fraco. Verifique o valor de RSSI na telemetria e garanta que cada placa tenha o seu próprio client ID.

O PubSubClient suporta MQTT 5?

Não. O PubSubClient implementa MQTT 3.1.1, que é totalmente suportado pelo broker. Se você precisar de recursos do MQTT 5 no ESP32, use o componente esp-mqtt do ESP-IDF.

É seguro usar setInsecure() para TLS no ESP32?

Apenas para experimentos rápidos. O setInsecure() criptografa o tráfego, mas pula a verificação do servidor, então não protege contra falsificação de identidade. Carregue o certificado de CA raiz com setCACert() para qualquer coisa além de um teste.

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.