Crea tu propio bot de Telegram con ESP32

Telegram se ha popularizado recientemente por ser una alternativa a WhatsApp por la privacidad de tus datos, pero Telegram va un poco más allá y también es de código abierto, además de que te da herramientas para desarrollar más cosas, como implementar bots para IoT. En este tutorial vamos a ver como controlar los puertos GPIO de tu ESP32 de forma remota desde la app de Telegram.

¿Qué es un bot de Telegram?

Los bots de Telegram son aplicaciones desarrolladas con Inteligencia Artificial que se pueden configurar para servir distintas funciones. Algunos ejemplos pueden ser, enviar información relevante del clima o artículos interesantes de noticias. Algunas se preconfiguran para mandar recordatorios, otras pueden reproducir melodías o crear listas de quehacer y mucho más.

Telegram
Vía: IoTDesignPro

Requisitos para desarrollar el proyecto

En este tutorial vamos a controlar el encendido y apagado de un LED con el bot. El LED estará conectado a la tarjeta del ESP32, pero puedes usar cualquier pin GPIO. Como este proyecto requiere de más software que hardware, no necesitas muchos materiales, pero sí algunas librerías. En este artículo estaremos desarrollando el código poco a poco para que tengas claro que hacer.

Materiales:

  • Tarjeta de Desarrollo ESP32
  • IDE de Arduino
  • Librerías de Arduino para usar el bot
  • App de Telegram

Creando el Bot de Telegram

Como primer paso, necesitamos crear el Bot en la aplicación. Para eso debes instalar la App y crearte una cuenta. El resto del código se hace en la tarjeta de desarrollo.

  • Ahora busca «botfather» y da clic en el Chat de BotFather como se muestra. También puedes abrir este link t.me/botfather desde tu celular. Botfather es un Bot pre-construido de Telegram que te permite administrar tus propios bots.
botfather in Telegram
Vía: IoTDesignPro
  • Da clic en empezar y selecciona /newbot
Telegram Bot
Vía: IoTDesignPro
  • Ahora debemos darle un nombre al Bot en name y crear un nombre de usuario en username. Si lograste crear tu bot correctamente recibirás un mensaje con el link hacia tu nuevo bot y un bot token. Este token es una identificación única de tu bot que nos permitirá establecer la comunicación posteriormente.
Making a Telegram Bot
Vía: IoTDesignPro

Configura tu id de Telegram

El id de usuario de Telegram es un número único para cada chat, grupo y usuario que le permite a Telegram identificar usuarios y chats. En este proyecto, cualquiera que tenga el enlace al bot puede interactuar con el. Para prevenir accesos no autorizados vamos a encriptar el bot usando dicho id. Haciendo esto, cada que la tarjeta ESP reciba un mensaje del bot revisará primeramente si es nuestro usuario quien manda el mensaje, y solo ejecutará el comando cuando seamos nosotros.

Pasos para configurar el ID:

IDBot in Telegram
Vía: IoTDesignPro
  • Envía un mensaje al bot con el comando /getid, lo que te dará tu ID de usuario. Anota el ID que lo usaremos después.
Telegram Bot IDBot
Vía: IoTDesignPro

Para seguir leyendo…

Instalando las librerías para usar el Bot

Librería de Telegram

Para establecer la comunicación con el Bot usaremos la librería Universal de Telegram creada por Brian Logh que provee una interfaz fácil de usar para la API de Telegram. Para instalarla necesitas descargarla primero desde aquí y luego en el IDE de Arduino le das Sketch Include Library > Add.ZIP Library... Y listo. Para más detalles de la librería puedes revisar la documentación en GitHub.

Librería de ArduinoJson

Para instalar la librería de Json necesitas buscarla desde el administrador de librerías de Arduino. Abre Sketch Include Library > Manage Libraries y busca ArduinoJson. Selecciona la versión más reciente e instálala. Si necesitas revisar la documentación puede revisar el perfil del autor en GitHub.

Programando la tarjeta ESP32

Tenemos que programar la tarjeta de modo que reciba cualquier mensaje enviado por el bot, compare el ID de usuario y encienda o apague el LED de acuerdo al mensaje recibido. A continuación te daremos poco a poco el código que irás agregando al editor. Para empezar, agreguemos las librerías instaladas previamente:

#ifdef ESP32
#include <WiFi.h>
#else
#include <ESP8266WiFi.h>
#endif
#include <WiFiClientSecure.h>
#include <UniversalTelegramBot.h> // Universal Telegram Bot Library written by Brian Lough: https://github.com/witnessmenow/Universal-Arduino-Telegram-Bot
#include <ArduinoJson.h>

Después de eso, inicializamos las variables para guardar el nombre y la contraseña de nuestro WiFi.

const char* SSID = "Your_SSID";
const char* password = "Your_pass";

Del mismo modo, definimos las variables para guardar el token del bot y el ID de usuario. En este caso tienes que editar las variables con tus identificaciones personales en donde dice «Your_Bot_Token» y «Your_Chat_id».

#define BOTtoken "Your_Bot_Token" // your Bot Token (Get from Botfather)
#define CHAT_ID "Your_chat_id"

Después, creamos un nuevo cliente WiFi con WiFiClientSecure

WiFiClientSecure client;

Creamos ahora un nuevo bot con el token y el cliente que definimos anteriormente.

UniversalTelegramBot bot(BOTtoken, client);

Las siguientes dos variables se usan para revisar los nuevos mensajes de Telegram cada cierto tiempo. En nuestro caso, definimos que revise cada 1000ms si hay nuevos mensajes. Podemos cambiar ese periodo dependiendo de nuestras necesidades, como cada 5000ms por ejemplo, cambiando la variable botRequestDelay.

int botRequestDelay = 1000;
unsigned long lastTimeBotRan;

La función handleNewMessages() mantiene un control de qué pasa cuando llega un nuevo mensaje.

void handleNewMessages(int numNewMessages) {
  Serial.println("handleNewMessages");
  Serial.println(String(numNewMessages));
for (int i=0; i<numNewMessages; i++) {

Necesitamos obtener el ID de ese mensaje y guardarlo en una variable llamada chat_id. Esto nos permitirá identificar quién envió el mensaje.

String chat_id = String(bot.messages[i].chat_id);

Si el chat_id es diferente del que habíamos definido anteriormente, significa que alguién más tiene el enlace del bot. En ese caso, necesitamos ignorar el mensaje y esperar a uno nuevo.

if (chat_id != CHAT_ID) {
  bot.sendMessage(chat_id, "Unauthorized user", "");
  continue;
}

De otro modo, significa que el bot recibió nuestro mensaje y debemos guardar la información en una variable de texto.

String text = bot.messages[i].text;
Serial.println(text);

La variable from_name guarda el nombre de la persona que lo envía.

String from_name = bot.messages[i].from_name;

Si recibimos el mensaje /start, enviaremos un comando válido a la ESP32. Esta modalidad puede ser muy útil si no recuerdas los comandos específicos que controlan tu tarjeta.

if (text == "/start") {
  String welcome = "Welcome, " + from_name + ".\n";
  welcome += "Use the following commands to control your outputs.\n\n";
  welcome += "/led_on to turn GPIO ON \n";
  welcome += "/led_off to turn GPIO OFF \n";
  welcome += "/state to request current GPIO state \n";
  bot.sendMessage(chat_id, welcome, "");
}

Podemos mandarle un mensaje a nuestro chatbot simplemente usando el método sendMessage() en el objeto bot y mandándole el ID del usuario, el mensaje y el argumento parse_mode

bool sendMessage(String chat_id, String text, String parse_mode = "")

En nuestro ejemplo particular, enviaremos el mensaje al ID almacenado en el chat_id y enviaremos el mensaje guardado en la variable de bienvenida.

bot.sendMessage(chat_id, welcome, "");

Si recibe el mensaje /led_on, enciende el LED y envía un mensaje confirmando que hemos recibido el comando. Además, actualiza la variable ledState con el nuevo estado.

if (text == "/led_on") {
  bot.sendMessage(chat_id, "LED state set to ON", "");
  ledState = HIGH;
  digitalWrite(ledPin, ledState);
}

Hacemos algo similar para el comando /led_off.

if (text == "/led_off") {
  bot.sendMessage(chat_id, "LED state set to OFF", "");
  ledState = LOW;
  digitalWrite(ledPin, ledState);
}

Finalmente, verificamos el mensaje recibido usando el comando /state, verificando el estado actual de GPIO y enviando el mensaje en consecuencia, ya sea si está encendido o apagado.

if (text == "/state") {
  if (digitalRead(ledPin)){
    bot.sendMessage(chat_id, "LED is ON", "");
  }
  else{
    bot.sendMessage(chat_id, "LED is OFF", "");
  }
}
Inicializa Wi-Fi y conecta el ESP a tu red SSID y contraseña que definimos anteriormente.
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
  delay(1000);
  Serial.println("Connecting to WiFi..");
}

En la función loop() revisamos un mensaje nuevo cada segundo

void loop() {
  if (millis() > lastTimeBotRan + botRequestDelay)  {
    int numNewMessages = bot.getUpdates(bot.last_message_received + 1);
    while(numNewMessages) {
      Serial.println("got response");
      handleNewMessages(numNewMessages);
      numNewMessages = bot.getUpdates(bot.last_message_received + 1);
    }
    lastTimeBotRan = millis();
  }
}

Cuando llega un nuevo mensaje, lo manejamos con la función handleNewMessages().

while(numNewMessages) {
  Serial.println("got response");
  handleNewMessages(numNewMessages);
  numNewMessages = bot.getUpdates(bot.last_message_received + 1);
}

Con eso concluimos nuestro código. ahora solo necesitas subir el programa a la tarjeta y con eso es suficiente.

Haciendo pruebas

Ya que subiste el código es hora de probar si funciona. Abre el monitor serial y espera a que la tarjeta se conecte a WiFi. Después, abre Telegram y empieza la conversación con tu bot, usando el comando /start. Manda los comandos /led_on /led_off o /state para probar el funcionamiento del programa.

ESP32 Based Telegram Bot
Vía: IoTDesignPro

Si todo está bien deberías poder ver como se enciende el LED integrado de la tarjeta y los comandos que se ejecutan en el monitor serial.

Control GPIO Pins through Telegram chat
Vía: IoTDesignPro

Referencias:

Telegram Bot with ESP32 – Control GPIO Pins through Telegram Chat

Telegram Group: Control ESP32/ESP8266 Outputs (Arduino IDE)

Vía: Random Nerd Tutorials