Guías · 15 min de lectura

Bot de Telegram con ESP32: alertas y control de LED y relé

Crea un bot de Telegram con ESP32: token con BotFather, chat ID, UniversalTelegramBot, alertas de movimiento y gas, relé por comando y respuesta solo a tu ID.

Un bot de Telegram con ESP32 permite que la placa ESP32 de tu casa te envíe mensajes al móvil y ejecute las órdenes que tú le mandes. Cuando hay movimiento en la puerta o se detecta gas en la cocina, te llega una notificación al instante; escribes "/ac" y un relé enciende la lámpara, escribes "/kapat" y la apaga. No necesitas programar tu propia app, abrir puertos en el router ni pagar un servicio en la nube: basta con la Bot API gratuita de Telegram y el Wi-Fi integrado del ESP32.

En esta guía montarás desde cero un sistema que funciona: crearás un bot con BotFather y obtendrás su token, averiguarás tu chat ID, instalarás las librerías UniversalTelegramBot y ArduinoJson y enviarás tu primer mensaje desde el ESP32. Después añadirás alertas de movimiento y gas con un sensor PIR y un sensor de gas MQ-2, y el control de un LED y un relé con comandos de Telegram. También veremos cómo hacer que el bot responda solo a tu ID, cómo funciona el ajuste del certificado, qué cambia en el ESP8266 y en la Raspberry Pi Pico W y cuáles son los errores más habituales.

Placa de desarrollo ESP32 funcionando como bot de Telegram
Gracias a su Wi-Fi integrado, el ESP32 se conecta directamente al servidor de Telegram; no hace falta ningún módulo ni pasarela extra.

¿Qué es un bot de Telegram con ESP32 y cómo funciona?

En Telegram, un bot es una cuenta especial que maneja un programa en lugar de una persona; en nuestro proyecto ese programa lo ejecuta el ESP32. El ESP32 y tu móvil nunca se conectan directamente: los dos hablan con el servidor de Telegram. Cuando le escribes "/ac" al bot desde el móvil, el mensaje espera en el servidor. Cada segundo, el ESP32 envía una petición HTTPS cifrada (getUpdates) a api.telegram.org preguntando "¿hay mensajes nuevos para mí?", recoge el mensaje y lo ejecuta. Para enviar una alerta hace una petición sendMessage en sentido contrario. Como siempre es el ESP32 quien abre la conexión, no necesitas redirigir puertos ni tener IP fija: la placa funciona en cualquier red Wi-Fi de 2,4 GHz con salida a internet.

Concepto¿Para qué sirve?Ejemplo
BotFatherEl bot de Telegram para crear y gestionar bots/newbot, /setcommands, /revoke
Token del botLa contraseña del bot; tu código se conecta a Telegram con ella1234567890:AAE... (número, dos puntos, cadena larga)
Chat IDEl número de la persona o grupo que recibe el mensajePersona: 123456789, grupo: -1001234567890
getUpdatesDescarga del servidor los mensajes nuevos enviados al botbot.getUpdates(...)
sendMessageEnvía un mensaje al chat ID indicadobot.sendMessage(CHAT_ID, "Hola")
ComandoMensaje corto que empieza por / y que el bot entiende/ac, /kapat, /durum

¿Por qué Telegram? Comparación con otras formas de recibir avisos

MétodoVentajasInconvenientesIdeal para
Bot de TelegramGratis, avisos al instante, comandos en ambos sentidos, sin abrir puertosSin gráficas ni panel ya hechoAlarmas y control remoto sencillo
Blynk IoTBotones, indicadores y gráficas listos para usarLímites de mensajes y dispositivos en el plan gratuitoPaneles de monitorización de sensores
Correo electrónico (SMTP)Funciona en cualquier móvil, admite informes largosCon retraso, difícil recibir comandosInformes diarios
SMS (SIM800L)No necesita Wi-Fi ni internetCoste de la SIM y de los SMS, módulo extraCasas de campo o almacenes sin internet
Servidor web en el ESP32Totalmente local y gratuitoNormalmente solo accesible desde la misma red, sin avisosPanel de control dentro de casa

En resumen, Telegram es la opción más fácil y barata para proyectos del tipo "avísame cuando pase algo y haz esto cuando te mande un comando". Si quieres ver los datos de los sensores en gráficas, te encajará mejor la guía de Blynk con ESP32; si necesitas avisos desde un lugar sin Wi-Fi, échale un vistazo a la guía del módulo GSM SIM800L.

Paso 1: crear el bot con BotFather y obtener el token

  1. Abre Telegram en el móvil o el ordenador, escribe BotFather en el buscador y elige la cuenta oficial, la que tiene la marca azul de verificación junto al nombre. Ojo con las cuentas falsas de nombre parecido.
  2. Pulsa Iniciar (Start) y envía el comando /newbot.
  3. BotFather te pide primero el nombre visible del bot; escribe el que quieras, por ejemplo "Alarma Casa".
  4. Después te pide un nombre de usuario. Debe ser único, usar solo letras latinas, números y guiones bajos, y terminar en bot, por ejemplo alarma_casa_bot. Si ya está cogido, añade un número al final y prueba otra vez.
  5. BotFather responde con "Done! Congratulations on your new bot.", el enlace a tu bot y su token. El token tiene la forma 1234567890:AAE...: un número, dos puntos y una cadena larga de caracteres. Cópialo entero y guárdalo en un lugar seguro.
  6. Toca el enlace que te envió BotFather para abrir tu bot y pulsa Iniciar. Este paso es obligatorio: en Telegram los bots no pueden enviar el primer mensaje a un usuario, así que siempre tienes que empezar tú la conversación.
El token es la llave de tu bot: quien lo tenga puede leer los mensajes que recibe tu bot, escribir en su nombre y llevarse los comandos destinados a tu ESP32 antes que él. No compartas nunca código con el token en foros, capturas de pantalla ni repositorios públicos de GitHub. Si crees que se ha filtrado, anula el antiguo con el comando /revoke de BotFather, obtén un token nuevo y vuelve a cargar tu código.

Paso 2: ¿cómo saber tu chat ID de Telegram?

El token del bot responde a "¿qué bot?", y el chat ID a "¿quién recibe el mensaje?". Cada usuario, grupo y canal de Telegram tiene un identificador numérico fijo, que no es lo mismo que tu nombre de usuario con @. Hay tres formas sencillas de averiguar tu propio chat ID:

  1. Con un bot de identificación: busca en Telegram un bot como @userinfobot y pulsa Iniciar; te envía tu número en la línea Id. Estos bots no son tuyos, solo te muestran tu ID.
  2. Con el navegador: primero envía cualquier mensaje a tu propio bot. Luego abre api.telegram.org/botTOKEN/getUpdates en el navegador del ordenador (pega tu token en lugar de TOKEN y deja la palabra "bot" delante). En el texto que aparece, el número de "chat":{"id":123456789 es tu chat ID. Si la página muestra una lista result vacía, vuelve a escribir al bot y recarga la página.
  3. Con el ESP32: cuando cargues el código de comandos de más abajo, el ID de cualquier persona no autorizada se imprime en el Monitor Serie con la línea "unauthorized ID". Si quieres añadir a un familiar, pídele que escriba al bot y lee allí su número.
Si vas a usar el bot en un grupo familiar, añádelo al grupo, escribe un mensaje allí y vuelve a mirar la página de getUpdates: los ID de grupo empiezan con un signo menos, y los de supergrupo con -100. Olvidar el signo menos es la causa más frecuente del error "chat not found". En el modo de privacidad por defecto, el bot no lee la conversación del grupo; solo ve los comandos que empiezan por / dirigidos a él, y para un bot de comandos eso basta.

Paso 3: instalar UniversalTelegramBot y ArduinoJson

  1. Si todavía no tienes 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 UniversalTelegramBot en el buscador e instala la librería de Brian Lough. Los códigos de esta guía se han compilado con UniversalTelegramBot 1.3.0, ArduinoJson 7 y la versión 2.0.11 del paquete de placas ESP32.
  3. Si el instalador te pregunta por las dependencias, elige Install all; si no te pregunta, busca ArduinoJson en la misma ventana e instala aparte la librería de Benoit Blanchon.
  4. En Archivo > Ejemplos > UniversalTelegramBot > ESP32 encontrarás ejemplos listos como FlashLED; los códigos de esta guía son versiones simplificadas de ellos con seguridad añadida.

UniversalTelegramBot está escrita con la sintaxis de la versión 6 de ArduinoJson, pero compila sin problemas con ArduinoJson 7. Si has activado los avisos del compilador en el Arduino IDE verás líneas como "'DynamicJsonDocument' is deprecated: use JsonDocument instead"; son advertencias, no errores, y el programa funciona con normalidad. Si tienes problemas para instalar librerías, consulta la guía Cómo añadir una librería en Arduino.

Materiales y esquema de conexión

Para el proyecto completo necesitas una placa de desarrollo ESP32, un sensor de movimiento PIR HC-SR501, un módulo sensor de gas MQ-2, un módulo de relé de 5 V, una resistencia de 10 kΩ y otra de 20 kΩ, una protoboard y cables jumper. Como LED usaremos el LED azul integrado del ESP32 en el GPIO 2. Para probar los dos primeros pasos solo necesitas el ESP32 y un cable USB; los sensores puedes añadirlos después.

ESP32
ESP32
PIR HC-SR501
PIR HC-SR501
MQ-2
MQ-2
Módulo de relé
Módulo de relé
ConexiónESP32ESP8266 (NodeMCU)Raspberry Pi Pico W
PIR VCCVIN (5V)VIN (5V)VBUS (5V)
PIR OUTGPIO 27D5 (GPIO 14)GP16
MQ-2 VCCVIN (5V)VIN (5V)VBUS (5V)
MQ-2 AO (con divisor de 10 kΩ / 20 kΩ)GPIO 34A0GP26 (ADC0)
Relé VCCVIN (5V)VIN (5V)VBUS (5V)
Relé INGPIO 26D1 (GPIO 5)GP15
LEDGPIO 2 (integrado)D4 (integrado, se enciende con LOW)"LED" (integrado)
Todas las GNDGNDGNDGND
Los pines del ESP32, el ESP8266 y la Pico trabajan a 3,3 V. Cuando el módulo MQ-2 se alimenta a 5 V, su salida AO puede llegar a 5 V, así que monta un Divisor de tensión: conecta AO al pin analógico a través de 10 kΩ y el pin analógico a GND a través de 20 kΩ. Así los 5 V bajan a unos 3,3 V. Si vas a conmutar una carga de red de 230 V con el relé, haz siempre las conexiones con el enchufe desconectado y pide ayuda a un adulto; tienes los detalles en ¿Qué es un módulo de relé?.

Cuida también la alimentación: solo el calentador del MQ-2 consume unos 150 mA y la bobina del relé unos 70 mA, mientras que el ESP32 puede llegar brevemente a 250 mA cuando transmite por Wi-Fi. El puerto USB del ordenador no siempre da para todo eso, y la placa puede reiniciarse justo al enviar un mensaje. Usa un adaptador de 5 V de al menos 1 A y un buen cable; si el problema sigue, lee ESP32 Brownout y Guru Meditation. Puedes ver todos los pines de tu placa en la herramienta Pinout.

Primera prueba: enviar un mensaje del ESP32 a Telegram

Antes de pasar a los sensores, comprobemos el token y el chat ID con el código más sencillo posible. En el código de abajo, cambia el nombre de la red Wi-Fi, la contraseña y las líneas BOT_TOKEN y CHAT_ID por tus datos y cárgalo en la placa. Después abre el Monitor Serie a 115200 baudios:

C++ (Arduino IDE)
1#include <WiFi.h>
2#include <WiFiClientSecure.h>
3#include <UniversalTelegramBot.h>
4#include <ArduinoJson.h>
5
6const char* WIFI_SSID = "AgAdi";          // Wi-Fi adın (yalnız 2,4 GHz) / your Wi-Fi name (2.4 GHz only)
7const char* WIFI_PASS = "Sifre123";       // Wi-Fi şifren / your Wi-Fi password
8#define BOT_TOKEN "1234567890:AAExxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"   // BotFather'ın verdiği token / token from BotFather
9#define CHAT_ID   "123456789"             // kendi Telegram ID'n / your own Telegram ID
10
11WiFiClientSecure client;                  // şifreli (HTTPS) bağlantı / encrypted (HTTPS) connection
12UniversalTelegramBot bot(BOT_TOKEN, client);
13
14void setup() {
15  Serial.begin(115200);
16  WiFi.mode(WIFI_STA);
17  WiFi.begin(WIFI_SSID, WIFI_PASS);
18  Serial.print("Wi-Fi'ye baglaniyor / connecting to Wi-Fi");
19  while (WiFi.status() != WL_CONNECTED) {
20    delay(500);
21    Serial.print(".");
22  }
23  Serial.println();
24  Serial.println(WiFi.localIP());
25
26  client.setCACert(TELEGRAM_CERTIFICATE_ROOT);   // api.telegram.org kök sertifikası / root certificate of api.telegram.org
27
28  if (bot.sendMessage(CHAT_ID, "Merhaba! ESP32 çevrimiçi / Hello! ESP32 is online")) {
29    Serial.println("Mesaj gonderildi / message sent");
30  } else {
31    Serial.println("Mesaj gonderilemedi / message failed");
32  }
33}
34
35void loop() {
36}

En unos segundos tu bot debería enviarte "Hello! ESP32 is online" por Telegram y el Monitor Serie debería mostrar "Mesaj gonderildi / message sent". sendMessage() devuelve true cuando el mensaje se entrega; si ves "message failed", el problema está en la conexión Wi-Fi, el token, el chat ID o el ajuste del certificado. Antes de culpar al código, abre api.telegram.org/botTOKEN/getMe en el navegador: con un token válido verás "ok":true y el nombre de tu bot; con uno incorrecto, "Unauthorized".

Ajuste del certificado: ¿setCACert o setInsecure?

Telegram solo acepta HTTPS, por eso el código usa WiFiClientSecure en lugar de un WiFiClient normal. En una conexión cifrada, el ESP32 debe asegurarse de que el servidor con el que habla es de verdad api.telegram.org; lo hace comprobando el certificado del servidor con el certificado raíz que está en lo alto de la cadena. UniversalTelegramBot incluye ese certificado raíz listo para usar con el nombre TELEGRAM_CERTIFICATE_ROOT. La cadena de certificados de Telegram llega hasta Go Daddy Root Certificate Authority - G2, válido hasta finales de 2037; si algún día Telegram cambia de proveedor de certificados, habrá que actualizar también la librería.

AjusteQué haceSeguridadCuándo usarlo
client.setCACert(TELEGRAM_CERTIFICATE_ROOT)Cifra la conexión y verifica la identidad del servidorAltaSiempre; es el ajuste recomendado
client.setInsecure()Cifra la conexión pero no comprueba quién es el servidorMedia: no detecta un servidor falso intermedioPrueba rápida para descartar problemas de certificado
Ninguno de los dosCon los núcleos ESP32 actuales la conexión no llega a establecerseNo funcionaNunca: no sale ningún mensaje y tampoco aparece error en el Monitor Serie
ESP8266: setTrustAnchors(&cert)El equivalente en el ESP8266; el certificado se pasa como X509ListAltaNodeMCU y Wemos D1 Mini; necesita la hora correcta

Controlar un LED y un relé con comandos de Telegram (/ac, /kapat)

Ahora hagamos el bot bidireccional. El código de abajo pregunta a Telegram una vez por segundo si hay mensajes nuevos; si el texto es /ac ("encender" en turco) enciende el relé y el LED, /kapat ("apagar") los apaga, /durum ("estado") informa del estado actual y /start envía la lista de comandos. Puedes renombrarlos como /encender y /apagar, pero ten en cuenta que los comandos de Telegram solo admiten letras latinas minúsculas, números y guiones bajos, con un máximo de 32 caracteres. Un comando con tilde o eñe, como "/apagar_baño", no se reconoce como comando pulsable.

C++ (Arduino IDE)
1#include <WiFi.h>
2#include <WiFiClientSecure.h>
3#include <UniversalTelegramBot.h>
4#include <ArduinoJson.h>
5
6const char* WIFI_SSID = "AgAdi";
7const char* WIFI_PASS = "Sifre123";
8#define BOT_TOKEN "1234567890:AAExxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
9#define CHAT_ID   "123456789"                 // yalnız bu ID'ye yanıt verilir / only this ID gets answers
10
11const int LED_PIN  = 2;                       // çoğu DevKit'te dahili LED / onboard LED on most DevKits
12const int ROLE_PIN = 26;                      // röle modülünün IN pini / relay module IN pin
13const bool ROLE_AKTIF_LOW = true;             // çoğu modül LOW'da çeker / most modules switch on with LOW
14
15const unsigned long KONTROL_ARALIGI = 1000;   // Telegram'a saniyede bir sor / ask Telegram once per second
16unsigned long sonKontrol = 0;
17bool roleAcik = false;
18
19WiFiClientSecure client;
20UniversalTelegramBot bot(BOT_TOKEN, client);
21
22void roleYaz(bool acik) {
23  roleAcik = acik;
24  if (ROLE_AKTIF_LOW) digitalWrite(ROLE_PIN, acik ? LOW : HIGH);
25  else                digitalWrite(ROLE_PIN, acik ? HIGH : LOW);
26  digitalWrite(LED_PIN, acik ? HIGH : LOW);   // LED röle durumunu gösterir / LED mirrors the relay
27}
28
29void mesajlariIsle(int adet) {
30  for (int i = 0; i < adet; i++) {
31    String chatId = bot.messages[i].chat_id;
32    String metin  = bot.messages[i].text;
33
34    // Güvenlik: tanımadığın kişiye cevap verme / security: never answer strangers
35    if (chatId != CHAT_ID) {
36      Serial.println("Yetkisiz ID / unauthorized ID: " + chatId);
37      continue;
38    }
39
40    int at = metin.indexOf('@');              // gruptaki "/ac@bot_adi" -> "/ac" / "/ac@bot_name" in groups -> "/ac"
41    if (at > 0) metin = metin.substring(0, at);
42
43    if (metin == "/start") {
44      String yardim = "Merhaba " + bot.messages[i].from_name + "!\n";
45      yardim += "/ac - röleyi aç / relay ON\n";
46      yardim += "/kapat - röleyi kapat / relay OFF\n";
47      yardim += "/durum - son durum / status";
48      bot.sendMessage(chatId, yardim);
49    } else if (metin == "/ac") {
50      roleYaz(true);
51      bot.sendMessage(chatId, "Röle AÇIK / relay ON");
52    } else if (metin == "/kapat") {
53      roleYaz(false);
54      bot.sendMessage(chatId, "Röle KAPALI / relay OFF");
55    } else if (metin == "/durum") {
56      bot.sendMessage(chatId, roleAcik ? "Röle AÇIK / relay ON" : "Röle KAPALI / relay OFF");
57    } else {
58      bot.sendMessage(chatId, "Bilinmeyen komut, /start yaz / unknown command, send /start");
59    }
60  }
61}
62
63void setup() {
64  Serial.begin(115200);
65  pinMode(LED_PIN, OUTPUT);
66  pinMode(ROLE_PIN, OUTPUT);
67  roleYaz(false);                             // açılışta röle kapalı / relay off at boot
68
69  WiFi.mode(WIFI_STA);
70  WiFi.begin(WIFI_SSID, WIFI_PASS);
71  while (WiFi.status() != WL_CONNECTED) delay(500);
72  Serial.println(WiFi.localIP());
73
74  client.setCACert(TELEGRAM_CERTIFICATE_ROOT);
75  bot.sendMessage(CHAT_ID, "Bot hazır, /start yaz / bot ready, send /start");
76}
77
78void loop() {
79  if (millis() - sonKontrol > KONTROL_ARALIGI) {
80    int adet = bot.getUpdates(bot.last_message_received + 1);   // yeni mesaj var mı? / any new messages?
81    while (adet) {
82      mesajlariIsle(adet);
83      adet = bot.getUpdates(bot.last_message_received + 1);
84    }
85    sonKontrol = millis();
86  }
87}
LíneaFunción
bot.getUpdates(bot.last_message_received + 1)Pide los mensajes posteriores al último procesado y devuelve cuántos han llegado; el +1 evita que vuelva el mismo mensaje
bot.messages[i].chat_idEl ID del chat del que viene el mensaje; la respuesta va allí y el control de seguridad lo usa
bot.messages[i].textEl texto recibido; con él comparamos el comando
metin.indexOf('@')Corta la parte @nombre_bot que Telegram añade a los comandos en los grupos
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
KONTROL_ARALIGICada cuánto se consulta; 1000 ms responde rápido, 3000–5000 ms carga menos la red

Seguridad: que el bot solo responda a tu ID

En Telegram, los nombres de usuario de los bots son públicos y se pueden buscar. Si alguien adivina alarma_casa_bot o lo ve en una captura y le escribe /ac, un ESP32 sin control también obedecerá esa orden. Por eso la línea más importante del código es la comprobación chatId != CHAT_ID. Tu chat ID no tiene por qué ser secreto; la protección viene de que el propio Telegram verifica quién envía cada mensaje y nadie puede suplantar el ID de otra persona. No contestar a desconocidos también es una decisión consciente: mientras el bot calla, nadie sabe siquiera que está funcionando.

  • Usa una lista blanca: guarda los ID autorizados en un array, ignora todos los demás mensajes y añade a los familiares uno a uno.
  • En grupos, comprueba la persona: en un grupo el chat ID es el del grupo; si solo ciertas personas deben dar órdenes, compara from_id en lugar de chat_id.
  • Guarda el token en un archivo aparte: pon el token y la contraseña del Wi-Fi en un archivo como secrets.h y déjalo fuera cuando compartas tu código.
  • Descarta los comandos antiguos: un /ac enviado durante un corte de luz no debería ejecutarse en un momento inesperado cuando la placa vuelva; la limpieza inicial del código completo se encarga de ello.
  • Estado inicial seguro: arranca siempre con el relé apagado; es muy importante con cargas como calefactores o bombas.
  • No dejes lo crítico solo en manos del bot: en una cerradura o una caldera piensa qué puede provocar una orden equivocada y añade un mensaje de confirmación o un límite de tiempo.

Alarma de movimiento y gas: proyecto completo con avisos por Telegram

Ahora juntamos todas las piezas. El código de abajo te envía un aviso de Telegram con la hora cuando el sensor PIR detecta movimiento y cuando la lectura de gas del MQ-2 supera el umbral. Al mismo tiempo escucha los comandos /ac, /kapat, /alarm_ac, /alarm_kapat y /durum, muestra un menú de botones en la parte inferior de la pantalla cuando escribes /start y añade los comandos al botón Menú de Telegram. Para los detalles de cada sensor, consulta las guías del sensor de movimiento PIR y del sensor de gas MQ-2.

C++ (Arduino IDE)
1#include <WiFi.h>
2#include <WiFiClientSecure.h>
3#include <UniversalTelegramBot.h>
4#include <ArduinoJson.h>
5#include <time.h>
6
7const char* WIFI_SSID = "AgAdi";
8const char* WIFI_PASS = "Sifre123";
9#define BOT_TOKEN "1234567890:AAExxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
10#define CHAT_ID   "123456789"                  // bildirimlerin gideceği ID / the ID that receives alerts
11
12// Komut verebilecek kişiler; aile üyesi eklemek için: { CHAT_ID, "222222222" }
13// People allowed to send commands; to add a family member: { CHAT_ID, "222222222" }
14const char* YETKILI[] = { CHAT_ID };
15const int YETKILI_SAYISI = sizeof(YETKILI) / sizeof(YETKILI[0]);
16
17const int LED_PIN  = 2;                        // dahili LED / onboard LED
18const int ROLE_PIN = 26;                       // röle modülü IN / relay module IN
19const int PIR_PIN  = 27;                       // PIR sensörü OUT / PIR sensor OUT
20const int GAZ_PIN  = 34;                       // MQ-2 AO, gerilim bölücü üzerinden / MQ-2 AO through a voltage divider
21const bool ROLE_AKTIF_LOW = true;              // çoğu modül LOW'da çeker / most modules switch on with LOW
22
23const int GAZ_ESIK = 1800;                     // temiz havadaki değere göre ayarla / tune it from your clean-air reading
24const int GAZ_FARK = 200;                      // histerezis payı / hysteresis margin
25const unsigned long HAREKET_BEKLEME = 60000;   // iki hareket bildirimi arası en az 60 sn / at least 60 s between motion alerts
26const unsigned long GAZ_ISINMA = 120000;       // MQ-2 ilk 2 dakika ısınır / MQ-2 warms up for the first 2 minutes
27const unsigned long KONTROL_ARALIGI = 1000;    // Telegram'a saniyede bir sor / poll Telegram once per second
28
29WiFiClientSecure client;
30UniversalTelegramBot bot(BOT_TOKEN, client);
31
32bool alarmKurulu = true;                       // hareket alarmı açık mı / is the motion alarm armed
33bool roleAcik = false;
34bool gazVar = false;
35unsigned long sonKontrol = 0;
36unsigned long sonHareket = 0;
37
38String saat() {                                // "14:05:31" biçiminde saat / time as "14:05:31"
39  struct tm t;
40  if (!getLocalTime(&t, 100)) return "--:--:--";
41  char buf[9];
42  strftime(buf, sizeof(buf), "%H:%M:%S", &t);
43  return String(buf);
44}
45
46bool yetkiliMi(const String& id) {
47  for (int i = 0; i < YETKILI_SAYISI; i++) {
48    if (id == YETKILI[i]) return true;
49  }
50  return false;
51}
52
53void roleYaz(bool acik) {
54  roleAcik = acik;
55  if (ROLE_AKTIF_LOW) digitalWrite(ROLE_PIN, acik ? LOW : HIGH);
56  else                digitalWrite(ROLE_PIN, acik ? HIGH : LOW);
57}
58
59String durumMetni() {
60  String s = "Röle / relay: ";
61  s += roleAcik ? "AÇIK / ON" : "KAPALI / OFF";
62  s += "\nAlarm: ";
63  s += alarmKurulu ? "KURULU / ARMED" : "KAPALI / DISARMED";
64  s += "\nGaz / gas: " + String(analogRead(GAZ_PIN));
65  s += "\nWi-Fi: " + String(WiFi.RSSI()) + " dBm";
66  return s;
67}
68
69void mesajlariIsle(int adet) {
70  for (int i = 0; i < adet; i++) {
71    String chatId = bot.messages[i].chat_id;
72    String metin  = bot.messages[i].text;
73
74    if (!yetkiliMi(chatId)) {                  // yabancıya sessiz kal / stay silent to strangers
75      Serial.println("Yetkisiz ID / unauthorized ID: " + chatId);
76      continue;
77    }
78    int at = metin.indexOf('@');               // "/ac@bot_adi" -> "/ac"
79    if (at > 0) metin = metin.substring(0, at);
80
81    if (metin == "/ac") {
82      roleYaz(true);
83      bot.sendMessage(chatId, "Röle AÇIK / relay ON");
84    } else if (metin == "/kapat") {
85      roleYaz(false);
86      bot.sendMessage(chatId, "Röle KAPALI / relay OFF");
87    } else if (metin == "/alarm_ac") {
88      alarmKurulu = true;
89      bot.sendMessage(chatId, "Hareket alarmı kuruldu / motion alarm armed");
90    } else if (metin == "/alarm_kapat") {
91      alarmKurulu = false;
92      bot.sendMessage(chatId, "Hareket alarmı kapatıldı / motion alarm disarmed");
93    } else if (metin == "/durum") {
94      bot.sendMessage(chatId, durumMetni());
95    } else {                                   // /start ve diğer her şey: tuş menüsü / /start and anything else: button menu
96      String klavye = "[[\"/ac\",\"/kapat\"],[\"/alarm_ac\",\"/alarm_kapat\"],[\"/durum\"]]";
97      bot.sendMessageWithReplyKeyboard(chatId, "Komut seç / choose a command", "", klavye, true);
98    }
99  }
100}
101
102void setup() {
103  Serial.begin(115200);
104  pinMode(LED_PIN, OUTPUT);
105  pinMode(ROLE_PIN, OUTPUT);
106  pinMode(PIR_PIN, INPUT);
107  roleYaz(false);                              // açılışta röle kapalı / relay off at boot
108
109  WiFi.mode(WIFI_STA);
110  WiFi.begin(WIFI_SSID, WIFI_PASS);
111  while (WiFi.status() != WL_CONNECTED) {
112    delay(500);
113    Serial.print(".");
114  }
115  Serial.println(WiFi.localIP());
116
117  client.setCACert(TELEGRAM_CERTIFICATE_ROOT); // api.telegram.org kök sertifikası / root certificate of api.telegram.org
118  bot.maxMessageLength = 4000;                 // büyük mesajlarda takılmayı önler / prevents hanging on big messages
119  configTime(3 * 3600, 0, "pool.ntp.org");     // Türkiye UTC+3; kendi saat dilimini yaz / Turkey is UTC+3, set your own zone
120
121  // Telegram'daki Menü düğmesi; komutlar küçük harf, Türkçe karakter yok
122  // The Menu button in Telegram; commands are lowercase with no special letters
123  bot.setMyCommands("[{\"command\":\"ac\",\"description\":\"Röleyi aç\"},"
124                    "{\"command\":\"kapat\",\"description\":\"Röleyi kapat\"},"
125                    "{\"command\":\"alarm_ac\",\"description\":\"Hareket alarmını kur\"},"
126                    "{\"command\":\"alarm_kapat\",\"description\":\"Hareket alarmını kapat\"},"
127                    "{\"command\":\"durum\",\"description\":\"Durumu göster\"}]");
128
129  // Kart kapalıyken gelen eski komutları atla / skip old commands sent while the board was off
130  while (bot.getUpdates(bot.last_message_received + 1)) { }
131
132  bot.sendMessage(CHAT_ID, "Sistem açıldı / system started " + saat());
133}
134
135void loop() {
136  unsigned long simdi = millis();
137
138  // 1) Hareket alarmı / motion alarm
139  if (alarmKurulu && digitalRead(PIR_PIN) == HIGH && simdi - sonHareket > HAREKET_BEKLEME) {
140    sonHareket = simdi;
141    digitalWrite(LED_PIN, HIGH);
142    bot.sendMessage(CHAT_ID, "Hareket algılandı! / motion detected! " + saat());
143    digitalWrite(LED_PIN, LOW);
144  }
145
146  // 2) Gaz alarmı: ısınmadan sonra, susturulamaz / gas alarm: after warm-up, cannot be muted
147  if (simdi > GAZ_ISINMA) {
148    int gaz = analogRead(GAZ_PIN);             // 0-4095
149    if (!gazVar && gaz > GAZ_ESIK) {
150      gazVar = true;
151      bot.sendMessage(CHAT_ID, "GAZ ALARMI! / GAS ALARM! " + String(gaz) + " " + saat());
152    } else if (gazVar && gaz < GAZ_ESIK - GAZ_FARK) {
153      gazVar = false;
154      bot.sendMessage(CHAT_ID, "Gaz normale döndü / gas back to normal: " + String(gaz));
155    }
156  }
157
158  // 3) Telegram komutları / Telegram commands
159  if (simdi - sonKontrol > KONTROL_ARALIGI && WiFi.status() == WL_CONNECTED) {
160    int adet = bot.getUpdates(bot.last_message_received + 1);
161    while (adet) {
162      mesajlariIsle(adet);
163      adet = bot.getUpdates(bot.last_message_received + 1);
164    }
165    sonKontrol = millis();
166  }
167}
AjusteValorExplicación
GAZ_ESIK1800Valor ADC en bruto de 0 a 4095; fíjalo a partir de tu medida en aire limpio
GAZ_FARK200La lectura debe bajar esto por debajo del umbral antes de avisar de "vuelta a la normalidad"; evita avisos que van y vienen en el límite
HAREKET_BEKLEME60000 msDeja al menos 60 segundos entre dos avisos de movimiento
GAZ_ISINMA120000 msEl MQ-2 da valores altos mientras se calienta; el gas no se comprueba durante los 2 primeros minutos
KONTROL_ARALIGI1000 msCada cuánto se pregunta a Telegram por mensajes nuevos
bot.maxMessageLength4000La respuesta más larga que lee la librería; por defecto, 1500

Las dos alarmas del código funcionan de forma distinta a propósito. La de movimiento está protegida por un tiempo de espera: un sensor PIR se dispara una y otra vez mientras alguien camina por la habitación, y sin esa espera tu móvil se llenaría de decenas de mensajes por minuto. Como el contador empieza en cero, el primer aviso llega como pronto 60 segundos después de arrancar la placa, lo que coincide además con el minuto aproximado que necesita un sensor PIR para estabilizarse al encenderse. La de gas, en cambio, usa histéresis: avisa una vez cuando la lectura supera el umbral, solo dice "vuelta a la normalidad" cuando baja 200 unidades por debajo y, por seguridad, no se puede silenciar con /alarm_kapat. Telegram tampoco permite mensajes demasiado seguidos: si intentas enviar más de un mensaje por segundo al mismo chat o más de 20 por minuto a un grupo, recibirás el error "Too Many Requests: retry after".

Ajusta GAZ_ESIK midiendo, no a ojo: deja la placa funcionando 5–10 minutos en aire limpio, envía /durum por Telegram y apunta el valor de gas que te devuelve. Coloca el umbral unos cientos de unidades por encima. También conviene conocer la variable bot.longPoll: si le das un valor como 20, getUpdates espera hasta 20 segundos a que llegue un mensaje y los comandos se responden al instante, pero loop() se queda parado ese tiempo y los sensores no se leen. En proyectos de alarma, deja longPoll en 0.
El MQ-2 es un sensor para aprender y para hobby, no un detector de gas certificado, y si se cae el Wi-Fi o internet tampoco llega ningún aviso. No lo uses nunca como única protección contra fugas de gas en casa; instala un detector comercial homologado y considera este proyecto un sistema de aviso adicional.

Bot de Telegram con el ESP8266 (NodeMCU)

La misma librería funciona también en las placas ESP8266 NodeMCU y Wemos D1 Mini; la lógica de comandos y alarmas es idéntica y solo cambia la parte de la conexión. Se usa ESP8266WiFi.h en lugar de WiFi.h, el certificado raíz se pasa como X509List a setTrustAnchors() y, como el ESP8266 comprueba las fechas de validez del certificado, hay que obtener la hora por NTP antes de conectar. Sin la hora, todas las conexiones fallan en silencio. El LED integrado del NodeMCU está en el pin D4 y se enciende con LOW, y solo hay una entrada analógica, A0.

C++ (Arduino IDE)
1#include <ESP8266WiFi.h>
2#include <WiFiClientSecure.h>
3#include <UniversalTelegramBot.h>
4#include <ArduinoJson.h>
5#include <time.h>
6
7const char* WIFI_SSID = "AgAdi";
8const char* WIFI_PASS = "Sifre123";
9#define BOT_TOKEN "1234567890:AAExxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
10#define CHAT_ID   "123456789"
11
12X509List cert(TELEGRAM_CERTIFICATE_ROOT);      // ESP8266'da kök sertifika böyle verilir / how ESP8266 takes the root certificate
13WiFiClientSecure client;
14UniversalTelegramBot bot(BOT_TOKEN, client);
15
16void setup() {
17  Serial.begin(115200);
18  configTime(0, 0, "pool.ntp.org");            // sertifika kontrolü için saat şart / the clock is needed to check the certificate
19  client.setTrustAnchors(&cert);
20
21  WiFi.mode(WIFI_STA);
22  WiFi.begin(WIFI_SSID, WIFI_PASS);
23  while (WiFi.status() != WL_CONNECTED) delay(500);
24
25  time_t simdi = time(nullptr);                // NTP saatini bekle / wait for the NTP time
26  while (simdi < 24 * 3600) {
27    delay(100);
28    simdi = time(nullptr);
29  }
30  bot.sendMessage(CHAT_ID, "ESP8266 çevrimiçi / ESP8266 is online");
31}
32
33void loop() {
34}

Bot de Telegram con la Raspberry Pi Pico W y MicroPython

La Raspberry Pi Pico W no necesita ninguna librería aparte: con el módulo requests de MicroPython puedes enviar peticiones directamente a la Bot API de Telegram. El código de abajo envía un aviso cuando detecta movimiento, maneja con /ac y /kapat el relé conectado a GP15 y el LED integrado de la placa, y solo responde a tu chat ID. Graba un MicroPython actualizado en la Pico W con Thonny y guarda el código como main.py. El módulo requests de MicroPython cifra la conexión pero no verifica el certificado del servidor, así que su nivel de seguridad es el mismo que setInsecure() en el ESP32.

MicroPython
1import network, time
2import requests
3from machine import Pin
4
5WIFI_SSID = "AgAdi"                    # Wi-Fi adın / your Wi-Fi name
6WIFI_PASS = "Sifre123"                 # Wi-Fi şifren / your Wi-Fi password
7TOKEN = "1234567890:AAExxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
8CHAT_ID = 123456789                    # sayı olarak yaz / write it as a number
9API = "https://api.telegram.org/bot" + TOKEN
10
11led = Pin("LED", Pin.OUT)              # Pico W dahili LED / Pico W onboard LED
12role = Pin(15, Pin.OUT, value=1)       # aktif LOW röle kapalı başlar / active-LOW relay starts off
13pir = Pin(16, Pin.IN)                  # PIR OUT
14
15wlan = network.WLAN(network.STA_IF)
16wlan.active(True)
17wlan.connect(WIFI_SSID, WIFI_PASS)
18while not wlan.isconnected():
19    time.sleep(0.5)
20print("IP:", wlan.ifconfig()[0])
21
22def gonder(metin):
23    try:
24        r = requests.post(API + "/sendMessage", json={"chat_id": CHAT_ID, "text": metin})
25        r.close()
26    except Exception as e:
27        print("Gonderilemedi / send failed:", e)
28
29def yeni_mesajlar(offset):
30    try:
31        r = requests.get(API + "/getUpdates?timeout=0&limit=5&offset=%d" % offset)
32        sonuc = r.json().get("result", [])
33        r.close()
34        return sonuc
35    except Exception as e:
36        print("Okunamadi / read failed:", e)
37        return []
38
39# Kart kapalıyken gelen eski komutları atla / skip old commands sent while the board was off
40offset = 0
41eski = yeni_mesajlar(offset)
42while eski:
43    offset = eski[-1]["update_id"] + 1
44    eski = yeni_mesajlar(offset)
45
46gonder("Pico W çevrimiçi / Pico W is online")
47son_hareket = time.ticks_ms()          # ilk 60 sn PIR dengelenir / the PIR settles in the first 60 s
48
49while True:
50    if pir.value() and time.ticks_diff(time.ticks_ms(), son_hareket) > 60000:
51        son_hareket = time.ticks_ms()
52        gonder("Hareket algılandı! / motion detected!")
53
54    for u in yeni_mesajlar(offset):
55        offset = u["update_id"] + 1
56        mesaj = u.get("message", {})
57        if mesaj.get("chat", {}).get("id") != CHAT_ID:     # yalnız sana yanıt ver / answer only you
58            continue
59        komut = mesaj.get("text", "").split("@")[0]
60        if komut == "/ac":
61            role.value(0)              # aktif LOW: 0 = açık / active LOW: 0 = on
62            led.on()
63            gonder("Röle AÇIK / relay ON")
64        elif komut == "/kapat":
65            role.value(1)
66            led.off()
67            gonder("Röle KAPALI / relay OFF")
68        elif komut == "/durum":
69            gonder("Röle / relay: " + ("AÇIK / ON" if role.value() == 0 else "KAPALI / OFF"))
70    time.sleep(1)

Ideas de proyectos con un bot de Telegram y ESP32

  • Alarma de puertas y ventanas: con un sensor reed o un sensor PIR, envía un mensaje al móvil cuando haya movimiento sin nadie en casa.
  • Cámara de seguridad con fotos: haz una foto con una ESP32-CAM al detectar movimiento y envíala a Telegram; los pasos están en la guía ESP32-CAM y Telegram.
  • Control de habitación o invernadero: recibe un aviso cuando la temperatura medida con un DHT11 pase de un límite y consulta el valor actual con /durum.
  • Recordatorio de riego: recibe un aviso cuando un sensor de humedad del suelo marque seco y activa la bomba unos segundos con un comando como /sula ("regar").
  • Aviso de incendio: combina un sensor de llama con el MQ-2 para vigilar los dos peligros a la vez.
  • Sensor de buzón a pilas: deja el ESP32 en deep sleep, despiértalo al abrirse la tapa, envía un único mensaje y vuelve a dormirlo.
  • Enchufe remoto: enciende y apaga una lámpara o un ventilador desde cualquier lugar del mundo con /ac y /kapat a través de un relé.

Errores comunes del bot de Telegram con ESP32 y soluciones

Síntoma o mensajeCausaSolución
sendMessage devuelve false y no hay error en el Monitor SerieFalta la línea setCACert o setInsecure, el token tiene un espacio o el Wi-Fi no está conectadoAñade la línea del certificado, vuelve a copiar el token y comprueba primero la conexión Wi-Fi
"Forbidden: bot can't initiate conversation with a user" en la prueba del navegadorNunca pulsaste Iniciar en el bot o lo bloqueasteAbre el bot en Telegram y pulsa Iniciar; si lo bloqueaste, desbloquéalo
"Bad Request: chat not found"Chat ID incorrecto, falta el signo menos en un ID de grupo o el bot fue expulsado del grupoVuelve a leer el ID con getUpdates y escribe los ID de grupo con el signo menos
"Unauthorized"El token es incorrecto o se cambió con /revokeCopia el token actual de BotFather y vuelve a cargar el código
Envía mensajes pero no responde a los comandosUn delay() largo en loop(), un chat ID incorrecto o el @nombre_bot añadido al comando en un grupoEspera con millis(), corta la parte del @ y revisa la línea "unauthorized ID" del Monitor Serie
El bot se quedó mudo tras una foto o un stickerLa librería solo lee los primeros 1500 caracteres de la respuesta; una respuesta larga no se puede interpretar y el mismo mensaje vuelve una y otra vezAñade la línea bot.maxMessageLength = 4000; en setup()
La placa ejecuta comandos antiguos al arrancarTelegram guarda los mensajes no leídos hasta 24 horasAl arrancar, lee y descarta los mensajes pendientes
"Conflict: terminated by other getUpdates request"El mismo token funciona a la vez en dos dispositivos o en un script de tu ordenadorCrea un bot distinto en BotFather para cada dispositivo
"Too Many Requests: retry after 30"Se envían mensajes demasiado seguidosAñade un tiempo de espera; como máximo un mensaje por segundo al mismo chat
Al compilar, "ArduinoJson.h: No such file or directory"La librería ArduinoJson no está instaladaInstala ArduinoJson desde el Gestor de bibliotecas
La placa se reinicia al enviar un mensajeLa alimentación no aguanta el pico de corriente al transmitir por Wi-Fi (brownout)Adaptador de 1 A, cable corto de calidad y un condensador de 100–470 µF entre 3V3 y GND
Sigue un orden al buscar el fallo: primero confirma en el Monitor Serie que el Wi-Fi está conectado, luego prueba en el navegador el token con getMe y el chat ID con sendMessage, y deja el código para el final. Para la prueba del navegador basta con abrir api.telegram.org/botTOKEN/sendMessage?chat_id=123456789&text=prueba; Telegram explica el motivo de cualquier error en texto plano en la línea description. Si te atascas en la parte del Wi-Fi, consulta la guía El ESP32 no se conecta al Wi-Fi.

Con un token, un chat ID y unas pocas líneas de código, tu ESP32 se ha convertido en un pequeño asistente que te informa de lo que pasa en casa y obedece tus órdenes. Puedes ampliar el mismo montaje con sensores de temperatura, de nivel de agua o de puerta y enviar los avisos a un grupo familiar. En la app BlueGrays encontrarás, paso a paso y con esquemas y código, el sistema de alarma de movimiento con ESP32 que avisa por Telegram con PIR, zumbador y LED, la alarma con detector de gas y humo MQ-2 y los proyectos Wi-Fi con ESP32.

Preguntas frecuentes

¿Un bot de Telegram con ESP32 es gratis?

Sí. Crear un bot en Telegram, usar la Bot API y enviar mensajes es totalmente gratuito y no hay cupo mensual de mensajes. Solo hay límites de velocidad: alrededor de un mensaje por segundo al mismo chat y 20 mensajes por minuto a un grupo. Para proyectos caseros, estos límites sobran.

¿Cómo encuentro mi chat ID de Telegram?

Lo más fácil es pulsar Iniciar en un bot de identificación como @userinfobot; te envía tu número de ID. También puedes escribir a tu propio bot, abrir api.telegram.org/botTOKEN/getUpdates en el navegador y leer el valor id de la sección "chat". Los ID de grupo empiezan con un signo menos.

¿Por qué mi ESP32 no envía mensajes a Telegram?

Las causas más habituales son no haber pulsado nunca Iniciar en el bot, un chat ID incorrecto, un espacio en el token o que falte la línea setCACert o setInsecure en el código. Con las direcciones getMe y sendMessage en el navegador puedes probar el token y el chat ID sin depender del código. Comprueba también que la placa esté conectada a una red Wi-Fi de 2,4 GHz.

¿Otra persona puede controlar mi bot de Telegram?

Los nombres de usuario de los bots son públicos, así que si no añades una comprobación de ID en el código, sí: cualquiera que encuentre el bot puede enviarle órdenes. Comparar el chat ID de cada mensaje con el tuyo e ignorar el resto lo impide, porque Telegram verifica la identidad del remitente. No compartas tampoco el token; si se filtra, cámbialo con /revoke en BotFather.

¿Se puede hacer un bot de Telegram con el ESP8266?

Sí. La librería UniversalTelegramBot también funciona en placas ESP8266 como NodeMCU y Wemos D1 Mini. El certificado raíz se pasa como X509List a setTrustAnchors() y hay que obtener la hora por NTP antes de conectar. Como el ESP8266 tiene menos memoria, el ESP32 se maneja mejor con mensajes largos.

¿El ESP32 puede enviar fotos a Telegram?

Sí. Con la función sendPhotoByBinary() de la librería puedes enviar directamente a Telegram una imagen tomada con una ESP32-CAM. Un ESP32 sin cámara puede enviar del mismo modo una imagen guardada en una tarjeta SD, o la dirección de una imagen de internet con sendPhoto(). Los sistemas que mandan una foto al detectar movimiento están entre los proyectos de seguridad más populares.

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
Parpadeo del LED interno del ESP32
#106Principiante

Parpadeo del LED interno del ESP32

Parpadeo del LED azul incorporado en el ESP32 DevKit V1. ¡No se necesitan componentes externos! El primer proyecto que debe probar cuando compra un ESP32. GPIO 2 está conectado al LED interno.

4.8(29)
53
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
Alarma de detector de gas/humo ESP32 MQ-2
#122Intermedio

Alarma de detector de gas/humo ESP32 MQ-2

En este proyecto, la detección de gases combustibles (GLP, metano, propano) y humo se realiza mediante un módulo sensor de gas MQ-2; al detectarlos, se emite un sonido de alarma similar a una sirena a través de un zumbador pasivo. La salida digital de umbral (DO) del sensor se conecta al GPIO 4 del ESP32; cuando el gas o el humo superan el umbral, DO pasa a LOW y se activa la alarma. La sensibilidad se ajusta con el potenciómetro del módulo. El zumbador se controla con tone().

4.7(28)
43
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
Iluminación automática con el sensor de movimiento PIR del ESP32
#121Intermedio
Premium

Iluminación automática con el sensor de movimiento PIR del ESP32

En este proyecto, utilizaremos el sensor de movimiento PIR HC-SR501 para detectar a las personas que entren en la habitación y encender el LED automáticamente. Controlaremos el tiempo de encendido del LED con millis(); cada lectura HIGH del sensor actualizará el instante del último movimiento, y el LED se apagará cuando hayan transcurrido al menos 10 segundos desde la última lectura HIGH. El código actual también espera 50 ms en cada iteración mediante delay(50), por lo que el bucle de la ap

4.4(24)
38
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