A Versatile (Door) Alarm System With Telegram Bot & RF Remote Control

by Ernest Nga in Circuits > Microcontrollers

1244 Views, 5 Favorites, 0 Comments

A Versatile (Door) Alarm System With Telegram Bot & RF Remote Control

20210719_144924_0000.png

Many entry alert systems require an outer interface such as keypad, fingerprint sensor or RFID reader. This requires electronic components to be installed on both sides of the door. However, such configuration could be tricky in certain use cases.

The goal of this project is to make the alert system portable and versatile, which unlocks its potential to be used in a vast number of places such as:

  • windows
  • table drawers, wardrobes and boxes
  • hotel rooms and college accommodation
  • and more!

This is achieved by activating or deactivating alarm remotely / from a short distance - so we can communicate with the microcontroller hidden behind the door without any physical component on the outside.

In this project, we explore how to use a radio frequency remote control to turn the alarm on or off. By creating a Telegram bot ourselves, we can get message notification on Telegram when the alarm is triggered. At the same time, there are additional functionalities to activate / deactivate alarm by messaging the bot, and to check whether the door is closed and alarm is activated.

Demonstration

A Versatile (Door) Alarm System With Telegram Bot & RF Remote Control - on Instructables

When the door is open and the alarm is on, the microcontroller will take a few seconds to send a Telegram message before triggering the buzzer (alternatively, you can change the order). The buzzer cannot be turned off by closing the door - user can only deactivate it by RF remote control or Telegram message.

Supplies

IMG_20210719_153059_1.jpg
  1. ESP8266 NodeMCU (or ESP 32)
  2. YK04 RF Remote Control Transmitter Receiver Module
  3. Passive buzzer
  4. Magnetic reed switch
  5. Jumper wires
  6. USB Micro B cable
  7. Two 1k ohm resistors and one 220 ohm resistor (resistor divider to convert 5V to 3.3V)
  8. Mini breadboard
  9. Cardboard box
  10. Powerbank

Circuit Connection

Annotation 2021-07-18 231915.png
IMG_20210719_142028_1.jpg

5V and 3.3V

  • ESP8266 board operates at 3.3V but the YK04 radio frequency remote control module uses 5V. Therefore, we construct a simple voltage divider circuit to convert the output voltage to a value close to 3.3V. Two 1k ohm resistors are connected in parallel to make the effective resistance 500 ohm. Hence the ratio of 500 ohm resistance to total resistance (720 ohm) is close to the desired ratio of 0.66.

Digital input - what to expect

  • When the magnet and the reed switch are together, the circuit is completed hence the GPIO pin reads LOW. When the magnet is further away, or if the wire of the magnetic contact switch is cut off by intruder, the GPIO pin will read HIGH as the pin is pulled up internally
  • When YK04 module receives signal from the RF remote control, the GPIO pin reads HIGH. Otherwise, it's LOW

Telegram Bot

Screenshot_20210719-143332.png

We will use BotFather bot to create our own bot

  1. Search for @BotFather on Telegram
  2. Press /start
  3. Type /newbot
  4. Follow the instructions and enter your bot's name and username
  5. You will receive a message containing the bot's token, which will be needed later
  6. Use /mybot command to edit the bot we have just created. You may change the bot's name, description, profile picture etc

To receive messages from our bot, we'll need to specify our Telegram user id. We will also implement codes to check that all messages received by the bot are from us.

  1. Search for @myidbot on Telegram
  2. Press /start
  3. Use /getid command to get our Telegram User ID. Save this for later

In our code, we will include Universal Telegram Bot Library by Brian Lough.

Code With Arduino IDE

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

///////////////////////////////////////////////

// Replace with your network credentials
const char* ssid = "XXXXXXXX";
const char* password = "XXXXXXXXXXX";

// your Bot Token (Get from @BotFather)
#define BOTtoken "XXXXXXXXXX:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
// chat ID of an individual or a group (Get from @myidbot)
#define CHAT_ID "XXXXXXXXXX"

// Pin number
const int doorSensor = D5; 
const int buzzerPin = D3;
const int radioPin = D8;

// Status of door and alarm, updated by ISR or received message
volatile bool doorTrigger = false;
volatile bool alarmTrigger = false;

// Checks for new messages every 1 second, refer to loop() function
int botDelay = 1000;
unsigned long lastTimeGotMessage = 0;

///////////////////////////////////////////////

#ifdef ESP8266
  X509List cert(TELEGRAM_CERTIFICATE_ROOT);
#endif

WiFiClientSecure client;
UniversalTelegramBot bot(BOTtoken, client);

// ISR callback function
void ICACHE_RAM_ATTR detectsDoorTrigger() {
  doorTrigger = true;
}

// ISR callback function
void ICACHE_RAM_ATTR detectsAlarmTrigger() {
  alarmTrigger = !alarmTrigger;
}


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

    if (text == "/start"){
      String welcome = "Welcome!\n";
      welcome += "Use the following commands to control your entry system\n\n";
      welcome += "/status to check if the door is open or closed\n";
      welcome += "/alarm_on to disable alarm\n";
      welcome += "/alarm_off to enable alarm\n";
      bot.sendMessage(chat_id, welcome, "");
    }

    else if (text == "/status") {
      String outputstr = "";
      outputstr += "Door is ";
      (digitalRead(doorSensor)) ? outputstr += "OPEN " : outputstr += "CLOSED ";
      outputstr += "and alarm is ";
      (alarmTrigger) ? outputstr += "ON" : outputstr += "OFF";
      bot.sendMessage(chat_id, outputstr, "");
    }

    else if (text == "/alarm_on") {
      alarmTrigger = true;
      bot.sendMessage(chat_id, "Alarm is now ON", "");
    }

    else if (text == "/alarm_off") {
      alarmTrigger = false;
      bot.sendMessage(chat_id, "Alarm is now OFF", "");
    }

    else {
      bot.sendMessage(chat_id, "Wrong command. Try /start", "");
    }
    
  }
}

// check if there is any unread messages
void checkNewMessages() {
    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);
    }
    lastTimeGotMessage = millis();
}


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(doorSensor, INPUT_PULLUP);
  pinMode(radioPin, INPUT);
  // Set doorSensor pin and radioPin as interrupt, assign interrupt function and set RISING mode
  attachInterrupt(digitalPinToInterrupt(doorSensor), detectsDoorTrigger, RISING);
  attachInterrupt(digitalPinToInterrupt(radioPin), detectsAlarmTrigger, RISING);

  // Attempt to connect to Wifi network:
  Serial.print("Connecting Wifi: ");
  Serial.println(ssid);

  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) {
    Serial.print(".");
    delay(500);
  }

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());

  bot.sendMessage(CHAT_ID, "Bot started up", "");
}

void loop() {
  if(doorTrigger && alarmTrigger){
    Serial.println("Alert!! Door alarm is triggered");
    bot.sendMessage(CHAT_ID, "Alert!! Door alarm is triggered", "");
    tone(buzzerPin, 400);
    while (alarmTrigger){
      checkNewMessages();
      delay(100);
    }
    noTone(buzzerPin);
    doorTrigger = false;
  }
  
  if (doorTrigger && !alarmTrigger) doorTrigger = false;
  
  if (millis() > lastTimeGotMessage + botDelay)  {
    checkNewMessages();
  }

}

Code Explanation

If this is your first project with ESP8266 NodeMCU, you may need to do the following:

Check if you have the following libraries installed. If not, head over to the "Sketch" menu and click Include Library > Manage Libraries, then search for the names of the following libraries to install them.

  • Universal Telegram Bot Library by Brian Lough
  • ArduinoJson Library

You'll need to replace your network's SSID, password, telegram bot token and telegram chat id.

// Look for the following line in the code sample above and replace the value
const char* ssid = "XXXXXXXX";
const char* password = "XXXXXXXXXXX";
#define BOTtoken "XXXXXXXXXX:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
#define CHAT_ID "XXXXXXXXXX"

The main idea is as follows:

To ensure that the RF remote control signal is not missed, we use interrupt service routines (ISR) to update the global variable alarmTrigger when the digital input goes from LOW to HIGH (button on RF remote control is pressed). The same button is used to activate and deactivate the alarm. Similarly, we use ISR to update doorTrigger if there is any changes in the digital input from magnetic contact sensor.

In the loop() function, we are checking if the global variables doorTrigger and alarmTrigger are both true, as well as checking for any new Telegram messages.

void loop() {
  if (doorTrigger && alarmTrigger) {
    // send an alert message and turn the buzzer on
    // "trap" using a while loop, keep checking for new message until alarmTrigger is set to false 
    // by Telegram bot or by remote control
  }
  if (doorTrigger && !alarmTrigger) {
    // doorTrigger should be set to false. It's not a valid trigger as alarm is off
  }  
  if (millis() > lastTimeGotMessage + botDelay)  {
    // check if there is a new message but only
    // after it has been more than botDelay milliseconds since the last time we checked it
  }
}

Reference and Useful Resources