Welcome to Project 38. A little while back, in Project 28: ESP32-CAM Video Streaming Web Server, we built a live IP camera. It was cool. It was incredibly cheap. But letâs be honestâit was also completely dumb.
Streaming video 24/7 over Wi-Fi is a great way to eat up network bandwidth, generate enough heat on your ESP32-CAM to fry an egg, and stare at an empty hallway for hours. What we really need is a camera that actually pays attention and only activates when your cat jumps on the counter or a porch pirate strikes.
Today, we are upgrading that basic stream into a True Smart Security Camera. We are adding hardware-level motion detection by integrating the legendary HC-SR501 PIR (Passive Infrared) sensor.
You might be asking, âCanât I just write code to detect motion in the video stream?â
Yes, you can (itâs called pixel-difference motion detection). But running a standard web server loop that constantly captures JPEG frames and compares thousands of pixels will cause the ESP32-CAM to run blisteringly hot and max out its processor.
By offloading the âdetectionâ phase to a dedicated hardware sensor like the PIR, the ESP32 can idle. It doesnât have to think at all until the PIR sensor sends a high-voltage spike to a GPIO pin. Itâs the difference between staring out the window all day to see if the mailman arrived, versus just waiting for him to ring the doorbell.
If you built Project 28, you already have most of this. Here is the complete list:
The HC-SR501 PIR sensor has three pins: VCC, GND, and OUT.
Note: The ESP32-CAM is notoriously short on available GPIO pins because the camera and microSD card monopolize most of them. GPIO 13 is generally safe to use as an input.
If you get weird, random motion triggers when absolutely nothing is moving, you might have a floating pin. Check out our guide on Fixing Floating Pins to learn how to add a pull-down resistor to stabilize it.
In Project 28, we used the standard CameraWebServer example. This time, we need to write code that relies on Hardware Interrupts.
An interrupt tells the processor to stop whatever itâs doing immediately and run a specific block of code (the ISR - Interrupt Service Routine).
#define PIR_PIN 13 // The pin connected to the PIR sensor OUT
// This function runs IMMEDIATELY when motion is detected
void IRAM_ATTR detectMotion() {
Serial.println("MOTION DETECTED! Capturing Image...");
// Trigger camera capture function here
}
void setup() {
Serial.begin(115200);
pinMode(PIR_PIN, INPUT_PULLDOWN);
// Attach the interrupt to the PIR pin.
// RISING means it triggers when the pin goes from LOW (0V) to HIGH (3.3V).
attachInterrupt(digitalPinToInterrupt(PIR_PIN), detectMotion, RISING);
}
void loop() {
// The loop can stay mostly empty!
// The ESP32 just chills until the interrupt wakes it up.
}
Donât forget the cardinal rule of the ESP32-CAM: You must jumper GPIO 0 to GND to put it into flashing mode! If you are getting error messages in the Arduino IDE during upload, review our guide on Why Your ESP32 Wonât Upload Code (The Boot Button Trick).
When the PIR sensor detects motion, the ESP32-CAM suddenly wakes up, initializes the Wi-Fi radio, and flashes the bright onboard LED to take a picture. This causes a massive spike in current draw.
If your camera suddenly reboots every time you wave your hand in front of it, you are experiencing a voltage drop. The ESP32 will throw a Brownout detector was triggered error in the Serial Monitor.
To fix this, make sure you are using a high-quality 5V, 2A power supply. Do not try to power the final rig from your computerâs USB port via the FTDI adapter. For a deep dive into this issue, check out our guide on Fixing the ESP32 Brownout Reset.
By adding a simple $2 PIR sensor and utilizing hardware interrupts, youâve transformed a basic streaming module into a highly efficient, event-driven security camera. It saves power, runs cooler, and actually does the watching for you.
Now, go forth and set your traps. Just be prepared to receive 400 photos of a moth fluttering near your porch light at 3 AM!