Difficulty: Intermediate
Time Required: 2-3 hours
Cost: $20-30
ESP Board: ESP32-CAM
What You’ll Need
| Component | Approximate Cost | Where to Buy |
|---|---|---|
| ESP32-CAM Module | $6-10 | Amazon / AliExpress |
| FTDI Programmer | $4-6 | Amazon |
| 5V Relay Module | $3-5 | Amazon |
| Push Button | $1-2 | Amazon |
| Buzzer | $1-2 | Amazon |
| Jumper Wires | $2 | Amazon |
| Power Supply (5V) | $3-5 | Amazon |
Circuit Diagram
Connections:
| ESP32-CAM Pin | Component | Notes |
|---|---|---|
| 5V | Relay VCC | Power |
| GND | Relay GND | Ground |
| GPIO 2 | Relay IN | Control signal |
| GPIO 14 | Push Button | Doorbell button |
| 3.3V | Buzzer + | Passive buzzer |
| GND | Buzzer – | Ground |
| U0T (GPIO 1) | FTDI TX | For programming only |
| U0R (GPIO 3) | FTDI RX | For programming only |
Step 1: Install Required Libraries
Open Arduino IDE and install these libraries:
- UniversalTelegramBot – GitHub
- WiFi – Built-in (ESP32)
- ESP32 Camera – Official Library
Note: ESP32-CAM requires special board configuration. See Random Nerd Tutorials for setup.
Step 2: The Complete Code
/*********************************************************************
* ESP32-CAM Smart Doorbell with Telegram Notifications
*
* Features:
* - Motion detection
* - Photo capture on button press
* - Telegram notifications with photo
* - Buzzer alert
*
* Hardware: ESP32-CAM, Relay, Push Button, Buzzer
*
* Libraries Required:
* - UniversalTelegramBot (install from Library Manager)
* - ESP32 Camera (install from Library Manager)
*********************************************************************/
#include
#include
#include
#include "esp_camera.h"
// ============== WIFI CONFIGURATION ==============
const char* wifi_ssid = "YOUR_WIFI_SSID";
const char* wifi_password = "YOUR_WIFI_PASSWORD";
// ============== TELEGRAM CONFIGURATION ==============
#define BOT_TOKEN "YOUR_TELEGRAM_BOT_TOKEN"
#define CHAT_ID "YOUR_CHAT_ID"
WiFiClientSecure client;
UniversalTelegramBot bot(BOT_TOKEN, client);
// ============== PIN CONFIGURATION ==============
#define DOORBELL_BUTTON 14
#define RELAY_PIN 2
#define BUZZER_PIN 12
#define MOTION_SENSOR 13
// ============== CONFIGURATION ==============
#define FLASH_LED_PIN 4
bool doorbellState = false;
unsigned long lastMotionTime = 0;
const unsigned long MOTION_COOLDOWN = 5000; // 5 seconds
// ============== CAMERA PINS (AI-THINKER) ==============
#define PWDN_GPIO_NUM 32
#define RESET_GPIO_NUM -1
#define XCLK_GPIO_NUM 0
#define SDA_GPIO_NUM 26
#define SCL_GPIO_NUM 27
#define Y9_GPIO_NUM 35
#define Y8_GPIO_NUM 34
#define Y7_GPIO_NUM 39
#define Y6_GPIO_NUM 36
#define Y5_GPIO_NUM 21
#define Y4_GPIO_NUM 19
#define Y3_GPIO_NUM 18
#define Y2_GPIO_NUM 5
#define VSYNC_GPIO_NUM 25
#define HREF_GPIO_NUM 23
#define PCLK_GPIO_NUM 22
// ============== SETUP ==============
void setup() {
Serial.begin(115200);
Serial.println(F("\n======================================"));
Serial.println(F("ESP32-CAM Smart Doorbell Starting..."));
Serial.println(F("======================================"));
// Configure pins
pinMode(DOORBELL_BUTTON, INPUT_PULLUP);
pinMode(RELAY_PIN, OUTPUT);
pinMode(BUZZER_PIN, OUTPUT);
pinMode(MOTION_SENSOR, INPUT);
pinMode(FLASH_LED_PIN, OUTPUT);
digitalWrite(RELAY_PIN, LOW);
digitalWrite(BUZZER_PIN, LOW);
digitalWrite(FLASH_LED_PIN, LOW);
// Connect to WiFi
connectToWiFi();
// Initialize Camera
initializeCamera();
// Initialize Telegram
client.setCACert(TELEGRAM_CERTIFICATE_ROOT);
Serial.println(F("Setup complete!"));
Serial.println(F("Doorbell is active. Press button or detect motion..."));
}
// ============== MAIN LOOP ==============
void loop() {
// Check doorbell button
if (digitalRead(DOORBELL_BUTTON) == LOW) {
Serial.println(F("Doorbell pressed!"));
triggerDoorbell();
delay(1000); // Debounce
}
// Check motion sensor
if (digitalRead(MOTION_SENSOR) == HIGH) {
if (millis() - lastMotionTime > MOTION_COOLDOWN) {
Serial.println(F("Motion detected!"));
triggerDoorbell();
lastMotionTime = millis();
}
}
delay(100);
}
// ============== FUNCTIONS ==============
void connectToWiFi() {
Serial.print(F("Connecting to WiFi"));
WiFi.begin(wifi_ssid, wifi_password);
int attempts = 0;
while (WiFi.status() != WL_CONNECTED && attempts < 30) {
delay(500);
Serial.print(F("."));
attempts++;
}
if (WiFi.status() == WL_CONNECTED) {
Serial.println(F(" Connected!"));
Serial.print(F("IP Address: "));
Serial.println(WiFi.localIP());
} else {
Serial.println(F(" Connection failed!"));
}
}
void initializeCamera() {
camera_config_t config;
config.ledc_channel = LEDC_CHANNEL_0;
config.ledc_timer = LEDC_TIMER_0;
config.pin_d0 = Y2_GPIO_NUM;
config.pin_d1 = Y3_GPIO_NUM;
config.pin_d2 = Y4_GPIO_NUM;
config.pin_d3 = Y5_GPIO_NUM;
config.pin_d4 = Y6_GPIO_NUM;
config.pin_d5 = Y7_GPIO_NUM;
config.pin_d6 = Y8_GPIO_NUM;
config.pin_d7 = Y9_GPIO_NUM;
config.pin_xclk = XCLK_GPIO_NUM;
config.pin_pclk = PCLK_GPIO_NUM;
config.pin_vsync = VSYNC_GPIO_NUM;
config.pin_href = HREF_GPIO_NUM;
config.pin_sscb_sda = SDA_GPIO_NUM;
config.pin_sscb_scl = SCL_GPIO_NUM;
config.pin_pwdn = PWDN_GPIO_NUM;
config.pin_reset = RESET_GPIO_NUM;
config.xclk_freq_hz = 20000000;
config.pixel_format = PIXFORMAT_JPEG;
// Init with high quality for face recognition
config.frame_size = FRAMESIZE_SVGA;
config.jpeg_quality = 10;
config.fb_count = 2;
esp_err_t err = esp_camera_init(&config);
if (err != ESP_OK) {
Serial.printf(F("Camera init failed with error 0x%x\n"), err);
return;
}
Serial.println(F("Camera initialized successfully!"));
}
void triggerDoorbell() {
Serial.println(F("=== DOORBELL TRIGGERED ==="));
// Play buzzer sound
playBuzzer();
// Turn on flash LED
digitalWrite(FLASH_LED_PIN, HIGH);
delay(500);
// Capture photo
camera_fb_t *fb = esp_camera_fb_get();
if (fb) {
// Send photo to Telegram
sendTelegramPhoto(fb->buf, fb->len);
esp_camera_fb_return(fb);
}
// Turn off flash
digitalWrite(FLASH_LED_PIN, LOW);
Serial.println(F("Doorbell action complete!"));
}
void playBuzzer() {
// Play doorbell sound
for (int i = 0; i < 3; i++) {
digitalWrite(BUZZER_PIN, HIGH);
delay(200);
digitalWrite(BUZZER_PIN, LOW);
delay(100);
}
}
void sendTelegramPhoto(uint8_t* image_data, size_t image_len) {
Serial.println(F("Sending photo to Telegram..."));
// Send notification first
String message = "🔔 Someone is at your door!\nTime: " + String(millis()/1000) + "s ago";
if (bot.sendMessage(CHAT_ID, message, "")) {
Serial.println(F("Notification sent!"));
}
// Send photo
if (bot.sendPhotoByBinary(CHAT_ID, "image/jpeg", image_len,
[]()(size_t buffer_len, uint8_t* buffer, size_t* idx, uint8_t* data, size_t len)->size_t {
for (size_t i = 0; i < len; i++) {
buffer[*idx + i] = data[i];
}
*idx += len;
return len;
}, nullptr, image_data)) {
Serial.println(F("Photo sent successfully!"));
} else {
Serial.println(F("Failed to send photo"));
}
}
// ============== END OF CODE ==============
Step 3: Get Your Telegram Bot Token
- Open Telegram and search for @BotFather
- Send
/newbotto create a new bot - Follow instructions to name your bot
- Copy the API Token
- Search for your bot and start a conversation
- Get your Chat ID from @userinfobot
Step 4: Upload and Test
- Connect ESP32-CAM to FTDI programmer (GPIO 0 to GND for boot mode)
- Select Tools → Board → ESP32 Wrover Module
- Select Tools → Partition Scheme → Huge APP
- Upload code
- Remove GPIO 0 from GND and press RESET
- Open Serial Monitor to see IP address
- Test by pressing doorbell button
Troubleshooting
| Problem | Solution |
|---|---|
| Camera init failed | Check pin connections; ensure camera ribbon cable is secure |
| No Telegram messages | Verify Bot Token and Chat ID; check internet connection |
| FTDI not detected | Install CP2102 drivers |
| Brownout error | Use external 5V power supply (USB alone may not be enough) |
| Black photo | Increase delay before capture; flash LED may need adjustment |
Official Documentation
- Universal Telegram Bot Library - Official GitHub
- ESP32 Camera Library - Official repository
- Random Nerd ESP32-CAM Guide - Comprehensive tutorial
- Telegram Bot API - Official documentation
Enhancement Ideas
- Add ESP32-CAM for WiFi streaming to web server
- Integrate Home Assistant for automation
- Add MQTT for IoT integration
- Implement face recognition with ESP32 DL Library
Frequently Asked Questions
Q: Can I use ESP32-CAM without FTDI programmer?
A: No. ESP32-CAM doesn't have USB-to-UART built-in. You need an FTDI programmer for uploading code.
Q: Why does the camera sometimes fail to initialize?
A: This is common with cheap camera modules. Try reseating the camera connector or using a different camera module.
Q: Can I send photos to multiple users?
A: Yes. Store multiple Chat IDs in an array and loop through them when sending notifications.
Q: How long can the doorbell run on battery?
A: ESP32-CAM consumes too much power for battery operation. Use USB power supply (5V/2A recommended).
Q: Can I view the camera stream remotely?
A: Yes. Use the ESP32-CAM Web Server example to stream video to any browser.

