Building a local raspberry pi security camera gives you complete ownership of your video data, bypassing the monthly cloud fees and privacy concerns of commercial IP cameras. With the release of the Raspberry Pi 5 and the picamera2 library, the hardware is now capable of processing high-resolution video streams locally without dropping frames.
This guide targets the Raspberry Pi 5 (4GB variant) paired with the Raspberry Pi Camera Module 3. We will wire a hardware PIR motion sensor to trigger captures, write a robust Python script using the modern libcamera stack, and cover the exact debugging steps for the most common pipeline failures.
Hardware Spec Sheet & Parts List
The Pi 5 introduces a new, smaller CSI (Camera Serial Interface) connector. If you are upgrading from a Pi 4, your old 15-pin ribbon cable will not fit without an adapter. Ensure you purchase the correct 22-pin cable.
| Component | Exact Model / Variant | Estimated Price (2026) | Notes |
|---|---|---|---|
| Compute Board | Raspberry Pi 5 (4GB RAM) | $60.00 | 4GB is sufficient for 1080p/2K capture; 8GB only needed for heavy AI NVR loads. |
| Camera Module | Raspberry Pi Camera Module 3 (Standard) | $30.00 | 12MP Sony IMX708 sensor. Avoid the 'Wide' variant unless you need a 120-degree FOV. |
| CSI Ribbon Cable | 22-pin to 22-pin (Pi 5 specific) | $4.00 | Pi 5 uses a 22-pin 0.5mm pitch connector. Pi 4 uses 15-pin 1mm. |
| Motion Sensor | HC-SR501 PIR Sensor | $2.50 | Adjustable delay and sensitivity potentiometers on board. |
| Power Supply | Official 27W USB-C PD Power Supply | $12.00 | Required for Pi 5 to prevent USB peripheral brownouts. |
| Storage | 64GB A2 Class microSD (SanDisk Extreme) | $11.00 | A2 rating ensures fast random I/O for OS and database writes. |
Pin Mapping & Physical Assembly
While the Camera Module 3 connects via the dedicated CSI port, the HC-SR501 PIR sensor requires GPIO pins. The PIR sensor outputs a 3.3V logic HIGH when motion is detected, which is perfectly safe for the Pi 5's GPIO bank.
PIR Sensor to Raspberry Pi 5 GPIO Mapping
| HC-SR501 Pin | Wire Color (Typical) | Pi 5 Physical Pin | Pi 5 BCM GPIO |
|---|---|---|---|
| VCC | Red | Pin 2 (5V Power) | N/A |
| OUT | Yellow | Pin 11 | GPIO 17 |
| GND | Black | Pin 6 (Ground) | N/A |
Calibration: Before sealing the enclosure, use a small Phillips screwdriver to adjust the two orange potentiometers on the HC-SR501. Turn the 'Delay Time' pot fully counter-clockwise for a ~3-second reset time, and the 'Sensitivity' pot to the middle position to avoid false triggers from small pets.
Software Configuration & Python Capture Script
Flash Raspberry Pi OS (64-bit, Bookworm or later) using the Raspberry Pi Imager. Enable SSH and configure your WiFi during the flashing process. Once booted, update the system and install the required libraries:
sudo apt update && sudo apt upgrade -y
sudo apt install python3-picamera2 python3-gpiozero python3-libcamera -y
mkdir -p ~/security_captures
The legacy picamera library is deprecated on Pi 5. We must use picamera2, which interfaces directly with the libcamera pipeline. Below is the complete, compilable Python script. It initializes the camera, waits for the PIR sensor to trigger, captures a high-resolution still, and handles hardware interrupts gracefully.
import time
import signal
import sys
import os
from datetime import datetime
from picamera2 import Picamera2
from gpiozero import MotionSensor
# --- PIN & PATH DEFINITIONS ---
PIR_GPIO_PIN = 17
OUTPUT_DIR = "/home/pi/security_captures/"
COOLDOWN_SECONDS = 5
# Initialize PIR Sensor on GPIO 17
pir = MotionSensor(PIR_GPIO_PIN)
# Initialize Picamera2
picam2 = Picamera2()
# Configure camera for high-res stills (2304x1296 is the 2K mode for IMX708)
config = picam2.create_still_configuration(
main={"size": (2304, 1296), "format": "RGB888"},
buffer_count=2
)
picam2.configure(config)
def graceful_exit(sig, frame):
print("\n[INFO] Shutting down camera and cleaning up GPIO...")
picam2.stop()
pir.close()
sys.exit(0)
# Catch Ctrl+C and termination signals
signal.signal(signal.SIGINT, graceful_exit)
signal.signal(signal.SIGTERM, graceful_exit)
def capture_event():
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
filename = os.path.join(OUTPUT_DIR, f"motion_{timestamp}.jpg")
print(f"[{timestamp}] Motion detected! Capturing image...")
try:
# start() initializes the pipeline, capture_file() grabs the frame
picam2.start()
time.sleep(1) # Allow auto-exposure to settle
picam2.capture_file(filename)
picam2.stop()
print(f"[SUCCESS] Saved to {filename}")
except Exception as e:
print(f"[ERROR] Capture failed: {e}")
# Attempt to reset the pipeline if it hangs
try:
picam2.stop()
except:
pass
if __name__ == "__main__":
print(f"[INFO] Raspberry Pi Security Camera active. Monitoring GPIO {PIR_GPIO_PIN}...")
try:
while True:
pir.wait_for_motion()
capture_event()
# Hardware cooldown to prevent rapid-fire writes to SD card
time.sleep(COOLDOWN_SECONDS)
except Exception as e:
print(f"[FATAL] Main loop crashed: {e}")
graceful_exit(None, None)
Debugging: Camera Acquisition and Pipeline Errors
The transition from MMAL (Pi 4) to libcamera (Pi 5) introduced new error paradigms. If your script fails, do not blindly reboot. Read the traceback.
First 3 Things to Check When It Fails
- Ribbon Cable Seating: The 22-pin connector on the Pi 5 is notoriously finicky. If the cable is inserted even 0.5mm crooked, the I2C control lines will connect but the MIPI data lanes won't, resulting in silent initialization failures.
- Power Supply Brownout: The Camera Module 3 draws peak current during the initial sensor power-up. If you are using a third-party phone charger instead of the official 27W PD supply, the Pi 5 will throttle or drop the USB/CSI bus voltage.
- Conflicting Processes: Only one process can hold the
libcameradevice node at a time. Ensurelibcamera-hello,rpicam-vid, or a background Frigate service isn't running.
Exact Error Strings and Ranked Causes
Error 1: RuntimeError: Failed to acquire camera: Device or resource busy
- Cause A (Most Likely): Another process is holding
/dev/video0. Runfuser /dev/video0to find the PID and kill it. - Cause B: Your previous Python script crashed without calling
picam2.stop(), leaving the pipeline locked in the kernel. A quick reboot clears this.
Error 2: TimeoutError: Failed to capture frame within 5000ms
- Cause A (Most Likely): The camera pipeline was not fully started before calling
capture_file(). The IMX708 sensor requires ~500ms to lock auto-exposure and white balance. Ensuretime.sleep(1)exists betweenpicam2.start()and the capture command. - Cause B: Insufficient memory allocated for buffers. If you increased the resolution to the full 12MP (4608x2592) without increasing
buffer_countin the configuration dictionary, the DMA engine will stall.
export LIBCAMERA_LOG_LEVELS=debug. This will print exact MIPI lane synchronization states to your terminal.
Extending and Simplifying the Build
Once the baseline hardware trigger is working, you have two distinct paths for modifying the system based on your deployment environment.
How to Simplify: Software Motion Vectors
If you want to eliminate the HC-SR501 PIR sensor and its wiring, you can use the camera's built-in hardware motion estimation. The picamera2 library can output motion vectors directly from the ISP (Image Signal Processor). By analyzing the magnitude of these vectors in a Python loop, you can trigger captures purely via software. This simplifies the physical build but increases the Pi 5's CPU load by roughly 15%.
How to Extend: AI Object Detection with Frigate NVR
A simple motion trigger captures everything from swaying trees to stray cats. To filter alerts for humans or vehicles, integrate Frigate NVR. Frigate acts as a centralized video management system. You will need to switch from the Python script above to streaming an RTSP feed using rpicam-vid, and ideally add a Google Coral USB Accelerator ($35-$60) to handle the TensorFlow Lite inference without maxing out the Pi 5's CPU.
FAQ: Raspberry Pi Security Camera Questions
Can I use a Raspberry Pi Zero 2 W for a security camera?
Yes, but with significant compromises. The Zero 2 W has only 512MB of RAM. While it can run picamera2 and capture 1080p stills, it lacks the memory headroom to run continuous AI object detection or buffer high-framerate video streams. Furthermore, the Zero 2 W relies on WiFi; if your signal drops below -70dBm, you will experience severe packet loss and corrupted image files. Use the Zero 2 W only for low-traffic, battery-powered still-capture deployments, not continuous NVR recording.
How do I view the raspberry pi security camera feed remotely without port forwarding?
Never expose your Pi's SSH or RTSP ports directly to the public internet via port forwarding; automated botnets will brute-force your credentials within hours. Instead, use a mesh VPN like Tailscale or ZeroTier. Install the Tailscale client on your Pi and your mobile device. This creates a secure, encrypted peer-to-peer tunnel, allowing you to access the Pi's local IP address (e.g., http://100.x.y.z:8080) from anywhere in the world as if you were on your home WiFi.
Does the Raspberry Pi Camera Module 3 work in low light or at night?
The standard Camera Module 3 features an IR-cut filter, meaning it blocks infrared light to produce accurate colors during the day. In low light, it will produce noisy, dark images. For night vision, you must either purchase the Camera Module 3 NoIR (which lacks the IR-cut filter) and pair it with an external 850nm or 940nm IR illuminator, or use the Camera Module 3 Wide which has slightly better low-light photon collection due to its shorter focal length, though it still requires ambient light or IR supplementation for total darkness.
How much storage does a raspberry pi security camera use per day?
Storage depends entirely on your capture mode. If you are capturing 2K (2304x1296) JPEG stills triggered by motion, a typical 50-event day will consume roughly 150MB to 250MB. A 64GB SD card will hold months of stills. However, if you switch to continuous 1080p H.264 video recording at 30fps (approx. 4Mbps bitrate), you will consume about 42GB per 24 hours. For continuous video, abandon the microSD card and boot the Pi 5 from an external NVMe SSD via the PCIe HAT, or use a network-attached storage (NAS) target.






