Integrate Your Telegram Bot With Real World via ESP32/ESP8266 Arduino Microcontroller

Written by chingiz | Published 2022/03/20
Tech Story Tags: arduino | arduino-tutorial | telegram | telegram-bot | build-a-telegram-bot | esp8266 | esp32 | tutorial

TLDRIn this article, I will tell you how to write a telegram bot that integrates with the real world via a microcontroller (Arduino) I will explain everything through a practical project from my experience. I did a project for controlling the queue to our office gaming room by Arduino-based Telegram. The Arduino with servo motor was installed to lock and unlock the door. We will control it with our microcontroller by processing messages from users. The project code is published on my GitHub project page.via the TL;DR App

In this article, I will tell you how to write a telegram bot that integrates with the real world via a

microcontroller (Arduino).

Everything is remembered better in practice. So, I will explain everything through a practical project from my experience. The project code is published on my GitHub ‘Smart Queue’ project page. This article will explain how to create a telegram bot, process messages, and respond to users. Also, in the end, will be given some ideas for future projects for you.

Shortly about project

I did a project for controlling the queue to our office gaming room by Arduino-based Telegram. The Arduino with servo motor was installed to lock and unlock the door. People could take a queue and check how many people were in the queue via telegram bot.

In this project, NodeMCU has been used but the same logic works for Arduino with ESP32/ESP8266.

Telegram

Telegram is a messenger with mobile applications (iPhone and Android) and desktop applications (Mac, Windows, and Linux). In Telegram, we have an opportunity to create a bot. We will control it with our microcontroller by processing messages from users.

Creating Telegram Bot

To create a Telegram Bot, we need to request it from the “botfather” telegram bot. All you need is to find the bot by search or get it by the link: https://t.me/botfather. The bot is user-friendly and as you open the chat with the bot, our next steps should be clear for you.

Send /start command to start the bot. Send /newbot command to create a new bot. We will be asked to enter the name and username of the new bot. After the successful creation of the bot, the botfather will send us a token. This one will be required to receive all messages sent to the bot and send messages from the bot to users.

Connection

We will use a servo motor to lock and unlock the door and an LED to indicate if the door is locked.

Servo motors have 3 pins: orange, red and brown: Red - 5V, Brown - GND, Orange - 14. LED connected to pin 2.

Code

First of all, we should import all required libraries:

#ifdef ESP32
  #include <WiFi.h>
#else
  #include <ESP8266WiFi.h>
#endif
#include <WiFiClientSecure.h>
#include <UniversalTelegramBot.h>  
#include <ArduinoJson.h>

#include <Servo.h>
Servo myservo;

Write credentials of wi-fi to which microcontroller will be connected:

const char* ssid = "";      //wifi name
const char* password = "";  //wifi password

Write token of our bot, which we received after its creation:

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

Define the outputs and other required variables:

// Checks for new messages every 0.1 second.
int botRequestDelay = 100;
unsigned long lastTimeBotRan;

int servo_pin = 14;//servo pin
int servo_locked_value = 180;
int servo_unlocked_value = 30;

const int ledPin = 2;

String queue[10] ={};//array of queue
int queue_array_len = 0;//len of queue
bool room_is_free = true;//initially the room is free
bool door_is_locked = true;// the door is locked

Create a new wi-fi client and a bot with the token and the client:

WiFiClientSecure client;
UniversalTelegramBot bot(BOTtoken, client);

In the setup section we will initialize led and servo, begin serial and connect to wi-fi:

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, HIGH);
  
  // 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());

  //Servo - close:
  myservo.attach(servo_pin);
  myservo.write(180);
}

In the loop section we will do three main things:

  • check if there are any new messages to the telegram bot;
  • check if the room is free and if so, invite the next person in the queue;
  • indicate if door locked and open/close the door

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();

    //check if the room free
    if(room_is_free ==true && queue[0]!=""){
      room_is_free = false;
      //invite to the room:
      Serial.println("Invinting to the room: "+queue[0]);
      bot.sendMessage(queue[0], "The room is free! \n Please come and send /unlock_the_door_from_outside to unlock the door.", "");
    }

    //Indicating and opening/closing the door:
    digitalWrite(ledPin, door_is_locked);//ledState
    if(door_is_locked){
      myservo.write(servo_locked_value);//locked
    }else{
      myservo.write(servo_unlocked_value);//unlocked
    }
    
  }
}

Here is how we will handle new messages and respond to /start message:

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);

    // Print the received message
    String text = bot.messages[i].text;
    Serial.print("From: ");Serial.println(chat_id);
    Serial.print("Message: ");Serial.println(text);

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

    if (text == "/start") {
      String welcome = "Welcome, " + from_name + ".\n";
      welcome += "By this bot you can stand in line to the Gaming room.\n";
      welcome += "Please see my /options.\n\n";
      bot.sendMessage(chat_id, welcome, "");
    }    
  }
}

Here is how we respond to /options message and send buttons for easy interactions:

if (text == "/options") {
  String keyboardJson = "[[\"/Stand_in_line\"],[\"/cancel\", \"/status\"]]";
  bot.sendMessageWithReplyKeyboard(chat_id, "Here is my options:", "", keyboardJson, true);
}

When we receive /Stand_in_line message we need to check if person already in the queue and if not add the person to the queue and inform it:

if (text == "/Stand_in_line") {
  //check if person already in the queue:
  if(if_chat_id_not_in_queue(chat_id)){
    //add person to the queue
    queue[queue_array_len] = chat_id;//array of queue
    queue_array_len++;
    bot.sendMessage(chat_id, "You joined the queue.", "");
  }else{
    bot.sendMessage(chat_id, "You are already in the queue.", "");
  }
      
  //printing the queue
  print_queue();
}

**
**

When we receive /cancel message, we need to remove the person from the queue by checking if he is there. Also if the person was already invited to the room, we will set the room status back to free.

if (text == "/cancel") {
  //check if person already in the queue:
  if(if_chat_id_not_in_queue(chat_id)){
    bot.sendMessage(chat_id, "You were not in the queue.", "");
  }else{
    //checking if the person first one to set room to free again.
    if (queue[0]=chat_id){
      room_is_free = true;
    }   
    //remove person from the queue
    for(int i = 0; i < queue_array_len; i++){
      if(queue[i]=chat_id){
        queue[i] = "";
        //move items after the deleted one:
        for(int j = i;j < queue_array_len; j++){
          queue[j] = queue[j+1];
        }
      }
    }
    queue_array_len--;
    bot.sendMessage(chat_id, "You are no longer in the queue.", "");

    //printing the queue
    print_queue();
  }
}

When we receive /status message, we will send how many persons in the queue and if person in it, we will also send person's position in the queue:

if (text == "/status") {
  //printing the queue
  print_queue();
      
  int current_person_id_in_queue = -1;
  for(int i = 0; i < queue_array_len; i++){
    if(queue[i]==chat_id){
      current_person_id_in_queue = i+1;
    }
  }
  String message = "The queue consist of " + String(queue_array_len ) + " person(s).\n";
  if(current_person_id_in_queue != -1){
        message +="You are #"+String(current_person_id_in_queue)+ " in line.\n";
  }
      
  bot.sendMessage(chat_id, message, "");
}

When person queue comes, we will send an invitation message:

When we receive /unlock_the_door_from_outside message we need to check if the person is first in the queue and if so, unlock the door and send response:

if (text == "/unlock_the_door_from_outside") {
  //checking if this first person in queue:
  if(chat_id == queue[0]){
    door_is_locked = false;
    myservo.write(servo_unlocked_value);//unlocked
    bot.sendMessage(chat_id, "The door is unlocked! \nCome in and lock the door by sending /lock_the_door_from_inside.", "");
  }else{
    bot.sendMessage(chat_id, "Something went wrong. \nPlease try to check your status in queue by /status command.", "");
  }
}

In the next /lock_the_door_from_inside and /unlock_the_door_from_inside commands as before we need to check if the person is the first one in the queue. We do this to make sure the door is locked or unlocked by the right person.

For /lock_the_door_from_inside message, we need to just lock the door:

if (text == "/lock_the_door_from_inside") {
  //checking if this first person in queue:
  if(chat_id == queue[0]){
    door_is_locked = true;
    myservo.write(servo_locked_value);//locked
    bot.sendMessage(chat_id, "The door is locked! \nTo unlock the door send /unlock_the_door_from_inside.", "");
  }else{
    bot.sendMessage(chat_id, "Something went wrong. \nPlease try to check your status in queue by /status command.", "");
  }
}

As we receive /unlock_the_door_from_inside message, we will unlock the door for three seconds and lock it back. Also, we will remove the person from the queue and set the room status back to free. This required to invite next person from the queue:

if (text == "/unlock_the_door_from_inside") {
    //checking if this first person in queue:
    if(chat_id == queue[0]){
    door_is_locked = false;
    myservo.write(servo_unlocked_value);//unlocked
    bot.sendMessage(chat_id, "The door is unlocked! We will lock it in 3 sec", "");
    delay(3000);
    door_is_locked = true;
    room_is_free = true;
    myservo.write(servo_locked_value);//locked
        
    //remove the person from the queue
    for(int i = 0; i < queue_array_len; i++){
        if(queue[i]=chat_id){
        queue[i] = "";
        //move items after the deleted one:
        for(int j = i;j < queue_array_len; j++){
            queue[j] = queue[j+1];
        }
        }
    }
    queue_array_len--;
    bot.sendMessage(chat_id, "The door is locked. Bye!", "");

    }else{
    bot.sendMessage(chat_id, "Something went wrong. \nPlease try to check your status in queue by /status command.", "");
    }
}

Here are our helper functions. These two parts of the code are used many times. So, I decided to separate them for convenience of the code:

//check if person already in the queue:
bool if_chat_id_not_in_queue(String chat_id){
  for(int i = 0; i < queue_array_len; i++){ 
    if(chat_id == queue[i]){
      return false;
    }
  }
  return true;
}

//printing the queue
void print_queue(){
  Serial.print("In queue - ");Serial.println(queue_array_len);
  for(int i = 0; i < queue_array_len; i++){
    Serial.println(queue[i]);
  }
}

Conclusion

Through this tutorial you’ve learned how to interact with your microcontroller with Telegram Bot.

The microcontroller can process messages sent to the bot and send messages back.

This project is an example and showcase for you. The possibilities are limited by your imagination. Here are some ideas for you: make a Motion Detector which will send a message as motion will be detected; connect a camera module and send image by request; control LED strip or get any sensor indication. Also, there could be done global project such as making a big led matrix and giving control of it to everyone by telegram bot.

The great thing about integrated Telegram bot projects is that they can be controlled from anywhere in the world. This gives your projects the opportunity to reach a new level.


Written by chingiz | Love Robotics and IoT
Published by HackerNoon on 2022/03/20