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!

If you want to use the Signal messenger service, check here.

32 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 —————————————————-

    1. Where does it go wrong?
      Did you create a bot?
      Did you get your API ?
      Did you get your chat ID?

      I am a bit confused as there are no approachES, there is only one way to go and you have to do all 3 steps. Where exactly did it go wrong?

  2. Hello, the explanation is very good, but I loaded the program, it executes it, but it only sends the welcome message, and when I want to send some command “/led_on” that message does not reach the esp and it does not receive anything else. What could be the error? Thanks

    1. Sorry to hear that. The text contains a section ‘if it does not work’. Did you go through those options?

  3. Hallo, thanks firstly! Your site is good explained!
    But I dont yet understand one thing: I want to send a command with curl to my ESP8266 as if I would send ‚Äú/start‚ÄĚ or ‚Äú/status‚ÄĚ or any command which I have in my sketch, uploaded to my ESP8266.
    When I send the sendMessage command with my text, it is send from the Bot, but not to my ESP8266.
    I might have not understood the whole thing ūüėČ
    Thanks. frank.

  4. I don’t get it. When I send /start to the bot from my phone (in Telegram), the ESP answers with the programmed code from my sketch (switching on e.g. the LED).
    What could I send with curl from my phone to do exact that?
    I want to use https requests in Tasker, so I don’t need to open telegram.
    Thank.

    1. Ah ok, i understand. I did not try it myself but i would think it iscurl –data chat_id=”892915001″ –data “text=/start” “https://api.telegram.org/bot977142506:AAGYWypUbMN8BCthML-tFM25M403r2yCsFj/sendMessage

      Or did you try that already?

      I do not use tasker, but i have an ESP sending messages to my phone via Telegram. I am on mobile right now so will check later (that will be in C++ though)

      1. Yes, I tried that. First I got my chat_id with your howto (thanks!) and then I tried this with curl. But I get then in my Telegram chat just the text, e.g. /start coming from the bot (as answer) but not the “real” answer of my ESP, which should be then to send me all possible commands (with /start, or to switch the led on, with /ledon, etc.). That is why I thought that the answer is NOT coming from my ESP but only from the bot.

        I wonder why this is not a common setting, what I want to do. I mean: automate things means to use less manual commands, aint it?
        I want to build a switch on my phone to open the main door from our house. I want to have just an icon “Open Door” or “Sesamy” something like this, I dont want to open Telegram chat and type in the command, this is no much automatized engough ūüėČ
        Thanks!

  5. Yes, i see your problem. Controlling a device via telegram is possible when opening the telegram app, but that is not what you want. I am not sure if a telegram channel is to be controlled directly while bypassing the app. Have not been able to find anything on that and I would think the telegram owners are not interested in making that available.
    Initially I thought you wanted the other way around: receiving telegram messages from some project on your phone.
    For what you want I see only 3 options (other than opening your telegram app):
    make an app and put that on your phone (e.g. through MIT app inventor)
    make a web server that has the two buttons and put that as icon on your phone
    make a PWA (Progressive Web App) that does that.
    Sorry, that I do not see a possibility of using telegram for that in the way you want

    1. Thank you very much! I appreciate your help!
      I guess I will keep it simple, I already spent more time in this that I wanted, I will just put the command (/open) in every answer from my ESP sketch.
      So I open my chat with my Telegram-Bot on my phone (I can create shortcuts to a special Telegram-chat, this is possible, I can even configure the Button on my phone’s desktop as I use good old Lightning Launcher) and the last message is there e.g.:

      Press /open to open the door or /status for the ESP-status
      /open /status

      That is a bit like a single button. Needs two clicks but thats okay.
      When I click /open (or /status), the ESP opens (or shows some status) AND sends again the upper message, so I dont need to scroll or type.
      Developing an own App for it would take weeks for me, even implent the webserver on the ESP seems to long for me (though I think there are many examples for ESP-webserver already and libraries). And PWA I havent even heard ūüėČ
      Thank!

      1. I think you will be saving yourself a lot of work doing it that way.
        PWA: Well, learned something new then. Goodluck

  6. One next, maybe last thought: If I had the chat_id from the Bot, I could do what I want.

    I did some tests with my sketch and gave out with Serial.print() the chat_id the sketch uses.
    First I wondered that this is the same chat_id than I got from IDBot, but then I realized, this is my chat_id and this exactly is the reason why my curl message to this chat_id was send to me, but not to my NodeMCU (which gets the messages sent from my phone and Telegram).

    So the question is: does the bot himself has a chat_id? Or has the Bot only that “Bot Token”?

    I doubt a Bot has a chat_id, at least one I could find ūüė¶

    1. If it does have a chat_id, i would not know what it is. Even if you had it i am not sure if it would help you to do what you want

      1. Yeah, will stick to my “solution”.

        But just curious, I tested to send a message (/open) to my bot from another Telegram account (connected to another phonenumber) – and what surprise, I could easily send my commands to the ESP and they are commuted!
        This is not a good idea for a door opener, everybody could then open the front door of the house where I live!

        I need to implement a kind of code and also I will name the bot something not easy, e.g. 7cef8a734855777c2a9d0caf42666e69_bot (this hash is “open” > md5).
        At the moment the bot’s name is human readable.

    1. Sorry, hit the wrong button…
      There is in the “UniversalTelegramBot” Object in the structure “telegramMessage” of this library I use (Universal-Arduino-Telegram-Bot) more than the text, I can filter by chat_id, which is individual. So if I grant only access to my own (and my wife’s) chat_id there shouldnt be any security issues (if someone steals my phone and could open it, there are much worse security issues).
      So I send /open to my Bot and only if the chat_id fits to my sketch, the door will open ūüôā

  7. By the way, the Bot has indeed a Chat-ID, it is as easy as the fist part of the token, the numbers, which is obvious (when I thought a bit about it). BUT: when I send with curl a message to my Bot, as (where Bot’s chat_id is here 1234567890, found in the token) e.g.:

    curl https://api.telegram.org/bot1234567890:ABCDef-A123B456C789D012etceterablabla00/sendMessage –data chat_id=1234567890 –data text/info

    then I get from Telegram this answer:

    {“ok”:false,”error_code”:403,”description”:”Forbidden: bot can’t send messages to bots”}

    So it is definetly not possible to send as Bot to the Bot.

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 )

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.

%d bloggers like this: