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
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 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.
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:
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.
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.
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:
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]);
}
}
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
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.