The most reliable architecture for DIY raspberry pi security cameras in 2026 pairs the Raspberry Pi 5 (4GB) with the Camera Module 3 (IMX708 sensor) and a hardware PIR motion sensor. While legacy builds relied on the deprecated picamera library, modern setups must use the picamera2 Python wrapper over the libcamera C++ stack. This guide provides the exact hardware bill of materials, MIPI CSI-2 pin mapping, and a complete, error-handled Python script to trigger H.264 video recording only when physical motion breaks the PIR beam.
Project Spec Sheet & Parts List
Estimated Build Time: 90 minutes
Estimated Cost: $115 - $135 USD
Target Board Variant: Raspberry Pi 5 (4GB RAM) running Raspberry Pi OS Bookworm (64-bit)
| Component | Exact Model / Variant | Notes & Pricing (Approx.) |
|---|---|---|
| Compute Board | Raspberry Pi 5 (4GB) | 8GB is overkill for pure recording; 4GB handles 1080p H.264 encoding easily. ($60) |
| Camera Module | Camera Module 3 (IMX708) | Features built-in autofocus and HDR. Ensure you buy the standard or wide version, not the "NoIR" unless you plan to use external IR illuminators. ($25) |
| Motion Sensor | HC-SR501 PIR Sensor | Standard 3-pin PIR. Adjust the onboard potentiometer to minimum delay for fast triggers. ($2) |
| Power Supply | Official 27W USB-C PD (5V/5A) | Crucial: Pi 5 requires 5A to prevent peripheral brownouts when the camera and PIR draw peak current. ($12) |
| Storage | 32GB SanDisk Extreme A2 microSD | A2 rating ensures high IOPS for sustained video write operations without dropping frames. ($9) |
| Ribbon Cable | 15-pin to 15-pin CSI FFC | The Pi 5 uses the same 15-pin connector as Pi 4, but ensure the cable is rated for MIPI CSI-2. ($3) |
Hardware Assembly & CSI Pin Mapping
The Camera Module 3 connects via the MIPI CSI-2 interface, not standard GPIO. The physical connection is a 15-pin Flexible Flat Cable (FFC). Mishandling this cable is the number one cause of hardware failure in raspberry pi security cameras.
CSI Port Connection Rules
- De-energize the board: Never hot-plug the CSI ribbon cable. Doing so can short the 3.3V I2C lines and permanently fry the camera's PMIC (Power Management IC).
- Unlock the connector: Gently pull the black plastic locking collar outward (away from the board) by about 1mm. Do not force it.
- Insert the cable: The blue stiffener tab on the ribbon cable must face away from the board's center (towards the Ethernet port on the Pi 5). The exposed copper traces must face inward, touching the board's contacts.
- Lock it down: Push the collar back in evenly on both sides.
15-Pin MIPI CSI-2 FFC Pinout
While you do not wire these pins manually, understanding the pinout helps when debugging I2C initialization failures. The Camera Module 3 relies on Pins 13 and 14 for I2C communication to configure the IMX708 sensor before streaming video data over the MIPI lanes.
| Pin # | Function | Description |
|---|---|---|
| 1 | GND | Ground reference |
| 2 | CAM_D0_N | MIPI Data Lane 0 (Negative) |
| 3 | CAM_D0_P | MIPI Data Lane 0 (Positive) |
| 13 | CAM_SCL | I2C Clock (Used for sensor configuration) |
| 14 | CAM_SDA | I2C Data (Used for sensor configuration) |
| 15 | GND | Ground reference |
PIR Sensor GPIO Wiring
- VCC: Connect to Pi 5 Pin 2 (5V Power). The HC-SR501 requires 5V to operate reliably; 3.3V will cause false triggers.
- OUT: Connect to Pi 5 GPIO 17 (Pin 11).
- GND: Connect to Pi 5 Pin 6 (Ground).
Python Motion Capture Code (picamera2)
The following script uses the modern picamera2 library. It initializes the camera in a low-power preview mode, waits for the PIR sensor on GPIO 17 to go HIGH, and then records a 10-second H.264 MP4 file. Save this as security_cam.py.
import time
import os
from datetime import datetime
from picamera2 import Picamera2
from picamera2.encoders import H264Encoder
from picamera2.outputs import FileOutput
from gpiozero import MotionSensor
import signal
import sys
# --- Pin & Path Definitions ---
PIR_GPIO_PIN = 17
SAVE_DIR = '/home/pi/security_footage'
CLIP_DURATION_SEC = 10
# Ensure save directory exists
os.makedirs(SAVE_DIR, exist_ok=True)
# Initialize PIR Sensor (gpiozero handles pull-downs automatically)
pir = MotionSensor(PIR_GPIO_PIN)
# Initialize Camera
cam = Picamera2()
encoder = H264Encoder(bitrate=4000000) # 4 Mbps for 1080p
# Configure camera for video recording
video_config = cam.create_video_configuration(main={'size': (1920, 1080), 'format': 'YUV420'})
cam.configure(video_config)
def graceful_exit(signum, frame):
print('\n[INFO] Shutting down camera and cleaning up...')
cam.stop()
sys.exit(0)
signal.signal(signal.SIGINT, graceful_exit)
signal.signal(signal.SIGTERM, graceful_exit)
def record_clip():
timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
filename = os.path.join(SAVE_DIR, f'motion_{timestamp}.h264')
print(f'[ALERT] Motion detected! Recording to {filename}')
try:
cam.start_recording(encoder, FileOutput(filename))
time.sleep(CLIP_DURATION_SEC)
cam.stop_recording()
print('[INFO] Clip saved successfully.')
except Exception as e:
print(f'[ERROR] Recording failed: {e}')
cam.stop_recording()
def main():
print('[INFO] Starting Raspberry Pi Security Camera...')
print('[INFO] Warming up PIR sensor for 30 seconds...')
# Start camera in preview mode to keep ISP warm
cam.start()
time.sleep(30)
print('[INFO] System armed. Waiting for motion...')
try:
while True:
pir.wait_for_motion()
record_clip()
# Small debounce to prevent overlapping file writes
time.sleep(2)
except Exception as e:
print(f'[CRITICAL] Main loop error: {e}')
finally:
cam.stop()
if __name__ == '__main__':
main()
To run this headless, create a systemd service file at
/etc/systemd/system/securitycam.service pointing to your Python script. Do not use rc.local or crontab @reboot, as they often execute before the libcamera daemon has fully initialized the I2C bus, resulting in boot-time crashes.
Debugging: "no cameras available" & First 3 Checks
When building raspberry pi security cameras, the most common failure mode occurs during camera initialization. If your script crashes immediately, you will likely see one of these two exact error strings in your terminal:
CLI Error (libcamera backend):
[0:11:33.456789012] ERROR Camera camera.cpp:1023 *** no cameras available ***
Python Error (picamera2 wrapper):
RuntimeError: Failed to initialize cameraorpicamera2.utils.Picamera2Error: no cameras available
This error means the libcamera daemon cannot communicate with the IMX708 sensor over the I2C bus. Before replacing hardware, perform these first three checks in exact order:
- Verify Ribbon Cable Seating and Orientation: 90% of these errors are caused by the ribbon cable being inserted upside down or not fully seated. Power down, disconnect the cable, inspect the copper contacts for scratches, and reseat it. Ensure the blue tab faces the Ethernet port.
- Confirm I2C Interface is Enabled: The Pi 5 disables the I2C bus by default on some minimal OS images. Run
sudo raspi-config, navigate to Interface Options > I2C, and enable it. Reboot and check withls /dev/i2c*. You should see/dev/i2c-10(the dedicated camera I2C bus on Pi 5). - Isolate the Python Layer: Bypass your script entirely and test the C++ backend. Run
libcamera-hello -t 5000in the terminal. If this command successfully opens a preview window for 5 seconds, your hardware is fine, and the issue is a Python environment conflict (e.g., running inside a virtual environment that lacks thelibcamerasystem bindings). Iflibcamera-helloalso throws the "no cameras available" error, your camera module or ribbon cable is physically defective.
Extending and Simplifying the Build
Depending on your deployment environment, you may need to alter the architecture of this security camera setup.
How to Simplify (Software-Only Motion Detection)
If you want to eliminate the HC-SR501 PIR sensor and its wiring, you can use software-based motion detection via OpenCV (cv2.absdiff). You capture low-res frames (e.g., 320x240), convert them to grayscale, and compare the pixel delta between consecutive frames. Trade-off: This spikes CPU usage to 40-60% on a Pi 5, which will cause thermal throttling within 15 minutes unless you have the official Active Cooler attached. It also generates false positives from shadows and swaying trees.
How to Extend (Frigate NVR & AI Object Detection)
For a production-grade property security system, local MP4 saving is insufficient. Extend this build by replacing the local recording loop with an RTSP stream using mediamtx. Point a Docker container running Frigate NVR (hosted on a NAS or beefier x86 server) at the RTSP URL. Frigate uses Google Coral TPU acceleration to perform real-time AI object detection, filtering out animals and cars, and only alerting you when a human is detected in a specific zone.
Raspberry Pi Security Camera FAQ
How to make a Raspberry Pi security camera record only when motion is detected?
The most efficient method is using a hardware PIR (Passive Infrared) sensor, as demonstrated in the code above. The PIR sensor detects changes in infrared heat signatures and pulls a GPIO pin HIGH, waking the camera encoder only when needed. This keeps CPU usage near 1% during idle times. Software-based motion detection (using OpenCV pixel differencing) is an alternative, but it requires the camera ISP to constantly process frames, increasing power draw and thermal output.
Can I use a Raspberry Pi security camera without an internet connection?
Yes, the hardware and picamera2 stack operate entirely offline. However, you must address time drift. Without an internet connection to reach NTP (Network Time Protocol) servers, the Pi's real-time clock (RTC) will reset to the epoch (1970) or its last known time on every reboot, resulting in video files with incorrect timestamps. To fix this for off-grid builds, wire a DS3231 I2C hardware RTC module to the Pi's GPIO header and configure the hwclock daemon to sync the system time on boot.
Why is my Raspberry Pi Camera Module 3 showing a green tint or flickering?
A green tint usually indicates that the camera's IR-cut filter is stuck or that you are using a "NoIR" (No Infrared Filter) module in daylight, which allows IR light to wash out the color balance. Flickering (strobing) under artificial light is caused by a mismatch between the camera's shutter speed and the AC mains frequency. If you are in a 60Hz region (US/Canada), configure the picamera2 controls to set the exposure time to a multiple of 1/120th of a second to eliminate the banding effect.
How much storage does a Raspberry Pi security camera use per day?
Storage consumption depends entirely on the H.264 bitrate and how much motion occurs. In the provided script, the encoder is set to 4,000,000 bits per second (4 Mbps).
The Math: 4 Mbps = 0.5 Megabytes per second.
If the camera records continuously for 24 hours: 0.5 MB/s * 86,400 seconds = 43,200 MB, or roughly 42.2 GB per day.
If you use the PIR sensor and only record 10-second clips for an average of 2 hours of cumulative motion per day, your storage drops to approximately 3.5 GB per day, allowing a 32GB microSD card to hold over a week of footage before overwriting.
For deeper integration with the official camera stack, refer to the Raspberry Pi Picamera2 Documentation and the Camera Module 3 Hardware Guide.






