Using Telegram with ESP8266 or ESP32

Telegram is a ‘Whatsapp’ like app for mobile phones to exchange messages.
An advantage over Whatsapp or Viber is that it also allows you to communicate with your (micro)computer.
That means your phone can receive messages sent from your ESP8266 or ESP32, but also that your phone can be used to control your ESP8266 or ESP32.

In order to do so you need to have the telegram app installed, create your own bot to handle the traffic, get an API_key and the chat_id for your bot

Install Telegram
Visit Telegram official website and download the official application for your smartphone, or get it from the playstore

Create your Bot
Create your bot by using a bot called “BotFather”. To do this, add BotFather to your contacts or visit telegram.me/botfather and follow the instructions to create your own bot.

Get your API
When your bot is created, BotFather gives you the HTTP API token which follows a pattern like 123456789:AABBCCDD_abcdefghijklmnopqrstuvwxyz. You need this token to send messages.

Get your chat_id
You will need this ID to send messages, you do not need it to receive messages. Getting this ID is not straightforward and most of the methods i have seen on the internet do not work (anymore).
The only ones I found working is to the IDBot (and follow the instructions). and the get_id_bot. The latter can be a bit slow though. (I will mention a 3rd option further down)

Getting your chat ID with IDBot
Getting your chat ID with get_id bot

The id is an integer and it follows a pattern like 123456789

Now it is time to test your bot.
You can do that with cURL

curl --data chat_id="892915001" --data "text=Hello World" "https://api.telegram.org/bot977142506:AAGYWypUbMN8BCthML-tFM25M403r2yCsFj/sendMessage

from your commandline prompt

or with a GET URL in a browser like this:

https://api.telegram.org/bot977142506:AAGYWypUbMN8BCthML-tFM25M403r2yCsFj/sendMessage?chat_id=892915001&text=Hello-World

There is an other element that can be added at the end and that is &parse_mode=, but for normal operations we can leave that out or make it “&parse_mode=HTML”.  A bit more on this further down

Using GET
So now we have our communication with Telegram working, we can go do something useful with it.
The fact that the API can be reached with a GET message opens up possibilities for an ESP8266, ESP32, Raspberry Pi or other controller that is connected to internet.

You would do that with

botclient.print(String("GET ") + url + " HTTP/1.1\r\n" +
"Host: " + host + "\r\n" +
"User-Agent: BuildFailureDetectorESP8266\r\n" +
"Connection: close\r\n\r\n");

in which

const char* host = "api.telegram.org"

and the
String url is the sum of the strings and variables you want to send

In your declaration section you would be stating:

WiFiClientSecure botclient;

The reason I am not putting a complete and ready “Telegram via GET” program here is because there is actually a pretty decent library program available, so if you insist on using your own GET statements rather than a library, I presume you do that to make very lean code in which case I presume you are versed enough in coding to build your own routine with the help of the above info.
If you use a GET URL to connect your ESP to Telegram and you are sure your code is correct, you may have a secure connection problem. Read On

Using a library
There are several libraries for Telegram available and you probably already find them in your library manager. The “UniversalTelegramBot” is a pretty decent one and the examples should get you up and running fast, even if from first glance it is not always clear what they do 🙂 .
So, install the library via library manager and lets have a look at the “PhotoFromURL”example.

When you fill in your WiFi credentials and Telegram API, you may wonder “where the heck goes my chat_id”.
Well, remember earlier I said you only needed the chat_id when you wanted to send something from yr micro to your phone? Well, that’s the case right here.
“Yes, but this program IS supposed to send me something and I clearly see a variable called chat_id, so where do I put mine” I hear you say.
Well this program will send you a picture ONLY when you tell it to do that and then the program will just read your chat_id from the incoming message and use that. This is also the 3rd method of finding your client ID

So here is  what you do to use that example: After you upload it to your ESP8266, go to your Telegram app on your phone. select the bot you just created to send a message to and message /start.

After a few moments the bot responds with an overview of the commands you can give (only one in this case). Tap on that command to execute it.

It is not working
If nothing happens, it is time to open the serial monitor.
You should see the IP number being printed. Make sure you type the correct command in your Telegram app and make sure you are sending it to the proper bot.

If you don’t see the ‘got response’ message appearing and you are sure you have inserted the right API, then apparently something else is keeping the program from opening a socket to the bot.

Could it be that you are still using the 2.5.0 ESP8266 core? There are plenty good reasons to use that core, but apparently it has a problem with secure connections. But not all is lost. Here is what you do:

Go to setup() and add

client.setInsecure();

and then compile and upload the file again.

Beware! In this example the WiFiSecure() client IS called client. That maybe different in other examples (in the Bulkmessages example it is called ‘secured_client’. Change your setInsecure statement accordingly.

Controlling your ESP8266/ESP32 via Telegram
It is possible to control your ESP via your Telegram App. In fact, that is what the previous example was already doing: we  instructed it to send a photo.

The FlashLed example shows very clear how to control your ESP. If for testing you want to use the inbuild led from the Wemos, the ledPin should be ‘2’, the ledon routine should make the pin LOW and the ledoff routine should make the pin HIGH.

You could combine functions like so:

/*******************************************************************
 *  How to use basic functiond of a Telegrambot
 *  A completely changed example based on a sketch from  
 *      Vadim Sinitski
 *******************************************************************/
#include <ESP8266WiFi.h>
#include <WiFiClientSecure.h>
#include <UniversalTelegramBot.h>

// Initialize Wifi connection to the router
char ssid[] = "NETGEAR1";     // your network SSID (name)
char password[] = "SECRET"; // your network key

// Initialize Telegram BOT
#define BOTtoken "XXXXXXXXX:YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY"  // your Bot Token (Get from Botfather)

WiFiClientSecure client;
UniversalTelegramBot bot(BOTtoken, client);

int Bot_mtbs = 1000; //mean time between scan messages
long Bot_lasttime;   //last time messages' scan has been done
bool Start = false;

const int ledPin = 2;
int ledStatus = 0;

String test_photo_url = "https://img.srgcdn.com/e/w:750/cjh2NWp4S0FiNWxJQVNsQ3JUU28uanBn.jpg"; // can insert any picture URL

void handleNewMessages(int numNewMessages) {
  Serial.println("handleNewMessages");
  Serial.println(String(numNewMessages));


  for (int i = 0; i < numNewMessages; i++) {
    String chat_id = String(bot.messages[i].chat_id);
    String text = bot.messages[i].text;

    String from_name = bot.messages[i].from_name;
    if (from_name == "") from_name = "Guest";

    if (text == "/get_photo") {
      bot.sendPhoto(chat_id, test_photo_url, "Who");
    }

    //-------------
    //add more commands here
    //-------------
    
    if (text == "/ledon") {
      digitalWrite(ledPin, LOW);   // turn the LED on (HIGH is the voltage level)
      ledStatus = 1;
      bot.sendMessage(chat_id, "Led is ON", "");
    }

    if (text == "/ledoff") {
      ledStatus = 0;
      digitalWrite(ledPin, HIGH);    // turn the LED off (LOW is the voltage level)
      bot.sendMessage(chat_id, "Led is OFF", "");
    }

    if (text == "/status") {
      if (ledStatus) {
        bot.sendMessage(chat_id, "Led is ON", "");
      } else {
        bot.sendMessage(chat_id, "Led is OFF", "");
      }
    }
    

    if (text == "/start") {
      String welcome = "Welcome to Telegram Bot, " + from_name + ".\n";
      welcome += "This will show several properies.\n\n";
      welcome += "/get_photo : getting photo\n";
      welcome += "/ledon : to switch the Led ON\n";
      welcome += "/ledoff : to switch the Led OFF\n";
      welcome += "/status : Returns current status of LED\n";


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

void setup() {
  Serial.begin(115200);

  // Set WiFi to station mode and disconnect from an AP if it was Previously connected
  WiFi.mode(WIFI_STA);
  WiFi.disconnect();
  delay(100);

  // attempt to connect to Wifi network:
  Serial.print("Connecting Wifi: ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    delay(500);
  }

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
  client.setInsecure(); // if yr core cannot handle secure connections

  pinMode(ledPin, OUTPUT); // initialize digital ledPin as an output.
  delay(10);
  digitalWrite(ledPin, HIGH); // initialize pin as off

}

void loop() {
  if (millis() > Bot_lasttime + Bot_mtbs)  {
    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);
    }

    Bot_lasttime = millis();
  }
}

Or download here.

I just want to have my ESP send notifications
Well in fact the previous examples kinda did that, but if you really just want to have notifications sent to your phone from your ESP, then the only command you will need from the library is

bot.sendMessage(chat_id, "My message", "");

Provided of course you called your library object ‘bot’. Those empty quotes at the end are there for the parse_mode (read on).
Instead of “my message” you can also insert a String variable in which you add text and variables and you can even use simple HTML coding in that string.  In that case the command needs to be:

bot.sendMessage(chat_id, messagestring, "HTML");

your messagestring could for instance be:

String messagestring="The temperature is  <b>"+String(tempreading+ "</b>Celsius";

more about the API here!

11 thoughts on “Using Telegram with ESP8266 or ESP32”

  1. Hello. Sorry if I missed it, but how about security, like, if anyone knows about the bot he/she will be able to access it and so gaining access to the ESP in the other end?

    1. Commands are being sent through Telegram that filters out anything that won’t make sense and the bot only reacts to defined commands.
      So there is no gaining access to the ESP

      1. Ok, I see, my point is, can someone else *access the bot*, is it open, (suppose it tries and find out the commands, even if I put no “help” on it), then use it?

      2. No i do not really see any possibility for that. The commands can be any word of your choosing and would be impossible to access the bot. The entire whatsapp layer is in between and your esps firmware is just not rigged to be accessed in such a way

    2. I think the simplest solution is to create a list of allowed senders by their ID. Then, before responding, your bot should check that the request comes from a legitimate user. If sender ID not in the allowed users list, ignore and… do not reply. This is the method I’ve used in my project.
      (Please, don’t ask me to write down the code.)

      1. I think you got my point, good suggestion.This method should avoid basic “intrusion” trials. After all I am not of such importance to the point of someone try to fake id to gain access to my bot (don’t know if possible, however if faking MAC address to break MAC filtering on routers is possible then…). I will try that (in fact I tried to show who is interacting with the bot but information seems to be empty), maybe I missed how to use part of the API or how to obtain the info.
        I won’t ask your code, but if could you confirm what API and what part of the API worked for you it would be nice.
        – I used CTBot (https://www.arduinolibraries.info/libraries/ct-bot) .
        The empty information was ‘msg.sender.username’;
        – just confirm please, I presume you used ‘msg.sender.id’ for that ? Thanks

      2. I’m also using CBot currently (and I say “Grazie mille Stefano, for your library”). 
        From a more general prospective, bots in Telegram resolve safety matters in a simple but nice manner, I think. In any case, I cannot comment in depth ’cause I’m just a novice.
        Back to our discussion…
        Somewhere in Telegram API docs is written that name and user name may not be defined, but every Telegram user has a unique ID, hence it remains the simplest solution. Now, in order to unambiguously get the ID of the users will be allowed to interact with my bot, I’ve used the simplest library example with an “Serial.print” added for the user ID of each received message. Then, I’ve asked all other future legitimated users to send some message to my bot, and I collected the results from the serial monitor.
        There are many possibilities in using and reusing the IDs, it’s all up to you.
        Nethertheless my previous statement on source code, here below I’ve pasted, as an example, some parts of my bot, that implement an alert mechanism in case of messages from unknown users. 
        A note, dulcis in fundo: it is now more than 3 months that by bot does perfectly the job. In this period, I’ve never received any message from unknown users, surely because I’m also an unimportant person :-).
        For the sake of clarity, note that the ellipses below indicate things that you will have to implement.

        // begin code ——————————————–
        // vector with allowed users of this bot 
        // (my old-man-habit: end the sequence with a zero, i.e. an invalid ID)
        int32_t theIDs[MY_BOT_MAX_USERS] = {
          …..
        };

        ….. here goes your globals, setup() and any other initialisation

        void loop()
        {  
        TBMessage msg;     // telegram message data 
        int8_t  iAdmin = 0;  // index of whose receiving the alerts
        int iOk;

        …. check if there are new messages and collect the content

        // in case a message is present, sender is checked against the vector of legitimate users
          for(iOk=0; iOk<MY_BOT_MAX_USERS; iOk++) {  // legitimate user ?
              if (theIDs[iOk] == msg.sender.id) break;  
           }

          if ( (iOk<MY_BOT_MAX_USERS) && (theIDs[iOk] != 0) ) {    // …redundancy is my second name  
        …. OK – may process message and respond to caller 
        }
          else { iOk = -1; }  /* ignore the message */

          … here insert the code for the things your bot will do

          // finally, bot may want to reply… 
        if (iOk < 0)  { // inform the current "administrator"     
        myBot.sendMessage(iAdmin, "Alert: unknown user");
          }  else { // reply to the sender     
        myBot.sendMessage(msg.sender.id, your_message_goes_here);
          }

        … some cleanning  may go here

        } // loop ends here

        // end code —————————————————-

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.