Skip to content

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: cputype: 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
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/renderD128 is 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:
  cpu1:
    type: cpu
to:
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]