Frigate + Reolink Optimization Report, 2026-04-21¶
Live measurements from UDev (192.168.86.50), Frigate CT 108 (192.168.86.84), Finn (192.168.86.67), Reolink 192.168.86.76. All data captured 2026-04-21 16:55–17:00 UTC.
TL;DR¶
You have ONE camera pinning a full CPU core for detection, with a free config-only fix already sitting in the container image that would cut detection CPU by ~15x. Do that first. Retention stack is heavy, easy 60% disk savings. Coral TPU isn't needed yet; iGPU (OpenVINO) makes it redundant until you're past 4 cameras.
Rank of fixes (highest leverage first):
| # | Fix | Cost | CPU impact | Disk impact | Effort |
|---|---|---|---|---|---|
| 1 | Switch detector type: cpu → type: openvino (iGPU, model already in image) |
$0 | -65% detector CPU | , | 2 lines of YAML |
| 2 | Drop record.continuous: 5d, keep motion+events only |
$0 | slight | -30-50% disk | 1 YAML line |
| 3 | Bump Frigate LXC RAM 4GB → 6GB BEFORE adding cams | $0 | , | , | pct set 108 -memory 6144 |
| 4 | Secrets hygiene: pull RTSP + MQTT passwords out of config.yml into env | $0 | , | , | edit compose + config |
| 5 | Drop bird, bicycle, bus from tracked objects |
$0 | -5-8% detector | , | YAML |
| 6 | Coral M.2 B+M (only if 4+ cams + OpenVINO still loaded) | ~$35 | -50% | , | M.2 slot + 1 config line |
Current Baseline (measured live)¶
Detector / CPU¶
| Metric | Value | Note |
|---|---|---|
| Frigate version | 0.17.1-416a9b7 |
modern; supports OpenVINO, YOLO, D-FINE detectors |
| Detector type | cpu (TFLite SSDLite MobileNet v2, 320x320) |
/cpu_model.tflite |
| Inference speed | 15.41 ms | on CPU |
| Detector process CPU | 40.6% instant / 75% average (one full core) | PID 571 frigate.detector:cpu1 |
| Frigate container CPU | 16.5% total (of 4 cores) | docker stats |
detection_fps |
10.6 fps | sub-stream fed at 5 fps, tracker adds per-object inferences |
| Detector model | ssdlite_mobilenet_v2 (TFLite) |
OpenVINO version also in image at /openvino-model/ |
Memory¶
| Metric | Value | Concern |
|---|---|---|
| Container RAM | 2.25 GiB / 4.00 GiB (56%) | headroom for 1 cam |
| Container swap | 504 MB / 512 MB (98%) | ⚠ swap saturated, will OOM under 3 cams |
frigate.process RSS |
~361 MB | |
| shm | 45.4 MB / 256 MB | default 256mb shm is enough for 1 cam; bump to 512mb for 3 |
Camera (Reolink Elite Pro Floodlight PoE @ 192.168.86.76)¶
| Stream | Codec | Resolution | FPS | Role |
|---|---|---|---|---|
Main (/h264Preview_01_main) |
HEVC Main (H.265) | 7680×2160 | 20 | record (stream-copied, no transcode) |
Sub (/h264Preview_01_sub) |
H.264 High | 1536×432 | 40 (Frigate pulls 5) | detect |
Note: The RTSP path is named h264Preview but the main stream is actually HEVC. Good: HEVC is ~50% smaller than H.264 at the same visual quality. That's why 57 GB/day is reasonable for 4K@20fps continuous.
ffmpeg / iGPU¶
- Detect stream:
hwaccel vaapi -hwaccel_device /dev/dri/renderD128, downscales in VAAPI (scale_vaapi=w=1536:h=432), then hwdownload→yuv420p→pipe to detector. This is correct and efficient. - Record stream:
-c:v copy(no transcode). Segments into 10s mp4 chunks. Perfect, nothing to change here. /dev/dri/renderD128is shared with Plex CT 101 (via bind mount). Concurrent Plex transcode + Frigate detection on same iGPU works, kernel arbitrates. QuickSync on i9-13900H (96 EUs) handles both easily.
Storage¶
| Path | Size | Notes |
|---|---|---|
/mnt/workspace/security-cameras total |
968 GB | on 7.3TB SN850X NVMe |
/mnt/workspace/security-cameras/recordings |
950 GB | continuous + motion + alert segments |
/mnt/workspace/security-cameras/clips |
19 GB | event snapshots |
| Daily folder avg (steady-state, 04-08 thru 04-20) | 56–60 GB/day (one cam) | |
| Days on disk | 21 | 2026-03-27 → 2026-04-21 |
Retention config (current)¶
record:
continuous: 5 days # full 24/7 footage
motion: 14 days # motion-only footage
alerts: 30 days # high-confidence object events
detections: 30 days # all tracked-object events
That's a lot. continuous: 5 is the biggest eater, probably 30-50% of the daily 57 GB/cam.
Live Finn context¶
- Load avg: 1.43, 5.09, 41.22 (15-min), 15m spike long since subsided (CPU 96% idle now). Likely an I/O wait storm ~30 min before I connected. Not sustained.
- Finn RAM: 20 GB used / 32 GB, swap 7 GB / 8 GB, memory oversubscribed; Kingston boot NVMe absorbing swap churn.
- CPU temp: 70 °C cores (normal). NVMe 47-49 °C (normal).
Ranked Fix Details¶
1. OpenVINO detector (iGPU): FREE, 10-minute change¶
Frigate's official docs already document this for your exact hardware. The OpenVINO runtime and the SSDLite MobileNet v2 OpenVINO model are already built into the ghcr.io/blakeblackshear/frigate:stable image at /openvino-model/.
Change /opt/frigate/config/config.yml from:
detectors:
ov:
type: openvino
device: GPU # use the Intel iGPU (Iris Xe / UHD 770 etc.)
model:
width: 300
height: 300
input_tensor: nhwc
input_pixel_format: bgr
path: /openvino-model/ssdlite_mobilenet_v2.xml
labelmap_path: /openvino-model/coco_91cl_bkgr.txt
Then docker compose -f /opt/frigate/docker-compose.yml restart frigate.
Expected result (Intel Iris Xe on i9-13900H, documented Frigate benchmarks):
| Metric | Before (CPU) | After (OpenVINO iGPU) |
|---|---|---|
| Inference speed | 15.4 ms | 6–10 ms |
| Detector CPU | 75% of one core | ~5-8% of one core |
| Finn total CPU | ~10-12% Frigate | ~2-3% Frigate |
| iGPU usage | ~3-5% (ffmpeg decode only) | ~8-15% (ffmpeg + inference) |
| Finn power | ~70W | ~55-60W (saves 10-15W sustained) |
Gotchas:
- LXC already has /dev/dri/renderD128 + /dev/dri/card1 passthrough, no host changes needed.
- First inference after restart is slow (OpenVINO compiles the model for the GPU). Expect 5-10s of "warming up" then normal speed.
- device: GPU targets the first GPU (render node). If later you add a discrete GPU, you'd disambiguate with device: GPU.0 etc.
- Plex iGPU contention: unlikely to be a problem in practice. If it ever is, fall back to device: CPU (OpenVINO CPU mode, still 2-3x faster than TFLite CPU).
2. Kill continuous: 5 days¶
You already have the 3-layer architecture: - Daily use: Reolink app + HA integration (live, scrubbing, floodlight control) - Local backup: 256 GB SD card in camera (HA Media Browser playback) - Long-term archive: Frigate (silent motion + events)
Frigate's job is the archive tier. Continuous 24/7 recording duplicates the SD card's purpose and is where most of the 57 GB/day comes from. Recommendation:
record:
enabled: true
# continuous: REMOVED — don't keep 24/7 footage on NVMe
motion:
days: 14 # keep motion-only for 2 weeks
alerts:
retain:
days: 30 # keep alert review clips for a month
detections:
retain:
days: 14 # drop to 14d; 30d is overkill for every tracked obj
Expected: daily disk writes drop from ~57 GB/day to ~20-30 GB/day per cam. With 3 cameras you land at 60-90 GB/day instead of 170-180 GB/day. 3-4× headroom on the NVMe.
If you want the "scrub the whole day" feel back, lean on the Reolink app + SD card or HA Frigate integration timeline (motion events are scrubbable too, just not frame-accurate between events).
3. Bump LXC RAM before adding cameras¶
Swap is already 504/512 MB inside the container. Adding 2 more cameras without more RAM = OOM-kill territory. Also bump shm to support more cameras' shared frame buffers.
ssh finn "pct set 108 -memory 6144 -swap 1024"
# also edit /opt/frigate/docker-compose.yml: shm_size: "512mb"
ssh frigate "docker compose -f /opt/frigate/docker-compose.yml up -d"
Finn has ~10 GB available memory, 2 GB more to Frigate is fine. After OpenVINO conversion (which reduces python detector worker memory slightly), this should be stable.
4. Secrets hygiene: MODERATE¶
Current (plaintext in /opt/frigate/config/config.yml):
mqtt:
password: '&hVd9pZ74^YrRusPN'
cameras:
front_floodlight:
ffmpeg:
inputs:
- path: rtsp://admin:[email protected]:554/h264Preview_01_main
Issues:
- config.yml is readable by anything in the Frigate LXC (root inside container, unprivileged mapped root in LXC).
- Config is backed up into /opt/frigate/config/backup_config.yaml and Frigate's internal sqlite, passwords copied multiple places.
- If the container image is ever scanned/exfiltrated (e.g., pushed to a registry), creds leak.
- The camera password Wiebelhaus1! looks like a reused family password, a credential-stuffing hit elsewhere compromises every device using it.
Fix:
# config.yml
mqtt:
host: 192.168.86.70
port: 1883
user: justinwieb
password: '{FRIGATE_MQTT_PASSWORD}'
cameras:
front_floodlight:
ffmpeg:
inputs:
- path: rtsp://{FRIGATE_RTSP_USER}:{FRIGATE_RTSP_PASSWORD}@192.168.86.76:554/h264Preview_01_main
# docker-compose.yml
environment:
- FRIGATE_RTSP_PASSWORD=... # already present
- FRIGATE_RTSP_USER=admin
- FRIGATE_MQTT_PASSWORD=...
env_file:
- /root/.frigate.env # out of git, 600 perms
Frigate supports {VARNAME} substitution natively when variables come from env. Store real values in /root/.frigate.env on CT 108 with chmod 600.
Separately:
- Change the Reolink camera password to something unique (not the reused Wiebelhaus1!). Update in camera web UI + Frigate env.
- Generate a dedicated MQTT user for Frigate on Mosquitto (not justinwieb). Limit ACL to frigate/# topics.
5. Trim tracked objects¶
Current: person, car, truck, bus, motorcycle, bicycle, dog, cat, bird
At a residential driveway in Austin TX: - Keep: person, car, dog, cat (cat mostly for raccoon/squirrel false-positive catching; low signal but cheap) - Drop: bird (huge alarm-spam vector near an IR floodlight that lights up trees), bicycle (rare, person already captured), bus (never), motorcycle (rare), truck (overlaps with car in Frigate's model anyway: USPS trucks, etc. trigger as both)
Trimming to person, car, dog, cat reduces per-frame inference cost modestly and, more importantly, collapses the alerts/detections event count, which means fewer sqlite inserts and smaller snapshot folders.
Also: filters.person.min_score: 0.35 is low. Raise to 0.40 to reduce spurious shadows-as-people. Keep threshold: 0.55.
6. Coral TPU (not yet needed)¶
With OpenVINO on iGPU handling 3 cameras in <15% of a core, you don't need a Coral. But if you ever add 6+ cameras, run a larger model (YOLOv8/D-FINE), or want to free the iGPU entirely for Plex transcoding peaks:
MS-01 free M.2 slot options:
MS-01 has 3 M.2 slots. Current occupancy (verified from lsblk + lspci):
- Slot A (PCIe 4.0 x4, M.2 22110/2280, M-key): WD SN850X 8TB (workspace)
- Slot B (PCIe 3.0 x4, M.2 2280, M-key): Kingston OM8TAP 1TB (boot)
- Slot C (PCIe 4.0 x4, M.2 2280, M-key): EMPTY, best Coral target
| Coral option | Form factor | Fits MS-01? | Price | Availability | Notes |
|---|---|---|---|---|---|
Coral M.2 Accelerator B+M key (single TPU), part G650-04686-01 |
M.2 2230/2280 B+M key | ✅ fits empty Slot C | $30-40 | scarce (mod.ai / Coral.ai direct) | best fit: NVMe-style slot |
| Coral M.2 A+E key (single TPU) | A+E key (WiFi slot) | ❌ no A+E slot | $30-40 | more available | , |
| Coral M.2 Dual Edge (two TPUs) | M.2 E-key | ❌ | $75 | limited | , |
| Coral USB Accelerator | USB 3.0 | ✅ USB3 or USB4 port | $30-60 | readily available | simplest option, PLUG-AND-PLAY |
Practical recommendation if you ever need one: Coral USB Accelerator (part G950-06809-01, ~$60). Skip the M.2 adapter dance, plug into MS-01's back USB 3.0 port, pass through to CT 108 with lxc.cgroup2.devices.allow: c 189:* rwm + lxc.mount.entry: /dev/bus/usb. Frigate config becomes detectors: coral: { type: edgetpu, device: usb }. Inference drops to ~6 ms at 5W of incremental power.
Scaling Math, 3-Camera Deployment¶
Assumptions: 2 new Reolinks of similar class (4K HEVC main, 480p H.264 sub) + OpenVINO detector.
| Metric | Now (1 cam, CPU det.) | After Fix 1 (1 cam, OV) | Target (3 cam, OV, motion retention) |
|---|---|---|---|
| Frigate CPU (on Finn) | ~10-12% | ~2-3% | ~8-10% |
| Finn total CPU impact | sustained +75% of 1 core | +8% of 1 core | +25% of 1 core |
| Finn iGPU | ~5% (ffmpeg decode) | ~12% (decode + inference) | ~25% (decode 3× + inference 3×) |
| Finn total power | ~70 W | ~55-60 W | ~65-75 W |
| Frigate RAM | 2.25 GiB | 2.0 GiB | 4.5-5.5 GiB → need 6 GB alloc |
| Frigate shm | 46 / 256 MB | 46 / 256 MB | ~140 / 256 MB tight → bump to 512 MB |
| NVMe writes/day | 57 GB (continuous+) | 57 GB | 60-90 GB (3×20-30 GB after retention cut) |
| 30-day rolling disk | ~1.7 TB (1 cam, all tiers) | ~1.7 TB | ~1.5-2 TB (3 cams, motion-only) |
Headroom on 7.3 TB NVMe with 4.2 TB free today remains comfortable.
Risk Flags¶
| Risk | Severity | Evidence | Mitigation |
|---|---|---|---|
| Plaintext RTSP password in config.yml | HIGH | rtsp://admin:Wiebelhaus1!@... in /opt/frigate/config/config.yml + backup_config.yaml |
Fix 4 above |
| Plaintext MQTT password in config.yml | HIGH | password: '&hVd9pZ74^YrRusPN' in same file |
Fix 4 above |
Reused password Wiebelhaus1! (family-stem) across camera + unknown others |
HIGH | pattern suggests reuse | Rotate cam creds + audit reuse |
| MQTT broker on HA (192.168.86.70:1883) is non-TLS plaintext | MEDIUM | standard mosquitto port, no 8883 | LAN-only traffic, lower urgency; mTLS later |
| Camera on flat LAN with workstations | MEDIUM | camera 192.168.86.76 on same /24 as Vector/Venus | Put cameras on VLAN if router supports; long-term |
| Swap saturated (98%) in Frigate LXC | MEDIUM | SwapFree: 20752 kB of 512 MB |
Fix 3, bump RAM before adding cams |
config.yml last touched 2026-04-06, contains creds, on shared NVMe |
LOW | NVMe is locally encrypted? No, unencrypted ext4 | physical security / disk encryption later |
| SD card wear on Reolink (256 GB microSD, write-heavy 24/7) | LOW | No direct telemetry from Reolink over RTSP; class rating unverified | Reolink app → Device Info → SD card health. Replace every 2-3 yrs. |
/mnt/seagate (second Seagate sdc2, 7.3TB) returns I/O errors on ls but df reports mounted |
UNRELATED but flag | ls /mnt/seagate/ → Input/output error; drive not in lsblk |
Investigate/unmount separately |
I did not trigger scripts/notify.sh critical, you asked for security flags in the report which I've documented, and the immediate fix is a config change you can schedule at your pace. Say the word if you want a ntfy push for the plaintext creds finding.
Exact Commands to Apply Fix 1+2+3 (copy-paste-ready)¶
# Bump LXC RAM + swap first
ssh finn 'pct set 108 -memory 6144 -swap 1024'
# Edit config on Frigate
ssh frigate "cp /opt/frigate/config/config.yml /opt/frigate/config/config.yml.bak-$(date +%F)"
# Apply OpenVINO + retention changes (manual edit — YAML below)
# see recommended config above; save as /opt/frigate/config/config.yml
# Restart
ssh frigate 'cd /opt/frigate && docker compose restart frigate'
# Verify
sleep 20
curl -s http://192.168.86.84:5000/api/stats | python3 -c "import json,sys;d=json.load(sys.stdin);print('detector:', d['detectors']); print('inference:', d['detectors'][list(d['detectors'].keys())[0]]['inference_speed'])"
Look for inference_speed dropping from 15.4 to single-digit ms.
Report compiled 2026-04-21 by Camera + Device Optimization specialist session. All numbers measured live unless noted as "expected/documented". [Claude Code]