In this project, we’ll use an Myduino AIoT Education Kit with built-in PIR motion sensor, LEDs, and the UniversalTelegramBot library to build a Motion Alert System with Telegram Notifications. You’ll be able to detect motion and instantly receive notifications on your Telegram chat, plus get visual feedback through LEDs. The system connects to WiFi and sends real-time alerts whenever motion is detected.
Perfect for students, makers, or IoT beginners who want to explore motion sensing + instant messaging notifications integration with ESP32. Let’s go from zero to hero!
Objective
In this project, you’ll learn how to:
- Detect motion with a PIR sensor and trigger LED indicators.
- Connect ESP32 to WiFi network for internet connectivity.
- Send instant Telegram messages when motion is detected.
- Create a Telegram bot and obtain bot token for messaging.
- Understand how sensors, WiFi, and messaging APIs work together in IoT systems.
By the end, you’ll have your own Motion Alert System with Telegram notifications running on ESP32!
Circuit Connections

| Components | ESP32 Dev Module |
| PIR Sensor | IO2 |
| Green LED | IO16 |
| Red LED | IO17 |
| Buzzer | IO4 |
Logic Flow
- ESP32 connects to WiFi network on startup.
- The PIR motion sensor continuously monitors for movement.
- Motion Detection: When motion is detected:
- Red LED turns ON for 3 seconds
- Green status LED blinks to show activity
- Gentle buzzer notification (3 pleasant beeps at 800Hz)
- System sends instant Telegram message with timestamp
- Status Monitoring: Green LED shows system is active and connected.
- Cooldown Period: Prevents spam by waiting 10 seconds between detections.
Telegram Setup
Step 1: Create Telegram Bot
- Open Telegram app and search for “BotFather”

- Open the bot and click “Start” or type “/start”

- Click or type “/newbot”

- Put any name for your bot project. For me, I put Motion Detection Telegram

- Now choose username for your bot but must end the username with “bot”

- Then you will get the Bot channel and token that you will use later in Arduino IDE. Save the token and do not share it to anyone without your permission. Your token will looks like this: “123456789:ABCdefGhIJKlmNoPQRsTUVwxyZ”

- Now you need to search “IDBot” to get you Telegram Chat ID

- Click “Start” or type “/start”. Then you type “/getid”. You will get your Telegram Chat ID. Do not share your ID with anyone. Your ID will looks like: “111213149”

Code Lab
Step 1: Install Libraries
Before you upload the code, you need to install the libraries first in Arduino IDE. Search this in the Library Manager:
- UniversalTelegramBot.h by Brian Lough (for telegram messaging)
- ArduinoJson.h by Benoit Blanchon (dependency for Telegram bot)
- WiFi.h (already included in ESP32, no need to download)
For example:

Step 2: Code
Copy and paste this code into Arduino IDE:
#include <WiFi.h>
#include <WiFiClientSecure.h>
#include <UniversalTelegramBot.h>
#include <ArduinoJson.h>
// WiFi credentials
const char* ssid = "YOUR_WIFI_SSID";
const char* password = "YOUR_WIFI_PASSWORD";
// Telegram bot credentials
#define BOT_TOKEN "YOUR_BIT_TOKEN"
#define CHAT_ID "YOUR_CHAT_ID"
// Pin definitions
#define PIR_PIN 2 // PIR motion sensor pin
#define GREEN_LED_PIN 16 // Status LED (Green)
#define RED_LED_PIN 17 // Alert LED (Red)
#define BUZZER_PIN 4 // Buzzer pin
// Telegram setup
WiFiClientSecure client;
UniversalTelegramBot bot(BOT_TOKEN, client);
// Variables
bool motionDetected = false;
unsigned long lastMotionTime = 0;
unsigned long motionCooldown = 10000; // 10 seconds cooldown
unsigned long ledOffTime = 0;
bool ledState = false;
unsigned long lastStatusBlink = 0;
unsigned long lastBotCheck = 0;
void setup() {
Serial.begin(115200);
// Initialize pins
pinMode(PIR_PIN, INPUT);
pinMode(GREEN_LED_PIN, OUTPUT);
pinMode(RED_LED_PIN, OUTPUT);
pinMode(BUZZER_PIN, OUTPUT);
// Initial LED and buzzer state
digitalWrite(GREEN_LED_PIN, LOW);
digitalWrite(RED_LED_PIN, LOW);
digitalWrite(BUZZER_PIN, LOW);
// Connect to WiFi
Serial.print("Connecting to WiFi");
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.print(".");
// Blink red LED while connecting
digitalWrite(RED_LED_PIN, !digitalRead(RED_LED_PIN));
}
Serial.println("");
Serial.println("WiFi connected!");
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
// Turn off red LED and turn on green LED (connected)
digitalWrite(RED_LED_PIN, LOW);
digitalWrite(GREEN_LED_PIN, HIGH);
// Configure secure client - IMPORTANT FIX
client.setInsecure(); // For simplicity, not recommended for production
// Add delay before first Telegram message
delay(2000);
// Test Telegram connection
Serial.println("Testing Telegram connection...");
bool messageStatus = sendTelegramMessage(" Motion Detection System Started!\n WiFi Connected\n System Ready");
if (messageStatus) {
Serial.println(" Telegram test message sent successfully!");
playStartupSound();
} else {
Serial.println("❌ Failed to send Telegram test message");
// Blink red LED to indicate Telegram error
for (int i = 0; i < 5; i++) {
digitalWrite(RED_LED_PIN, HIGH);
delay(200);
digitalWrite(RED_LED_PIN, LOW);
delay(200);
}
}
Serial.println("Motion Detection System Initialized");
Serial.println("Waiting for motion...");
}
void loop() {
// Read PIR sensor
int pirValue = digitalRead(PIR_PIN);
unsigned long currentTime = millis();
// Handle bot messages (important for keeping connection alive)
if (currentTime - lastBotCheck > 1000) {
bot.getUpdates(bot.last_message_received + 1);
lastBotCheck = currentTime;
}
// Check for motion detection
if (pirValue == HIGH && !motionDetected && (currentTime - lastMotionTime > motionCooldown)) {
motionDetected = true;
lastMotionTime = currentTime;
ledOffTime = currentTime + 3000; // Turn off LED after 3 seconds
// Turn on red alert LED
digitalWrite(RED_LED_PIN, HIGH);
// Play gentle notification sound
playGentleAlert();
// Send Telegram alert
String message = "🚨 MOTION DETECTED! 🚨\n";
message += "📍 Location: ESP32 Motion Sensor\n";
message += "⚠️ Alert: Movement detected in monitored area";
bool alertSent = sendTelegramMessage(message);
if (alertSent) {
Serial.println(" Motion alert sent to Telegram successfully!");
} else {
Serial.println("❌ Failed to send motion alert to Telegram");
}
} else if (pirValue == LOW) {
motionDetected = false;
}
// Turn off red LED after 3 seconds
if (ledOffTime > 0 && currentTime > ledOffTime) {
digitalWrite(RED_LED_PIN, LOW);
ledOffTime = 0;
}
// Blink green status LED to show system is active
if (currentTime - lastStatusBlink > 2000) {
ledState = !ledState;
digitalWrite(GREEN_LED_PIN, ledState);
lastStatusBlink = currentTime;
}
delay(100);
}
bool sendTelegramMessage(String message) {
Serial.println("Attempting to send Telegram message...");
Serial.println("Message: " + message);
Serial.println("Chat ID: " + String(CHAT_ID));
if (WiFi.status() != WL_CONNECTED) {
Serial.println("❌ WiFi not connected!");
return false;
}
// Check if bot token and chat ID are set
if (strlen(BOT_TOKEN) == 0 || strlen(CHAT_ID) == 0) {
Serial.println("❌ Bot token or Chat ID is empty!");
return false;
}
// Try to send message
bool result = bot.sendMessage(CHAT_ID, message, "");
if (result) {
Serial.println(" Telegram message sent successfully!");
return true;
} else {
Serial.println("❌ Failed to send Telegram message");
// Additional debugging
Serial.println("Debug info:");
Serial.println("- WiFi Status: " + String(WiFi.status()));
Serial.println("- Free Heap: " + String(ESP.getFreeHeap()));
Serial.println("- Bot Token Length: " + String(strlen(BOT_TOKEN)));
Serial.println("- Chat ID: " + String(CHAT_ID));
return false;
}
}
String getFormattedTime() {
unsigned long currentTime = millis();
unsigned long seconds = currentTime / 1000;
unsigned long minutes = seconds / 60;
unsigned long hours = minutes / 60;
seconds %= 60;
minutes %= 60;
hours %= 24;
String timeString = "";
if (hours < 10) timeString += "0";
timeString += String(hours) + ":";
if (minutes < 10) timeString += "0";
timeString += String(minutes) + ":";
if (seconds < 10) timeString += "0";
timeString += String(seconds);
return timeString + " (System Uptime)";
}
void playGentleAlert() {
// Play 3 gentle beeps - pleasant and not annoying
for (int i = 0; i < 3; i++) {
tone(BUZZER_PIN, 800, 150); // 800Hz frequency, 150ms duration
delay(200); // Wait 200ms between beeps
}
noTone(BUZZER_PIN); // Ensure buzzer is off
}
void playStartupSound() {
// Play 2 beeps to indicate system ready
for (int i = 0; i < 2; i++) {
tone(BUZZER_PIN, 1000, 100); // 1000Hz frequency, 100ms duration
delay(150);
}
noTone(BUZZER_PIN);
}
Step 3: Configuration
- Replace WiFi credentials with your own WiFi or Hotspot:

2. Replace the Telegram credentials:

Step 4: Upload and Run
- Connect your ESP32 board with your computer/laptop
- Select the correct board (ESP32 Dev Module) and port in Arduino IDE
- Upload the code
- Open Serial Monitor at 115200 baud
- Wait for WiFi connection and system initialization (you’ll hear 2 startup beeps)
- Move in front of the PIR sensor to test (you’ll hear 3 gentle beeps)
System Check
When working properly:
- WiFi Connection: Green LED stays solid, Serial Monitor shows IP address
- Startup Sound: 2 beeps when system initializes successfully
- Motion Detection: Red LED turns on for 3 seconds when motion detected
- Audio Alert: 3 gentle beeps when motion detected
- Telegram Alerts: Instant messages sent to your Telegram chat with timestamp
- Status Indication: Green LED blinks every 2 seconds showing the system is active
- Cooldown: 10 seconds delay between motion detections to prevent spam messages
Troubleshooting Guide
| Problem | Solution |
| WiFi not connecting | Check SSID and password. Ensure your network 2.4GHz frequency(ESP32 not support 5GHz frequency). |
| No Telegram messages | Check the Bot Token and Chat ID. Check internet connection. |
| PIR sensor not detecting | Check connection pin is IO2 |
| LEDs not working | Check connections Green LED pin is IO16, Red LED is IO17 |
| Buzzer not working | Check buzzer connection to IO4 |
| Compile errors | Install required libraries: UniversalTelegramBot and ArduinoJson |
| Buzzer to loud/annoying | Adjust frequency (800Hz) or duration (150ms) in playGentleAlert() function |
| Telegram Bot not responding | Ensure the bot is active, try sending “/start” to your bot first |
Tips: If you want to find any lines in Arduino IDE, click CTRL+F (CMD + F on Mac) and search the line you want to find (applicable to any platform).
Advanced Features & Customizations
Custom Alert Sounds
// You can try change the value if you want to custom the sound
void playGentleAlert() {
// Option 1: Single pleasant beep
tone(BUZZER_PIN, 1000, 300); // 1000Hz=frequency, 300ms=delay
// Option 2: Two-tone notification
tone(BUZZER_PIN, 800, 200);
delay(100);
tone(BUZZER_PIN, 1200, 200);
// Option 3: Melody pattern
int melody[] = {800, 1000, 1200};
for (int i = 0; i < 3; i++) {
tone(BUZZER_PIN, melody[i], 150);
delay(100);
}
}
Motion Sensitivity
// You can try change the cooldown value here
unsigned long motionCooldown = 5000; // Change to 5 seconds
Custom Messages
String message = "🏠 Home Security Alert!\n";
message += "Motion detected in living room\n";
message += "Time: " + getFormattedTime();
Security Considerations
- Bot Token: Keep your bot token secure and never share publicly
- WiFi: Use WPA2/WPA3 encrypted networks
- Rate Limiting: Implement cooldown to prevent message spam
Perfect for: Home security systems, office monitoring, IoT learning projects, smart home automation, and real-time notification systems with audio feedback!
Buy from:
Myduino AIoT Education Kit (click here) from Myduino.com






