Skip to main content

Frigate NVR

Frigate (blakeblackshear/frigate) is a self-hosted, open-source NVR built around real-time object detection. This driver connects to a Frigate server on the LAN over its REST API (/api/… on port 5000 by default), polls per-camera events for motion and object-class detections (person, car, dog, license plate, …), and exposes per-camera toggles for object detection, motion detection, continuous recording, and snapshot capture.

One GEM device represents a single Frigate server. Each Frigate camera that GEM should track becomes a zone whose address is the camera name from Frigate's config.

Prerequisites

  • A running Frigate server, version 0.13.x or newer, reachable on the LAN from the GEM host. Confirm this in a browser first — the Frigate UI should load at http://<frigate-host>:5000/.
  • One or more cameras defined in Frigate's config.yml (or via the web UI on 0.14+) and appearing under cameras: in /api/config.
  • If Frigate's native authentication is enabled (0.14+ with AUTHENTICATION on), a username and password GEM can use to log in. On earlier builds — or when Frigate is fronted by a reverse proxy that handles auth — leave both blank.
  • TCP to the Frigate host on the configured port (default 5000) open from the GEM host.

MQTT is Frigate's real-time event bus but is deliberately not required here. The driver reads from /api/events on its poll interval so an integrator can add Frigate without also standing up a broker; adding MQTT for sub-second reactions is a future upgrade path, not a prerequisite.

Setup

  1. Verify Frigate is reachable in a browser at http://<frigate-host>:<port>/. Sort out any networking issues at this step, not from inside GEM.
  2. In GEM admin, add a device with the Frigate NVR driver, placed under a Security or Cameras subsystem. Only one GEM device per Frigate server — cameras are added as zones underneath.
  3. Set the device attributes:
    • ip — Frigate host or IP.
    • port — HTTP port Frigate is bound to. Default 5000.
    • protocolhttp, or https if Frigate sits behind a TLS-terminating reverse proxy.
    • username and password — only when Frigate's native auth is enabled. Leave both blank otherwise.
  4. Save and reload the device. On boot the driver hits /api/config, notes the configured cameras, and starts polling /api/events every status_interval ms.
  5. Run the get_cameras command to print every camera name Frigate knows about.
  6. For each camera you want to track, add a zone under the same subsystem, bind it to the Frigate device, and set its address to the camera name exactly as it appears in Frigate — camera names are case-sensitive and any renames in Frigate will break the binding until zone address is updated to match.
One zone per camera — created by you

GEM does not auto-create zones from Frigate discovery. A camera only surfaces state once a zone whose address matches its Frigate name exists and is bound to the Frigate device. Cameras without a matching zone still appear in get_cameras, but their events are ignored — nothing is tracked for them until you add the zone. Copy the exact name from get_cameras.

Attribute reference

Device

AttributeRequiredDescription
ipyesLAN IP / hostname of the Frigate server.
portnoHTTP port. Defaults to 5000.
protocolnohttp (default) or https when Frigate is behind a TLS reverse proxy.
usernamenoOnly when Frigate 0.14+ native auth is enabled.
passwordnoOnly when Frigate 0.14+ native auth is enabled. Stored encrypted; used to mint a JWT held in memory.
status_intervalnoEvent-poll interval in milliseconds. Defaults to 3000. Lower it for tighter reaction times at the cost of more requests.

Zone

AttributeDescription
statemotion while any active event exists for the camera, clear when the last event ends. Driver-managed.
last_motionUnix-millisecond timestamp of the last event start. Driver-managed.
person, car, dog, license_plate, …Object-class flags — 1 while a detected object of that class is present, 0 when its event ends. One attribute per object label Frigate emits, converted to snake_case. A flag auto-clears after 120 s if the event's end frame is never observed (server restart, network blip mid-detection).

The zone address is required and must match the camera name in Frigate's config.

Commands

CommandArgsDescription
get_configReturn the full /api/config document (Frigate's live config as JSON).
get_camerasList the camera names Frigate is running.
get_statsReturn /api/stats — process and camera runtime stats.
get_eventslimitReturn the most recent events (default 50).
snapshotaddressFetch latest.jpg for the camera and save it under static/snapshots/<device-id>-<camera>.jpg. Returns the served URL, usable directly in a UI image widget or a notification.
set_detectaddress, stateToggle object detection for a camera. state = ON / OFF.
set_motionaddress, stateToggle motion detection for a camera.
set_recordingaddress, stateToggle continuous / event recording for a camera.
set_snapshotsaddress, stateToggle snapshot capture for a camera.
restartAsk Frigate to restart itself via /api/restart.

Event polling

Every status_interval the driver requests /api/events?limit=50&after=<lastId>, walks the new events oldest-first, and applies them:

  • On an event start (no end_time) — the zone's state flips to motion, last_motion gets the start timestamp, and the per-object-class flag (person, car, …) is set to 1.
  • On an event end (end_time populated) — the per-object-class flag goes back to 0 and the zone state flips back to clear. The driver does not reference-count overlapping detections: the first event end it observes flips state to clear, even if another object is still being tracked on the same camera (that object's own class flag stays 1 until its event ends or the 120 s timer clears it).
  • Missed end frames — a 120 s per-flag timer clears any object-class flag whose end frame never arrives, and a 30 s per-camera timer flips state back to clear if no further activity is observed. This bounds the "stuck at motion" failure mode when Frigate crashes mid-event.

The very first poll after connect seeds the "last seen event id" without emitting any state changes, so pre-existing events don't spam the log on startup.

Authentication

Frigate 0.13 and earlier have no built-in authentication — the API is open on the LAN and usually fronted by a reverse proxy that handles it externally. Leave username and password blank in that case.

Frigate 0.14 added native authentication with JWT. When the device has both username and password set, the driver:

  1. POSTs to /api/login on connect with {user, password} and stores the returned JWT.
  2. Sends it in an Authorization: Bearer … header on every subsequent request.
  3. If any request returns 401 (token expired or invalidated), the driver re-logs in once and retries the request. A second 401 in a row surfaces frigate 401 after re-login attempt as the error.

The token is held in memory only. A device reload triggers a fresh login. Persisting the token across restarts is a possible future addition but not needed for correctness — Frigate's JWTs are cheap to mint.

Limitations

  • HTTP polling only in this build. MQTT-backed sub-second reactions require a broker and are not wired through yet. status_interval (default 3 s) is the practical floor.
  • No live video. Snapshots only. The RTSP restream URL published by Frigate is not surfaced as a command here — use the ONVIF driver on the camera itself when you need streaming.
  • PTZ control is not exposed. Frigate has a PTZ command surface for supported cameras; a future revision may add ptz / ptz_move verbs.
  • Manual events and audio detections are not tracked separately. They still show up in the events feed, so the zone state will still flip to motion, but the object-class breakdown is what the driver focuses on.
  • set_detect / set_motion / set_recording / set_snapshots live under /api/<camera>/<endpoint>/set and are present in 0.13+. Very old builds without those routes return 404 — leave the toggles alone and manage state in config.yml on those.

Troubleshooting

  • get_cameras returns an empty list. Frigate's /api/config returned no cameras or a non-200. Load http://<host>:5000/api/config directly and confirm the cameras: block is populated. If it's empty, fix config.yml first.
  • All commands return frigate GET … status 401. Frigate's native auth is on but username / password on the device are blank or wrong. Check the Frigate server log for the login attempt.
  • Zone state stays clear during actual detections. Almost always a wrong zone.address — confirm against get_cameras; names are case-sensitive.
  • snapshot returns snapshot not available for camera <name>. Frigate returns 404 when snapshots are disabled per-camera or the camera has never captured one. Enable with set_snapshots ON and wait for a detection.
  • Object-class flags stuck at 1. Frigate lost the event's end frame (a server restart mid-detection is the usual cause). The 120 s auto-clear will resolve it; if it keeps happening, look at Frigate's own logs for restarts or watchdog kills.
  • Poll interval feels too slow. Lower status_interval on the device (500 ms is the enforced minimum). For real sub-second reaction times, wire an MQTT broker and consider Frigate → MQTT as a separate ingress alongside this driver.
  • Devices — adding the Frigate server as a single device.
  • Zones — creating one zone per Frigate camera, addressed by the camera name.
  • Subsystems — the Security / Cameras subsystem the Frigate device and its camera zones live under.
  • Commands — running snapshot, set_detect, and the recording / snapshots toggles from the admin UI, macros, or automations.
  • Triggers — firing automations off a camera zone's state flipping to motion or a class flag like person going to 1.
  • ONVIF — the vendor-neutral camera path when live RTSP video is needed instead of Frigate's event surface.
  • UniFi Protect — the closest commercial-NVR equivalent for reference.