Project Overview & Hardware Spec Sheet

Building a security camera raspberry pi system gives you complete ownership of your video data, bypassing the cloud subscriptions and privacy compromises of commercial smart cameras. This build uses the Raspberry Pi 5 paired with the Sony IMX708-based Camera Module 3, delivering 12MP stills and 1080p60 H.264 video. We are adding a hardware PIR (Passive Infrared) sensor to handle motion detection, which is vastly more reliable and CPU-efficient than software-based pixel-diffing.

Difficulty: Intermediate | Time: 45 minutes | Target OS: Raspberry Pi OS Bookworm (64-bit)

Parts List & Exact Variants

ComponentExact Model / VariantEst. PriceNotes
Compute BoardRaspberry Pi 5 (4GB RAM)$608GB is overkill for 1080p H.264 encoding; 4GB is the sweet spot.
Camera ModulePi Camera Module 3 (Standard)$30Get the 'NoIR' variant if you plan to use infrared night vision.
Motion SensorHC-SR501 PIR Sensor$3Must be the 3-pin variant with the BISS0001 chip.
Power SupplyOfficial 27W USB-C PD Supply$12Do not use a standard phone charger; Pi 5 will throttle peripherals.
Storage32GB microSD (A2 Rated)$10A2 rating ensures high random I/O for OS and log writing.

Wiring the PIR Motion Sensor & Camera Module

The HC-SR501 PIR sensor has an onboard 3.3V LDO regulator. Bench Gotcha: If you power the HC-SR501 from the Pi's 3.3V pin, the internal voltage drops too low and the sensor will trigger erratically or not at all. You must power it from the 5V rail. Fortunately, when powered by 5V, the sensor's OUT pin outputs exactly 3.3V, making it perfectly safe for the Raspberry Pi 5's GPIO pins.

Pin Mapping Table

HC-SR501 PinFunctionRaspberry Pi 5 Physical PinBCM GPIO
VCC (Left)Power (5V)Pin 2 (5V Power)N/A
OUT (Middle)Signal (3.3V High)Pin 11GPIO 17
GND (Right)GroundPin 9 (Ground)N/A
Tip: Adjust the two orange potentiometers on the HC-SR501 before sealing the enclosure. Turn the 'Time Delay' pot fully counter-clockwise for a minimal ~0.3s hardware hold time (our Python code handles the recording duration). Turn the 'Sensitivity' pot to the 12 o'clock position to avoid false triggers from ambient heat shifts.

For the Camera Module 3, lift the black plastic retention flap on the Pi 5's CSI port, insert the ribbon cable with the blue tape facing away from the Ethernet port (towards the board edge), and press the flap down firmly. Use the cable included with the Module 3; older Pi Zero cables have a different pitch and will short the pins.

Python Code: Motion-Triggered Recording with picamera2

The legacy picamera library is deprecated on Bookworm. We use the modern picamera2 library, which interfaces directly with libcamera. This script targets the Raspberry Pi 5 (4GB/8GB) and records a 15-second H.264 clip every time the PIR sensor pulls GPIO 17 high.

#!/usr/bin/env python3
"""
Raspberry Pi 5 Security Camera with PIR Motion Detection
Target Board: Raspberry Pi 5 (4GB/8GB) running Raspberry Pi OS Bookworm
Camera: Pi Camera Module 3 (IMX708)
Sensor: HC-SR501 PIR Motion Sensor
"""
import time
import os
import logging
from datetime import datetime
from gpiozero import MotionSensor
from picamera2 import Picamera2
from picamera2.encoders import H264Encoder
from picamera2.outputs import FileOutput

# --- PIN DEFINITIONS ---
PIR_GPIO_PIN = 17  # Physical Pin 11, BCM GPIO 17

# --- CONFIGURATION ---
VIDEO_DIR = "/home/pi/security_footage"
RECORD_SECONDS = 15
RESOLUTION = (1920, 1080)

# Setup logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')

def setup_environment():
    if not os.path.exists(VIDEO_DIR):
        os.makedirs(VIDEO_DIR)
        logging.info(f"Created directory: {VIDEO_DIR}")

def main():
    setup_environment()

    # Initialize PIR Sensor
    # queue_len=3 and threshold=0.8 debounces the hardware signal
    pir = MotionSensor(PIR_GPIO_PIN, queue_len=3, threshold=0.8)
    logging.info(f"PIR Sensor initialized on GPIO {PIR_GPIO_PIN}. Calibrating for 5 seconds...")
    time.sleep(5) # Let PIR settle to ambient IR levels

    # Initialize Camera
    try:
        picam2 = Picamera2()
        video_config = picam2.create_video_configuration(main={"size": RESOLUTION, "format": "RGB888"})
        picam2.configure(video_config)
        encoder = H264Encoder(10000000) # 10 Mbps bitrate for crisp 1080p
        logging.info("Camera configured successfully.")
    except Exception as e:
        logging.critical(f"Failed to initialize camera: {e}")
        return

    try:
        while True:
            if pir.motion_detected:
                timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
                filename = os.path.join(VIDEO_DIR, f"motion_{timestamp}.h264")
                logging.info(f"Motion detected! Recording to {filename}")

                try:
                    picam2.start_recording(encoder, FileOutput(filename))
                    time.sleep(RECORD_SECONDS)
                    picam2.stop_recording()
                    logging.info("Recording finished.")
                except Exception as rec_err:
                    logging.error(f"Recording error: {rec_err}")
                    try:
                        picam2.stop_recording()
                    except Exception:
                        pass

                # Hardware cooldown to prevent overlapping file writes
                time.sleep(2)
            else:
                time.sleep(0.1)

    except KeyboardInterrupt:
        logging.info("Shutting down gracefully...")
    finally:
        try:
            picam2.stop_recording()
        except Exception:
            pass
        picam2.stop()

if __name__ == "__main__":
    main()

Debugging: Camera Failures and Exact Error Strings

When working with libcamera and the Pi 5's new PCIe-based RP1 I/O controller, hardware initialization errors are common. If your script crashes on startup, here are the first three things to check:

  1. Verify Hardware Detection: Run rpicam-hello in the terminal. If it fails, the OS doesn't see the sensor. Check your FFC cable seating.
  2. Check for Zombie Processes: Run sudo fuser -v /dev/video0. If another process is holding the camera node, kill it.
  3. Verify Power Delivery: Run vcgencmd get_throttled. If it returns anything other than 0x0, your power supply is browning out and the RP1 chip is dropping the CSI bus.

Ranked Causes for Common Errors

Error String: OSError: [Errno 16] Device or resource busy or RuntimeError: Failed to acquire camera handle

  • Cause 1 (Most Likely): Another process is using the camera. The official motion daemon, rpicam-vid, or a stray Python script from a previous run is holding /dev/video0. Fix: sudo killall python3 rpicam-vid motion.
  • Cause 2: You are running the script via a cron job or systemd service under a different user context that lacks the video group permissions. Fix: Add the service user to the video group: sudo usermod -aG video pi.

Error String: ERROR RPI raspberrypi.cpp:123 Failed to register camera or Unable to open camera device

  • Cause 1 (Most Likely): The FFC ribbon cable is not fully seated, or the blue tape is facing the wrong direction. The contacts must touch the bottom of the CSI port. Fix: Reseat the cable and lock the flap.
  • Cause 2: You are using an incompatible ribbon cable (e.g., a 22-pin Pi Zero cable forced into the 15-pin Pi 5 slot). Fix: Use the 15-pin 1mm pitch cable included with the Module 3.

Error String: ModuleNotFoundError: No module named 'picamera2'

  • Cause 1: You are running an older OS (Bullseye) or installed it via pip instead of apt. The picamera2 library relies on system-level libcamera bindings. Fix: Run sudo apt update && sudo apt install python3-picamera2.

Extending and Simplifying the Build

Depending on your deployment environment, you may want to scale this build up or strip it down.

How to Simplify (Software Motion Detection):
If you want to eliminate the HC-SR501 PIR sensor and its wiring, you can use libcamera's built-in hardware-accelerated motion detection. By analyzing the difference between low-resolution frames directly on the ISP, you can trigger recordings purely in software. This reduces your BOM cost by $3 and removes GPIO wiring, at the expense of a slight increase in CPU usage and a higher rate of false positives from shifting shadows.

How to Extend (NVR Integration & Alerts):
To turn this standalone node into a multi-camera security network, strip the recording logic out of the Python script and stream the H.264 feed via RTSP using mediamtx. You can then ingest multiple Pi streams into Frigate NVR. Frigate uses Google Coral TPUs for local, AI-powered object detection (differentiating humans from pets), completely replacing the dumb PIR sensor logic while keeping all data on your local LAN.

Frequently Asked Questions

How to make a security camera raspberry pi setup without internet?

You can run this build entirely offline. Assign the Raspberry Pi a static IP address via your router's DHCP reservation table. To view the footage, mount a local NAS (Network Attached Storage) via SMB/CIFS in your /etc/fstab and change the VIDEO_DIR path in the Python script to point to the network share. As long as your phone or laptop is on the same local Wi-Fi, you can access the footage via an SMB file manager app without the Pi ever touching the WAN.

Can a raspberry pi security camera record at night?

Yes, but you must swap the standard Camera Module 3 for the Camera Module 3 NoIR (No Infrared Filter). Standard cameras have an IR-blocking filter that makes night vision impossible. With the NoIR module, you must pair it with an external 850nm IR illuminator. (Avoid 940nm illuminators; while they are invisible to the human eye, the IMX708 sensor's quantum efficiency drops off sharply past 850nm, resulting in dark, noisy footage). Note that 850nm LEDs emit a faint red glow that is visible to intruders.

Is a raspberry pi security camera better than Ring or Wyze?

It depends on your priority: privacy or convenience. A Raspberry Pi build is vastly superior for data sovereignty and local processing. You pay no monthly subscriptions, your video never leaves your LAN, and you can integrate it with Home Assistant via local MQTT. However, commercial cameras like Ring or Wyze win on convenience and form factor. They offer polished mobile apps, two-way audio out-of-the-box, and weatherproof enclosures that would cost you upwards of $40 to replicate for a Pi. If you want a 'set it and forget it' outdoor camera, buy Wyze. If you want a customizable, private, AI-ready node, build the Pi.