A smart doorbell with a camera lets you see who is at your door from your phone, even when you are not at home. Commercial video doorbells like Ring, Eufy, and Xiaomi cost ₹5,000–₹15,000 in India and often require monthly cloud subscriptions. With an ESP32-CAM module, you can build your own smart video doorbell for under ₹1,500 — with features like live video streaming, motion-triggered photo capture, and push notifications to your phone.
This guide walks you through building a practical video doorbell using the ESP32-CAM, one of the most capable and affordable camera modules available.
ESP32-CAM Module Overview
The ESP32-CAM is a compact development board that combines an ESP32 microcontroller with a 2MP OV2640 camera module. Key specifications:
- Camera: OV2640, 2 Megapixel, supports JPEG and BMP output
- Video: Up to 1600×1200 resolution, MJPEG streaming at 12-15 FPS
- Processor: ESP32 dual-core 240MHz with 520KB SRAM
- WiFi: 802.11 b/g/n, built-in antenna or external antenna option
- Storage: MicroSD card slot for photo storage
- Flash LED: Built-in white LED for night illumination
- Size: Just 27mm x 40mm — fits inside any doorbell housing
Components Required
| Component | Price (₹) |
|---|---|
| ESP32-CAM with OV2640 | 400–550 |
| ESP32-CAM-MB (USB programmer) | 150–200 |
| Push button (doorbell) | 20–40 |
| 5V 2A power supply | 80–120 |
| MicroSD card (16GB) | 150–250 |
| Waterproof enclosure | 100–200 |
| Buzzer (indoor unit) | 20–30 |
| Total | ₹920–₹1,390 |
Programming the ESP32-CAM
Setting Up Arduino IDE
- In Arduino IDE, go to File → Preferences → Additional Board Manager URLs, add:
https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json - Install “ESP32 by Espressif” from Board Manager
- Select Board: “AI Thinker ESP32-CAM”
- Attach the ESP32-CAM-MB module and select the correct COM port
Important GPIO Notes
The ESP32-CAM has limited free GPIO pins because most are used by the camera and SD card:
- GPIO 13: Free — use for doorbell button
- GPIO 14: Free — use for buzzer or LED indicator
- GPIO 2: Connected to SD card, but usable if SD is not needed
- GPIO 4: Flash LED — built-in white LED for night vision
- GPIO 33: Connected to onboard red LED (active LOW)
Setting Up Live Video Streaming
#include "esp_camera.h"
#include <WiFi.h>
#include "esp_http_server.h"
// WiFi credentials
const char* ssid = "Your_WiFi";
const char* password = "Your_Password";
// AI-Thinker ESP32-CAM pin configuration
#define PWDN_GPIO_NUM 32
#define RESET_GPIO_NUM -1
#define XCLK_GPIO_NUM 0
#define SIOD_GPIO_NUM 26
#define SIOC_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
#define DOORBELL_PIN 13
#define FLASH_LED 4
httpd_handle_t stream_httpd = NULL;
// MJPEG stream handler
static esp_err_t stream_handler(httpd_req_t *req) {
camera_fb_t *fb = NULL;
esp_err_t res = ESP_OK;
char part_buf[64];
res = httpd_resp_set_type(req, "multipart/x-mixed-replace;boundary=frame");
while (true) {
fb = esp_camera_fb_get();
if (!fb) {
res = ESP_FAIL;
break;
}
size_t hlen = snprintf(part_buf, 64,
"Content-Type: image/jpeg
Content-Length: %u
", fb->len);
res = httpd_resp_send_chunk(req, "--frame
", 9);
res = httpd_resp_send_chunk(req, part_buf, hlen);
res = httpd_resp_send_chunk(req, (const char *)fb->buf, fb->len);
res = httpd_resp_send_chunk(req, "
", 2);
esp_camera_fb_return(fb);
if (res != ESP_OK) break;
}
return res;
}
void startStream() {
httpd_config_t config = HTTPD_DEFAULT_CONFIG();
config.server_port = 81;
httpd_uri_t stream_uri = {
.uri = "/stream",
.method = HTTP_GET,
.handler = stream_handler
};
if (httpd_start(&stream_httpd, &config) == ESP_OK) {
httpd_register_uri_handler(stream_httpd, &stream_uri);
}
}
void setup() {
Serial.begin(115200);
pinMode(DOORBELL_PIN, INPUT_PULLUP);
pinMode(FLASH_LED, OUTPUT);
digitalWrite(FLASH_LED, LOW);
// Camera configuration
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_sccb_sda = SIOD_GPIO_NUM;
config.pin_sccb_scl = SIOC_GPIO_NUM;
config.pin_pwdn = PWDN_GPIO_NUM;
config.pin_reset = RESET_GPIO_NUM;
config.xclk_freq_hz = 20000000;
config.pixel_format = PIXFORMAT_JPEG;
config.frame_size = FRAMESIZE_VGA; // 640x480
config.jpeg_quality = 12;
config.fb_count = 2;
esp_err_t err = esp_camera_init(&config);
if (err != ESP_OK) {
Serial.printf("Camera init failed: 0x%x
", err);
return;
}
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.print("
Camera Stream: http://");
Serial.print(WiFi.localIP());
Serial.println(":81/stream");
startStream();
}
void loop() {
// Check doorbell button
if (digitalRead(DOORBELL_PIN) == LOW) {
Serial.println("DOORBELL PRESSED!");
// Flash LED briefly for the photo
digitalWrite(FLASH_LED, HIGH);
delay(200);
// Capture and save photo to SD (optional)
camera_fb_t *fb = esp_camera_fb_get();
if (fb) {
// Send notification here (Telegram, Blynk, etc.)
Serial.printf("Photo captured: %d bytes
", fb->len);
esp_camera_fb_return(fb);
}
digitalWrite(FLASH_LED, LOW);
delay(1000); // Debounce
}
}
Adding the Doorbell Button
The doorbell button connects to GPIO 13. When pressed, the system:
- Captures a photo with the flash LED
- Sends a notification to your phone (via Telegram, Blynk, or email)
- Triggers an indoor buzzer (if connected to a second ESP32 inside)
For the physical button, use a waterproof doorbell push button from any electrical shop (₹30–₹80). Wire it between GPIO 13 and GND.
Push Notifications to Phone
The easiest way to receive doorbell notifications is through Telegram Bot API:
#include <HTTPClient.h>
String telegramToken = "YOUR_BOT_TOKEN";
String chatID = "YOUR_CHAT_ID";
void sendTelegramPhoto(camera_fb_t *fb) {
HTTPClient http;
String url = "https://api.telegram.org/bot" + telegramToken + "/sendPhoto";
// Create multipart form data
String boundary = "----WebKitFormBoundary";
String head = "--" + boundary + "
";
head += "Content-Disposition: form-data; name="chat_id"
";
head += chatID + "
";
head += "--" + boundary + "
";
head += "Content-Disposition: form-data; name="caption"
";
head += "Doorbell pressed!
";
head += "--" + boundary + "
";
head += "Content-Disposition: form-data; name="photo"; filename="doorbell.jpg"
";
head += "Content-Type: image/jpeg
";
String tail = "
--" + boundary + "--
";
uint32_t totalLen = head.length() + fb->len + tail.length();
http.begin(url);
http.addHeader("Content-Type", "multipart/form-data; boundary=" + boundary);
http.addHeader("Content-Length", String(totalLen));
// Send in chunks
WiFiClient *stream = http.getStreamPtr();
// ... (simplified - use WiFiClientSecure for full implementation)
http.end();
}
When someone presses the doorbell, you receive a Telegram message with a photo of the visitor — even if you are at the office or travelling.
Weatherproof Housing for Indian Conditions
Your doorbell will be exposed to Indian weather — scorching sun, monsoon rain, and dust. Here are housing recommendations:
- Enclosure: Use an ABS plastic junction box (IP65 rated) from any electrical shop (₹80–₹200). Cut holes for the camera lens, button, and LED.
- Camera window: Use a small piece of clear acrylic sheet glued over the camera hole. This protects the lens from rain while allowing clear photos.
- Sun shade: Mount a small metal or plastic visor above the camera to prevent direct sunlight from washing out the image.
- Ventilation: The ESP32 generates heat. Drill a few small holes on the bottom (not top!) of the enclosure for air circulation without letting rain in.
- Power cable entry: Use cable glands (available for ₹20) for waterproof cable entry. Seal with silicone if needed.
Frequently Asked Questions
What is the video quality like?
The OV2640 captures 2MP photos and streams VGA (640×480) video at about 12 FPS. This is adequate for identifying visitors. It is not as sharp as a Ring doorbell, but for ₹1,500 total cost, the quality-to-price ratio is excellent.
Does it work at night?
The built-in flash LED on GPIO 4 provides illumination for night photos. For continuous night streaming, you can add an infrared LED module and remove the IR filter from the camera — but this is an advanced modification.
Can I record video continuously?
Yes, using the MicroSD card slot. However, continuous recording at VGA fills a 16GB card in about 8 hours. For practical use, record only when the doorbell is pressed or motion is detected.
How do I view the camera when I am outside my home network?
Set up port forwarding on your router (forward port 81 to the ESP32-CAM’s local IP). Better yet, use a Telegram bot for on-demand photos, or set up a VPN to securely access your home network.
Can I add face recognition?
The ESP32-CAM supports basic face detection and recognition (up to 7 faces). However, accuracy is limited compared to commercial solutions. It works best in well-lit conditions with faces directly facing the camera.
Conclusion
A smart doorbell with ESP32-CAM gives you the core functionality of a ₹10,000+ commercial video doorbell for under ₹1,500. You get live video streaming, photo capture on button press, push notifications via Telegram, and no monthly subscription fees. For Indian homes, where delivery persons, domestic help, and unexpected visitors are a daily occurrence, a video doorbell adds both convenience and security.
Get started today with an ESP32-CAM module and USB programmer from Zbotic.in — your one-stop shop for all electronics components in India.
Add comment