This article demonstrates how to use Telegram to control the GPIOs on an ESP32 or ESP8266 NodeMCU from anywhere in the world. We’ll control an LED as an example, but you can control any other output. To set your outputs HIGH or LOW, simply send a message to your Telegram Bot. The Arduino IDE will be used to programme the ESP boards.
PROJECT OVERVIEW
We’ll use Telegram to control the ESP32 or ESP8266 development board’s inbuilt LED. We’ll start by downloading the Telegram app to our phone and then creating a Telegram Bot for our ESP board. Second, we’ll start talking with it using the bot token. Then, because we want to toggle the LED, we’ll send a message to the bot instructing it to carry out that action. As a result, the bot will get the message and respond appropriately.
The table below shows the messages we will send to the bot to execute upon.
COMMANDS | DESCRIPTION |
/led2_on | This message will turn the onboard LED on. |
/led2_off | This message will turn the onboard LED off. |
/get_state | This message will send the current LED state (OFF or ON) to the telegram bot. |
/start | This message will display a welcome message and the commands to control the ESP32/ESP8266 module to the user. |
INTRODUCING TELEGRAM
Telegram is a free messaging service that allows users to send messages as well as perform audio and video chats. It runs on a variety of platforms, including Windows, macOS, Linux, Android, and Apple iOS. It also contains a feature that allows third-party developers to construct bots.
These bots are simple to put up and can carry out commands via cross messaging. They can also be added to various groups and interfaced with any software programme to initiate an event. To interface with the bot, we’ll utilise our ESP32 or ESP8266 module. In turn, this will receive and process the messages, as well as deliver relevant responses to the user.
CREATING TELEGRAM BOT
STEP 1: Go to Google Play or App Store, download and install Telegram.
STEP 2: Open Telegram and search for “botfather”.
STEP 3:Type /newbot and follow the instructions to create your bot. Give it a name and username.
STEP 4:If your bot is successfully created, you’ll receive a message with a link to access the bot and the bot token. Save the bot token because you’ll need it so that the ESP32/ESP8266 can interact with the bot.
TO GET TELEGRAM USER ID
We’ll now create our Telegram user ID. This will be really beneficial because it will filter out all needless communications that we did not send or that were not sent by a person with permission. This user id will be unique to each user, and it will aid the ESP module in determining if the message was delivered by us or by someone else who had access to our bot.
Go to the search tab on your Telegram app. Enter ‘IDBot’ into the search box.
Start a conversation with that bot and type /getid. You will get a reply back with your user ID. Save that user ID, because you’ll need it later in this tutorial.
UNIVERSAL TELEGRAM BOT LIBRARY
To interact with the Telegram bot, we’ll use the Universal Telegram Bot Library created by Brian Lough that provides an easy interface for the Telegram Bot API.
Follow the next steps to install the latest release of the library.
1. Download the universal telegram bot library
2. Go to Sketch > Include Library > Add.ZIP Library
3. Add the library you’ve just downloaded.
The library is installed.
CODE
The following code allows you to control your ESP32 or ESP8266 NodeMCU GPIOs by sending messages to a Telegram Bot. To make it work for you, you need to insert your network credentials (SSID and password), the Telegram Bot Token and your Telegram User ID.
#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> // Replace with your network credentials const char* ssid = "REPLACE_WITH_YOUR_SSID"; const char* password = "REPLACE_WITH_YOUR_PASSWORD"; // Initialize Telegram BOT #define BOTtoken "XXXXXXXXXX:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" // your Bot Token (Get from Botfather) // Use @myidbot to find out the chat ID of an individual or a group // Also note that you need to click "start" on a bot before it can // message you #define CHAT_ID "XXXXXXXXXX" #ifdef ESP8266 X509List cert(TELEGRAM_CERTIFICATE_ROOT); #endif WiFiClientSecure client; UniversalTelegramBot bot(BOTtoken, client); // Checks for new messages every 1 second. int botRequestDelay = 1000; unsigned long lastTimeBotRan; const int ledPin = 2; bool ledState = LOW; // Handle what happens when you receive new messages void handleNewMessages(int numNewMessages) { Serial.println("handleNewMessages"); Serial.println(String(numNewMessages)); for (int i=0; i<numNewMessages; i++) { // Chat id of the requester String chat_id = String(bot.messages[i].chat_id); if (chat_id != CHAT_ID){ bot.sendMessage(chat_id, "Unauthorized user", ""); continue; } // Print the received message String text = bot.messages[i].text; Serial.println(text); String from_name = bot.messages[i].from_name; 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, ""); } if (text == "/led_on") { bot.sendMessage(chat_id, "LED state set to ON", ""); ledState = HIGH; digitalWrite(ledPin, ledState); } if (text == "/led_off") { bot.sendMessage(chat_id, "LED state set to OFF", ""); ledState = LOW; digitalWrite(ledPin, ledState); } if (text == "/state") { if (digitalRead(ledPin)){ bot.sendMessage(chat_id, "LED is ON", ""); } else{ bot.sendMessage(chat_id, "LED is OFF", ""); } } } } void setup() { Serial.begin(115200); #ifdef ESP8266 configTime(0, 0, "pool.ntp.org"); // get UTC time via NTP client.setTrustAnchors(&cert); // Add root certificate for api.telegram.org #endif pinMode(ledPin, OUTPUT); digitalWrite(ledPin, ledState); // Connect to Wi-Fi WiFi.mode(WIFI_STA); WiFi.begin(ssid, password); #ifdef ESP32 client.setCACert(TELEGRAM_CERTIFICATE_ROOT); // Add root certificate for api.telegram.org #endif while (WiFi.status() != WL_CONNECTED) { delay(1000); Serial.println("Connecting to WiFi.."); } // Print ESP32 Local IP Address Serial.println(WiFi.localIP()); } 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(); } }
HOW CODE WORKS
These sections explain how the code works. Start by importing the required libraries.
#ifdef ESP32
#include <WiFi.h>
#else
#include <ESP8266WiFi.h>
#endif
#include <WiFiClientSecure.h>
#include <UniversalTelegramBot.h>
#include <ArduinoJson.h>
Network Credentials
Insert your network credentials in the following variables.
const char* ssid = “REPLACE_WITH_YOUR_SSID”;
const char* password = “REPLACE_WITH_YOUR_PASSWORD”;
Define Output
Set the GPIO you want to control. In our case, we’ll control GPIO 2 (built-in LED) and its state is LOW by default.
const int ledPin = 2;
bool ledState = LOW;
Telegram Bot Token
Insert your Telegram Bot token you’ve got from Botfather on the BOTtoken variable.
#define BOTtoken “XXXXXXXXXX:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX” // your Bot Token (Get from Botfather)
Telegram User ID
Insert your chat ID. The one you’ve got from the IDBot.
#define CHAT_ID “XXXXXXXXXX”
Create a new WiFi client with WiFiClientSecure.
WiFiClientSecure client;
Create a bot with the token and client defined earlier.
UniversalTelegramBot bot(BOTtoken, client);
The botRequestDelay and lastTimeBotRan are used to check for new Telegram messages every x number of seconds. In this case, the code will check for new messages every second (1000 milliseconds). You can change that delay time in the botRequestDelay variable.
int botRequestDelay = 1000;
unsigned long lastTimeBotRan;
HandleNewMessages()
The handleNewMessages() function handles what happens when new messages arrive.
void handleNewMessages(int numNewMessages) {
Serial.println(“handleNewMessages”);
Serial.println(String(numNewMessages));
It checks the available messages:
for (int i=0; i<numNewMessages; i++) {
Get the chat ID for that particular message and store it in the chat_id variable. The chat ID allows us to identify who sent the message.
String chat_id = String(bot.messages[i].chat_id);
If the chat_id is different from your chat ID (CHAT_ID), it means that someone (that is not you) has sent a message to your bot. If that’s the case, ignore the message and wait for the next message.
if (chat_id != CHAT_ID) {
bot.sendMessage(chat_id, “Unauthorized user”, “”);
continue;
}
Otherwise, it means that the message was sent from a valid user, so we’ll save it in the text variable and check its content.
String text = bot.messages[i].text;
Serial.println(text);
The from_name variable saves the name of the sender.
String from_name = bot.messages[i].from_name;
If it receives the /start message, we’ll send the valid commands to control the ESP32/ESP8266. This is useful if you happen to forget what are the commands to control your board.
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, “”);
}
Sending a message to the bot is very simply. You just need to use the sendMessage() method on the bot object and pass as arguments the recipient’s chat ID, the message, and the parse mode.
bool sendMessage(String chat_id, String text, String parse_mode = “”)
In our particular example, we’ll send the message to the ID stored on the chat_id variable (that corresponds to the person who’ve sent the message) and send the message saved on the welcome variable.
bot.sendMessage(chat_id, welcome, “”);
If it receives the /led_on message, turn the LED on and send a message confirming we’ve received the message. Also, update the ledState variable with the new state.
if (text == “/led_on”) {
bot.sendMessage(chat_id, “LED state set to ON”, “”);
ledState = HIGH;
digitalWrite(ledPin, ledState);
}
Do something similar for the /led_off message.
if (text == “/led_off”) {
bot.sendMessage(chat_id, “LED state set to OFF”, “”);
ledState = LOW;
digitalWrite(ledPin, ledState);
}
Finally, if the received message is /state, check the current GPIO state and send a message accordingly.
if (text == “/state”) {
if (digitalRead(ledPin)){
bot.sendMessage(chat_id, “LED is ON”, “”);
}
else{
bot.sendMessage(chat_id, “LED is OFF”, “”);
}
}
setup()
In the setup(), initialize the Serial Monitor.
Serial.begin(115200);
If you’re using the ESP8266, you need to use the following line:
#ifdef ESP8266
client.setInsecure();
#endif
In the library examples for the ESP8266 they say: “This is the simplest way of getting this working. If you are passing sensitive information, or controlling something important, please either use certStore or at least client.setFingerPrint“.
Set the LED as an output and set it to LOW when the ESP first starts:
pinMode(ledPin, OUTPUT);
digitalWrite(ledPin, ledState);
Init Wi-Fi
Initialize Wi-Fi and connect the ESP to your local network with the SSID and password defined earlier.
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println(“Connecting to WiFi..”);
}
loop()
In the loop(), check for new messages every second.
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();
}
}
When a new message arrives, call the handleNewMessages function.
while(numNewMessages) {
Serial.println(“got response”);
handleNewMessages(numNewMessages);
numNewMessages = bot.getUpdates(bot.last_message_received + 1);
}
DEMONSTRATION
The code should be uploaded to your ESP32 or ESP8266 board. Don’t forget to pick the board you’re using from Tools > Board. Select the COM port your board is linked to under Tools > Port.
After uploading the code, push the on-board EN/RST button on the ESP32/ESP8266 to begin running it. Then you may verify what’s going on in the background by opening the Serial Monitor.
Open a conversation with your bot in your Telegram account. Send the bot the following commands to see how it responds:
- /start shows the welcome message with the valid commands.
- /led_on turns the LED on.
- /led_off turns the LED off.
- /state requests the current LED state.
The on-board LED should turn on and turn off accordingly (the ESP8266 on-board LED works in reverse, it’s off when you send /led_on and on when you send /led_off).
At the same time, on the Serial Monitor you should see that the ESP is receiving the messages.
If you try to interact with your bot from another account, you’ll get the the “Unauthorized user” message.
CONCLUSION
We learned how to make a Telegram Bot that interacts with the ESP32 or ESP8266 in this lesson. You can send messages to the ESP and control its outputs using your Telegram account with this bot. In order to send responses, the ESP can interact with the bot.