En este tutorial de programación con la NodeMCU ESP8266 vamos a ver cómo enviar un mensaje en nombre de un Bot de Telegram a cualquier usuario, grupo o canal de Telegram.
Solo vas a necesitar tu tarjeta ESP8266 para conectarte al Wi-Fi y enviar mensajes a la API de Telegram. Debido a que la API de Bots de Telegram usa HTTP, puedes enviar mensajes a Telegram desde una ESP8266.
Instalando drivers y configurando entorno
En caso de que no hayas instalado tu NodeMCU ni le hayas cargado código por favor revisa el siguiente vídeo para una guía:
Token de Telegram e id de chat
En este post asumo que ya tienes tu token del Bot, mismo que el BotFather te debió brindar. Si no, solo habla con él en https://t.me/botfather y crea un nuevo Bot para obtener tu token.
También estoy suponiendo que ya conoces el id de chat, grupo o canal. Si no lo tienes puedes obtener el id de usuario reenviando un mensaje al Bot https://t.me/get_id_bot o https://t.me/JsonDumpBot (no estoy afiliado ni tengo relación con ellos) y estoy seguro de que debe haber distintas maneras de obtenerlo
Especificación de la API
El proceso para comunicar la ESP8266 con Telegram es realmente sencillo. Solo debemos hacer una petición HTTP de tipo POST a la siguiente URL:
https://api.telegram.org/botTU_TOKEN/sendMessage
Enviando, codificado como JSON, los valores chat_id
y text
que corresponden al id de chat y contenido del mensaje respectivamente.
Un ejemplo de dichos datos (ya codificados) se ve así:
String cargaUtil = "{\"chat_id\":\"123\",\"text\":\"Hola mundo\"}";
La carga útil que se debe enviar a la API de Telegram es un objeto JSON con las propiedades previamente definidas. No he investigado si existe una librería para codificar JSON en esta tarjeta, pero podemos codificar manualmente.
Nota: la API de Telegram puede ser consumida en varios lenguajes de programación. Este mismo ejemplo ya lo hice con JavaScript.
Entonces solo debemos hacer una petición a esa URL enviando los datos codificados como JSON. Puedes armar el mensaje con cualquier cantidad de variables.
Enviar mensaje a Telegram desde NodeMCU ESP8266
El código importante es el siguiente:
String mensaje = "Hola Telegram desde ESP8266!";
String url = "https://api.telegram.org/bot" + tokenTelegram + "/sendMessage";
String cargaUtil = "{\"chat_id\":\"" + idChat + "\",\"text\":\"" + mensaje + "\"}";
if (clienteHttp.begin(*clienteWifi, url))
{
clienteHttp.addHeader("Content-Type", "application/json", false, true);
int httpCode = clienteHttp.POST(cargaUtil);
if (httpCode > 0)
{
String respuestaDelServidor = clienteHttp.getString();
if (httpCode == HTTP_CODE_OK)
{
Serial.println("Petición OK. Respuesta: " + respuestaDelServidor);
}
Primero definimos el mensaje como cadena. Este mensaje puede venir de cualquier lugar; podría ser el resultado de concatenar la lectura de algún sensor, por ejemplo.
Después definimos la carga útil que será enviada al servidor; esto se hace concatenando los valores y codificando como JSON “manualmente”. Dicho JSON es enviado al invocar a clienteHttp.POST
, no sin antes indicarle al servidor de Telegram que le estamos enviando JSON usando addHeader
.
Al hacer la petición POST para enviar un mensaje en nombre de un Bot de Telegram desde la NodeMCU ESP8266 se nos devolverá un código. Si el código es mayor a 0 es porque la petición fue exitosa (incluso si hubo un error de servidor).
Si el código de respuesta es menor a 0 es debido a que hubo otro error, así que lo estamos imprimiendo para depurar.
Recordemos que una petición HTTP exitosa es la que devuelve el código 200. La API de Telegram está muy bien programada y en caso de que todo sea correcto nos devolverá el código 200, que es el valor de la constante HTTP_CODE_OK
.
Sobre los certificados SSL
Para mantener las cosas simples, yo no estoy verificando los certificados del servidor de Telegram. Si bien la información estará encriptada, no sabremos si el servidor es realmente quien dice ser.
Recuerda que estamos haciendo la petición desde un sistema embebido. No es tan simple hacer peticiones seguras y verificar los certificados como cuando lo hacemos con cURL o JavaScript, mismos que se ejecutan en un sistema operativo completo.
Yo he preferido confiar para mantener las cosas simples, pero siempre es posible agregar un certificado. Vas a encontrar más información en: https://randomnerdtutorials.com/esp8266-nodemcu-https-requests/
Te repito: a mí me funciona perfectamente y no tengo ningún problema; no estoy enviando información confidencial o descargando datos importantes del servidor.
Poniendo todo junto
Anteriormente te mostré el código más importante, pero no es el código completo. El código completo queda como se ve a continuación.
Solo debes configurar el nombre de tu red, contraseña, id de chat al que se le enviarán los mensajes y el token del Bot de Telegram.
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <WiFiClientSecureBearSSL.h>
// Puede ser de un usuario, canal o grupo
const String idChat = "";
// Obtenido con el @Botfather
const String tokenTelegram = "";
// Red WiFi para conectarse
const char *NOMBRE_RED_WIFI = "";
const char *CLAVE_RED_WIFI = "";
void setup()
{
Serial.begin(9600);
WiFi.mode(WIFI_STA);
WiFi.begin(NOMBRE_RED_WIFI, CLAVE_RED_WIFI);
while (WiFi.status() != WL_CONNECTED)
{
delay(1000);
}
}
void loop()
{
if ((WiFi.status() == WL_CONNECTED))
{
std::unique_ptr<BearSSL::WiFiClientSecure> clienteWifi(new BearSSL::WiFiClientSecure);
clienteWifi->setInsecure();
HTTPClient clienteHttp;
String mensaje = "Hola Telegram desde ESP8266!";
String url = "https://api.telegram.org/bot" + tokenTelegram + "/sendMessage";
String cargaUtil = "{\"chat_id\":\"" + idChat + "\",\"text\":\"" + mensaje + "\"}";
if (clienteHttp.begin(*clienteWifi, url))
{
clienteHttp.addHeader("Content-Type", "application/json", false, true);
int httpCode = clienteHttp.POST(cargaUtil);
if (httpCode > 0)
{
String respuestaDelServidor = clienteHttp.getString();
if (httpCode == HTTP_CODE_OK)
{
Serial.println("Petición OK. Respuesta: " + respuestaDelServidor);
}
else
{
Serial.printf(
"Petición realizada pero hubo un error en el servidor. Código HTTP: %d. Respuesta: %s\n",
httpCode,
respuestaDelServidor.c_str());
}
}
else
{
// Petición Ok pero código no es 200
Serial.printf("Error haciendo petición: %s\n", clienteHttp.errorToString(httpCode).c_str());
}
clienteHttp.end();
}
else
{
Serial.println("Error con clienteHttp.begin");
}
}
else
{
Serial.println("No hay WiFi");
}
// Esperar 10 segundos antes de enviar el siguiente mensaje
delay(10000);
}
En próximos tutoriales te voy a enseñar a enviar información de sensores a Telegram desde este mismo chip.
Exelente, muchas gracias