Guías · 18 min de lectura

ESP32 MQTT: tutorial con Mosquitto, Home Assistant y ESPHome

Tutorial ESP32 MQTT: instala Mosquitto, publica datos de sensores y controla un relé con PubSubClient, descubrimiento en Home Assistant, YAML de ESPHome y QoS.

La combinación ESP32 y MQTT es la forma más habitual de que los sensores y relés de tu casa hablen entre sí y con un sistema domótico como Home Assistant. MQTT es un protocolo de mensajería ligero pensado para dispositivos pequeños: el ESP32 deja la temperatura que ha medido en un topic como "ev/salon/sicaklik" y cualquier programa que escuche ese topic recibe el valor al instante. Del mismo modo, cuando pulsas un botón en la app de Home Assistant del móvil, el comando "ON" llega al ESP32 en mucho menos de un segundo y activa el relé. A diferencia de HTTP, no abre una conexión nueva en cada petición; funciona sobre una única conexión abierta con cabeceras de solo dos bytes, así que es rápido y apenas carga el Wi-Fi y el procesador.

En esta guía vas a montar desde cero un nodo domótico que funciona. Primero aprenderás los conceptos de MQTT broker, topic, publish y subscribe, y después instalarás el broker Mosquitto en Home Assistant o en una Raspberry Pi. Luego usarás la librería PubSubClient para publicar desde el ESP32 la temperatura y la humedad de un DHT22, escuchar comandos para un relé y añadir MQTT Discovery para que el dispositivo aparezca solo en Home Assistant. También veremos QoS y retain, el mensaje de última voluntad (LWT) que marca el dispositivo como "no disponible" cuando se corta la conexión, la alternativa ESPHome que hace lo mismo sin escribir C++, las diferencias con el ESP8266 y la Raspberry Pi Pico W, y los errores más comunes uno por uno.

Placa de desarrollo ESP32 conectada a Home Assistant por MQTT
Gracias a su Wi-Fi integrado, el ESP32 se conecta directamente al broker MQTT de tu red doméstica; los datos de los sensores y los comandos del relé viajan por la misma conexión.

¿Qué es MQTT y cómo funciona?

MQTT (Message Queuing Telemetry Transport) funciona con un modelo de publicación/suscripción. En el centro hay un servidor llamado broker; el ESP32, Home Assistant, tu móvil o un programa del ordenador se conectan a él como clientes. Los clientes no se conocen ni saben las direcciones IP de los demás: uno publica un mensaje en un topic y el broker lo reenvía a todos los que están suscritos a ese topic. Piénsalo como una oficina de correos: el ESP32 echa una carta en el buzón "ev/salon/sicaklik" y Home Assistant, que vigila ese buzón, la recibe al momento. Como siempre es el cliente quien abre la conexión, el ESP32 no necesita una IP fija ni abrir puertos en el router; solo tiene que conocer la dirección del broker.

ConceptoPara qué sirveEjemplo
BrokerServidor que recibe los mensajes y los reparte entre los suscriptoresMosquitto, el broker Mosquitto de Home Assistant
ClienteCualquier dispositivo o programa que se conecta al broker; cada uno tiene un identificador único (client ID)ESP32, Home Assistant, MQTT Explorer
Topic (tema)Dirección del mensaje, formada por niveles separados por barrasev/salon/sicaklik
Publish (publicar)Enviar un mensaje a un topicMandar el valor "23.4" a ev/salon/sicaklik
Subscribe (suscribirse)Registrarse para recibir los mensajes de un topicEl ESP32 escuchando ev/salon/role/komut
Payload (carga útil)Contenido del mensaje: texto, número o JSONON, 23.4, {"sicaklik":23.4}
RetainEl broker guarda el último mensaje de un topic y se lo entrega enseguida a los nuevos suscriptoresEstado del relé: ON
LWT (última voluntad)Mensaje que el broker publica en nombre de un cliente si este se desconecta sin avisarev/salon/baglanti: offline
QoSNivel de garantía de entrega del mensaje (0, 1 o 2)QoS 1 para los comandos del relé

¿Por qué MQTT? Comparación con servidor web, Blynk y Telegram

MétodoVentajasInconvenientesIdeal para
MQTT + Home AssistantLocal y rápido, bidireccional; cientos de dispositivos en un panel, automatizacionesHay que tener un brokerGestionar toda la casa desde un solo sitio
Servidor web en el ESP32Sin servidor extra, se abre en el navegadorCada dispositivo tiene su propia página, sin automatizaciones entre ellosPanel de control de un solo dispositivo
Blynk IoTPanel para el móvil ya hecho, acceso por internetDepende de la nube, límites en el plan gratuitoPrototipos móviles rápidos
Bot de TelegramNotificaciones gratis al instante, sin abrir puertosSin gráficas ni panelAlarmas y comandos sencillos
ESP-NOWLas placas ESP se comunican sin router ni brokerSolo entre placas ESP, no llega directamente a Home AssistantLlevar datos de un sensor a pilas hasta una pasarela

En resumen, MQTT brilla cuantos más dispositivos tienes: al añadir un sensor nuevo no tocas ningún código existente, simplemente empiezas a publicar en un topic nuevo. Si quieres controlar un único dispositivo desde el navegador, la guía ESP32 Async Web Server y WebSocket te lleva antes al resultado; para notificaciones en el móvil tienes Bot de Telegram con ESP32 y para un panel móvil ya hecho, Blynk con ESP32. Para un sensor del jardín fuera del alcance del router, una buena solución es llevar los datos con ESP-NOW a un ESP32 pasarela conectado a MQTT.

Estructura de los topics MQTT y comodines

Los topics se parecen a rutas de carpetas: "ev/salon/sicaklik" (en turco, casa/salón/temperatura) tiene tres niveles y distingue mayúsculas de minúsculas, así que "Ev/Salon" y "ev/salon" son dos topics distintos. No empieces con una barra ("/ev/salon" crea un primer nivel vacío) y evita espacios, tildes y la ñ; bastan letras simples, números, guiones y guiones bajos. Al suscribirte puedes usar dos comodines: + sustituye exactamente un nivel ("ev/+/sicaklik" devuelve la temperatura de todas las habitaciones) y # abarca todo lo que viene detrás y solo puede ir al final ("ev/#" devuelve todos los mensajes de la casa). Los comodines solo valen al suscribirse; un mensaje siempre se publica en un topic concreto. Los topics que empiezan por $ (como $SYS) están reservados para las estadísticas del propio broker y una suscripción a # no los incluye. Para el proyecto de esta guía usaremos esta estructura:

TopicLo publicaLo escuchaRetain
ev/salon/sicaklikESP32 (cada 30 segundos)Home AssistantSí
ev/salon/nemESP32 (cada 30 segundos)Home AssistantSí
ev/salon/role/komutHome Assistant, móvil, automatizacionesESP32No
ev/salon/role/durumESP32 (en cada cambio)Home AssistantSí
ev/salon/baglantiESP32 (online), broker (offline)Home AssistantSí
homeassistant/statusHome Assistant (online al arrancar)ESP32No

Instalar un broker MQTT: Mosquitto

El broker MQTT gratuito más popular es Eclipse Mosquitto; incluso en una Raspberry Pi maneja sin esfuerzo cientos de mensajes por segundo. Hay tres formas sencillas de instalarlo: la aplicación oficial Mosquitto broker si usas Home Assistant OS, el paquete apt en una Raspberry Pi u ordenador Linux aparte, o el instalador de Mosquitto en Windows. Elijas la que elijas, el broker usa el puerto 1883 para MQTT sin cifrar y el 8883 para MQTT cifrado con TLS, y basta con que esté en la misma red doméstica que el ESP32. En Home Assistant, la instalación es así:

  1. En Home Assistant abre Ajustes > Aplicaciones (en versiones anteriores esta sección se llama Complementos o Add-ons), pulsa Instalar aplicación y elige Mosquitto broker en la lista.
  2. Pulsa Instalar; cuando termine, pulsa Iniciar y deja activada la opción de arrancar al inicio.
  3. Crea un usuario propio para el ESP32: en Ajustes > Personas > Usuarios, añade un usuario llamado "esp32" con una contraseña segura. Si no ves esa pestaña, activa el modo avanzado en tu perfil. Los nombres "homeassistant" y "addons" están reservados para el broker, no los uses.
  4. En la página Ajustes > Dispositivos y servicios, la integración MQTT suele aparecer sola como "Descubierto"; pulsa Configurar y confirma. Si no aparece, busca MQTT con Añadir integración y elige la opción que configura Mosquitto automáticamente.
  5. En el código del ESP32 pondrás como dirección del broker la IP de Home Assistant (por ejemplo 192.168.1.10), como puerto 1883 y el usuario que acabas de crear.

En una máquina Linux como una Raspberry Pi o Ubuntu bastan unos pocos comandos. Instala el broker y las herramientas de prueba con sudo apt install mosquitto mosquitto-clients. Crea el usuario "esp32" con sudo mosquitto_passwd -c /etc/mosquitto/passwd esp32 y escribe la contraseña dos veces; la opción -c crea el archivo desde cero, así que no la pongas al añadir un segundo usuario o se borrarán los anteriores. Después crea un archivo llamado local.conf en la carpeta /etc/mosquitto/conf.d/, escribe en él las tres líneas de abajo y reinicia el servicio con sudo systemctl restart mosquitto. En Windows basta con añadir las mismas líneas al archivo mosquitto.conf de la carpeta de instalación y reiniciar el servicio Mosquitto Broker.

LíneaSignificado
listener 1883Escucha en el puerto 1883 en todas las interfaces de red; sin esta línea, Mosquitto 2.x solo acepta conexiones desde el mismo ordenador
allow_anonymous falseRechaza las conexiones sin usuario y contraseña; en la versión 2.x ya es el valor por defecto, pero escribirlo es un buen hábito
password_file /etc/mosquitto/passwdUsa el archivo de contraseñas que creaste con mosquitto_passwd; las contraseñas se guardan en él como hash
Si la configuración no define ningún listener, Mosquitto 2.0 y posteriores solo escuchan en 127.0.0.1 y escriben en el registro el aviso "Starting in local only mode. Connections will only be possible from clients running on this machine.". En ese caso el ESP32 no puede conectarse y obtienes el error rc=-2. Por otro lado, nunca abras el puerto 1883 a internet en tu router (sin redirección de puertos): el tráfico MQTT sin cifrar se puede leer por el camino y los relés de tu casa podrían acabar en manos ajenas. Si necesitas acceso desde fuera, usa una VPN o las opciones de acceso remoto de Home Assistant.

Antes de pasar al ESP32, prueba el broker desde el ordenador; separar desde el principio los problemas del broker de los del código te ahorra mucho tiempo. En un terminal, empieza a escuchar todos los topics de la casa con mosquitto_sub -h 192.168.1.10 -u esp32 -P tucontrasena -t "ev/#" -v. En un segundo terminal escribe mosquitto_pub -h 192.168.1.10 -u esp32 -P tucontrasena -t ev/salon/test -m hola. Si en el primer terminal aparece la línea "ev/salon/test hola", el broker funciona y la contraseña es correcta. La opción -v muestra el topic delante de cada mensaje y la opción -r envía el mensaje como retenido.

Si no te gusta la línea de comandos, el programa gratuito MQTT Explorer muestra todos los topics del broker en forma de árbol, con los últimos valores y las marcas de retain. Dentro de Home Assistant también puedes ir a Ajustes > Dispositivos y servicios > MQTT > Configurar, escribir ev/# en el campo "Escuchar un tema" y empezar a escuchar, y usar la sección "Publicar un paquete" para mandar comandos al ESP32 a mano.

Materiales y esquema de conexión

Para el proyecto necesitas una placa de desarrollo ESP32, un sensor de temperatura y humedad DHT22, un módulo de relé que se pueda activar con 3,3 V, una protoboard y cables jumper. El DHT22 es más preciso que el DHT11: mide la temperatura con ±0,5 °C y la humedad con aproximadamente ±2–5 %, y funciona entre -40 y 80 °C; explicamos la familia de sensores en detalle en Sensor de temperatura y humedad DHT11. Si tienes un DHT11, solo cambia DHT22 por DHT11 en el código. Para la primera prueba de conexión basta con un ESP32 y un cable USB; el sensor y el relé puedes añadirlos después.

ESP32
ESP32
DHT22
DHT22
Módulo de relé
Módulo de relé
ConexiónESP32ESP8266 (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
Los pines del ESP32, el ESP8266 y la Pico trabajan a 3,3 V y no toleran 5 V; por eso alimentamos el DHT22 desde el pin 3V3. Los módulos DHT22 de tres pines suelen llevar ya una resistencia pull-up en la placa; si usas el sensor suelto de cuatro patas, pon una resistencia de 4,7–10 kΩ entre DATA y VCC. Si vas a conmutar una carga de red de 230 V con el relé, haz todas las conexiones con el enchufe desconectado y pide ayuda a un adulto; tienes los detalles en ¿Qué es un módulo relé?. Puedes ver todos los pines de tu placa en la herramienta Pinout.

Instalar PubSubClient en el Arduino IDE

  1. Si todavía no tienes instalado el paquete de placas ESP32 en el Arduino IDE, instálalo primero; los pasos están en ¿Qué es el ESP32?.
  2. Abre Herramientas > Administrar bibliotecas, escribe PubSubClient en el buscador e instala la librería de Nick O'Leary. El código de esta guía se compiló con la versión 2.8.
  3. En la misma ventana busca DHT sensor library e instala la librería de Adafruit; cuando te pregunte por las dependencias, elige Install all para instalar también Adafruit Unified Sensor.
  4. Si tienes problemas al instalar librerías, consulta la guía Cómo añadir librerías en Arduino.

Primera prueba: conectar el ESP32 al broker MQTT

Antes de añadir sensores, vamos a comprobar con el código más sencillo posible que los datos del Wi-Fi, la dirección del broker y la contraseña son correctos. El siguiente código se conecta al broker, publica "merhaba" (hola) en el topic "test/esp32/durum" y muestra en el Monitor Serie cada mensaje que llega a "test/esp32/komut". Cambia el nombre del Wi-Fi, la contraseña, la IP del broker y el usuario MQTT por los tuyos, sube el código y abre el Monitor Serie a 115200 baudios:

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}

Cuando veas "baglandi" (conectado) en el Monitor Serie, envía desde un terminal de tu ordenador mosquitto_pub -h 192.168.1.10 -u esp32 -P tucontrasena -t test/esp32/komut -m hola; en pocos milisegundos aparecerá en el Monitor Serie la línea "Mesaj [test/esp32/komut] hola". Si la conexión falla, el código muestra un código de error con mqtt.state() y vuelve a intentarlo a los 5 segundos. Estos códigos te dicen exactamente dónde está el problema:

rcNombre en PubSubClientSignificado y solución
-4MQTT_CONNECTION_TIMEOUTEl broker no respondió a tiempo; red débil o broker sobrecargado
-3MQTT_CONNECTION_LOSTUna conexión establecida se cayó; normalmente porque loop() no se llamó durante mucho tiempo o se perdió el Wi-Fi
-2MQTT_CONNECT_FAILEDLa conexión TCP nunca se abrió: IP o puerto incorrectos, broker apagado, Mosquitto en modo solo local o un cortafuegos bloqueando el 1883
-1MQTT_DISCONNECTEDLa conexión se cerró de forma ordenada (se llamó a disconnect) o nunca llegó a conectarse
2MQTT_CONNECT_BAD_CLIENT_IDSe rechazó el identificador de cliente; se usó un client ID vacío o no válido
4MQTT_CONNECT_BAD_CREDENTIALSUsuario o contraseña incorrectos (algunos brokers devuelven este código)
5MQTT_CONNECT_UNAUTHORIZEDSin autorización; Mosquitto devuelve este código tanto con una contraseña errónea como al intentar conectar sin credenciales

Publicar datos de sensores y escuchar comandos del relé con el ESP32

Ahora montamos el proyecto de verdad. El siguiente código lee el DHT22 cada 30 segundos y publica la temperatura y la humedad con la bandera retain, controla el relé con los comandos ON, OFF y TOGGLE que llegan a "ev/salon/role/komut" e informa del nuevo estado del relé en "ev/salon/role/durum". Al conectarse deja una última voluntad en el broker, se presenta a Home Assistant mediante MQTT Discovery y, si se corta la conexión, reintenta cada 5 segundos sin bloquear loop(). Gracias al bloque #if defined(ESP8266) del principio, el mismo código también compila en un NodeMCU sin ningún cambio.

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}
LíneaQué hace
mqtt.connect(ISTEMCI_ID, ..., T_BAGLANTI, 1, true, "offline")Registra la última voluntad al conectarse: si el ESP32 se cae sin avisar, el broker escribe un "offline" retenido en ev/salon/baglanti
mqtt.publish(T_BAGLANTI, "online", true)Pone el estado en "online" nada más conectarse; Home Assistant vuelve a mostrar el dispositivo como disponible
mqtt.subscribe(T_KOMUT, 1)Escucha los comandos del relé con QoS 1; PubSubClient solo admite QoS 0 y 1 en las suscripciones
mqtt.setBufferSize(1024)Amplía el búfer de paquetes desde los 256 bytes por defecto; el mayor paquete de descubrimiento ocupa unos 355 bytes
mqtt.loop()Lee los mensajes entrantes y envía los paquetes keep-alive (PINGREQ); hay que llamarlo en cada vuelta de loop
ROLE_AKTIF_LOWLa mayoría de los módulos de relé se activan con LOW; si el tuyo se activa con HIGH, ponlo en false
OLCUM_ARALIGICada cuánto se mide; el DHT22 se puede leer como mucho cada 2 segundos y para la temperatura ambiente lo ideal son 30–60 segundos

Algunos detalles del código son intencionados. La función mesajGeldi() copia primero el topic y el payload en Strings, porque PubSubClient usa un único búfer para los mensajes entrantes y salientes: en cuanto llamas a publish() dentro del callback, se sobrescriben los datos a los que apuntan topic y payload. Además, el payload no termina en \0 como una cadena de C, así que leemos exactamente length caracteres. Usamos retain en las lecturas y en el estado del relé para que Home Assistant vea el último valor nada más reiniciarse, sin esperar 30 segundos. Los tiempos se controlan también con millis(): un delay() largo dentro de loop() retrasaría los paquetes keep-alive y el broker cortaría la conexión. Explicamos esta técnica en detalle en Arduino millis() frente a delay().

Nunca envíes mensajes a los topics de comandos con la bandera retain. Si en "ev/salon/role/komut" se queda un "ON" retenido, el ESP32 recibirá ese comando viejo cada vez que se reconecte tras un corte de luz o de Wi-Fi y encenderá el relé solo en mitad de la noche. Si enviaste un comando retenido por error, bórralo publicando un mensaje retenido vacío con mosquitto_pub -r -n -t ev/salon/role/komut. Los interruptores MQTT de Home Assistant envían los comandos sin retain por defecto.

Cómo se ve en Home Assistant: MQTT Discovery

Home Assistant escucha constantemente los topics que empiezan por el prefijo homeassistant/. Cuando un dispositivo publica una configuración JSON en un topic con la forma homeassistant/[componente]/[nodo]/[objeto]/config, Home Assistant crea esa entidad automáticamente; a esto se le llama MQTT Discovery. Nuestro código envía tres mensajes: dos para los sensores (temperatura y humedad) en homeassistant/sensor/esp32-salon/... y uno para el relé en homeassistant/switch/esp32-salon/role/config. Como son retenidos, sobreviven a un reinicio de Home Assistant. El código también está suscrito a homeassistant/status: Home Assistant escribe ahí "online" al arrancar y el ESP32 vuelve a presentarse. Si tienes muchos dispositivos, la documentación de Home Assistant recomienda añadir un pequeño retardo aleatorio antes de esa nueva presentación.

Campo JSONSignificadoNuestro valor
nameNombre visible de la entidad; delante se añade el nombre del dispositivoSıcaklık (aparece como Salon ESP32 Sıcaklık)
unique_idIdentificador permanente de la entidad; sin él no se pueden editar su nombre ni su área desde la interfazesp32-salon_sicaklik
state_topicTopic del que se lee el valorev/salon/sicaklik
command_topicTopic al que se envían los comandos del interruptor (switch)ev/salon/role/komut
device_classDefine el icono, las unidades disponibles y el tipo de gráficatemperature, humidity
unit_of_measurementUnidad de medida°C y %
state_classEl valor measurement activa las estadísticas a largo plazo y las gráficasmeasurement
availability_topicTopic del que se lee el estado online/offline; los payloads por defecto son online y offlineev/salon/baglanti
deviceAgrupa las entidades en una sola tarjeta de dispositivoidentifiers, name, model

Unos segundos después de subir el código aparece un dispositivo llamado "Salon ESP32" en Ajustes > Dispositivos y servicios > MQTT. Su tarjeta incluye los sensores de temperatura y humedad y un interruptor para el relé; si pulsas la temperatura se abre su historial y si accionas el interruptor el relé se activa. Puedes añadir estas entidades a un panel, exponerlas a asistentes de voz o usarlas en automatizaciones: por ejemplo, una regla como "si el salón supera los 27 °C, enciende el relé del ventilador y apágalo por debajo de 25 °C" se crea en unos pocos clics. Si desenchufas el ESP32, las entidades pasan a "No disponible" como mucho unos 22 segundos después, lo que demuestra que la última voluntad funciona. Si prefieres no usar el descubrimiento, también puedes definir las mismas entidades a mano en configuration.yaml, como sensor y switch bajo mqtt:.

Si cambiaste el nombre o los topics del dispositivo y en Home Assistant se quedan entidades antiguas, envía un mensaje retenido vacío al topic config correspondiente: mosquitto_pub -r -n -t homeassistant/sensor/esp32-salon/sicaklik/config. Home Assistant borra la entidad y, si el dispositivo se queda sin entidades, también lo elimina. Al dar a cada ESP32 un ISTEMCI_ID distinto, los unique_id también cambian automáticamente y puedes añadir varias habitaciones sin líos.

QoS y retain: cuál usar y cuándo

QoS (Quality of Service) define lo seguro que quieres estar de que un mensaje llega al otro lado. Un detalle importante: el QoS se aplica por separado en dos tramos. Entre quien publica y el broker vale el QoS de la publicación, y entre el broker y el suscriptor, el de la suscripción; la garantía que recibe el suscriptor es la menor de las dos. PubSubClient solo admite QoS 0 al publicar y QoS 0 y 1 en las suscripciones. En el Wi-Fi de casa es muy raro perder un mensaje con QoS 0, pero poner la suscripción de comandos en QoS 1 es un seguro barato.

QoSGarantíaCómo funcionaCuándo usarlo
0Como mucho una vezEl mensaje se envía una vez sin confirmación; puede perderse si la conexión se corta justo entoncesLecturas frecuentes de sensores
1Al menos una vezEl receptor confirma con PUBACK y, si no llega la confirmación, se reenvía; puede llegar dos vecesComandos del relé, alarmas
2Exactamente una vezNegociación en cuatro pasos con PUBREC, PUBREL y PUBCOMP; el nivel más lentoContadores y casos en los que los duplicados hacen daño; PubSubClient no lo admite

La bandera retain no tiene que ver con la entrega sino con la memoria: el broker guarda solo el último mensaje retenido de cada topic y se lo envía al momento a quien se suscriba. Es ideal para mensajes de "estado actual" como los valores de los sensores, el estado del relé o la conexión, pero peligrosa para comandos y eventos puntuales. La última voluntad (LWT) la complementa: si el broker no recibe ningún paquete del cliente durante 1,5 veces el periodo de keep-alive, da la conexión por perdida y publica el mensaje de última voluntad. El keep-alive por defecto de PubSubClient es de 15 segundos, así que un ESP32 desenchufado aparece como "offline" como mucho unos 22 segundos después. Puedes cambiarlo con una línea como mqtt.setKeepAlive(30), pero cuanto más largo, más tarde notarás una desconexión.

La alternativa sin código: ESPHome

ESPHome es una herramienta gratuita que convierte un dispositivo descrito en un archivo YAML en un firmware listo para el ESP32; no escribes ni una línea de C++. En Home Assistant instala ESPHome Device Builder desde Ajustes > Aplicaciones, abre su interfaz y crea una configuración con el asistente Nuevo dispositivo. La primera carga se hace una sola vez por USB: Chrome o Edge pueden programar la placa directamente y, si no funciona, puedes grabar el archivo que descarga el asistente con la página ESPHome Web. Todas las actualizaciones posteriores van por Wi-Fi (OTA). La siguiente configuración equivale al proyecto de Arduino anterior: lee el DHT22 del GPIO 4 cada 30 segundos y ofrece el relé activo a nivel bajo del GPIO 26 como interruptor. Los datos del Wi-Fi y las contraseñas se leen con !secret de un archivo secrets.yaml aparte:

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

Hay una diferencia que debes tener en cuenta: por defecto ESPHome no usa MQTT, sino su propia API nativa cifrada. Home Assistant encuentra el dispositivo solo en la red y no necesita ningún broker. Elige MQTT únicamente si quieres que otros sistemas, como Node-RED, lean los mismos datos o si no usas Home Assistant. Para ello, descomenta las líneas mqtt: del final del archivo y borra el bloque api:; si no lo borras, el dispositivo se reinicia cada vez que pasan 15 minutos sin que nadie se conecte a la API nativa (es el ajuste reboot_timeout). En modo MQTT, ESPHome envía por sí mismo los mensajes de descubrimiento de Home Assistant y los mensajes online/offline en salon-sensor/status, es decir, hace automáticamente todo lo que hicimos a mano en el código de Arduino.

CaracterísticaPubSubClient (código Arduino)ESPHome (YAML)
ProgramaciónEscribes todo tú en C++Solo YAML; el firmware se compila automáticamente
Integración en Home AssistantEnvías tú los JSON de descubrimientoSe detecta automáticamente
FlexibilidadIlimitada; puedes usar cualquier librería y lógicaLimitada a componentes ya hechos, aunque admite cientos de sensores; se puede añadir C++ con lambdas
Actualización inalámbricaTienes que añadir ArduinoOTA túViene incluida
Necesita brokerSíNo con la API nativa
Valor didácticoEnseña el protocolo MQTT y a programarResultados rápidos, oculta lo que pasa por debajo

MQTT con el ESP8266 y la Raspberry Pi Pico W

El código completo de arriba funciona sin cambios en las placas ESP8266 NodeMCU y Wemos D1 Mini: al elegir NodeMCU 1.0 en Herramientas > Placa, el bloque #if defined(ESP8266) selecciona automáticamente ESP8266WiFi.h en lugar de WiFi.h y los pines D2 y D1. En la Raspberry Pi Pico W usamos el módulo umqtt.simple de MicroPython. No viene incluido en el firmware MicroPython de la Pico W; instálalo en Thonny buscando umqtt.simple en Herramientas > Gestionar paquetes, o escribe import mip; mip.install("umqtt.simple") en la REPL con el Wi-Fi conectado. El módulo dht que necesita el DHT22, en cambio, sí viene con el firmware. El siguiente código hace que una Pico W en la cocina haga el mismo trabajo de medición y relé. Para que sea corto no incluye los mensajes de descubrimiento; para ver la Pico W en Home Assistant, publica los mismos JSON de descubrimiento que en el código del ESP32 con los topics ev/mutfak, o define las entidades a mano bajo mqtt: en configuration.yaml. Guarda el archivo como main.py y se ejecutará cada vez que la placa se encienda:

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)

Ideas de proyectos con ESP32 y MQTT

  • Mapa de temperatura por habitaciones: Pon en cada habitación un ESP32 con un DHT22 o un BME280 y sigue toda la casa en una sola gráfica con una suscripción a ev/+/sicaklik.
  • Lámpara y enchufe inteligentes: Conecta el relé a una automatización de Home Assistant que lo encienda al anochecer y lo apague a medianoche.
  • Sensor de puertas y ventanas: Con un interruptor reed, envía un mensaje MQTT al abrirse la puerta y recibe un aviso en el móvil cuando no haya nadie en casa.
  • Luz de pasillo con movimiento: Deja que un sensor PIR publique el movimiento y que una automatización de Home Assistant encienda la luz.
  • Estación de riego: Publica el valor del sensor de humedad del suelo y activa la bomba con un comando MQTT cuando la tierra esté seca.
  • Monitor de consumo: Mide la corriente de un aparato con un sensor de corriente ACS712 y representa su consumo diario.
  • Sensor a pilas: Monta un nodo que mida, envíe el dato por MQTT y vuelva a dormir; los detalles están en ESP32 Deep Sleep.

Errores comunes de ESP32 y MQTT y cómo solucionarlos

Síntoma o mensajeCausaSolución
rc=-2 todo el ratoIP o puerto del broker incorrectos, broker apagado o Mosquitto en modo solo localRevisa la IP, añade listener 1883 a la configuración y permite el puerto 1883 en el cortafuegos
rc=5Usuario o contraseña incorrectos, o intento de conexión sin credencialesPrueba la contraseña desde el ordenador con mosquitto_sub; si hace falta, vuelve a crear el usuario
Se conecta, se cae a los pocos segundos y vuelve a empezarDos dispositivos usan el mismo client ID; Mosquitto registra "Client esp32-salon already connected, closing old connection."Da a cada dispositivo un ISTEMCI_ID único
No llegan los mensajes de descubrimiento, publish() devuelve falseEl búfer de PubSubClient es de 256 bytes por defecto y el JSON no cabeLlama a mqtt.setBufferSize(1024) en setup()
rc=-3 frecuenteUn delay() largo dentro de loop() impide enviar los keep-alive, o la señal Wi-Fi es débilControla los tiempos con millis() y acerca la placa al router
Los comandos no llegan al ESP32El nombre del topic no coincide en mayúsculas o en la escritura, o subscribe() no se repite al reconectarComprueba el topic con mosquitto_sub; pon las líneas subscribe() dentro de la función de conexión
El relé se enciende solo al arrancarHay un mensaje retenido antiguo en el topic de comandosBórralo con mosquitto_pub -r -n -t ev/salon/role/komut
Entidades "No disponible" en Home AssistantEl topic de disponibilidad dice offline u online está escrito de otra formaEscucha ev/salon/baglanti y asegúrate de que el código publica online al conectarse
Caracteres extraños en lugar del valorEl payload no termina en \0 y se leyó sin usar lengthCopia el payload con un bucle hasta length
El dispositivo ESPHome se reinicia cada 15 minutosEn modo MQTT sigue el bloque api:, pero Home Assistant nunca se conectaBorra el bloque api: o añade reboot_timeout: 0s
Sigue un orden al buscar el fallo: primero comprueba en el Monitor Serie la conexión Wi-Fi y la dirección IP, luego mira en el ordenador con mosquitto_sub -v -t "#" qué llega de verdad al broker y, solo después, revisa Home Assistant. Si el mensaje aparece en el broker pero no en Home Assistant, el problema está en el JSON de descubrimiento; si ni siquiera llega al broker, está en el ESP32. Si te atascas en el Wi-Fi, consulta El ESP32 no se conecta al Wi-Fi, y si la placa se reinicia al activar el relé, ESP32 Brownout y Guru Meditation.

Con un broker, unos cuantos topics y PubSubClient, tu ESP32 se ha convertido en un dispositivo domótico que habla el mismo idioma que el resto de la casa. Puedes añadir sensores nuevos, otras habitaciones y placas distintas como la Pico W, y gestionarlo todo desde un único panel de Home Assistant. En la app BlueGrays encontrarás proyectos como la conexión Wi-Fi del ESP32, la medición de temperatura y humedad con el DHT22, la iluminación inteligente con PIR y relé, el control en tiempo real con WebSocket y el riego inteligente de plantas, paso a paso con esquemas de circuito y código.

Preguntas frecuentes

¿Qué es MQTT y para qué sirve?

MQTT es un protocolo de mensajería ligero en el que los dispositivos envían y reciben mensajes a través de un broker usando nombres de topic. Como consume poco ancho de banda y poca energía, es ideal para que dispositivos pequeños como el ESP32 envíen datos de sensores y reciban comandos. Home Assistant, Node-RED y la mayoría de los sistemas IoT industriales hablan MQTT.

¿Qué puerto usa MQTT?

MQTT sin cifrar usa por defecto el puerto 1883 y MQTT cifrado con TLS, el 8883. El puerto WebSocket para conexiones desde el navegador depende del broker; en el broker Mosquitto de Home Assistant es el 1884. En una red doméstica el ESP32 suele conectarse al 1883.

¿MQTT necesita conexión a internet?

No. Si el broker funciona en casa, en una Raspberry Pi o en Home Assistant, el tráfico entre el ESP32 y el broker se queda por completo en tu red local; los sensores y relés siguen funcionando aunque se caiga internet. Solo necesitas internet para acceder desde fuera o para usar un broker en la nube.

¿Por qué mi ESP32 no aparece en Home Assistant?

Las causas más habituales son un mensaje de descubrimiento que no cabe en el búfer de 256 bytes de PubSubClient, un topic config mal escrito o un error de comillas en el JSON. Escucha homeassistant/# con mosquitto_sub para comprobar si el mensaje llega al broker y asegúrate de que el código incluye la línea mqtt.setBufferSize(1024). Además, la integración MQTT de Home Assistant debe estar conectada al mismo broker.

¿Uso ESPHome o MQTT con Arduino?

Si tu objetivo es tener rápido un dispositivo domótico que funcione, ESPHome da menos trabajo: escribes YAML, el dispositivo aparece solo en Home Assistant y se actualiza por Wi-Fi. Si quieres aprender el protocolo MQTT, escribir tu propia lógica o trabajar con sistemas distintos de Home Assistant, Arduino con PubSubClient es más flexible. Ambos conviven sin problemas en la misma casa.

¿Qué diferencia hay entre MQTT QoS 0, 1 y 2?

QoS 0 envía el mensaje una vez sin esperar confirmación, QoS 1 lo reenvía hasta que se confirma aunque puede llegar dos veces, y QoS 2 garantiza con una negociación de cuatro pasos que llegue exactamente una vez. Para lecturas de sensores basta QoS 0 y para comandos, QoS 1. PubSubClient solo puede publicar con QoS 0 y suscribirse con QoS 0 o 1.

Ver todos los proyectos
LED Parpadeante con ESP32
#103Principiante

LED Parpadeante con ESP32

Enseña el uso básico de la salida GPIO con ESP32. Conseguimos un efecto de parpadeo encendiendo y apagando un LED desde el pin digital. Versión para ESP32 del clásico proyecto blink en Arduino UNO; los comandos básicos de blink en el entorno Arduino son los mismos, pero la distribución de pines y los niveles GPIO de 3,3 V del ESP32 difieren de los del Arduino UNO.

4.7(37)
99
Conexión Wi-Fi STA con ESP32 (con pantalla LCD)
#127Avanzado

Conexión Wi-Fi STA con ESP32 (con pantalla LCD)

En este proyecto, conectamos el ESP32 a la red Wi-Fi doméstica en modo Station (STA) de forma segura y tolerante a fallos. Separamos el SSID y la contraseña en el archivo secrets.h para evitar que se filtren a Git, configuramos un mecanismo de reconexión automática y mostramos el nivel de señal RSSI y la dirección IP en una pantalla LCD I2C. El LED interno actúa como indicador de estado.

4.4(21)
34
ESP32 DHT22 Temperatura y humedad (con pantalla LCD)
#117Intermedio

ESP32 DHT22 Temperatura y humedad (con pantalla LCD)

Se trata de un proyecto que mide la temperatura y la humedad ambientales mediante el sensor DHT22 y las muestra en tiempo real en una pantalla LCD I2C 16x2. Los datos del sensor se leen mediante el protocolo de un solo cable (one-wire) utilizando la biblioteca DHT de Adafruit. Este proyecto constituye la base para estaciones meteorológicas IoT, sistemas de automatización doméstica inteligente o sistemas de monitorización ambiental en invernaderos.

4.8(38)
56
Iluminación Inteligente ESP32 (PIR + LDR + Relé + OLED)
#141Avanzado
Premium

Iluminación Inteligente ESP32 (PIR + LDR + Relé + OLED)

¡Convierte tu pasillo, baño o despensa en iluminación inteligente con ESP32! Utilizando un sensor de movimiento PIR, un sensor de luz LDR y un módulo de relé, construimos el escenario clásico "la luz se enciende cuando se detecta movimiento en la oscuridad" — si el ambiente ya está iluminado, el movimiento NO activa la luz, ahorrando energía durante el día. La luz permanece encendida durante 30 segundos; si el movimiento continúa, el temporizador se reinicia y la luz permanece encendida más tiem

4.3(6)
11
Contador ESP32 WebSocket (2 botones + pantalla LCD + web en tiempo real)
#130Avanzado
Premium

Contador ESP32 WebSocket (2 botones + pantalla LCD + web en tiempo real)

En este proyecto, dos botones conectados al ESP32 (GPIO 5 suma, GPIO 4 resta) cambian un contador. El valor se actualiza al instante en una pantalla LCD I2C de 16x2 y, gracias al soporte WebSocket de ESPAsyncWebServer, en todos los navegadores conectados sin recargar la página. En lugar del sondeo HTTP se usa una única conexión persistente y el ESP32 envía el nuevo valor a todos con ws.textAll().

4.5(14)
23
ESP32 mDNS: Acceso al dispositivo mediante bluegrays-esp.local (con pantalla LCD)
#131Avanzado
Premium

ESP32 mDNS: Acceso al dispositivo mediante bluegrays-esp.local (con pantalla LCD)

En este proyecto, al añadir el servicio mDNS (Multicast DNS) al ESP32, permitimos el acceso mediante un nombre de host legible, como bluegrays-esp.local, en lugar de una dirección IP. Aunque la IP asignada por el DHCP cambie, siempre podrás acceder al dispositivo con el mismo nombre. Además, al ejecutar un pequeño servidor web en él, enviamos comandos de control de los LED desde el navegador mediante la dirección http://bluegrays-esp.local/. En la pantalla LCD I2C se muestran el nombre de ho

4.8(14)
23
Sistema de Alarma de Movimiento ESP32 (PIR + Buzzer + LED + Telegram)
#145Avanzado
Premium

Sistema de Alarma de Movimiento ESP32 (PIR + Buzzer + LED + Telegram)

Un sistema inteligente de alarma de seguridad que activa el buzzer y el LED cuando el sensor PIR detecta movimiento, y envía simultáneamente una notificación instantánea al propietario vía Telegram. Cuenta con un tiempo de espera de 30 segundos para limitar la frecuencia de las alarmas repetidas; este mecanismo no comprueba la validez de las detecciones del sensor PIR ni elimina las falsas detecciones. Ideal para seguridad del hogar, vigilancia de garajes, almacenes o salas de trabajo. Con ESP32

0.0(0)
9