Guias · 18 min de leitura

Tutorial de MQTT com ESP32: Mosquitto, Home Assistant e ESPHome

Tutorial de MQTT com ESP32: instale o Mosquitto, publique dados de sensores e controle um relé com PubSubClient, use o discovery do Home Assistant, veja um exemplo de YAML no ESPHome e entenda o QoS.

Juntar o ESP32 com MQTT é a forma mais comum de fazer os sensores e relés da sua casa conversarem entre si e com um sistema de casa inteligente como o Home Assistant. O MQTT é um protocolo de mensagens leve, criado para dispositivos pequenos: o ESP32 deixa a temperatura que mediu em um tópico como “ev/salon/sicaklik”, e todo programa que está ouvindo esse tópico recebe o valor na hora. Do mesmo jeito, quando você toca em um botão no app do Home Assistant no celular, o comando “ON” chega ao ESP32 em bem menos de um segundo e aciona o relé. Diferente do HTTP, ele não abre uma nova conexão a cada requisição; funciona sobre uma única conexão aberta, com cabeçalhos de apenas dois bytes, por isso é rápido e não sobrecarrega nem o Wi-Fi nem o processador.

Neste guia você vai montar do zero um nó de casa inteligente que funciona de verdade. Primeiro você vai aprender os conceitos de broker, tópico, publicar e assinar do MQTT e depois vai instalar o broker Mosquitto no Home Assistant ou em um Raspberry Pi. Em seguida, vai usar a biblioteca PubSubClient para publicar as leituras de temperatura e umidade do DHT22 a partir de um ESP32, ouvir comandos para o relé e adicionar o MQTT Discovery, para que o dispositivo apareça sozinho no Home Assistant. Também vamos ver o QoS e o retain, a mensagem de last will (LWT) que marca o dispositivo como “indisponível” quando a conexão cai, a alternativa ESPHome, que faz o mesmo trabalho sem uma única linha de C++, as diferenças no ESP8266 e no Raspberry Pi Pico W e, um por um, os erros mais comuns.

Placa de desenvolvimento ESP32 conectada ao Home Assistant por MQTT
Graças ao Wi-Fi integrado, o ESP32 se conecta direto ao broker MQTT da sua rede doméstica; os dados dos sensores e os comandos do relé passam pela mesma conexão.

O que é MQTT e como funciona?

O MQTT (Message Queuing Telemetry Transport) usa o modelo publicar/assinar (publish/subscribe). No meio fica um servidor chamado broker; o ESP32, o Home Assistant, o seu celular ou um programa no seu computador se conectam a ele como clientes. Os clientes não se conhecem nem sabem o endereço IP uns dos outros: um publica uma mensagem em um tópico, e o broker a repassa a todos que assinam esse tópico. Pense em uma agência dos correios: o ESP32 coloca uma carta na caixa com o endereço “ev/salon/sicaklik”, e o Home Assistant, que está de olho nessa caixa, recebe a carta na hora. Como é sempre o cliente que abre a conexão, o ESP32 não precisa de IP estático nem de uma porta aberta no roteador; a única coisa que ele precisa saber é o endereço do broker.

ConceitoPara que serveExemplo
BrokerO servidor que recebe as mensagens e as distribui aos assinantesMosquitto, o broker Mosquitto do Home Assistant
ClienteQualquer dispositivo ou programa que se conecta ao broker; cada um tem um ID de cliente (client ID) únicoESP32, Home Assistant, MQTT Explorer
Tópico (topic)O endereço de uma mensagem, formado por níveis separados por barrasev/salon/sicaklik
Publicar (publish)Enviar uma mensagem para um tópicoEnviar o valor “23.4” para ev/salon/sicaklik
Assinar (subscribe)Registrar-se para receber as mensagens de um tópicoO ESP32 ouvindo ev/salon/role/komut
Payload (conteúdo)O conteúdo de uma mensagem; texto, número ou JSONON, 23.4, {"sicaklik":23.4}
RetainO broker guarda a última mensagem de um tópico e a entrega na hora a novos assinantesEstado do relé: ON
LWT (last will)Uma mensagem que o broker publica em nome de um cliente se ele cair sem avisarev/salon/baglanti: offline (tópico e mensagem de último desejo)
QoSO nível de garantia de entrega de uma mensagem (0, 1 ou 2)QoS 1 para comandos do relé

Por que MQTT? Comparação com servidor web, Blynk e Telegram

MétodoVantagensDesvantagensMelhor para
MQTT + Home AssistantLocal e rápido, nos dois sentidos; centenas de dispositivos em um único painel, automaçõesÉ preciso manter um brokerGerenciar a casa inteira em um só lugar
Servidor web no ESP32Sem servidor extra, abre no navegadorCada dispositivo tem sua própria página, sem automações entre dispositivosPainel de controle de um único dispositivo
Blynk IoTPainel pronto no celular, acesso pela internetDepende da nuvem, limites no plano grátisProtótipos móveis rápidos
Bot do TelegramNotificações instantâneas grátis, sem redirecionamento de portasSem gráficos nem painelAlarmes e comandos simples
ESP-NOWAs placas ESP conversam sem roteador nem brokerSó entre placas ESP, não chega direto ao Home AssistantLevar dados de um sensor a bateria até um gateway

Resumindo, o MQTT brilha à medida que o número de dispositivos cresce: quando você adiciona um sensor novo, não mexe em nenhum código existente, só começa a publicar em um tópico novo. Se você quer controlar um único dispositivo pelo navegador, o guia ESP32 Async Web Server e WebSocket leva ao resultado mais rápido; para notificações no celular, veja bot do Telegram com ESP32, e para um painel móvel pronto, veja Blynk com ESP32. Para um sensor no jardim, fora do alcance do roteador, uma boa solução é usar o ESP-NOW para levar os dados até um ESP32 gateway conectado ao MQTT.

Estrutura dos tópicos MQTT e curingas

Os tópicos parecem caminhos de pastas: “ev/salon/sicaklik” (em turco, casa/sala/temperatura) tem três níveis e diferencia maiúsculas de minúsculas, então “Ev/Salon” e “ev/salon” são dois tópicos diferentes. Não comece com uma barra (“/ev/salon” cria um primeiro nível vazio) e evite espaços e caracteres acentuados; letras simples, números, hífens e sublinhados bastam. Ao assinar, você pode usar dois curingas: + substitui exatamente um nível (“ev/+/sicaklik” traz a temperatura de todos os cômodos), enquanto # cobre tudo o que vem depois dele e só pode aparecer no final (“ev/#” traz todas as mensagens da casa). Os curingas só valem na assinatura; uma mensagem é sempre publicada em um tópico exato. Tópicos que começam com $ (como $SYS) são reservados para as estatísticas do próprio broker e não entram em uma assinatura com #. Para o projeto deste guia, vamos usar esta organização:

TópicoQuem publicaQuem ouveRetain
ev/salon/sicaklikESP32 (a cada 30 segundos)Home AssistantSim
ev/salon/nemESP32 (a cada 30 segundos)Home AssistantSim
ev/salon/role/komut (tópico de comando do relé)Home Assistant, celular, automaçõesESP32Não
ev/salon/role/durum (tópico de estado do relé)ESP32 (a cada mudança)Home AssistantSim
ev/salon/baglantiESP32 (publica online), broker (publica offline)Home AssistantSim
homeassistant/statusHome Assistant (online ao iniciar)ESP32Não

Instalando um broker MQTT: Mosquitto

O broker MQTT gratuito mais popular é o Eclipse Mosquitto; mesmo em um Raspberry Pi ele aguenta tranquilamente centenas de mensagens por segundo. Há três jeitos fáceis de instalar: o app oficial Mosquitto broker, se você usa o Home Assistant OS; o pacote apt, em um Raspberry Pi ou computador Linux separado; ou o instalador do Mosquitto no Windows. Seja qual for a escolha, o broker usa a porta 1883 para MQTT sem criptografia e a 8883 para MQTT criptografado com TLS, e só precisa estar na mesma rede doméstica que o ESP32. No Home Assistant, a instalação é assim:

  1. No Home Assistant, abra Configurações > Aplicativos (chamada de Complementos / Add-ons em versões antigas), clique em Instalar aplicativo e escolha Mosquitto broker na lista.
  2. Clique em Instalar; quando terminar, clique em Iniciar e deixe ativada a opção de iniciar com o sistema.
  3. Crie um usuário separado para o ESP32: em Configurações > Pessoas > Usuários, adicione um usuário chamado “esp32” com uma senha forte. Se não aparecer essa aba, ative o Modo avançado no seu perfil. Os nomes “homeassistant” e “addons” são reservados para o broker, então não os use.
  4. Na página Configurações > Dispositivos e serviços, a integração MQTT normalmente aparece como “Descoberto”; clique em Configurar e confirme. Se ela não aparecer, use Adicionar integração, busque por MQTT e escolha a opção que configura o Mosquitto automaticamente.
  5. No código do ESP32, você vai colocar o endereço IP do Home Assistant como endereço do broker (por exemplo 192.168.1.10), 1883 como porta e o usuário que acabou de criar.

Em uma máquina Linux, como um Raspberry Pi ou um Ubuntu, a instalação leva poucos comandos. Instale o broker e as ferramentas de teste com sudo apt install mosquitto mosquitto-clients. Crie o usuário “esp32” com sudo mosquitto_passwd -c /etc/mosquitto/passwd esp32 e digite a senha duas vezes; a opção -c cria o arquivo do zero, então deixe-a de fora quando for adicionar um segundo usuário, senão os usuários existentes serão apagados. Depois crie um arquivo chamado local.conf na pasta /etc/mosquitto/conf.d/, coloque nele as três linhas abaixo e reinicie o serviço com sudo systemctl restart mosquitto. No Windows, adicione as mesmas linhas ao arquivo mosquitto.conf da pasta de instalação do Mosquitto e reinicie o serviço Mosquitto Broker.

LinhaSignificado
listener 1883 (porta de escuta)Escuta na porta 1883 em todas as interfaces de rede; sem essa linha, o Mosquitto 2.x só aceita conexões do próprio computador
allow_anonymous false (sem acesso anônimo)Recusa conexões sem usuário e senha; já é o padrão no 2.x, mas escrever isso explicitamente é um bom hábito
password_file /etc/mosquitto/passwd (arquivo de senhas)Usa o arquivo de senhas criado com mosquitto_passwd; as senhas ficam guardadas nele como hash
Se nenhum listener estiver definido na configuração, o Mosquitto 2.0 e posteriores só escutam em 127.0.0.1 e gravam no log o aviso “Starting in local only mode. Connections will only be possible from clients running on this machine.”. Nesse caso o ESP32 não consegue se conectar e você recebe o erro rc=-2. Por outro lado, nunca abra a porta 1883 para a internet no seu roteador (nada de redirecionamento de portas): o tráfego MQTT sem criptografia pode ser lido no caminho, e os relés da sua casa podem acabar nas mãos de outra pessoa. Se precisar de acesso de fora, use uma VPN ou as opções de acesso remoto do Home Assistant.

Antes de passar para o ESP32, teste o broker pelo computador; separar logo de cara os problemas do broker dos problemas do código economiza muito tempo. Em um terminal, comece a ouvir todos os tópicos da casa com mosquitto_sub -h 192.168.1.10 -u esp32 -P suasenha -t "ev/#" -v. Em um segundo terminal, digite mosquitto_pub -h 192.168.1.10 -u esp32 -P suasenha -t ev/salon/test -m ola. Se a linha “ev/salon/test ola” aparecer no primeiro terminal, o broker está funcionando e a senha está certa. A opção -v mostra o tópico na frente de cada mensagem, e a opção -r envia a mensagem como retida (retain).

Se você não curte linha de comando, o programa gratuito MQTT Explorer mostra todos os tópicos do broker em forma de árvore, com os últimos valores e as marcações de retain. Dentro do Home Assistant, você também pode ir em Configurações > Dispositivos e serviços > MQTT > Configurar, digitar ev/# no campo “Ouvir um tópico” e começar a ouvir, e usar a seção “Publicar um pacote” para enviar comandos ao ESP32 manualmente.

Lista de componentes e esquema de ligação

Para este projeto você precisa de uma placa de desenvolvimento ESP32, um sensor de temperatura e umidade DHT22, um módulo relé que possa ser acionado com 3,3 V, uma protoboard e jumpers. O DHT22 é mais preciso que o DHT11: mede a temperatura com ±0,5 °C e a umidade com cerca de ±2–5% e funciona de -40 a 80 °C; falamos dessa família de sensores em detalhes em Sensor de temperatura e umidade DHT11. Se você tem um DHT11, basta trocar DHT22 por DHT11 no código. Para o primeiro teste de conexão, um ESP32 e um cabo USB bastam; o sensor e o relé podem ser adicionados depois.

ESP32
ESP32
DHT22
DHT22
Módulo relé
Módulo relé
ConexãoESP32ESP8266 (NodeMCU)Raspberry Pi Pico W
DHT22 VCC3V33V33V3(OUT)
DHT22 DATAGPIO 4D2 (GPIO 4)GP15
DHT22 GNDGNDGNDGND
Relé VCCVIN (5V)VIN (5V)VBUS (5V)
Relé INGPIO 26D1 (GPIO 5)GP14
Relé GNDGNDGNDGND
Os pinos do ESP32, do ESP8266 e do Pico trabalham com 3,3 V e não toleram 5 V, por isso alimentamos o DHT22 pelo pino 3V3. Os módulos DHT22 de três pinos normalmente já têm um resistor de pull-up na placa; se você estiver usando o sensor sozinho, de quatro pinos, coloque um resistor de 4,7–10 kΩ entre DATA e VCC. Se for chavear uma carga de 230 V da rede elétrica com o relé, faça toda a ligação com o plugue fora da tomada e peça ajuda a um adulto; os detalhes estão em O que é um módulo relé?. Você pode ver todos os pinos da sua placa na ferramenta Pinagem.

Instalando o PubSubClient na Arduino IDE

  1. Se o pacote de placas do ESP32 ainda não estiver instalado na Arduino IDE, instale-o primeiro; os passos estão em O que é o ESP32?.
  2. Abra Ferramentas > Gerenciar Bibliotecas, digite PubSubClient no campo de busca e instale a biblioteca de Nick O'Leary. O código deste guia foi compilado com a versão 2.8.
  3. Na mesma janela, busque por DHT sensor library e instale a biblioteca da Adafruit; quando ela perguntar sobre as dependências, escolha Instalar tudo para que a Adafruit Unified Sensor também seja instalada.
  4. Se tiver problemas para instalar bibliotecas, veja o guia Como instalar uma biblioteca no Arduino.

Primeiro teste: conectando o ESP32 ao broker MQTT

Antes de adicionar os sensores, vamos confirmar com o código mais simples possível que os dados do Wi-Fi, o endereço do broker e a senha estão certos. O código abaixo se conecta ao broker, publica “merhaba” (olá) no tópico “test/esp32/durum” e mostra no Monitor Serial toda mensagem que chega em “test/esp32/komut”. Troque o nome e a senha do Wi-Fi, o IP do broker e o usuário MQTT pelos seus, carregue o código e abra o Monitor Serial em 115200 baud:

C++ (Arduino IDE)
1#include <WiFi.h>
2#include <PubSubClient.h>
3
4const char* WIFI_SSID = "AgAdi";              // Wi-Fi adın (yalnız 2,4 GHz) / your Wi-Fi name (2.4 GHz only)
5const char* WIFI_PASS = "Sifre123";           // Wi-Fi şifren / your Wi-Fi password
6const char* MQTT_SUNUCU = "192.168.1.10";     // broker'ın IP adresi / broker IP address
7const int   MQTT_PORT = 1883;                 // şifresiz MQTT portu / unencrypted MQTT port
8const char* MQTT_KULLANICI = "esp32";         // broker kullanıcı adı / broker username
9const char* MQTT_SIFRE = "mqttSifre";         // broker şifresi / broker password
10
11WiFiClient wifiIstemci;                       // TCP bağlantısı / TCP connection
12PubSubClient mqtt(wifiIstemci);               // MQTT istemcisi / MQTT client
13
14// Abone olunan konuya mesaj gelince çalışır / runs when a subscribed topic receives a message
15void mesajGeldi(char* topic, byte* payload, unsigned int length) {
16  Serial.print("Mesaj [");
17  Serial.print(topic);
18  Serial.print("] ");
19  for (unsigned int i = 0; i < length; i++) {
20    Serial.print((char)payload[i]);           // payload sonunda \0 yoktur / payload is not null-terminated
21  }
22  Serial.println();
23}
24
25void setup() {
26  Serial.begin(115200);
27  WiFi.mode(WIFI_STA);
28  WiFi.begin(WIFI_SSID, WIFI_PASS);
29  while (WiFi.status() != WL_CONNECTED) {
30    delay(500);
31    Serial.print(".");
32  }
33  Serial.print("\nIP: ");
34  Serial.println(WiFi.localIP());
35
36  mqtt.setServer(MQTT_SUNUCU, MQTT_PORT);     // broker adresi / broker address
37  mqtt.setCallback(mesajGeldi);               // gelen mesaj fonksiyonu / incoming message handler
38}
39
40void loop() {
41  if (!mqtt.connected()) {
42    Serial.print("MQTT baglaniyor... ");
43    if (mqtt.connect("esp32-test", MQTT_KULLANICI, MQTT_SIFRE)) {   // istemci kimliği benzersiz olmalı / client ID must be unique
44      Serial.println("baglandi");
45      mqtt.subscribe("test/esp32/komut");                  // bu konuyu dinle / listen to this topic
46      mqtt.publish("test/esp32/durum", "merhaba");         // ilk mesaj / first message
47    } else {
48      Serial.print("hata, rc=");
49      Serial.println(mqtt.state());                        // hata kodu / error code
50      delay(5000);
51      return;
52    }
53  }
54  mqtt.loop();                                             // mesajları işle, bağlantıyı canlı tut / process messages, keep the connection alive
55}

Quando aparecer “baglandi” (conectado) no Monitor Serial, envie mosquitto_pub -h 192.168.1.10 -u esp32 -P suasenha -t test/esp32/komut -m oi de um terminal no seu computador; em poucos milissegundos a linha “Mesaj [test/esp32/komut] oi” aparece no Monitor Serial. Se a conexão falhar, o código mostra um código de erro com mqtt.state() e tenta de novo depois de 5 segundos. Esses códigos dizem exatamente onde está o problema:

rcNome no PubSubClientSignificado e solução
-4MQTT_CONNECTION_TIMEOUTO broker não respondeu a tempo; rede fraca ou broker sobrecarregado
-3MQTT_CONNECTION_LOSTUma conexão estabelecida caiu; normalmente porque loop() ficou muito tempo sem ser chamado ou o Wi-Fi caiu
-2MQTT_CONNECT_FAILEDA conexão TCP nem chegou a abrir: IP ou porta errados, broker desligado, Mosquitto em modo só local ou um firewall bloqueando a 1883
-1MQTT_DISCONNECTEDA conexão foi fechada normalmente (disconnect foi chamado) ou nunca chegou a conectar
2MQTT_CONNECT_BAD_CLIENT_IDO ID de cliente foi recusado; foi usado um client ID vazio ou inválido
4MQTT_CONNECT_BAD_CREDENTIALSUsuário ou senha errados (alguns brokers devolvem esse código)
5MQTT_CONNECT_UNAUTHORIZEDSem autorização; o Mosquitto devolve esse código tanto para senha errada quanto para uma tentativa de conexão sem credenciais

Publicando dados de sensor e ouvindo comandos do relé com o ESP32

Agora vamos montar o projeto de verdade. O código abaixo lê o DHT22 a cada 30 segundos e publica a temperatura e a umidade com a flag retain, controla o relé com os comandos ON, OFF e TOGGLE que chegam em “ev/salon/role/komut” e informa o novo estado do relé em “ev/salon/role/durum”. Ao se conectar, ele deixa um last will no broker, se apresenta ao Home Assistant pelo MQTT Discovery e, se a conexão cair, tenta reconectar a cada 5 segundos sem travar o loop(). Graças ao bloco #if defined(ESP8266) no início, o mesmo código também compila em uma NodeMCU sem nenhuma alteração.

C++ (Arduino IDE)
1#if defined(ESP8266)
2#include <ESP8266WiFi.h>
3#else
4#include <WiFi.h>
5#endif
6#include <PubSubClient.h>
7#include <DHT.h>
8
9// ---- Ayarlar / Settings ----
10const char* WIFI_SSID = "AgAdi";
11const char* WIFI_PASS = "Sifre123";
12const char* MQTT_SUNUCU = "192.168.1.10";        // broker IP (Home Assistant ya da Raspberry Pi) / broker IP (Home Assistant or Raspberry Pi)
13const int   MQTT_PORT = 1883;
14const char* MQTT_KULLANICI = "esp32";
15const char* MQTT_SIFRE = "mqttSifre";
16const char* ISTEMCI_ID = "esp32-salon";          // her cihazda farklı olmalı / must be different on every device
17
18#if defined(ESP8266)
19const int DHT_PIN = 4;                           // NodeMCU D2
20const int ROLE_PIN = 5;                          // NodeMCU D1
21#else
22const int DHT_PIN = 4;                           // ESP32 GPIO 4
23const int ROLE_PIN = 26;                         // ESP32 GPIO 26
24#endif
25const bool ROLE_AKTIF_LOW = true;                // çoğu röle modülü LOW ile çeker / most relay modules switch on LOW
26const unsigned long OLCUM_ARALIGI = 30000;       // 30 saniyede bir ölçüm / one reading every 30 s
27
28// ---- Konular (topic) / Topics ----
29const char* T_SICAKLIK = "ev/salon/sicaklik";
30const char* T_NEM      = "ev/salon/nem";
31const char* T_KOMUT    = "ev/salon/role/komut";  // ON, OFF ya da TOGGLE / ON, OFF or TOGGLE
32const char* T_DURUM    = "ev/salon/role/durum";
33const char* T_BAGLANTI = "ev/salon/baglanti";    // online / offline (son vasiyet / last will)
34const char* T_HA_DURUM = "homeassistant/status"; // HA açılınca "online" yayınlar / HA publishes "online" when it starts
35
36WiFiClient wifiIstemci;
37PubSubClient mqtt(wifiIstemci);
38DHT dht(DHT_PIN, DHT22);
39
40bool roleAcik = false;
41unsigned long sonOlcum = 0;
42unsigned long sonDeneme = 0;
43
44// Röleyi sür ve yeni durumu kalıcı (retain) yayınla / drive the relay and publish the new state as retained
45void roleAyarla(bool acik) {
46  roleAcik = acik;
47  bool seviye = ROLE_AKTIF_LOW ? !acik : acik;
48  digitalWrite(ROLE_PIN, seviye ? HIGH : LOW);
49  mqtt.publish(T_DURUM, acik ? "ON" : "OFF", true);
50  Serial.println(acik ? "Role: ON" : "Role: OFF");
51}
52
53// Tek bir Home Assistant keşif mesajı gönder / send one Home Assistant discovery message
54void kesifYayinla(const char* tur, const char* nesne, const char* ad, const char* ekAlanlar) {
55  char konu[96];
56  snprintf(konu, sizeof(konu), "homeassistant/%s/%s/%s/config", tur, ISTEMCI_ID, nesne);
57  char json[600];
58  snprintf(json, sizeof(json),
59           "{\"name\":\"%s\",\"unique_id\":\"%s_%s\",%s,\"availability_topic\":\"%s\","
60           "\"device\":{\"identifiers\":[\"%s\"],\"name\":\"Salon ESP32\",\"model\":\"ESP32 + DHT22\"}}",
61           ad, ISTEMCI_ID, nesne, ekAlanlar, T_BAGLANTI, ISTEMCI_ID);
62  if (!mqtt.publish(konu, json, true)) {         // false: tampon küçük ya da bağlantı yok / false: buffer too small or not connected
63    Serial.println("Kesif mesaji gonderilemedi");
64  }
65}
66
67// Sıcaklık, nem ve röleyi Home Assistant'a tanıt / announce temperature, humidity and relay to Home Assistant
68void haKesifGonder() {
69  char ek[200];
70  snprintf(ek, sizeof(ek), "\"state_topic\":\"%s\",\"device_class\":\"temperature\",\"unit_of_measurement\":\"°C\",\"state_class\":\"measurement\"", T_SICAKLIK);
71  kesifYayinla("sensor", "sicaklik", "Sıcaklık", ek);
72  snprintf(ek, sizeof(ek), "\"state_topic\":\"%s\",\"device_class\":\"humidity\",\"unit_of_measurement\":\"%%\",\"state_class\":\"measurement\"", T_NEM);
73  kesifYayinla("sensor", "nem", "Nem", ek);
74  snprintf(ek, sizeof(ek), "\"state_topic\":\"%s\",\"command_topic\":\"%s\"", T_DURUM, T_KOMUT);
75  kesifYayinla("switch", "role", "Röle", ek);
76}
77
78// DHT22'yi oku ve değerleri yayınla / read the DHT22 and publish the values
79void olcumGonder() {
80  float t = dht.readTemperature();
81  float h = dht.readHumidity();
82  if (isnan(t) || isnan(h)) {
83    Serial.println("DHT22 okunamadi");
84    return;
85  }
86  char deger[12];
87  snprintf(deger, sizeof(deger), "%.1f", t);     // 23.4 gibi / like 23.4
88  mqtt.publish(T_SICAKLIK, deger, true);
89  snprintf(deger, sizeof(deger), "%.0f", h);     // 45 gibi / like 45
90  mqtt.publish(T_NEM, deger, true);
91  Serial.printf("Sicaklik %.1f C, nem %.0f %%\n", t, h);
92}
93
94// Abone olunan konulara mesaj gelince çalışır / runs when a subscribed topic receives a message
95void mesajGeldi(char* topic, byte* payload, unsigned int length) {
96  // Önce kopyala: yayın yapınca kütüphane aynı tamponu kullanır / copy first: publishing reuses the same buffer
97  String konu = topic;
98  String mesaj;
99  for (unsigned int i = 0; i < length; i++) mesaj += (char)payload[i];
100  mesaj.trim();
101
102  if (konu == T_KOMUT) {
103    if (mesaj == "ON") roleAyarla(true);
104    else if (mesaj == "OFF") roleAyarla(false);
105    else if (mesaj == "TOGGLE") roleAyarla(!roleAcik);
106  } else if (konu == T_HA_DURUM && mesaj == "online") {
107    haKesifGonder();                             // HA yeniden başladı, tanıtımı yenile / HA restarted, announce again
108    mqtt.publish(T_DURUM, roleAcik ? "ON" : "OFF", true);
109  }
110}
111
112bool mqttBaglan() {
113  Serial.print("MQTT baglaniyor... ");
114  // Bağlantı koparsa broker T_BAGLANTI'ya "offline" yazar / if we drop, the broker publishes "offline" to T_BAGLANTI
115  if (!mqtt.connect(ISTEMCI_ID, MQTT_KULLANICI, MQTT_SIFRE, T_BAGLANTI, 1, true, "offline")) {
116    Serial.print("hata, rc=");
117    Serial.println(mqtt.state());
118    return false;
119  }
120  Serial.println("baglandi");
121  mqtt.publish(T_BAGLANTI, "online", true);
122  mqtt.subscribe(T_KOMUT, 1);                    // komutları QoS 1 ile dinle / listen to commands with QoS 1
123  mqtt.subscribe(T_HA_DURUM);
124  haKesifGonder();
125  mqtt.publish(T_DURUM, roleAcik ? "ON" : "OFF", true);
126  return true;
127}
128
129void setup() {
130  Serial.begin(115200);
131  pinMode(ROLE_PIN, OUTPUT);
132  roleAyarla(false);                             // güvenli başlangıç: röle kapalı / safe start: relay off
133  dht.begin();
134
135  WiFi.mode(WIFI_STA);
136  WiFi.begin(WIFI_SSID, WIFI_PASS);
137  Serial.print("Wi-Fi");
138  while (WiFi.status() != WL_CONNECTED) {
139    delay(500);
140    Serial.print(".");
141  }
142  Serial.print(" IP: ");
143  Serial.println(WiFi.localIP());
144
145  mqtt.setServer(MQTT_SUNUCU, MQTT_PORT);
146  mqtt.setCallback(mesajGeldi);
147  mqtt.setBufferSize(1024);                      // keşif JSON'u varsayılan 256 bayta sığmaz / discovery JSON doesn't fit the default 256 bytes
148}
149
150void loop() {
151  if (!mqtt.connected()) {
152    unsigned long simdi = millis();
153    if (sonDeneme == 0 || simdi - sonDeneme >= 5000) {   // 5 sn'de bir dene, loop'u kilitleme / retry every 5 s without blocking
154      sonDeneme = simdi;
155      if (mqttBaglan()) sonOlcum = simdi - OLCUM_ARALIGI;  // bağlanınca hemen ölç / measure right after connecting
156    }
157    return;
158  }
159  mqtt.loop();                                   // gelen komutlar ve keep-alive / incoming commands and keep-alive
160
161  if (millis() - sonOlcum >= OLCUM_ARALIGI) {
162    sonOlcum = millis();
163    olcumGonder();
164  }
165}
LinhaO que faz
mqtt.connect(ISTEMCI_ID, ..., T_BAGLANTI, 1, true, "offline") (conexão com last will)Registra o last will durante a conexão: se o ESP32 cair sem avisar, o broker grava um “offline” retido em ev/salon/baglanti
mqtt.publish(T_BAGLANTI, "online", true) (estado online)Muda o estado para “online” logo após conectar; o Home Assistant volta a mostrar o dispositivo como disponível
mqtt.subscribe(T_KOMUT, 1) (assinatura)Ouve os comandos do relé com QoS 1; o PubSubClient só suporta QoS 0 e 1 nas assinaturas
mqtt.setBufferSize(1024) (tamanho do buffer)Aumenta o buffer de pacotes dos 256 bytes padrão; o maior pacote de discovery tem cerca de 355 bytes
mqtt.loop() (ciclo do MQTT)Lê as mensagens recebidas e envia os pacotes de keep-alive (PINGREQ); precisa ser chamado a cada ciclo do loop
ROLE_AKTIF_LOW (relé ativo em LOW)A maioria dos módulos relé aciona com sinal LOW; mude para false se o seu acionar com HIGH
OLCUM_ARALIGI (intervalo de medição)Com que frequência medir; o DHT22 pode ser lido no máximo a cada 2 segundos, e 30–60 segundos é o ideal para temperatura ambiente

Alguns detalhes do código são propositais. A função mesajGeldi() copia primeiro o tópico e o payload para Strings, porque o PubSubClient usa um único buffer para as mensagens que chegam e as que saem: no momento em que você chama publish() dentro do callback, os dados para os quais os ponteiros de tópico e payload apontam são sobrescritos. O payload também não termina com \0 como uma string em C, por isso lemos exatamente length caracteres. Usamos retain nas leituras e no estado do relé para que o Home Assistant veja o último valor logo depois de reiniciar, em vez de esperar 30 segundos. A temporização também é feita com millis(): um delay() longo dentro do loop() seguraria os pacotes de keep-alive, e o broker derrubaria a conexão. Explicamos essa técnica em detalhes em Arduino: millis() em vez de delay().

Nunca envie mensagens para tópicos de comando com a flag retain. Se um “ON” retido ficar em “ev/salon/role/komut”, o ESP32 recebe esse comando antigo toda vez que reconecta depois de uma queda de energia ou do Wi-Fi e liga o relé sozinho no meio da noite. Se você enviou um comando retido por engano, apague-o publicando uma mensagem retida vazia com mosquitto_pub -r -n -t ev/salon/role/komut. Os interruptores MQTT do Home Assistant enviam comandos sem retain por padrão.

Como fica no Home Assistant: MQTT Discovery

O Home Assistant ouve o tempo todo os tópicos que começam com o prefixo homeassistant/. Quando um dispositivo publica uma configuração em JSON em um tópico no formato homeassistant/[componente]/[nó]/[objeto]/config, o Home Assistant cria essa entidade automaticamente; isso se chama MQTT Discovery. Nosso código envia três mensagens: duas para os sensores (temperatura e umidade) em homeassistant/sensor/esp32-salon/... e uma para o relé em homeassistant/switch/esp32-salon/role/config. Como elas são retidas, sobrevivem a uma reinicialização do Home Assistant. O código também assina homeassistant/status: o Home Assistant escreve “online” ali quando inicia, e o ESP32 se apresenta de novo. Se você tiver muitos dispositivos, a documentação do Home Assistant recomenda acrescentar um pequeno atraso aleatório antes dessa nova apresentação.

Campo JSONSignificadoNosso valor
nameO nome de exibição da entidade; o nome do dispositivo é colocado na frenteSıcaklık (aparece como Salon ESP32 Sıcaklık)
unique_idO ID permanente da entidade; sem ele, o nome e a área da entidade não podem ser editados pela interfaceesp32-salon_sicaklik
state_topicO tópico de onde o valor é lidoev/salon/sicaklik
command_topicO tópico para onde vão os comandos do interruptor (switch)ev/salon/role/komut (tópico de comando do relé)
device_classDefine o ícone, as opções de unidade e o tipo de gráficotemperature, humidity
unit_of_measurementUnidade de medida°C e %
state_classO valor measurement ativa estatísticas e gráficos de longo prazomeasurement
availability_topicO tópico de onde o estado online/offline é lido; os payloads padrão são online e offlineev/salon/baglanti
deviceAgrupa as entidades em um único cartão de dispositivoidentifiers, name, model (identificadores, nome, modelo)

Poucos segundos depois de carregar o código, um dispositivo chamado “Salon ESP32” aparece em Configurações > Dispositivos e serviços > MQTT. O cartão do dispositivo traz os sensores de temperatura e umidade e um interruptor para o relé; clique na temperatura para abrir o gráfico de histórico, acione o interruptor e o relé estala. Você pode adicionar essas entidades a um painel (dashboard), liberá-las para assistentes de voz ou usá-las em automações: por exemplo, uma regra como “se a sala passar de 27 °C, ligue o relé em que o ventilador está conectado, e desligue abaixo de 25 °C” sai em poucos cliques. Se você tirar o ESP32 da tomada, as entidades passam para “Indisponível” depois de no máximo uns 22 segundos, o que mostra que a mensagem de last will está funcionando. Se preferir não usar o discovery, você também pode definir as mesmas entidades à mão no configuration.yaml, como entradas sensor e switch dentro de mqtt:.

Se você mudou o nome ou os tópicos do dispositivo e ficaram entidades antigas no Home Assistant, envie uma mensagem retida vazia para o tópico config correspondente: mosquitto_pub -r -n -t homeassistant/sensor/esp32-salon/sicaklik/config. O Home Assistant apaga a entidade e também remove o dispositivo se não houver outras entidades ligadas a ele. Quando você dá a cada ESP32 um ISTEMCI_ID diferente, os valores de unique_id também ficam diferentes automaticamente, e você pode adicionar vários cômodos sem confusão.

QoS e retain: qual usar e quando?

O QoS (Quality of Service) define o quanto você quer ter certeza de que uma mensagem chega ao outro lado. Um detalhe importante: o QoS vale separadamente em dois trechos. Entre quem publica e o broker vale o QoS de quem publica, e entre o broker e um assinante vale o QoS da assinatura; a garantia que o assinante recebe é a menor das duas. O PubSubClient só suporta QoS 0 para publicar e QoS 0 e 1 para assinar. No Wi-Fi de casa, perder uma mensagem com QoS 0 é muito raro, mas deixar a assinatura dos comandos em QoS 1 ainda é um seguro barato.

QoSGarantiaComo funcionaQuando usar
0No máximo uma vezA mensagem é enviada uma vez, sem confirmação; pode se perder se a conexão cair naquele momentoLeituras de sensor frequentes
1Pelo menos uma vezO receptor confirma com PUBACK, e a mensagem é reenviada se a confirmação não chegar; pode chegar duas vezesComandos do relé, alarmes
2Exatamente uma vezUm handshake de quatro etapas com PUBREC, PUBREL e PUBCOMP; o nível mais lentoCoisas como contadores, em que duplicatas atrapalham; não suportado pelo PubSubClient

A flag retain tem a ver com memória, e não com entrega: o broker guarda só a última mensagem retida de cada tópico e a envia na hora para quem assinar. Ela é ideal para mensagens de “estado atual”, como valores de sensores, estado do relé e status online, mas perigosa para comandos e eventos pontuais. O last will (LWT) a complementa: se o broker não receber nenhum pacote de um cliente durante 1,5 vez o período de keep-alive, ele conclui que a conexão caiu e publica a mensagem de last will. O keep-alive padrão do PubSubClient é de 15 segundos, então um ESP32 desconectado da tomada aparece como “offline” depois de no máximo uns 22 segundos. Você pode mudar isso com uma linha como mqtt.setKeepAlive(30), mas quanto maior o valor, mais tarde você vai perceber uma queda.

A alternativa sem código: ESPHome

O ESPHome é uma ferramenta gratuita que transforma um dispositivo descrito em um arquivo YAML em um firmware para ESP32 pronto para gravar; você não escreve uma única linha de C++. No Home Assistant, instale o ESPHome Device Builder em Configurações > Aplicativos, abra a interface dele e crie uma configuração com o assistente Novo dispositivo. O primeiro carregamento é feito uma vez pelo USB: o Chrome ou o Edge conseguem programar a placa diretamente e, se isso não funcionar, você pode gravar o arquivo que o assistente baixa usando a página ESPHome Web. Todas as atualizações seguintes vão pelo Wi-Fi, sem fio (OTA). A configuração abaixo é igual ao projeto Arduino acima: lê o DHT22 no GPIO 4 a cada 30 segundos e expõe o relé ativo em LOW do GPIO 26 como um interruptor. Os dados do Wi-Fi e as senhas são lidos de um arquivo secrets.yaml separado com !secret:

Código
1esphome:
2  name: salon-sensor               # küçük harf, rakam ve tire / lowercase, digits and hyphens
3  friendly_name: Salon Sensör
4
5esp32:
6  board: esp32dev
7
8logger:
9
10api:                               # Home Assistant ile doğrudan bağlantı / direct link to Home Assistant
11  encryption:
12    key: !secret api_anahtari
13
14ota:
15  - platform: esphome
16    password: !secret ota_sifresi
17
18wifi:
19  ssid: !secret wifi_ssid
20  password: !secret wifi_sifresi
21  ap:                              # Wi-Fi yoksa kendi ağını açar / opens its own network if Wi-Fi fails
22    ssid: "Salon-Sensor"
23    password: "yedek1234"
24
25captive_portal:
26
27sensor:
28  - platform: dht
29    pin: GPIO4
30    model: DHT22
31    update_interval: 30s
32    temperature:
33      name: "Sıcaklık"
34    humidity:
35      name: "Nem"
36
37switch:
38  - platform: gpio
39    name: "Röle"
40    pin:
41      number: GPIO26
42      inverted: true               # aktif LOW röle / active-LOW relay
43    restore_mode: ALWAYS_OFF       # açılışta kapalı / off at boot
44
45# MQTT ile kullanmak için api: bloğunu sil, bunu aç / to use MQTT, delete api: and uncomment this
46# mqtt:
47#   broker: 192.168.1.10
48#   username: esp32
49#   password: !secret mqtt_sifresi

Há uma diferença importante: por padrão, o ESPHome não usa MQTT, e sim sua própria native API criptografada. O Home Assistant encontra o dispositivo na rede sozinho e nem precisa de broker. Escolha MQTT só se quiser que outros sistemas, como o Node-RED, leiam os mesmos dados, ou se você não usa o Home Assistant. Para isso, descomente as linhas mqtt: no fim do arquivo e apague o bloco api:; se não fizer isso, o dispositivo se reinicia sozinho sempre que ninguém se conectar à native API por 15 minutos (essa é a configuração reboot_timeout). No modo MQTT, o ESPHome envia sozinho as mensagens de discovery do Home Assistant e as mensagens online/offline em salon-sensor/status, ou seja, faz automaticamente tudo o que fizemos à mão no código Arduino.

CaracterísticaPubSubClient (código Arduino)ESPHome (YAML)
Escrever códigoVocê escreve tudo em C++Só YAML; o firmware é compilado automaticamente
Adicionar ao Home AssistantVocê mesmo envia os JSON de discoveryDescoberto automaticamente
FlexibilidadeIlimitada; dá para usar qualquer biblioteca e lógicaLimitada a componentes prontos, mas centenas de sensores são suportados; dá para adicionar C++ com lambdas
Atualizações sem fioVocê mesmo adiciona o ArduinoOTA ao códigoJá vem integrado
Precisa de brokerSimNão, com a native API
Valor de aprendizadoEnsina o protocolo MQTT e programaçãoResultado rápido, esconde o que acontece por baixo

MQTT com o ESP8266 e o Raspberry Pi Pico W

O código completo acima roda sem alterações nas placas ESP8266 NodeMCU e Wemos D1 Mini: quando você seleciona NodeMCU 1.0 em Ferramentas > Placa, o bloco #if defined(ESP8266) escolhe automaticamente ESP8266WiFi.h no lugar de WiFi.h, junto com os pinos D2 e D1. Do lado do Raspberry Pi Pico W, usamos o módulo umqtt.simple do MicroPython. Ele não vem no firmware MicroPython do Pico W; instale-o no Thonny buscando umqtt.simple em Ferramentas > Gerenciar pacotes, ou digite import mip; mip.install("umqtt.simple") no REPL com a placa conectada ao Wi-Fi. Já o módulo dht, necessário para o DHT22, vem com o firmware. O código abaixo faz um Pico W na cozinha fazer o mesmo trabalho de medição e relé. Para deixá-lo curto, deixamos de fora as mensagens de discovery; para ver o Pico W no Home Assistant, publique os mesmos JSON de discovery do código do ESP32 com os tópicos ev/mutfak, ou defina as entidades à mão dentro de mqtt: no configuration.yaml. Salve o arquivo como main.py e ele roda toda vez que a placa ligar:

MicroPython
1import network, time, dht
2from machine import Pin
3from umqtt.simple import MQTTClient    # önce mip ile kur / install with mip first
4
5WIFI_SSID = "AgAdi"                    # Wi-Fi adın / your Wi-Fi name
6WIFI_PASS = "Sifre123"                 # Wi-Fi şifren / your Wi-Fi password
7MQTT_SUNUCU = "192.168.1.10"           # broker IP / broker IP
8ISTEMCI_ID = "pico-mutfak"             # benzersiz olmalı / must be unique
9
10T_SICAKLIK = b"ev/mutfak/sicaklik"
11T_NEM = b"ev/mutfak/nem"
12T_KOMUT = b"ev/mutfak/role/komut"
13T_DURUM = b"ev/mutfak/role/durum"
14T_BAGLANTI = b"ev/mutfak/baglanti"
15
16sensor = dht.DHT22(Pin(15))            # DHT22 DATA -> GP15
17role = Pin(14, Pin.OUT, value=1)       # aktif LOW röle kapalı başlar / active-LOW relay starts off
18led = Pin("LED", Pin.OUT)              # Pico W dahili LED / Pico W onboard LED
19
20wlan = network.WLAN(network.STA_IF)
21wlan.active(True)
22wlan.connect(WIFI_SSID, WIFI_PASS)
23while not wlan.isconnected():
24    time.sleep(0.5)
25print("IP:", wlan.ifconfig()[0])
26
27def mesaj_geldi(konu, mesaj):          # ikisi de bytes gelir / both arrive as bytes
28    if konu == T_KOMUT and mesaj in (b"ON", b"OFF"):
29        acik = mesaj == b"ON"
30        role.value(0 if acik else 1)
31        led.value(1 if acik else 0)
32        istemci.publish(T_DURUM, mesaj, retain=True)
33
34istemci = MQTTClient(ISTEMCI_ID, MQTT_SUNUCU, user="esp32", password="mqttSifre", keepalive=60)   # Mosquitto kullanıcısı / Mosquitto user
35istemci.set_callback(mesaj_geldi)
36istemci.set_last_will(T_BAGLANTI, b"offline", retain=True)   # son vasiyet / last will
37
38def baglan():
39    while True:
40        try:
41            if not wlan.isconnected():         # Wi-Fi koptuysa yeniden bağlan / reconnect Wi-Fi if it dropped
42                wlan.connect(WIFI_SSID, WIFI_PASS)
43                time.sleep(5)
44            istemci.connect()
45            istemci.publish(T_BAGLANTI, b"online", retain=True)
46            istemci.publish(T_DURUM, b"OFF" if role.value() else b"ON", retain=True)
47            istemci.subscribe(T_KOMUT)
48            print("MQTT baglandi")
49            return
50        except Exception as e:         # MQTTException(5): yetki yok / not authorized
51            print("MQTT hatasi:", e)
52            time.sleep(5)
53
54baglan()
55son = time.ticks_add(time.ticks_ms(), -30000)   # ilk ölçüm hemen / first reading right away
56while True:
57    try:
58        istemci.check_msg()            # bekleyen komut var mı? / any pending command?
59        if time.ticks_diff(time.ticks_ms(), son) >= 30000:
60            son = time.ticks_ms()
61            try:
62                sensor.measure()
63            except OSError:
64                print("DHT22 okunamadi")
65                istemci.ping()         # veri yoksa da bağlantıyı canlı tut / keep the link alive without data
66            else:
67                istemci.publish(T_SICAKLIK, "{:.1f}".format(sensor.temperature()).encode(), retain=True)
68                istemci.publish(T_NEM, "{:.0f}".format(sensor.humidity()).encode(), retain=True)
69    except OSError:
70        print("Baglanti koptu, yeniden baglaniliyor")
71        time.sleep(5)
72        baglan()
73    time.sleep_ms(100)

Ideias de projetos com ESP32 e MQTT

  • Mapa de temperatura cômodo por cômodo: coloque um ESP32 com DHT22 ou BME280 em cada cômodo e acompanhe a casa inteira em um único gráfico com uma assinatura ev/+/sicaklik.
  • Lâmpada e tomada inteligentes: ligue o relé a uma automação do Home Assistant que o acende ao pôr do sol e o desliga à meia-noite.
  • Sensor de porta e janela: use uma chave reed para enviar uma mensagem MQTT quando uma porta abrir e receba uma notificação no celular quando não houver ninguém em casa.
  • Luz do corredor acionada por movimento: deixe um sensor PIR publicar o movimento e uma automação do Home Assistant acender a luz.
  • Estação de irrigação de plantas: publique o valor do sensor de umidade do solo e ligue a bomba com um comando MQTT quando o solo ficar seco.
  • Monitoramento de energia: meça a corrente que um aparelho consome com um sensor de corrente ACS712 e faça um gráfico do consumo diário.
  • Sensor alimentado por bateria: monte um nó que faz uma leitura, envia por MQTT e volta a dormir; detalhes em ESP32 Deep Sleep.

Erros comuns de MQTT no ESP32 e soluções

Sintoma ou mensagemCausaSolução
rc=-2 o tempo todoIP ou porta do broker errados, broker desligado ou Mosquitto em modo só localConfira o IP, adicione listener 1883 à configuração, libere a porta 1883 no firewall
rc=5Usuário ou senha errados, ou tentativa de conexão sem credenciaisTeste a senha pelo computador com mosquitto_sub; recrie o usuário se precisar
Conecta, cai depois de alguns segundos e fica nesse cicloDois dispositivos usam o mesmo client ID; o Mosquitto grava no log “Client esp32-salon already connected, closing old connection.”Dê a cada dispositivo um ISTEMCI_ID único
As mensagens de discovery não chegam, publish() devolve falseO buffer do PubSubClient tem 256 bytes por padrão e o JSON não cabeChame mqtt.setBufferSize(1024) no setup()
rc=-3 com frequênciaUm delay() longo dentro do loop() impede os pacotes de keep-alive, ou o sinal do Wi-Fi está fracoFaça a temporização com millis() e aproxime a placa do roteador
Os comandos nunca chegam ao ESP32O nome do tópico difere em maiúsculas/minúsculas ou na grafia, ou o subscribe() não é repetido após reconectarConfira o tópico com mosquitto_sub; coloque as linhas de subscribe() dentro da função de conexão
O relé liga sozinho ao iniciarHá uma mensagem retida antiga no tópico de comandoApague-a com mosquitto_pub -r -n -t ev/salon/role/komut
As entidades aparecem como “Indisponível” no Home AssistantO tópico de disponibilidade diz offline ou online está escrito de outro jeitoOuça ev/salon/baglanti e verifique se o código publica online depois de conectar
Caracteres estranhos no lugar do valorO payload não termina com \0 e foi lido sem usar lengthCopie o payload com um laço até length
O dispositivo ESPHome reinicia a cada 15 minutosNo modo MQTT, o bloco api: continua lá, mas o Home Assistant nunca se conectaApague o bloco api: ou adicione reboot_timeout: 0s
Siga uma ordem na hora de procurar o problema: primeiro confira a conexão Wi-Fi e o endereço IP no Monitor Serial, depois veja o que realmente chega ao broker com mosquitto_sub -v -t "#" no computador e só então olhe o Home Assistant. Se a mensagem aparece no broker, mas não no Home Assistant, o problema está no JSON de discovery; se ela nunca chega ao broker, está do lado do ESP32. Se você estiver travado na etapa do Wi-Fi, veja ESP32 não conecta ao Wi-Fi, e se a placa reiniciar quando o relé aciona, veja Brownout e Guru Meditation no ESP32.

Com um broker, alguns tópicos e o PubSubClient, o seu ESP32 virou um dispositivo de casa inteligente que fala a mesma língua que o resto da casa. Você pode adicionar novos sensores, outros cômodos e placas diferentes, como o Pico W, à mesma estrutura e gerenciar tudo em um único painel do Home Assistant. No app BlueGrays você encontra projetos como conexão Wi-Fi com ESP32, medição de temperatura e umidade com DHT22, iluminação inteligente com PIR e relé, controle em tempo real com WebSocket e irrigação inteligente de plantas, passo a passo, com esquemas do circuito e código.

Perguntas frequentes

Para que serve o MQTT?

O MQTT é um protocolo de mensagens leve em que os dispositivos enviam e recebem mensagens por meio de um broker, usando nomes de tópicos. Como consome pouca banda e pouca energia, é ideal para dispositivos pequenos como o ESP32 enviarem dados de sensores e receberem comandos. O Home Assistant, o Node-RED e a maioria dos sistemas de IoT industrial falam MQTT.

Qual porta o MQTT usa?

O MQTT sem criptografia usa a porta 1883 por padrão, e o MQTT criptografado com TLS usa a porta 8883. A porta WebSocket, usada para conexões pelo navegador, depende do broker; no broker Mosquitto do Home Assistant ela é a 1884. Em uma rede doméstica, o ESP32 normalmente se conecta à 1883.

O MQTT precisa de conexão com a internet?

Não. Se o broker roda em um Raspberry Pi ou no Home Assistant em casa, o tráfego entre o ESP32 e o broker fica todo na sua rede local; sensores e relés continuam funcionando mesmo se a internet cair. Você só precisa de internet para acessar o sistema de fora de casa ou para usar um broker na nuvem.

Por que meu ESP32 não aparece no Home Assistant?

As causas mais comuns são uma mensagem de discovery que não cabe no buffer de 256 bytes do PubSubClient, um tópico config escrito errado ou um erro de aspas no JSON. Ouça homeassistant/# com mosquitto_sub para ver se a mensagem chega ao broker e confirme que o código tem a linha mqtt.setBufferSize(1024). A integração MQTT do Home Assistant também precisa estar conectada ao mesmo broker.

Devo usar ESPHome ou MQTT com Arduino?

Se o seu objetivo é colocar rapidamente um dispositivo de casa inteligente para funcionar, o ESPHome dá menos trabalho: você escreve YAML, o dispositivo aparece sozinho no Home Assistant e se atualiza sem fio. Se você quer aprender o protocolo MQTT, escrever sua própria lógica ou trabalhar com sistemas além do Home Assistant, Arduino com PubSubClient é mais flexível. Os dois convivem sem problemas na mesma casa.

Qual é a diferença entre QoS 0, 1 e 2 no MQTT?

O QoS 0 envia a mensagem uma vez sem esperar confirmação, o QoS 1 reenvia até receber a confirmação, mas a mensagem pode chegar duas vezes, e o QoS 2 usa um handshake de quatro etapas para garantir que ela chegue exatamente uma vez. O QoS 0 basta para leituras de sensores, e o QoS 1 para comandos. O PubSubClient só consegue publicar com QoS 0 e assinar com QoS 0 ou 1.

Ver todos os projetos
LED piscando com ESP32
#103Iniciante

LED piscando com ESP32

Ensina o uso básico de uma saída GPIO no ESP32. Fazemos um LED piscar ligando e desligando um pino digital. É a versão para ESP32 do clássico projeto blink do Arduino UNO: os comandos básicos de blink no ambiente Arduino são os mesmos, mas a disposição dos pinos e os níveis de 3,3 V dos GPIOs do ESP32 diferem dos do Arduino UNO.

4.7(37)
99
Conexão Wi-Fi STA com ESP32 e display LCD
#127Avançado

Conexão Wi-Fi STA com ESP32 e display LCD

Neste projeto, conectamos o ESP32 à rede Wi-Fi de casa no modo estação (STA), de forma segura e tolerante a falhas. Guardamos o SSID e a senha em um arquivo secrets.h separado para evitar que sejam expostos no Git, configuramos um mecanismo de reconexão automática e exibimos o nível de sinal RSSI e o endereço IP em um display LCD I2C. O LED integrado funciona como indicador de status. É um gerenciador de conexão pronto para uso em produção.

4.4(21)
34
Temperatura e umidade com ESP32 e DHT22 (com display LCD)
#117Intermediário

Temperatura e umidade com ESP32 e DHT22 (com display LCD)

Este projeto mede a temperatura e a umidade do ambiente com um sensor DHT22 e exibe os dados em tempo real em um LCD I2C 16x2. Os dados são lidos do sensor pelo protocolo de um fio (one-wire) com a biblioteca Adafruit DHT. Este projeto serve de base para estações meteorológicas IoT, automação residencial ou sistemas de monitoramento ambiental em estufas. A comunicação com o DHT22 é feita pelo pino GPIO 4 do ESP32.

4.8(38)
56
Iluminação inteligente com ESP32 (PIR + LDR + relé + OLED)
#141Avançado
Premium

Iluminação inteligente com ESP32 (PIR + LDR + relé + OLED)

Transforme a iluminação do corredor, banheiro ou despensa em iluminação inteligente com ESP32! Com um sensor de movimento PIR, um sensor de luz LDR e um módulo relé, montamos o cenário clássico de "acender a luz ao detectar movimento no escuro" — se o ambiente já estiver claro, o movimento NÃO aciona a luz, economizando energia durante o dia. A luz fica acesa por 30 segundos; se o movimento continuar, o temporizador reinicia e a luz permanece acesa por mais tempo.

4.3(6)
11
Contador WebSocket com ESP32 (2 botões + LCD + web em tempo real)
#130Avançado
Premium

Contador WebSocket com ESP32 (2 botões + LCD + web em tempo real)

Neste projeto, dois botões conectados ao ESP32 (GPIO 5 aumenta, GPIO 4 diminui) alteram um contador. O valor é atualizado instantaneamente no LCD I2C 16x2 e, com o suporte a WebSocket do ESPAsyncWebServer, em todos os navegadores conectados, sem recarregar a página. Em vez de consultas periódicas por HTTP, usamos uma única conexão persistente, e o ESP32 envia o novo valor a todos com ws.textAll().

4.5(14)
23
ESP32 mDNS: acesso via bluegrays-esp.local (com display LCD)
#131Avançado
Premium

ESP32 mDNS: acesso via bluegrays-esp.local (com display LCD)

Neste projeto, adicionamos o serviço mDNS (Multicast DNS) ao ESP32 para acessar o dispositivo por um nome de host fácil de ler, como bluegrays-esp.local, em vez de um endereço IP. Mesmo que o IP atribuído pelo DHCP mude, você pode acessar o dispositivo pelo mesmo nome. Também executamos um pequeno servidor web no dispositivo para enviar comandos de controle do LED pelo navegador no endereço http://bluegrays-esp.local/.

4.8(14)
23
Alarme de movimento com ESP32 (PIR + buzzer + LED + Telegram)
#145Avançado
Premium

Alarme de movimento com ESP32 (PIR + buzzer + LED + Telegram)

Um sistema de alarme de segurança inteligente que aciona o buzzer e o LED quando o sensor PIR detecta movimento e, ao mesmo tempo, envia uma notificação instantânea ao proprietário pelo Telegram. Inclui um intervalo de espera de 30 segundos para limitar a frequência dos alarmes repetidos; esse mecanismo não valida as detecções do PIR nem elimina disparos falsos. Pode ser usado na segurança de casas, no monitoramento de garagens, depósitos ou salas de trabalho.

0.0(0)
9