Frigate: NVR With Object Detection on Raspberry Pi 5 & Coral TPU
This article explains how to install and configure the Frigate NVR software on a Raspberry Pi 5 with a Coral Edge TPU.
Overview
What is Frigate?
Frigate is a free network video recorder (NVR) software. It collects your surveillance camera video streams (typically via RTSP), performs object detection and stores the resulting clips.
Local Object Detection With a Coral Edge TPU
One of the most important features of an NVR is object detection. You want to review relevant movement only (e.g., people), not leaves blowing in the wind. By offloading object detection to an inexpensive Coral Edge TPU, Frigate achieves excellent detection quality even on low-cost hardware like a Raspberry Pi. As a big plus, everything runs locally without uploading your video streams to the cloud.
Hardware Choices
I selected a Raspberry Pi 5 as the basis for my NVR. The OS goes on a 32 GB SD card while a 512 GB NVMe SSD provides reliable storage for the recordings.
Initially, I went for the PCIe version of the Coral Edge TPU but that turned out to be a bad idea. It requires a driver that doesn’t seem to be maintained anymore and causes errors when updating the OS. The USB version of the Coral Edge TPU is a much better choice. It doesn’t require any custom software on the OS. Everything that is needed is included in the Frigate Docker image.
Installing and Configuring Raspberry Pi OS
Raspberry Pi Imager
- Connect the SD card you want to use for the Raspberry Pi OS to your PC.
- Download, install, and run the Raspberry Pi Imager.
- Select your Pi model, the 64-bit Pi OS and your SD card. Click Next.
- The Use OS customization? dialog comes up.
- Click Edit settings and configure:
- General:
- Hostname:
nvr-int
- Username and password: set according to your preference
- Configure wireless LAN: specify your WiFi’s SSID and password
- Set locale settings: set according to your preference
- Hostname:
- Services:
- Enable SSH: checked
- Allow public-key authentication only: selected. Paste your public key into the text box.
- Click Save to close the settings dialog.
- General:
- You’re back in the Use OS customization? dialog. Select yes.
- Let the imager write the OS image to the SD card.
First Boot
- Insert the SD card into the Raspberry’s slot.
- If you use a HAT for SSD storage, put it in place and connect it to the Raspberry Pi.
- Connect the Coral Edge TPU with the included cable to one of the (blue) USB 3.0 ports.
- Connect the power supply, powering on the Raspberry.
- The Raspberry Pi should now be connected to your WiFi network.
- Convert the dynamic DHCP address to static and configure a DNS record for name resolution.
Initial Configuration
Connect via SSH to the Raspberry using the key you specified earlier.
Update the OS:
sudo apt update && sudo apt dist-upgrade
Partition and format the NVMe SSD:
sudo fdisk /dev/nvme0n1
sudo mkfs.ext4 /dev/nvme0n1p1
Create a mount point and mount the NVMe SSD:
sudo mkdir /data
sudo mount /dev/nvme0n1p1 /data
Configure mounting the NVMe SSD into the /data
directory at boot by editing /etc/fstab
:
/dev/nvme0n1p1 /data ext4 defaults 0 2
Reboot and verify that the SSD is mounted by running lsblk
.
Verify that the Coral Edge TPU USB device is connected correctly by running lsusb
. The device should show up as Global Unichip Corp.
as it’s still uninitialized. Once initialized by Frigate it’ll be listed as Google Inc
(docs).
Note: Some guides recommend assigning more RAM to the GPU by adding gpu_mem=512
to /boot/firmware/config.txt
. Due to the changed GPU memory allocation scheme of the Raspberry Pi 5, this is not only not necessary anymore, but the setting is completely ignored. The GPU memory as shown by vcgencmd get_mem gpu
is always a fixed carveout of 4 MB.
Installing Frigate
Installing Docker
Frigate comes as a Docker image, so we’ll first install and configure Docker according to my documentation here. Proceed only once Docker is installed.
Dockerized Frigate Directory Structure
This is what the directory structure will look like when we’re done:
data/
└── docker/
└── frigate/
├── config/
└── config.yml
├── data/
├── container-vars.env
└── docker-compose.yml
Create the new directories:
sudo mkdir -p /data/docker/frigate/config
sudo mkdir -p /data/docker/frigate/data
Frigate Docker Compose File
Create docker-compose.yml
with the following content:
services:
frigate:
container_name: frigate
image: ghcr.io/blakeblackshear/frigate:stable
privileged: true
restart: unless-stopped
shm_size: "512mb"
devices:
- /dev/bus/usb:/dev/bus/usb
volumes:
- /etc/localtime:/etc/localtime:ro
- /data/docker/frigate/config:/config
- /data/docker/frigate/data:/media/frigate
- type: tmpfs
target: /tmp/cache
tmpfs:
size: 1000000000
ports:
- "8971:8971" # WebGUI TLS self-signed cert
- "8554:8554" # RTSP feeds
Create Frigate’s config file config/config.yml
with the following content:
mqtt:
enabled: false
detectors:
coral:
type: edgetpu
device: usb
cameras:
# ADD CAMERA(S) HERE
record:
enabled: true
retain:
days: 0
alerts:
retain:
days: 30
mode: motion
detections:
retain:
days: 30
mode: motion
tls:
enabled: false # Handled by Caddy
auth:
enabled: false # Handled by Caddy
Note: The above config lacks the camera configuration as that depends on your camera hardware. See the docs for details.
Start the Frigate Container
Navigate into the directory with docker-compose.yml
and run:
sudo docker compose up -d
Notes:
- Be patient! It’ll take a while until Frigate is fully initialized.
- When started for the first time, Frigate may have to initialize the Coral. You may have to stop and restart the container after initialization.
Inspect the container logs for errors with the command sudo docker compose logs --tail 100 --timestamps
.
Expected Errors During Frigate Startup
[error] 177#177: *1 connect() failed (111: Connection refused) while connecting to upstream, client: 127.0.0.1, server: , request: "GET /api/version HTTP/1.1", subrequest: "/auth", upstream: "http://127.0.0.1:5001/auth", host: "127.0.0.1:5000"
[error] 177#177: *1 auth request unexpected status: 502 while sending to client, client: 127.0.0.1, server: , request: "GET /api/version HTTP/1.1", host: "127.0.0.1:5000"
Log Messages When Startup is Successful
INFO: Attempting to load TPU as usb
INFO: TPU found
INFO: Camera processor started for CAM_NAME
INFO: Capture process started for CAM_NAME
INFO: FastAPI started
Let’s Encrypt Certificate for Frigate via Caddy
Caddyfile
Add the following to Caddyfile
(details):
nvr.{$MY_DOMAIN} {
import auth
reverse_proxy nvr-int.{$MY_DOMAIN}:8971
tls {
dns cloudflare {env.CLOUDFLARE_API_TOKEN}
}
}
Note: the definition of the auth
snippet can be found here.
DNS A Records
Add the following A records to your DNS domain (details):
nvr.home.yourdomain.com 192.168.0.4 # replace with your Docker host's IP address
Try to resolve the name on a machine in your network (e.g., nslookup nvr.home.yourdomain.com
).
Reload Caddy’s Configuration
Instruct Caddy to reload its configuration by running:
docker exec -w /etc/caddy caddy caddy reload
You should now be able to access Frigate at https://nvr.home.yourdomain.com
without getting a certificate warning from your browser.
Frigate: Verification & Initial Configuration
Verifying Your Installation from the Web UI
If you configured your cameras correctly, you should see a thumbnail live view of each camera feed on the homepage.
Verify that the UI shows System is healthy in the lower-right corner.
Navigate the Settings > System logs. There should be no errors and only the following warning: Did not detect hwaccel, using a GPU for accelerated video decoding is highly recommended
. Currently, there doesn’t seem to be hardware acceleration for the GPU of the Raspberry Pi 5 (docs).
Frigate CPU & RAM Utilization
Navigate to Settings > System metrics and inspect all three tabs (General, Storage, Cameras). Frigate provides nicely detailed performance metrics.
In my setup with two video streams, Frigate uses the following system resources on average:
- Raspberry load average: 0.3 (as measured by
htop
) - Raspberry CPU: 6-8% (as measured by Frigate)
- Raspberry memory: 1.6 GB (as measured by
htop
) - Coral CPU: 0-5% (as measured by Frigate)
- Coral memory: 3.5% (as measured by Frigate)
Initial Configuration
UI Settings
Navigate to Settings > Configuration > Settings > UI Settings and configure the following:
- Recordings Viewer > Default Playback Rate:
2x
- Calendar > First weekday: Monday
Masks and Zones
You may want to define detection masks (also called zones). This prevents Frigate from recording when someone walks on the street, for example.
To define masks, navigate to Settings > Configuration > Settings > Masks/Zones and create a zone.
Switch over to the Camera Settings tab and enable the alerts and detections for the zone you created:
- Alerts: enabled (All person, car objects detected in ZONE on CAM will be shown as Alerts)
- Detections:
- Limit detections to specific zones: enabled (All objects not classified as Alerts that are detected in ZONE on CAM will be shown as Detections.)
Backup
OS & App Configuration
I’m using my Linux config file backup script to back up OS and Frigate config changes to a private GitHub repository. The following is the contents of my backup_src.txt
file:
/backup/.ssh
/backup/config/backup_src.txt
/etc/**/*.conf
/etc/ssh/sshd_config
/data/docker/frigate/config/config.yml
/data/docker/frigate/docker-compose.yml
Camera Recordings
It would make a lot of sense to synchronize Frigate’s recordings to a cloud storage service for safekeeping in case a burglar finds the NVR. Ideally, Frigate would have built-in functionality for cloud backup. Until that is the case, we can build it ourselves. Details to follow soon.