UniFi Protect
Ubiquiti UniFi Protect controllers (Cloud Key Gen2+, Dream Machine Pro, UNVR, UDM-SE) and the cameras / floodlights / chimes managed by them, integrated via the local Protect Integrations REST API on UniFi OS using a per-controller API key.
The driver is read-mostly: it polls camera state and motion timestamps, fetches JPEG snapshots, and exposes a small set of write commands (recording mode, status LED). Lights and chimes are listed but not yet controllable.
Prerequisites
- A UniFi OS console (Cloud Key Gen2+, Dream Machine Pro, UNVR, UDM-SE) running UniFi Protect 3.x or newer.
- Console firmware new enough to expose the Integrations API at
/proxy/protect/integrations/v1/(UniFi OS 3.2+). - An API key minted under Settings → Control Plane → Integrations → Create API Key. The key is shown only once at creation — copy it before navigating away.
- TCP/443 reachable from the GEM controller to the console (LAN IP or hostname).
Setup
- In the UniFi OS web UI, open Settings → Control Plane → Integrations, click Create API Key, and copy the key.
- In GEM admin, create a new device using the
unifi_protectdriver. - Set the device attributes:
ip— LAN IP or hostname of the UniFi OS console.api_key— the key you copied in step 1 (stored encrypted).
- Save and reload. On boot the driver hits
/meta/infoto confirm the key, then enumerates cameras, lights, and chimes. - Run the
get_camerascommand to print every discovered camera with its id (a long alphanumeric string) and friendly name. - For each camera you want to track in GEM, create a zone whose address is that camera id. The driver writes per-camera state onto these zones.
Attribute reference
Device
| Attribute | Required | Description |
|---|---|---|
ip | yes | LAN IP / hostname of the UniFi OS console. |
api_key | yes | Console API key. Stored encrypted; sent in the X-API-KEY header. |
port | no | HTTPS port. Defaults to 443. |
status_interval | no | Camera-state poll interval in milliseconds. Defaults to 5000. |
Zone
| Attribute | Description |
|---|---|
state | motion while a camera reports motion, clear otherwise. Driver-managed. |
last_motion | Unix-millisecond timestamp of the last reported motion event. Driver-managed. |
Zone address is required and must be the camera id from get_cameras (NOT the friendly name).
Commands
| Command | Args | Description |
|---|---|---|
get_info | — | Returns controller meta (Protect application version, etc.). |
get_cameras | — | Lists all cameras, refreshes the in-driver cache. |
get_lights | — | Lists Protect-managed flood lights. |
get_chimes | — | Lists Protect-managed chimes. |
snapshot | address | Saves a JPEG to static/snapshots/<device-id>-<address>.jpg and returns the relative path. |
set_recording_mode | address, mode | Mode is one of always, never, detections, schedule. |
set_status_light | address, enabled | Toggles the camera status LED. |
Limitations
- No event streaming. The Integrations API exposes an SSE endpoint at
/subscribe/eventsand/subscribe/devices. This build only polls — motion detection latency is bounded bystatus_interval. - Lights and chimes are read-only. They show up in discovery but per-zone control of flood lights / chime tones is not yet wired through.
- No live video. Snapshots only. RTSPS stream URLs are exposed by the API but not surfaced as a command in this build.
- No camera-side configuration writes beyond recording mode and status LED. Privacy zones, motion sensitivity, and detection types are reachable through the API but not exposed yet.
Troubleshooting
/meta/inforeturns 404 — the console firmware predates the Integrations API. Upgrade UniFi OS to 3.2 or newer./meta/inforeturns 401 — the API key is wrong, expired, or was deleted. Mint a new one and update theapi_keyattribute.- Snapshots return
status 400for some cameras — a few low-power battery cameras only return snapshots while their stream is active. Wake the camera in the Protect UI first. set_recording_mode schedulereturns 400 — the camera has no schedule configured on the controller. Save a schedule in the Protect UI before sending this mode.- All requests time out — confirm 443/tcp from the GEM host to the console. If you front the console behind a reverse proxy, the proxy must forward
/proxy/protect/integrations/v1/and pass through theX-API-KEYheader verbatim.