Skip to main content

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

  1. In the UniFi OS web UI, open Settings → Control Plane → Integrations, click Create API Key, and copy the key.
  2. In GEM admin, create a new device using the unifi_protect driver.
  3. 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).
  4. Save and reload. On boot the driver hits /meta/info to confirm the key, then enumerates cameras, lights, and chimes.
  5. Run the get_cameras command to print every discovered camera with its id (a long alphanumeric string) and friendly name.
  6. 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

AttributeRequiredDescription
ipyesLAN IP / hostname of the UniFi OS console.
api_keyyesConsole API key. Stored encrypted; sent in the X-API-KEY header.
portnoHTTPS port. Defaults to 443.
status_intervalnoCamera-state poll interval in milliseconds. Defaults to 5000.

Zone

AttributeDescription
statemotion while a camera reports motion, clear otherwise. Driver-managed.
last_motionUnix-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

CommandArgsDescription
get_infoReturns controller meta (Protect application version, etc.).
get_camerasLists all cameras, refreshes the in-driver cache.
get_lightsLists Protect-managed flood lights.
get_chimesLists Protect-managed chimes.
snapshotaddressSaves a JPEG to static/snapshots/<device-id>-<address>.jpg and returns the relative path.
set_recording_modeaddress, modeMode is one of always, never, detections, schedule.
set_status_lightaddress, enabledToggles the camera status LED.

Limitations

  • No event streaming. The Integrations API exposes an SSE endpoint at /subscribe/events and /subscribe/devices. This build only polls — motion detection latency is bounded by status_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/info returns 404 — the console firmware predates the Integrations API. Upgrade UniFi OS to 3.2 or newer.
  • /meta/info returns 401 — the API key is wrong, expired, or was deleted. Mint a new one and update the api_key attribute.
  • Snapshots return status 400 for 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 schedule returns 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 the X-API-KEY header verbatim.