Skip to content

API Reference

Rendering options (hidden sources, signature annotations, heading level) are configured globally for the mkdocstrings Python handler in mkdocs.yml.

API Client (uiprotect.api)

UniFi Protect Server Wrapper.

BaseApiClient

devices_ws_url: str property

Get Devices Websocket URL.

events_ws_url: str property

Get Events Websocket URL.

is_public_only: bool property

Whether this client was built with only an API key (no private login).

ws_url: str property

Get Websocket URL.

api_request_raw(url: str, method: str = 'get', require_auth: bool = True, raise_exception: bool = True, api_path: str | None = None, public_api: bool = False, **kwargs: Any) -> bytes | None async

Make a API request

async_disconnect_ws() -> None async

Disconnect from Websocket.

authenticate() -> None async

Authenticate and get a token.

clear_all_sessions() -> None async

Clears all stored sessions from the config file.

clear_session() -> None async

Clears stored session for this specific user/host combination.

close_public_api_session() -> None async

Closing and deletes public API client session.

close_session() -> None async

Closing and deletes all client sessions.

ensure_authenticated() -> None async

Ensure we are authenticated.

get_public_api_session() -> aiohttp.ClientSession async

Gets or creates current public API client session

get_session() -> aiohttp.ClientSession async

Gets or creates current client session

is_authenticated() -> bool

Check to see if we are already authenticated.

request(method: str, url: str, require_auth: bool = False, auto_close: bool = True, public_api: bool = False, **kwargs: Any) -> aiohttp.ClientResponse async

Make a request to UniFi Protect with automatic retry on transient errors.

Automatically retries requests that receive 408, 429, 500, 502, 503, or 504 status codes using exponential backoff.

set_header(key: str, value: str | None) -> None

Set header.

CameraPublicApiLcdMessageRequest

Bases: TypedDict

Type for lcdMessage in PATCH /v1/cameras/{id} request body (Public API).

Per the integration spec, type is always required. text is required for CUSTOM_MESSAGE and IMAGE; resetAt is optional for all variants (UNIX timestamp in ms; omit to use the NVR default, pass None for "forever").

LightPatchRequest

Bases: TypedDict

Type for PATCH /v1/lights/{id} request body.

ProtectApiClient

Bases: BaseApiClient

Main UFP API Client

UniFi Protect is a full async application. "normal" use of interacting with it is to call .update() which will initialize the .bootstrap and create a Websocket connection to UFP. This Websocket connection will emit messages that will automatically update the .bootstrap over time.

You can use the .get_ methods to one off pull devices from the UFP API, but should not be used for building an application on top of.

All objects inside of .bootstrap have a reference back to the API client so they can use .save_device() and update themselves using their own .set_ methods on the object.


Text Only
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
host: UFP hostname / IP address
port: UFP HTTPS port
username: UFP username
password: UFP password
api_key: API key for UFP
verify_ssl: Verify HTTPS certificate (default: `True`)
session: Optional aiohttp session to use (default: generate one)
override_connection_host: Use `host` as your `connection_host` for RTSP stream instead of using the one provided by UniFi Protect.
minimum_score: minimum score for events (default: `0`)
subscribed_models: Model types you want to filter events for WS. You will need to manually check the bootstrap for updates for events that not subscibred.
ignore_stats: Ignore storage, system, etc. stats/metrics from NVR and cameras (default: false)
debug: Use full type validation (default: false)

connection_host: IPv4Address | IPv6Address | str property

Connection host to use for generating RTSP URLs.

has_public_bootstrap: bool property

Whether :meth:update_public has been called at least once.

public_bootstrap: PublicBootstrap property

In-memory cache of Public Integration API resources.

Must be populated via :meth:update_public first; raises :class:BadRequest otherwise. This is a conscious mirror of :attr:bootstrap so that merely reading the property never changes WS-handler semantics (which keys off _public_bootstrap is not None).

activate_relay_output_public(relay_id: str, output_id: int, *, state: Literal['on', 'off'] | None = None, pulse_duration_ms: int | None = None) -> None async

Activate, toggle or pulse a relay output.

Omit state to toggle the current state. pulse_duration_ms is only valid together with state='on'; the output will auto-turn off after the given milliseconds.

active_events(device_id: str | None = None) -> list[ProtectEvent]

Return the in-flight public events, optionally filtered by device.

Derived directly from public_bootstrap.events, so it works before any subscribe_events call (e.g. restoring state after a reload). Returns [] until update_public() has primed the public bootstrap.

adopt_device(model_type: ModelType, device_id: str) -> None async

Adopts a device

clear_tamper_sensor(device_id: str) -> None async

Clears tamper status for sensor

create_api_key(name: str) -> str async

Create an API key with the given name and return the full API key.

create_arm_profile_public(*, name: str, automations: list[str], schedules: list[PublicArmScheduleDict], record_everything: bool, activation_delay: int) -> ArmProfile async

Create a new arm profile.

create_camera_rtsps_streams(camera_id: str, qualities: list[ChannelQuality | str] | ChannelQuality | str) -> RTSPSStreams | None async

Creates RTSPS streams for a camera using public API.

On success the result is written through to the matching cached :class:PublicCamera's rtsps_streams field (when update_public() has primed it), since stream creation is not signalled over the websocket.

create_liveview_public(*, name: str, is_default: bool, is_global: bool, owner: str, layout: int, slots: list[PublicLiveviewSlotDict]) -> PublicLiveview async

Create a new liveview using public API.

create_talkback_session_public(camera_id: str) -> TalkbackSession async

Create a talkback session for a camera using public API.

Returns the talkback stream URL and audio configuration.

delete_arm_profile_public(profile_id: str) -> None async

Delete an arm profile.

delete_camera_rtsps_streams(camera_id: str, qualities: list[ChannelQuality | str] | ChannelQuality | str) -> bool async

Deletes RTSPS streams for a camera using public API.

On success the deleted qualities are removed from the matching cached :class:PublicCamera's rtsps_streams (when present); a camera left with no streams has the field cleared to None.

disable_arm_alarm_public() -> None async

Disable the arm alarm.

disable_camera_mic_permanently_public(camera_id: str) -> PublicCamera async

Permanently disable a camera's microphone.

Irreversible without a factory reset of the camera. The spec returns the updated camera object (not a 204).

emit_devices_message(msg: WSSubscriptionMessage) -> None

Emit message to all devices subscriptions.

emit_events_message(msg: WSSubscriptionMessage) -> None

Emit message to all events subscriptions.

emit_message(msg: WSSubscriptionMessage) -> None

Emit message to all subscriptions.

enable_arm_alarm_public() -> None async

Enable the arm alarm with the currently selected profile.

get_aiport(device_id: str) -> AiPort async

Gets a AiPort straight from the NVR.

The websocket is connected and running, you likely just want to use self.bootstrap.aiport[device_id]

get_aiports() -> list[AiPort] async

Gets the list of aiports straight from the NVR.

The websocket is connected and running, you likely just want to use self.bootstrap.aiports

get_alarm_hub_public(hub_id: str) -> LinkStation async

Get a specific alarm hub using public API.

get_alarm_hubs_public() -> list[LinkStation] async

Get all alarm hubs using public API.

get_arm_manager_settings_public() -> NvrArmMode | None async

Return current arm-manager state from the NVR cache.

The arm-manager state is embedded in the NVR object (armMode field of GET /v1/nvrs) — there is no dedicated GET endpoint. If the bootstrap cache is not yet populated, fetches the NVR now via :meth:get_nvr_public so the full PublicNVR is always constructed through the same code path.

get_arm_profiles_public() -> list[ArmProfile] async

Get all arm profiles.

get_bootstrap() -> Bootstrap async

Gets bootstrap object from UFP instance

This is a great alternative if you need metadata about the NVR without connecting to the Websocket

get_bridge(device_id: str) -> Bridge async

Gets a bridge straight from the NVR.

The websocket is connected and running, you likely just want to use self.bootstrap.bridges[device_id]

get_bridge_public(bridge_id: str) -> PublicBridge async

Get a specific bridge using public API.

get_bridges() -> list[Bridge] async

Gets the list of bridges straight from the NVR.

The websocket is connected and running, you likely just want to use self.bootstrap.bridges

get_bridges_public() -> list[PublicBridge] async

Get all bridges using public API.

get_camera(device_id: str) -> Camera async

Gets a camera straight from the NVR.

The websocket is connected and running, you likely just want to use self.bootstrap.cameras[device_id]

get_camera_public(camera_id: str) -> PublicCamera async

Get a specific camera using public API.

get_camera_rtsps_streams(camera_id: str) -> RTSPSStreams | None async

Fetch a camera's RTSPS streams from the public API.

A flag-free fetch primitive with no cache side-effects: caching policy lives in the population layer (:meth:update_public priming, the WS-reconnect refresh, and create/delete write-through).

get_camera_snapshot(camera_id: str, width: int | None = None, height: int | None = None, dt: datetime | None = None) -> bytes | None async

Gets snapshot for a camera.

Datetime of screenshot is approximate. It may be +/- a few seconds.

get_camera_video(camera_id: str, start: datetime, end: datetime, channel_index: int = 0, validate_channel_id: bool = True, output_file: Path | None = None, iterator_callback: IteratorCallback | None = None, progress_callback: ProgressCallback | None = None, chunk_size: int = 65536, fps: int | None = None) -> bytes | None async

Exports MP4 video from a given camera at a specific time.

Start/End of video export are approximate. It may be +/- a few seconds.

It is recommended to provide a output file or progress callback for larger video clips, otherwise the full video must be downloaded to memory before being written.

Providing the fps parameter creates a "timelapse" export with the given FPS value. Protect app gives the options for 60x (fps=4), 120x (fps=8), 300x (fps=20), and 600x (fps=40).

get_cameras() -> list[Camera] async

Gets the list of cameras straight from the NVR.

The websocket is connected and running, you likely just want to use self.bootstrap.cameras

get_cameras_public() -> list[PublicCamera] async

Get all cameras using public API.

get_chime(device_id: str) -> Chime async

Gets a chime straight from the NVR.

The websocket is connected and running, you likely just want to use self.bootstrap.chimes[device_id]

get_chime_public(chime_id: str) -> PublicChime async

Get a specific chime using public API.

get_chimes() -> list[Chime] async

Gets the list of chimes straight from the NVR.

The websocket is connected and running, you likely just want to use self.bootstrap.chimes

get_chimes_public() -> list[PublicChime] async

Get all chimes using public API.

get_console_mac() -> str | None async

Resolve the console/NVR mac via the UniFi-OS /api/system endpoint.

The public Protect Integration API only exposes the NVR mac on Protect newer than 7.1; older firmware omits it (:attr:PublicNVR.mac is then None). This helper fills that gap so a :meth:public_only client on older firmware can still derive the console's stable, mac-based identity.

This is a transitional workaround for the hybrid/parallel phase in which the private and public paths coexist: identity must stay mac-based to match what the private path already produces, so a feature toggling between the two paths doesn't churn entity ids. The end-state identity is the public API's own primary key (nvr.id); this helper is expected to be retired once the private path is dropped and consumers migrate to id.

/api/system is an off-contract UniFi-OS endpoint (not the public Protect API): unauthenticated, and it returns the mac of the device at the configured Protect host. Returns the mac string (e.g. "AABBCCDDEEFF", matching the private NVR.mac format) or None when the endpoint is unreachable or carries no mac.

get_device(model_type: ModelType, device_id: str, expected_type: type[ProtectModelWithId] | None = None) -> ProtectModelWithId async

Gets a device give the device model_type and id, converted into Python object

get_device_raw(model_type: ModelType, device_id: str) -> dict[str, Any] async

Gets a raw device give the device model_type and id

get_devices(model_type: ModelType, expected_type: type[ProtectModel] | None = None) -> list[ProtectModel] async

Gets a device list given a model_type, converted into Python objects

get_devices_raw(model_type: ModelType) -> list[dict[str, Any]] async

Gets a raw device list given a model_type

get_event(event_id: str) -> Event async

Gets an event straight from the NVR.

This is a great alternative if the event is no longer in the self.bootstrap.events[event_id] cache

get_event_animated_thumbnail(thumbnail_id: str, width: int | None = None, height: int | None = None, *, speedup: int = 10, retry_timeout: int = RETRY_TIMEOUT) -> bytes | None async

Gets given animated thumbanil from a given event.

Animated thumbnail response is a GIF image.

Note: thumbnails / do not generate until after the event ends. Events that last longer then your retry timeout will always return 404.

get_event_heatmap(heatmap_id: str, retry_timeout: int = RETRY_TIMEOUT) -> bytes | None async

Gets given heatmap from a given event.

Heatmap response is a PNG image.

Note: thumbnails / heatmaps do not generate until after the event ends. Events that last longer then your retry timeout will always return None.

get_event_smart_detect_track(event_id: str) -> SmartDetectTrack async

Gets raw Smart Detect Track for a Smart Detection

get_event_smart_detect_track_raw(event_id: str) -> dict[str, Any] async

Gets raw Smart Detect Track for a Smart Detection

get_event_thumbnail(thumbnail_id: str, width: int | None = None, height: int | None = None, retry_timeout: int = RETRY_TIMEOUT) -> bytes | None async

Gets given thumbanail from a given event.

Thumbnail response is a JPEG image.

Note: thumbnails / heatmaps do not generate until after the event ends. Events that last longer then your retry timeout will always return 404.

get_events(start: datetime | None = None, end: datetime | None = None, limit: int | None = None, offset: int | None = None, types: list[EventType] | None = None, smart_detect_types: list[SmartDetectObjectType] | None = None, sorting: Literal['asc', 'desc'] = 'asc', descriptions: bool = True, category: EventCategories | None = None, _allow_manual_paginate: bool = True) -> list[Event] async

Same as get_events_raw, except

  • returns actual Event objects instead of raw Python dictionaries
  • filers out non-device events
  • filters out events with too low of a score

Text Only
1
2
3
4
5
6
7
8
9
start: start time for events
end: end time for events
limit: max number of events to return
offset: offset to start fetching events from
types: list of EventTypes to get events for
smart_detect_types: Filters the Smart detection types for the events
sorting: sort events by ascending or descending, defaults to ascending (chronologic order)
description: included additional event metadata
category: event category, will provide additional category/subcategory fields

If limit, start and end are not provided, it will default to all events in the last 24 hours.

If start is provided, then end or limit must be provided. If end is provided, then start or limit must be provided. Otherwise, you will get a 400 error from UniFi Protect

get_events_raw(*, start: datetime | None = None, end: datetime | None = None, limit: int | None = None, offset: int | None = None, types: list[EventType] | None = None, smart_detect_types: list[SmartDetectObjectType] | None = None, sorting: Literal['asc', 'desc'] = 'asc', descriptions: bool = True, all_cameras: bool | None = None, category: EventCategories | None = None, _allow_manual_paginate: bool = True) -> list[dict[str, Any]] async

Get list of events from Protect


Text Only
1
2
3
4
5
6
7
8
9
start: start time for events
end: end time for events
limit: max number of events to return
offset: offset to start fetching events from
types: list of EventTypes to get events for
smart_detect_types: Filters the Smart detection types for the events
sorting: sort events by ascending or descending, defaults to ascending (chronologic order)
description: included additional event metadata
category: event category, will provide additional category/subcategory fields

If limit, start and end are not provided, it will default to all events in the last 24 hours.

If start is provided, then end or limit must be provided. If end is provided, then start or limit must be provided. Otherwise, you will get a 400 error from UniFi Protect

get_files_public(file_type: AssetFileType | str = AssetFileType.ANIMATIONS) -> list[PublicFile] async

List uploaded device asset files of the given type.

get_fob_public(fob_id: str) -> Fob async

Get a specific key fob using public API.

get_fobs_public() -> list[Fob] async

Get all key fobs using public API.

get_light(device_id: str) -> Light async

Gets a light straight from the NVR.

The websocket is connected and running, you likely just want to use self.bootstrap.lights[device_id]

.. deprecated:: Use :meth:get_light_public instead. This method uses the private API and will be removed in a future version.

get_light_public(light_id: str) -> PublicLight async

Get a specific light using public API.

get_lights() -> list[Light] async

Gets the list of lights straight from the NVR.

The websocket is connected and running, you likely just want to use self.bootstrap.lights

.. deprecated:: Use :meth:get_lights_public instead. This method uses the private API and will be removed in a future version.

get_lights_public() -> list[PublicLight] async

Get all lights using public API.

Get a specific link station using public API.

Get all link stations using public API.

get_liveview(device_id: str) -> Liveview async

Gets a liveview straight from the NVR.

The websocket is connected and running, you likely just want to use self.bootstrap.liveviews[device_id]

get_liveview_public(liveview_id: str) -> PublicLiveview async

Get a specific liveview using public API.

get_liveviews() -> list[Liveview] async

Gets the list of liveviews straight from the NVR.

The websocket is connected and running, you likely just want to use self.bootstrap.liveviews

get_liveviews_public() -> list[PublicLiveview] async

Get all liveviews using public API.

get_meta_info() -> MetaInfo async

Get NVR metadata via the Public Integration API.

get_nvr() -> NVR async

Gets an NVR object straight from the NVR.

This is a great alternative if you need metadata about the NVR without connecting to the Websocket

get_nvr_public() -> PublicNVR async

Get NVR information using public API.

get_package_camera_snapshot(camera_id: str, width: int | None = None, height: int | None = None, dt: datetime | None = None) -> bytes | None async

Gets snapshot from the package camera.

Datetime of screenshot is approximate. It may be +/- a few seconds.

get_patrols_ptz_camera(device_id: str) -> list[PTZPatrol] async

Get PTZ Patrols for camera.

get_presets_ptz_camera(device_id: str) -> list[PTZPreset] async

Get PTZ Presets for camera.

get_public_api_camera_snapshot(camera_id: str, high_quality: bool = False, package: bool = False) -> bytes | None async

Gets snapshot for a camera using public api.

Parameters:

Name Type Description Default
camera_id str

Camera ID.

required
high_quality bool

Force 1080P+ resolution.

False
package bool

If True, fetch from the package camera (only supported on cameras with hasPackageCamera: true). Requires Protect on the NVR.

False

get_relay_public(relay_id: str) -> Relay async

Get a specific relay using public API.

get_relays_public() -> list[Relay] async

Get all relays using public API.

get_sensor(device_id: str) -> Sensor async

Gets a sensor straight from the NVR.

The websocket is connected and running, you likely just want to use self.bootstrap.sensors[device_id]

get_sensor_public(sensor_id: str) -> PublicSensor async

Get a specific sensor using public API.

get_sensors() -> list[Sensor] async

Gets the list of sensors straight from the NVR.

The websocket is connected and running, you likely just want to use self.bootstrap.sensors

get_sensors_public() -> list[PublicSensor] async

Get all sensors using public API.

get_siren_public(siren_id: str) -> Siren async

Get a specific siren using public API.

get_sirens_public() -> list[Siren] async

Get all sirens using public API.

get_speaker_public(speaker_id: str) -> Speaker async

Get a specific speaker using public API.

get_speakers_public() -> list[Speaker] async

Get all speakers using public API.

get_ulp_user_public(ulp_user_id: str) -> PublicUlpUser async

Get a specific UniFi Identity user using public API.

get_ulp_users_public() -> list[PublicUlpUser] async

Get all UniFi Identity users using public API.

get_user_public(user_id: str) -> PublicUser async

Get a specific Protect user using public API.

get_users_public() -> list[PublicUser] async

Get all Protect users using public API.

get_viewer(device_id: str) -> Viewer async

Gets a viewer straight from the NVR.

The websocket is connected and running, you likely just want to use self.bootstrap.viewers[device_id]

get_viewer_public(viewer_id: str) -> PublicViewer async

Get a specific viewer using public API.

get_viewers() -> list[Viewer] async

Gets the list of viewers straight from the NVR.

The websocket is connected and running, you likely just want to use self.bootstrap.viewers

get_viewers_public() -> list[PublicViewer] async

Get all viewers using public API.

is_api_key_set() -> bool

Check if the API key is set.

play_buzzer(device_id: str) -> None async

Plays chime tones on a chime

play_siren_public(siren_id: str, *, duration: SirenDuration | int | None = None) -> None async

Activate a siren. duration may be a supported integer or :class:SirenDuration; defaults to 5 seconds.

play_speaker(device_id: str, *, volume: int | None = None, repeat_times: int | None = None, ringtone_id: str | None = None, track_no: int | None = None) -> None async

Plays chime tones on a chime.


Text Only
1
2
3
4
5
6
7
8
device_id: The chime device ID
volume: Volume level for playback (0-100)
repeat_times: Number of times to repeat the tone
ringtone_id: The ringtone ID (UUID) to play. Preferred over track_no.
track_no: Legacy track number from speakerTrackList.
    .. deprecated::
        Use ringtone_id instead. track_no maps to the speaker track
        list but ringtone_id is the current API standard.

poll_events() -> None async

Poll for events.

ptz_goto_preset_public(camera_id: str, *, slot: int) -> None async

Move PTZ camera to preset position using public API.

ptz_patrol_start_public(camera_id: str, *, slot: int) -> None async

Start a PTZ patrol using public API.

ptz_patrol_stop_public(camera_id: str) -> None async

Stop the active PTZ patrol using public API.

public_only(host: str, port: int, api_key: str, *, verify_ssl: bool = True, public_api_session: aiohttp.ClientSession | None = None, ws_timeout: int = 30, ws_receive_timeout: int | None = None, subscribed_models: set[ModelType] | None = None, events_ws_subscribed_models: set[ModelType] | None = None, devices_ws_subscribed_models: set[ModelType] | None = None, ignore_unadopted: bool = True, max_retries: int = RETRY_DEFAULT_ATTEMPTS) -> Self classmethod

Construct a client that operates entirely on the Public Integration API.

No private login is performed. Private-session entry points (:meth:authenticate, :meth:update, :meth:get_bootstrap) raise :class:PublicOnlyModeError; use :meth:update_public, :meth:subscribe_events, :meth:subscribe_devices, the public get_*_public / update_*_public methods, and :meth:get_meta_info instead. A revoked or invalid key surfaces as :class:NotAuthorized.

reboot_device(model_type: ModelType, device_id: str) -> None async

Reboots an adopted device

reboot_nvr() -> None async

Reboots NVR

resolve_nvr_mac() -> str | None async

Resolve the NVR mac, normalized, by source priority: public bootstrap, then private bootstrap, then the /api/system console fallback; None if none resolve.

send_alarm_webhook_public(trigger_id: str) -> None async

Fire the alarm-manager webhook for the given trigger id.

set_api_key(api_key: str) -> None

Set the API key for the NVR.

set_current_arm_profile_public(profile_id: str) -> None async

Set the currently selected arm profile.

set_light_is_led_force_on(device_id: str, is_led_force_on: bool) -> None async

Sets isLedForceOn for light.

.. deprecated:: Use :meth:update_light_public instead. This method uses the private API and will be removed in a future version.

stop_siren_public(siren_id: str) -> None async

Stop an active siren.

subscribe_devices(callback: Callable[[ProtectDeviceChange], None]) -> Callable[[], None]

Subscribe to typed public device-state lifecycle callbacks.

The device-side analog of subscribe_events: each callback receives a :class:~uiprotect.devices.ProtectDeviceChange describing an ADDED / UPDATED / REMOVED device, carrying the merged public model (None for REMOVED) and, for UPDATED, the changed-field set. Single and bulk WS envelopes are expanded transparently to one change per device; state / connection transitions surface as ordinary UPDATEDs.

Requires update_public() to have primed the public bootstrap at least once before subscribing (a RuntimeError is raised otherwise) — the merged public models depend on that cache. Callers that need the websocket live during priming should use the raw subscribe_devices_websocket instead, which has no such ordering requirement.

The callback must not raise: an exception is caught and logged but otherwise swallowed. device_mac resolves with eventual consistency — a device not yet in the bootstrap yields None until the next update_public() / reconnect resync.

A revoked or invalid API key surfaces as WebsocketState.AUTH_FAILED via subscribe_devices_websocket_state after repeated 401 handshakes; call set_api_key() with a fresh key to re-arm.

subscribe_devices_and_prime(callback: Callable[[ProtectDeviceChange], None]) -> Callable[[], None] async

Subscribe to typed device changes and prime the public bootstrap, order-independent.

Connects the devices websocket before priming, then awaits :meth:update_public. Frames arriving during the prime are buffered and replayed onto the fresh snapshot, so no update is lost regardless of when the caller invokes this — it makes the prime/subscribe ordering question moot. Unlike :meth:subscribe_devices, it does not require the bootstrap to be primed beforehand.

Returns the same unsubscribe callable as :meth:subscribe_devices. If priming raises (e.g. :class:NotAuthorized), the subscription is rolled back before the error propagates.

subscribe_devices_websocket(ws_callback: Callable[[WSSubscriptionMessage], None]) -> Callable[[], None]

Subscribe to devices websocket events.

Returns a callback that will unsubscribe.

subscribe_devices_websocket_state(ws_callback: Callable[[WebsocketState], None]) -> Callable[[], None]

Subscribe to devices websocket state changes.

Returns a callback that will unsubscribe.

subscribe_events(callback: Callable[[ProtectEvent, EventChange], None]) -> Callable[[], None]

Subscribe to typed public event lifecycle callbacks.

Only events whose EventType maps to a non-OTHER ProtectEventChannel (detection / sensor / alarm-hub / access) are delivered; administrative events such as provision, factoryReset and fwUpdate are dropped. Callers needing the unfiltered stream should use subscribe_events_websocket instead.

The callback must not raise: an exception is caught and logged but otherwise swallowed, so a raising callback silently loses that delivery (e.g. an ENDED that never reaches the consumer). Do any fallible work inside a guard the callback owns.

Identity and device_mac resolve with eventual consistency: the first event for a freshly-enrolled ULP user can resolve to UnknownIdentity(reason="ulp_user_not_cached"), and a device not yet in the bootstrap yields device_mac=None, until the next update_public() / reconnect resync refreshes public_bootstrap.ulp_users and the device stores. Smart-detect detected attributes (license-plate text, face-match name) are not exposed over the public API today — fall back to the private path via event.raw when you need them.

A revoked or invalid API key surfaces as WebsocketState.AUTH_FAILED via subscribe_events_websocket_state after repeated 401 handshakes; call set_api_key() with a fresh key to re-arm.

subscribe_events_and_prime(callback: Callable[[ProtectEvent, EventChange], None]) -> Callable[[], None] async

Subscribe to typed event changes and prime the public bootstrap, order-independent.

The events-side analog of :meth:subscribe_devices_and_prime: connects the events websocket before priming, then awaits :meth:update_public. Frames arriving during the prime are buffered and replayed onto the fresh snapshot, so ordering is moot and the bootstrap need not be primed beforehand.

Returns the same unsubscribe callable as :meth:subscribe_events. If priming raises, the subscription is rolled back before the error propagates.

subscribe_events_websocket(ws_callback: Callable[[WSSubscriptionMessage], None]) -> Callable[[], None]

Subscribe to events websocket events.

Returns a callback that will unsubscribe.

subscribe_events_websocket_state(ws_callback: Callable[[WebsocketState], None]) -> Callable[[], None]

Subscribe to events websocket state changes.

Returns a callback that will unsubscribe.

subscribe_websocket(ws_callback: Callable[[WSSubscriptionMessage], None]) -> Callable[[], None]

Subscribe to websocket events.

Returns a callback that will unsubscribe.

subscribe_websocket_state(ws_callback: Callable[[WebsocketState], None]) -> Callable[[], None]

Subscribe to websocket state changes.

Returns a callback that will unsubscribe.

test_siren_sound_public(siren_id: str, *, volume: int | None = None) -> None async

Test the siren sound (5 seconds).

test_speaker_sound_public(speaker_id: str, *, volume: int | None = None) -> None async

Test the speaker sound at the given volume.

trigger_alarm_hub_output_public(hub_id: str, output_id: int, *, enable: bool | None = None, delay: int | None = None, duration: int | None = None) -> None async

Trigger an alarm-hub output channel using public API.

unadopt_device(model_type: ModelType, device_id: str) -> None async

Unadopt/Unmanage adopted device

update() -> Bootstrap async

Updates the state of devices, initializes .bootstrap

The websocket is auto connected once there are any subscriptions to it. update must be called at least once before subscribing to the websocket.

You can use the various other get_ methods if you need one off data from UFP

update_alarm_hub_public(hub_id: str, *, name: str | None = None) -> LinkStation async

Patch alarm hub settings using public API.

update_arm_profile_public(profile_id: str, *, name: str | None = None, automations: list[str] | None = None, schedules: list[PublicArmScheduleDict] | None = None, record_everything: bool | None = None, activation_delay: int | None = None) -> ArmProfile async

Update an existing arm profile (partial update).

update_bridge_public(bridge_id: str, *, name: str | None = None) -> PublicBridge async

Patch bridge settings using public API.

update_camera_public(camera_id: str, *, name: str | None = None, hdr_type: PublicHdrMode | None = None, video_mode: VideoMode | None = None, led_is_enabled: bool | None = None, led_welcome_led: bool | None = None, led_flood_led: bool | None = None, mic_volume: int | None = None, smart_detect_object_types: list[SmartDetectObjectType] | None = None, smart_detect_audio_types: list[SmartDetectAudioType] | None = None, lcd_message: CameraPublicApiLcdMessageRequest | None = None, osd_name_enabled: bool | None = None, osd_date_enabled: bool | None = None, osd_logo_enabled: bool | None = None, osd_nerd_mode_enabled: bool | None = None, osd_overlay_location: OsdOverlayLocation | None = None) -> PublicCamera async

Patch camera settings using public API.

Returns a fresh Camera object deserialized from the PATCH response. When a public bootstrap is loaded and holds this camera, the response is also written through into the cached twin (out-of-band rtsps_streams is preserved); the private bootstrap, if any, is left to the private-tree convenience methods.

update_chime_public(chime_id: str, *, name: str | None = None, camera_ids: list[str] | None = None, ring_settings: list[PublicApiChimeRingSettingRequest] | None = None) -> PublicChime async

Update chime settings using public API.

update_device(model_type: ModelType, device_id: str, data: dict[str, Any]) -> None async

Sends an update for a device back to UFP

USE WITH CAUTION, all possible combinations of updating objects have not been fully tested. May have unexpected side effects.

Tested updates have been added a methods on applicable devices.

update_fob_public(fob_id: str, *, name: str | None = None) -> Fob async

Patch key-fob settings using public API.

update_light_public(light_id: str, *, name: str | None = None, is_light_force_enabled: bool | None = None, light_mode_settings: LightModeSettings | PublicLightModeSettings | None = None, light_device_settings: LightDeviceSettings | PublicLightDeviceSettings | None = None) -> PublicLight async

Update light settings using public API.


Text Only
1
2
3
4
5
light_id: The light's ID
name: Light name
is_light_force_enabled: Force enable the light
light_mode_settings: Light mode settings (mode, enable_at)
light_device_settings: Light device settings (LED level, PIR settings, etc.)

Text Only
1
Updated Light object

Text Only
1
BadRequest: If no parameters are provided

Patch link station settings using public API.

update_liveview_public(liveview_id: str, *, name: str | None = None, is_default: bool | None = None, is_global: bool | None = None, owner: str | None = None, layout: int | None = None, slots: list[PublicLiveviewSlotDict] | None = None) -> PublicLiveview async

Patch an existing liveview (partial update) using public API.

update_nvr(data: dict[str, Any]) -> None async

Sends an update for main UFP NVR device

USE WITH CAUTION, all possible combinations of updating objects have not been fully tested. May have unexpected side effects.

Tested updates have been added a methods on applicable devices.

update_public() -> PublicBootstrap async

Populate :attr:public_bootstrap from the Public Integration API.

This is opt-in and completely independent of :meth:update / the private bootstrap. Safe to call multiple times — the :class:PublicBootstrap instance is created on first use and then updated in place on subsequent calls. All endpoint fetches run concurrently.

Each endpoint is requested best-effort; endpoints that the NVR doesn't (yet) expose (BadRequest / NvrError) are logged at DEBUG and ignored, and a partial public bootstrap is returned. If an endpoint fails, its previously cached data is left unchanged (not cleared). All results are classified before any are applied: an unexpected exception (e.g. a validation error from a new server payload) propagates to the caller with the snapshot left untouched, never half-applied.

A revoked or invalid API key surfaces as :class:NotAuthorized; catch it as the reauth signal.

Public events/devices WS frames that arrive while this method is priming are captured and replayed onto the fresh snapshot before it returns, so a subscriber that is already connected does not lose an update to the prime window — the subscribe-then-prime ordering is a library guarantee, not a caller obligation. To also make the prime-then-subscribe ordering moot for the typed callbacks, use :meth:subscribe_devices_and_prime / :meth:subscribe_events_and_prime.

After priming, public_bootstrap.nvr.mac carries the NVR mac whenever it is resolvable. On firmware that omits mac from the public payload it is backfilled from the console fallback and stored in the native UniFi format (uppercase, no separators) — the same format newer firmware already provides — so consumers can read a self-consistent mac regardless of firmware.

Concurrent calls are serialized: an overlapping prime could otherwise apply an older snapshot over a newer one (and over live WS merges in between). Each caller returns the then-current bootstrap.

update_relay_public(relay_id: str, *, name: str | None = None, led_is_enabled: bool | None = None) -> Relay async

Patch relay settings using public API.

update_sensor_public(sensor_id: str, *, name: str | None = None, light_settings: PublicSensorLightSettings | None = None, humidity_settings: PublicSensorHumiditySettings | None = None, temperature_settings: PublicSensorTemperatureSettings | None = None, motion_settings: PublicSensorMotionSettings | None = None, glass_break_settings: PublicSensorGlassBreakSettingsWrite | None = None, alarm_settings: PublicSensorAlarmSettings | None = None, schedule_mode: SensorScheduleMode | str | None = None, arm_profile_ids: list[str] | None = None, has_custom_sensitivity_when_armed: bool | None = None) -> PublicSensor async

Patch sensor settings using public API.

Each *_settings argument is a :class:~typing.TypedDict with total=False — pass only the keys you want to change.

update_siren_public(siren_id: str, *, name: str | None = None, volume: int | None = None, led_is_enabled: bool | None = None) -> Siren async

Patch siren settings using public API.

update_speaker_public(speaker_id: str, *, name: str | None = None, volume: int | None = None, mic_volume: int | None = None, is_mic_enabled: bool | None = None) -> Speaker async

Patch speaker settings using public API.

update_viewer_public(viewer_id: str, *, name: str | None = None, liveview: str | None | _UnsetType = _UNSET) -> PublicViewer async

Patch viewer settings using public API. Pass liveview=None to clear.

upload_file_public(file_type: AssetFileType | str, file: bytes, original_name: str, content_type: str = 'image/png') -> PublicFile async

Upload a device asset as multipart/form-data.

The spec accepts image/gif, image/jpeg, image/png, audio/mpeg, audio/mp4, audio/wave, audio/x-caf; content_type defaults to image/png for the common doorbell-animation case and must be overridden for other MIME types. aiohttp sets the multipart Content-Type header (with boundary) itself when data= is a :class:aiohttp.FormData, so this client never sets a JSON content-type for this call.

PublicApiChimePatchRequest

Bases: TypedDict

Type for PATCH /v1/chimes/{id} request body (Public API).

PublicApiChimeRingSettingRequest

Bases: TypedDict

Type for ringSettings items in PATCH /v1/chimes/{id} request body (Public API).

calculate_retry_delay(attempt: int, retry_after: float | None = None) -> float

Calculate delay before next retry attempt with exponential backoff and jitter.

Parameters:

Name Type Description Default
attempt int

Current retry attempt number (0-based).

required
retry_after float | None

Optional Retry-After header value in seconds.

None

Returns:

Type Description
float

Delay in seconds before next retry.

parse_retry_after(response: ClientResponse) -> float | None

Parse Retry-After header from response.

Parameters:

Name Type Description Default
response ClientResponse

HTTP response object.

required

Returns:

Type Description
float | None

Retry delay in seconds, or None if header not present/parseable.

Data Models (uiprotect.data)

AlarmHubBattery

Bases: ProtectBaseObject

Backup battery status of an alarm hub (alarmHub.battery sub-schema).

The battery object declares no required array in the OpenAPI spec, and a real hub with the backup battery disconnected emits only connection (omitting charging/voltage/batteryStatus), so every field is optional.

AlarmHubBatteryStatus

Bases: UnknownValuesEnumMixin, StrEnum

Alarm-hub backup-battery health (alarmHub.battery.batteryStatus field).

AlarmHubConnectionState

Bases: UnknownValuesEnumMixin, StrEnum

Alarm-hub backup-battery wiring state (alarmHub.battery.connection field).

AlarmHubCover

Bases: ProtectBaseObject

Tamper cover status of an alarm hub (alarmHub.cover sub-schema).

The cover object declares no required array in the OpenAPI spec, so both fields are optional.

AlarmHubCoverStatus

Bases: UnknownValuesEnumMixin, StrEnum

Alarm-hub tamper-cover status (alarmHub.cover.status field).

AlarmHubInput

Bases: ProtectBaseObject

A single alarm-hub input zone (alarmHub.input[<id>] sub-schema).

AlarmHubInputContactType

Bases: UnknownValuesEnumMixin, StrEnum

Alarm-hub input contact wiring (alarmHub.input[].type field).

AlarmHubInputStatus

Bases: UnknownValuesEnumMixin, StrEnum

Alarm-hub input zone status (alarmHub.input[].status field).

AlarmHubInputType

Bases: UnknownValuesEnumMixin, StrEnum

Alarm-hub input zone kind (alarmHub.input[].inputType field).

AlarmHubOutput

Bases: ProtectBaseObject

A single alarm-hub output channel (alarmHub.output[<id>] sub-schema).

AlarmHubOutputStatus

Bases: UnknownValuesEnumMixin, StrEnum

Alarm-hub output channel status (alarmHub.output[].status field).

ArmProfile

Bases: ProtectBaseObject

Public API arm profile (local alarm manager).

Arm profiles are configuration objects, not devices — the /v1/arm-profiles payload has no modelKey. The class therefore inherits directly from :class:ProtectBaseObject and carries its own id field.

AssetFileType

Bases: UnknownValuesEnumMixin, StrEnum

Public-API device asset file kind (/v1/files/{fileType}).

Bootstrap

Bases: ProtectBaseObject

has_media: bool property

Checks if user can read media for any camera.

has_smart_detections: bool property

Check if any camera has smart detections.

recording_start: datetime | None property

Get earliest recording date.

get_device_from_id(device_id: str) -> ProtectAdoptableDeviceModel | None

Retrieve a device from device ID (without knowing model type).

get_device_from_mac(mac: str) -> ProtectAdoptableDeviceModel | None

Retrieve a device from MAC address.

get_is_prerelease() -> bool async

[DEPRECATED] Always returns False. Will be removed after HA 2025.8.0.

process_ws_packet(packet: WSPacket, models: set[ModelType] | None = None, ignore_stats: bool = False, is_ping_back: bool = False) -> WSSubscriptionMessage | None

Process a WS packet.

refresh_device(model_type: ModelType, device_id: str) -> None async

Refresh a device in the bootstrap.

Camera

Bases: ProtectMotionDeviceModel

active_audio_detect_types: set[SmartDetectAudioType] property

Get active audio detection types.

active_recording_settings: RecordingSettings property

Get active recording settings.

active_smart_detect_settings: SmartDetectSettings property

Get active smart detection settings.

active_smart_detect_types: set[SmartDetectObjectType] property

Get active smart detection types.

hdr_mode_display: Literal['auto', 'off', 'always'] property

Get HDR mode similar to how Protect interface works.

icr_lux_display: int | None property

Get ICR Custom Lux value similar to how the Protect interface works.

is_animal_currently_detected: bool property

Is animal currently being detected

is_animal_detection_on: bool property

Is Animal Detection available and enabled (camera will produce package smart detection events)?

is_audio_currently_detected: bool property

Is audio detection currently being detected

is_baby_cry_currently_detected: bool property

Is Baby Cry currently being detected

is_baby_cry_detection_on: bool property

Is Baby Cry Detection available and enabled (camera will produce baby cry smart detection events)?

is_bark_currently_detected: bool property

Is Bark currently being detected

is_bark_detection_on: bool property

Is Bark Detection available and enabled (camera will produce barking smart detection events)?

is_car_alarm_currently_detected: bool property

Is Car Alarm currently being detected

is_car_alarm_detection_on: bool property

Is Car Alarm Detection available and enabled (camera will produce car alarm smart detection events)?

is_car_horn_currently_detected: bool property

Is Car Horn currently being detected

is_car_horn_detection_on: bool property

Is Car Horn Detection available and enabled (camera will produce car horn smart detection events)?

is_cmonx_currently_detected: bool property

Is CO alarm currently being detected

is_co_detection_on: bool property

Is CO Alarm Detection available and enabled (camera will produce smoke smart detection events)?

is_face_currently_detected: bool property

Is face currently being detected

is_face_detection_on: bool property

Is Face Detection available and enabled?

is_face_detections_allowed: bool property

Is face detections allowed for this camera?

is_glass_break_currently_detected: bool property

Is Glass Break currently being detected

is_glass_break_detection_on: bool property

Is Glass Break available and enabled (camera will produce glass break smart detection events)?

is_ir_led_slider_enabled: bool property

Return if IR LED custom slider is enabled.

is_license_plate_currently_detected: bool property

Is license plate currently being detected

is_license_plate_detection_on: bool property

Is License Plate Detection available and enabled (camera will produce face license plate detection events)?

is_license_plate_detections_allowed: bool property

Is license plate detections allowed for this camera?

is_motion_currently_detected: bool property

Is motion currently being detected

is_motion_detection_on: bool property

Is Motion Detection available and enabled (camera will produce motion events)?

is_package_currently_detected: bool property

Is package currently being detected

is_package_detection_on: bool property

Is Package Detection available and enabled (camera will produce package smart detection events)?

is_person_currently_detected: bool property

Is person currently being detected

is_person_detection_on: bool property

Is Person Detection available and enabled (camera will produce person smart detection events)?

is_person_tracking_enabled: bool property

Is person tracking enabled

is_ptz_patrolling: bool property

Is PTZ camera currently running a patrol?

is_recording_enabled: bool property

Is recording footage/events from the camera enabled?

If recording is not enabled, cameras will not produce any footage, thumbnails, motion/smart detection events.

is_siren_currently_detected: bool property

Is Siren currently being detected

is_siren_detection_on: bool property

Is Siren Detection available and enabled (camera will produce siren smart detection events)?

is_smart_currently_detected: bool property

Is smart detection currently being detected

is_smart_detections_allowed: bool property

Is smart detections allowed for this camera?

is_smoke_currently_detected: bool property

Is smoke alarm currently being detected

is_smoke_detection_on: bool property

Is Smoke Alarm Detection available and enabled (camera will produce smoke smart detection events)?

is_speaking_currently_detected: bool property

Is Speaking currently being detected

is_speaking_detection_on: bool property

Is Speaking Detection available and enabled (camera will produce speaking smart detection events)?

is_vehicle_currently_detected: bool property

Is vehicle currently being detected

is_vehicle_detection_on: bool property

Is Vehicle Detection available and enabled (camera will produce vehicle smart detection events)?

last_animal_detect: datetime | None property

Get the last animal smart detection event.

last_animal_detect_event: Event | None property

Get the last animal smart detection event.

last_baby_cry_detect: datetime | None property

Get the last Baby Cry smart detection event.

last_baby_cry_detect_event: Event | None property

Get the last Baby Cry smart detection event.

last_bark_detect: datetime | None property

Get the last Bark smart detection event.

last_bark_detect_event: Event | None property

Get the last Bark smart detection event.

last_car_alarm_detect: datetime | None property

Get the last Car Alarm smart detection event.

last_car_alarm_detect_event: Event | None property

Get the last Car Alarm smart detection event.

last_car_horn_detect: datetime | None property

Get the last Car Horn smart detection event.

last_car_horn_detect_event: Event | None property

Get the last Car Horn smart detection event.

last_cmonx_detect: datetime | None property

Get the last CO alarm smart detection event.

last_cmonx_detect_event: Event | None property

Get the last CO alarm smart detection event.

last_face_detect: datetime | None property

Get the last face smart detection event.

last_face_detect_event: Event | None property

Get the last face smart detection event.

last_glass_break_detect: datetime | None property

Get the last Glass Break smart detection event.

last_glass_break_detect_event: Event | None property

Get the last Glass Break smart detection event.

last_license_plate_detect: datetime | None property

Get the last license plate smart detection event.

last_license_plate_detect_event: Event | None property

Get the last license plate smart detection event.

last_package_detect: datetime | None property

Get the last package smart detection event.

last_package_detect_event: Event | None property

Get the last package smart detection event.

last_person_detect: datetime | None property

Get the last person smart detection event.

last_person_detect_event: Event | None property

Get the last person smart detection event.

last_siren_detect: datetime | None property

Get the last Siren smart detection event.

last_siren_detect_event: Event | None property

Get the last Siren smart detection event.

last_smart_audio_detect_event: Event | None property

Get the last smart audio detect event id.

last_smart_detect_event: Event | None property

Get the last smart detect event id.

last_smoke_detect: datetime | None property

Get the last smoke smart detection event.

last_smoke_detect_event: Event | None property

Get the last person smart detection event.

last_speaking_detect: datetime | None property

Get the last Speaking smart detection event.

last_speaking_detect_event: Event | None property

Get the last Speaking smart detection event.

last_vehicle_detect: datetime | None property

Get the last vehicle smart detection event.

last_vehicle_detect_event: Event | None property

Get the last vehicle smart detection event.

create_rtsps_streams(qualities: list[ChannelQuality | str] | ChannelQuality | str) -> RTSPSStreams | None async

Creates RTSPS streams for camera using public API.

create_talkback_stream(content_url: str, ffmpeg_path: Path | None = None, *, use_public_api: bool = True) -> TalkbackStream async

Creates a stream to play audio to a camera through its speaker.

Uses PyAV (libav) for audio encoding - compatible with Home Assistant.


Text Only
1
2
3
content_url: Either a URL accessible by python or a path to a file
ffmpeg_path: Deprecated, no longer used (PyAV handles encoding)
use_public_api: Use the public API to get talkback session (default: True)

Use either await stream.run_until_complete() or await stream.start() to start streaming after getting the stream.

.play_audio() is a helper that wraps this method and automatically runs the stream as well

delete_rtsps_streams(qualities: list[ChannelQuality | str] | ChannelQuality | str) -> bool async

Deletes RTSPS streams for camera using public API.

get_last_smart_audio_detect_event(smart_type: SmartDetectAudioType) -> Event | None

Get the last smart audio detect event for given type.

get_last_smart_detect_event(smart_type: SmartDetectObjectType) -> Event | None

Get the last smart detect event for given type.

get_package_snapshot(width: int | None = None, height: int | None = None, dt: datetime | None = None) -> bytes | None async

Gets snapshot from the package camera.

Datetime of screenshot is approximate. It may be +/- a few seconds.

get_ptz_patrols() -> list[PTZPatrol] async

Get PTZ Patrols for camera.

get_ptz_presets() -> list[PTZPreset] async

Get PTZ Presets for camera.

get_public_api_snapshot(high_quality: bool | None = None, package: bool = False) -> bytes | None async

Gets snapshot for camera using public API; package=True fetches the package camera.

get_rtsps_streams() -> RTSPSStreams | None async

Gets existing RTSPS streams for camera using public API.

get_snapshot(width: int | None = None, height: int | None = None, dt: datetime | None = None) -> bytes | None async

Gets snapshot for camera.

Datetime of screenshot is approximate. It may be +/- a few seconds.

get_video(start: datetime, end: datetime, channel_index: int = 0, output_file: Path | None = None, iterator_callback: IteratorCallback | None = None, progress_callback: ProgressCallback | None = None, chunk_size: int = 65536, fps: int | None = None) -> bytes | None async

Exports MP4 video from a given camera at a specific time.

Start/End of video export are approximate. It may be +/- a few seconds.

It is recommended to provide a output file or progress callback for larger video clips, otherwise the full video must be downloaded to memory before being written.

Providing the fps parameter creates a "timelapse" export with the given FPS value. Protect app gives the options for 60x (fps=4), 120x (fps=8), 300x (fps=20), and 600x (fps=40).

play_audio(content_url: str, ffmpeg_path: Path | None = None, blocking: bool = True, *, use_public_api: bool = True) -> None async

Plays audio to a camera through its speaker.

Uses PyAV (libav) for audio encoding - compatible with Home Assistant.


Text Only
1
2
3
4
content_url: Either a URL accessible by python or a path to a file
ffmpeg_path: Deprecated, no longer used (PyAV handles encoding)
blocking: Awaits stream completion
use_public_api: Use the public API to get talkback session (default: True)

ptz_goto_preset_public(*, slot: int) -> None async

Move PTZ camera to preset position using public API.

ptz_patrol_start_public(*, slot: int) -> None async

Start a PTZ patrol using public API.

ptz_patrol_stop_public() -> None async

Stop the active PTZ patrol using public API.

set_animal_detection(enabled: bool) -> None async

Toggles animal smart detection. Requires camera to have smart detection

set_animal_detection_public(enabled: bool) -> None async

Toggle animal smart detection via public API.

set_baby_cry_detection(enabled: bool) -> None async

Toggles baby_cry smart detection. Requires camera to have smart detection

set_baby_cry_detection_public(enabled: bool) -> None async

Toggle baby cry audio detection via public API.

set_bark_detection(enabled: bool) -> None async

Toggles bark smart detection. Requires camera to have smart detection

set_bark_detection_public(enabled: bool) -> None async

Toggle bark audio detection via public API.

set_burglar_detection_public(enabled: bool) -> None async

Toggle burglar audio detection via public API.

set_camera_zoom(level: int) -> None async

Sets zoom level for camera

set_car_alarm_detection(enabled: bool) -> None async

Toggles car_alarm smart detection. Requires camera to have smart detection

set_car_horn_detection(enabled: bool) -> None async

Toggles car_horn smart detection. Requires camera to have smart detection

set_car_horn_detection_public(enabled: bool) -> None async

Toggle car horn audio detection via public API.

set_chime_duration(duration: timedelta | float) -> None async

Sets chime duration for doorbell. Requires camera to be a doorbell

set_chime_type(chime_type: ChimeType) -> None async

Sets chime type for doorbell. Requires camera to be a doorbell

set_cmonx_detection(enabled: bool) -> None async

Toggles smoke smart detection. Requires camera to have smart detection

set_co_detection_public(enabled: bool) -> None async

Toggle CO audio detection via public API.

set_color_night_vision(enabled: bool) -> None async

Sets Color Night Vision on camera

set_face_detection(enabled: bool) -> None async

Toggles face smart detection. Requires camera to have smart detection

set_face_detection_public(enabled: bool) -> None async

Toggle face smart detection via public API.

set_flood_led_public(enabled: bool) -> None async

Set flood LED via public API.

set_glass_break_detection(enabled: bool) -> None async

Toggles glass_break smart detection. Requires camera to have smart detection

set_glass_break_detection_public(enabled: bool) -> None async

Toggle glass break audio detection via public API.

set_hdr(enabled: bool) -> None async

Sets HDR (High Dynamic Range) on camera

set_hdr_mode(mode: Literal['auto', 'off', 'always']) -> None async

Sets HDR mode similar to how Protect interface works.

set_hdr_mode_public(mode: PublicHdrMode) -> None async

Set HDR mode via public API.

set_icr_custom_lux(value: ICRLuxValue) -> None async

Set ICRCustomValue from lux value.

set_ir_led_model(mode: IRLEDMode) -> None async

Sets IR LED mode on camera

set_lcd_message_public(text_type: DoorbellMessageType, text: str | None = None, reset_at: datetime | None | DEFAULT_TYPE = DEFAULT) -> None async

Set doorbell LCD message via public API.

text is required for CUSTOM_MESSAGE and IMAGE, and must be omitted for DO_NOT_DISTURB and LEAVE_PACKAGE_AT_DOOR. reset_at controls when the message is cleared: omit for the NVR default, pass None for "forever", or pass a specific datetime.

set_lcd_text(text_type: DoorbellMessageType | None, text: str | None = None, reset_at: None | datetime | DEFAULT_TYPE = None) -> None async

Sets doorbell LCD text. Requires camera to be doorbell

set_license_plate_detection(enabled: bool) -> None async

Toggles license plate smart detection. Requires camera to have smart detection

set_license_plate_detection_public(enabled: bool) -> None async

Toggle license plate smart detection via public API.

set_mic_volume(level: int) -> None async

Sets the mic sensitivity level on camera

set_mic_volume_public(level: float) -> None async

Set microphone volume via public API.

set_motion_detection(enabled: bool) -> None async

Sets motion detection on camera

set_osd_bitrate(enabled: bool) -> None async

Sets whether camera bitrate is in the On Screen Display

set_osd_date(enabled: bool) -> None async

Sets whether current date is in the On Screen Display

set_osd_date_public(enabled: bool) -> None async

Toggle date overlay (OSD) via public API.

Sets whether the UniFi logo is in the On Screen Display

set_osd_logo_public(enabled: bool) -> None async

Toggle logo overlay (OSD) via public API.

set_osd_name(enabled: bool) -> None async

Sets whether camera name is in the On Screen Display

set_osd_name_public(enabled: bool) -> None async

Toggle name overlay (OSD) via public API.

set_osd_nerd_mode_public(enabled: bool) -> None async

Toggle bitrate/debug overlay (OSD) via public API.

set_osd_overlay_location_public(location: OsdOverlayLocation) -> None async

Set OSD overlay location via public API.

set_package_detection(enabled: bool) -> None async

Toggles package smart detection. Requires camera to have smart detection

set_package_detection_public(enabled: bool) -> None async

Toggle package smart detection via public API.

set_person_detection(enabled: bool) -> None async

Toggles person smart detection. Requires camera to have smart detection

set_person_detection_public(enabled: bool) -> None async

Toggle person smart detection via public API.

set_person_track(enabled: bool) -> None async

Sets person tracking on camera

set_privacy(enabled: bool, mic_level: int | None = None, recording_mode: RecordingMode | None = None, reenable_global: bool = False) -> None async

Adds/removes a privacy zone that blacks out the whole camera.

set_recording_mode(mode: RecordingMode) -> None async

Sets recording mode on camera

set_ring_volume(level: int) -> None async

Sets the doorbell ring volume. Requires camera to be a doorbell

set_siren_detection(enabled: bool) -> None async

Toggles siren smart detection. Requires camera to have smart detection

set_siren_detection_public(enabled: bool) -> None async

Toggle siren audio detection via public API.

set_smart_audio_detect_types(types: list[SmartDetectAudioType]) -> None async

Sets current enabled smart audio detection types. Requires camera to have smart detection

set_smart_detect_types(types: list[SmartDetectObjectType]) -> None async

Sets current enabled smart detection types. Requires camera to have smart detection

set_smoke_detection(enabled: bool) -> None async

Toggles smoke smart detection. Requires camera to have smart detection

set_smoke_detection_public(enabled: bool) -> None async

Toggle smoke audio detection via public API.

set_speaker_volume(level: int) -> None async

Sets the speaker output volume on camera. Requires camera to have speakers

set_speaking_detection(enabled: bool) -> None async

Toggles speaking smart detection. Requires camera to have smart detection

set_speaking_detection_public(enabled: bool) -> None async

Toggle speaking audio detection via public API.

set_status_light(enabled: bool) -> None async

Sets status indicicator light on camera

set_status_light_public(enabled: bool) -> None async

Set status LED via public API.

set_system_sounds(enabled: bool) -> None async

Sets system sound playback through speakers. Requires camera to have speakers

set_use_global(enabled: bool) -> None async

Sets if camera should use global recording settings or not.

set_vehicle_detection(enabled: bool) -> None async

Toggles vehicle smart detection. Requires camera to have smart detection

set_vehicle_detection_public(enabled: bool) -> None async

Toggle vehicle smart detection via public API.

set_video_mode(mode: VideoMode) -> None async

Sets video mode on camera

set_video_mode_public(mode: VideoMode) -> None async

Set video mode via public API.

set_volume(level: int) -> None async

Sets the general volume level on camera. Requires camera to have speakers

set_wdr_level(level: int) -> None async

Sets WDR (Wide Dynamic Range) on camera

set_welcome_led_public(enabled: bool) -> None async

Set welcome LED via public API.

stop_audio() -> None async

Stop currently playing audio.

wait_until_audio_completes() -> None async

Awaits stream completion of audio.

CameraChannel

Bases: ProtectBaseObject

rtsps_quality: ChannelQuality | None property

RTSPS quality tier for this channel (id 0→HIGH, 1→MEDIUM, 2→LOW, 3→PACKAGE).

ChannelQuality

Bases: UnknownValuesEnumMixin, StrEnum

RTSPS channel quality (qualities field on rtsps-stream endpoints).

Chime

Bases: ProtectAdoptableDeviceModel

cameras: list[Camera] property

Paired Cameras for chime

add_camera(camera: Camera) -> None async

Adds new paired camera to chime

play(*, volume: int | None = None, repeat_times: int | None = None, ringtone_id: str | None = None, track_no: int | None = None) -> None async

Plays chime tone.


Text Only
1
2
3
4
5
6
volume: Volume level for playback (0-100). Uses chime's current volume if None.
repeat_times: Number of times to repeat the tone.
ringtone_id: The ringtone ID (UUID) to play. If None, uses default tone.
track_no: Legacy track number from speakerTrackList.
    .. deprecated::
        Use ringtone_id instead.

play_buzzer() -> None async

Plays chime buzzer

remove_camera(camera: Camera) -> None async

Removes paired camera from chime

set_repeat_times(value: int) -> None async

Set repeat times on chime.

.. deprecated:: Use :meth:set_ring_settings_public instead. This method uses the private API.

set_repeat_times_for_camera(camera: Camera, value: int) -> None async

Set repeat times on chime for a specific camera.

.. deprecated:: Use :meth:set_ring_settings_public instead. This method uses the private API.

set_repeat_times_for_camera_public(camera: Camera, value: int) -> None async

Set the ring repeat times for a specific camera using public API.

This is the preferred method to change ring repeat times as it uses the official public API.


Text Only
1
2
camera: The doorbell camera to set repeat times for
value: Number of times to repeat the ring (1-6)

Text Only
1
2
BadRequest: If the camera is not paired with this chime
ValidationError: If value is not in range 1-6

set_ring_settings_public(ring_settings: list[PublicApiChimeRingSettingRequest]) -> None async

Update ring settings using public API.

This is the preferred method to change ring volume per camera as it uses the official public API.


Text Only
1
2
3
4
5
ring_settings: List of ring settings per camera. Each dict should contain:
    - cameraId: The camera ID this setting applies to
    - volume: Ring volume (0-100)
    - repeatTimes: How many times to repeat (1-10)
    - ringtoneId (optional): The ringtone ID to use
Example:
Text Only
1
2
3
4
5
6
7
8
>>> await chime.set_ring_settings_public([
...     {
...         "cameraId": "camera123",
...         "volume": 80,
...         "repeatTimes": 2,
...         "ringtoneId": "ringtone456"
...     }
... ])

set_volume(level: int) -> None async

Set the speaker volume on chime.

.. deprecated:: Use :meth:set_volume_for_camera_public instead. This method updates the speaker volume but not the doorbell ring volume.

set_volume_for_camera(camera: Camera, level: int) -> None async

Set the ring volume on chime for a specific camera.

.. deprecated:: Use :meth:set_volume_for_camera_public instead. This method uses the private API which may not properly update the ring volume.

set_volume_for_camera_public(camera: Camera, level: int) -> None async

Set the ring volume for a specific camera using public API.

This is the preferred method to change ring volume as it uses the official public API and properly updates the doorbell ring volume.


Text Only
1
2
camera: The doorbell camera to set volume for
level: Volume level (0-100)

Text Only
1
2
BadRequest: If the camera is not paired with this chime
ValidationError: If level is not in range 0-100

DeviceState

Bases: UnknownValuesEnumMixin, StrEnum

Public-API device connection state (state field).

Event

Bases: ProtectModelWithId

get_animated_thumbnail(width: int | None = None, height: int | None = None, *, speedup: int = 10) -> bytes | None async

Gets animated thumbnail for event

get_detected_thumbnail() -> EventDetectedThumbnail | None

Gets best detected thumbnail for event (UFP 6.x+).

Returns the thumbnail marked with clockBestWall, which indicates the optimal frame for this detection (highest confidence, best angle, etc.).

Returns:

Type Description
EventDetectedThumbnail | None

EventDetectedThumbnail with the best detection frame, or None if:

EventDetectedThumbnail | None
  • Event has no metadata
EventDetectedThumbnail | None
  • No detected thumbnails available
EventDetectedThumbnail | None
  • No thumbnail has clockBestWall set
Example usage
License Plate Recognition

thumbnail = event.get_detected_thumbnail() if thumbnail and thumbnail.group: ... plate = thumbnail.group.matched_name # "ABC123" ... confidence = thumbnail.group.confidence # 95 ... if thumbnail.attributes: ... color = thumbnail.attributes.get_value("color") # "white" ... vehicle = thumbnail.attributes.get_value("vehicleType") # "sedan"

Face Detection

thumbnail = event.get_detected_thumbnail() if thumbnail and thumbnail.group: ... face_name = thumbnail.group.matched_name # "John Doe" ... confidence = thumbnail.group.confidence # 87

get_heatmap() -> bytes | None async

Gets heatmap for event

get_smart_detect_track() -> SmartDetectTrack async

Gets smart detect track for given smart detect event.

If event is not a smart detect event, it will raise a BadRequest

get_smart_detect_zones() -> dict[int, CameraZone] async

Gets the triggering zones for the smart detection

get_thumbnail(width: int | None = None, height: int | None = None) -> bytes | None async

Gets thumbnail for event

get_video(channel_index: int = 0, output_file: Path | None = None, iterator_callback: IteratorCallback | None = None, progress_callback: ProgressCallback | None = None, chunk_size: int = 65536) -> bytes | None async

Get the MP4 video clip for this given event


Text Only
1
channel_index: index of `CameraChannel` on the camera to use to retrieve video from

Will raise an exception if event does not have a camera, end time or the channel index is wrong.

FixSizeOrderedDict

Bases: dict[KT, VT]

A fixed size ordered dict.

__init__(*args: Any, max_size: int = 0, **kwargs: Any) -> None

Create the FixSizeOrderedDict.

__setitem__(key: KT, value: VT) -> None

Set an update up to the max size.

Fob

Bases: PublicDeviceModel

Public API key fob device.

FobAwayState

Bases: UnknownValuesEnumMixin, StrEnum

Key-fob presence/away state (awayState field).

FobButton

Bases: UnknownValuesEnumMixin, StrEnum

Key-fob button kinds (featureFlags.buttons items).

Light

Bases: ProtectMotionDeviceModel

camera: Camera | None property

Paired Camera will always be none if no camera is paired

set_duration(duration: timedelta) -> None async

Sets motion sensitivity

set_duration_public(duration: timedelta) -> None async

Set how long the light stays on after motion (15s-900s) via public API.

set_flood_light(enabled: bool) -> None async

Sets the flood light (force on) for the light

set_flood_light_public(enabled: bool) -> None async

Force the flood light on/off via public API.

set_led_level(led_level: int) -> None async

Sets the LED level for the light

set_led_level_public(led_level: float) -> None async

Set the LED brightness level via public API.

set_light(enabled: bool, led_level: int | None = None) -> None async

Force turns on/off the light

set_light_mode_public(mode: LightModeType, enable_at: LightModeEnableType | None = None) -> None async

Set the lighting trigger mode (and optional schedule) via public API.

set_light_settings(mode: LightModeType, enable_at: LightModeEnableType | None = None, duration: timedelta | None = None, sensitivity: int | None = None) -> None async

Updates various Light settings.


Text Only
1
2
3
4
mode: Light trigger mode
enable_at: Then the light automatically turns on by itself
duration: How long the light should remain on after motion, must be timedelta between 15s and 900s
sensitivity: PIR Motion sensitivity

set_light_settings_public(mode: LightModeType, enable_at: LightModeEnableType | None = None, duration: timedelta | None = None, sensitivity: int | None = None) -> None async

Update mode, enable schedule, duration and PIR sensitivity via public API.

set_name_public(name: str) -> None async

Set light name via public API.

set_paired_camera(camera: Camera | None) -> None async

Sets the camera paired with the light

set_sensitivity(sensitivity: int) -> None async

Sets motion sensitivity

set_sensitivity_public(sensitivity: int) -> None async

Set PIR motion sensitivity via public API.

set_status_light(enabled: bool) -> None async

Sets the status indicator light for the light

set_status_light_public(enabled: bool) -> None async

Toggle the status indicator LED via public API.

LinkStation

Bases: PublicDeviceModel

Public API link station / alarm hub.

A single wire schema (modelKey: "linkstation") covers both the /v1/link-stations and /v1/alarm-hubs endpoints. The :attr:is_alarm_hub flag distinguishes the two; alarm_hub is only populated when :attr:is_alarm_hub is True.

alarm_hub_armed: OnOffState | None property

Return the typed armed flag, or None when the field is absent.

alarm_hub_battery: AlarmHubBattery | None property

Return the typed backup-battery status, or None when absent.

alarm_hub_cover: AlarmHubCover | None property

Return the typed tamper-cover status, or None when absent.

alarm_hub_inputs: dict[int, AlarmHubInput] property

Return input zones keyed by numeric id; non-integer keys are skipped.

alarm_hub_outputs: dict[int, AlarmHubOutput] property

Return output channels keyed by numeric id; non-integer keys are skipped.

set_name(name: str) -> LinkStation async

Rename via the matching endpoint for the device's role.

trigger_output(output_id: int, *, enable: bool | None = None, delay: int | None = None, duration: int | None = None) -> None async

Trigger an alarm-hub output channel. Raises if this is not an alarm hub.

unifi_dict_conversions() -> dict[str, object | Callable[[Any], Any]] cached classmethod

Parse the lastEvent epoch-ms wire value into datetime.

Liveview

Bases: ProtectModelWithId

owner: User | None property

Owner of liveview.

Will be none if the user only has read only access and it was not made by their user.

LiveviewCycleMode

Bases: UnknownValuesEnumMixin, StrEnum

Public-API liveview slot cycle mode (slots[].cycleMode field).

ModelType

Bases: UnknownValuesEnumMixin, StrEnum

devices_key() -> str

Return the devices key.

name() -> str

Return the name.

value() -> str

Return the value.

NVR

Bases: ProtectDeviceModel

is_face_detections_enabled: bool property

If smart detected enabled globally.

is_global_animal_detection_on: bool property

Is Animal Detection available and enabled (camera will produce package smart detection events)?

is_global_baby_cry_detection_on: bool property

Is Baby Cry Detection available and enabled (camera will produce baby cry smart detection events)?

is_global_bark_detection_on: bool property

Is Bark Detection available and enabled (camera will produce barking smart detection events)?

is_global_car_alarm_detection_on: bool property

Is Car Alarm Detection available and enabled (camera will produce car alarm smart detection events)?

is_global_car_horn_detection_on: bool property

Is Car Horn Detection available and enabled (camera will produce car horn smart detection events)?

is_global_co_detection_on: bool property

Is CO Alarm Detection available and enabled (camera will produce smoke smart detection events)?

is_global_face_detection_on: bool property

Is Face Detection available and enabled?

is_global_glass_break_detection_on: bool property

Is Glass Break available and enabled (camera will produce glass break smart detection events)?

is_global_license_plate_detection_on: bool property

Is License Plate Detection available and enabled (camera will produce face license plate detection events)?

is_global_package_detection_on: bool property

Is Package Detection available and enabled (camera will produce package smart detection events)?

is_global_person_detection_on: bool property

Is Person Detection available and enabled (camera will produce person smart detection events)?

is_global_person_tracking_enabled: bool property

Is person tracking enabled

is_global_recording_enabled: bool property

Is recording footage/events from the camera enabled?

If recording is not enabled, cameras will not produce any footage, thumbnails, motion/smart detection events.

is_global_siren_detection_on: bool property

Is Siren Detection available and enabled (camera will produce siren smart detection events)?

is_global_smoke_detection_on: bool property

Is Smoke Alarm Detection available and enabled (camera will produce smoke smart detection events)?

is_global_speaking_detection_on: bool property

Is Speaking Detection available and enabled (camera will produce speaking smart detection events)?

is_global_vehicle_detection_on: bool property

Is Vehicle Detection available and enabled (camera will produce vehicle smart detection events)?

is_license_plate_detections_enabled: bool property

If smart detected enabled globally.

is_smart_detections_enabled: bool property

If smart detected enabled globally.

vault_cameras: list[Camera] property

Vault Cameras for NVR

add_custom_doorbell_message(message: str) -> None async

Adds custom doorbell message

get_is_prerelease() -> bool async

[DEPRECATED] Always returns False. Will be removed after HA 2025.8.0.

reboot() -> None async

Reboots the NVR

remove_custom_doorbell_message(message: str) -> None async

Removes custom doorbell message

set_analytics(value: AnalyticsOption) -> None async

Sets analytics collection for NVR

set_anonymous_analytics(enabled: bool) -> None async

Enables or disables anonymous analytics for NVR

set_default_doorbell_message(message: str) -> None async

Sets default doorbell message

set_default_reset_timeout(timeout: timedelta) -> None async

Sets the default message reset timeout

set_face_recognition(value: bool) -> None async

Set if face detections are enabled. Requires smart detections to be enabled.

set_global_motion_detection(enabled: bool) -> None async

Sets motion detection on camera

set_global_osd_bitrate(enabled: bool) -> None async

Sets whether camera bitrate is in the On Screen Display

set_global_osd_date(enabled: bool) -> None async

Sets whether current date is in the On Screen Display

Sets whether the UniFi logo is in the On Screen Display

set_global_osd_name(enabled: bool) -> None async

Sets whether camera name is in the On Screen Display

set_global_recording_mode(mode: RecordingMode) -> None async

Sets recording mode on camera

set_insights(enabled: bool) -> None async

Sets analytics collection for NVR

set_license_plate_recognition(value: bool) -> None async

Set if license plate detections are enabled. Requires smart detections to be enabled.

set_smart_detections(value: bool) -> None async

Set if smart detections are enabled.

update_all_messages() -> None

Updates doorbell_settings.all_messages after adding/removing custom message

NvrArmMode

Bases: ProtectBaseObject

Current arm-manager state embedded in the NVR object (armMode field).

Returned by GET /v1/nvrs as part of the NVR payload. All fields that may legitimately be null on the wire are typed as Optional for forward-compatibility.

NvrArmModeStatus

Bases: UnknownValuesEnumMixin, StrEnum

Arm-manager status values embedded in the NVR armMode field.

OnOffState

Bases: UnknownValuesEnumMixin, StrEnum

Generic on/off wire state used by several alarm-hub fields.

OsdOverlayLocation

Bases: UnknownValuesEnumMixin, StrEnum

On-screen-display overlay location (osdSettings.overlayLocation).

Carries an UNKNOWN member so values added by newer firmware coerce to UNKNOWN instead of raising during Camera deserialization.

PermissionNode

Bases: UnknownValuesEnumMixin, StrEnum

name() -> str

Return the name.

value() -> str

Return the value.

ProtectAdoptableDeviceModel

Bases: ProtectDeviceModel

is_adopted_by_us: bool property

Verifies device is adopted and controlled by this NVR.

protect_url: str property

UFP Web app URL for this device

adopt(name: str | None = None) -> None async

Adopts a device

get_changed(data_before_changes: dict[str, Any]) -> dict[str, Any]

Gets dictionary of all changed fields

reboot() -> None async

Reboots an adopted device

set_ssh(enabled: bool) -> None async

Sets ssh status for protect device

unadopt() -> None async

Unadopt/Unmanage adopted device

ProtectBaseObject

Bases: BaseModel

Base class for building Python objects from UniFi Protect JSON.

  • Provides .unifi_dict_to_dict to convert UFP JSON to a more Pythonic formatted dict (camel case to snake case)
  • Add attrs with matching Pythonic name and they will automatically be populated from the UFP JSON if passed in to the constructor
  • Provides .unifi_dict to convert object back into UFP JSON

api: ProtectApiClient property

ProtectApiClient that the UFP object was created with. If no API Client was passed in time of creation, will raise BadRequest

__init__(api: ProtectApiClient | None = None, **data: Any) -> None

Base class for creating Python objects from UFP JSON data.

Use the static method .from_unifi_dict() to create objects from UFP JSON data from then the main class constructor.

dict_with_excludes() -> dict[str, Any]

Returns a dict of the current object without any UFP objects converted to dicts.

from_unifi_dict(api: ProtectApiClient | None = None, **data: Any) -> Self classmethod

Main constructor for ProtectBaseObject


Text Only
1
2
api: Optional reference to the ProtectAPIClient that created generated the UFP JSON
**data: decoded UFP JSON

api is is expected as a @property. If it is None and accessed, a BadRequest will be raised.

API can be used for saving updates for the Protect object or fetching references to other objects (cameras, users, etc.)

unifi_dict(data: dict[str, Any] | None = None, exclude: set[str] | None = None) -> dict[str, Any]

Can either convert current Python object into UFP JSON dict or take the output of a .dict() call and convert it.

  • Remaps items from ._get_unifi_remaps() in reverse
  • Converts snake_case to camelCase
  • Automatically removes any ProtectApiClient instances that might still be in the data
  • Automatically calls .unifi_dict() for any UFP Python objects that are detected

Text Only
1
2
3
data: Optional output of `.dict()` for the Python object. If `None`, will call `.dict` first
exclude: Optional set of fields to exclude from convert. Useful for subclassing and having custom
    processing for dumping to UFP JSON data.

unifi_dict_conversions() -> dict[str, object | Callable[[Any], Any]] cached classmethod

Helper method for overriding in child classes for converting UFP JSON data to Python data types.

Return format is { "ufpJsonName": Callable[[Any], Any] }

unifi_dict_to_dict(data: dict[str, Any]) -> dict[str, Any] classmethod

Takes a decoded UFP JSON dict and converts it into a Python dict

  • Remaps items from ._get_unifi_remaps()
  • Converts camelCase keys to snake_case keys
  • Injects ProtectAPIClient into any child UFP object Dicts
  • Runs .unifi_dict_to_dict for any child UFP objects

Text Only
1
data: decoded UFP JSON dict

update_from_dict(data: dict[str, Any]) -> Self

Updates current object from a cleaned UFP JSON dict.

The api client is injected into each dict for any child UFP objects that are detected.

ProtectDeviceIdentity

Bases: Protocol

Identity surface shared by the private and public device / NVR model trees.

Consumers that handle "the NVR" or "a camera" generically can type against this instead of cast()-ing between the unrelated private (NVR / Camera / ...) and public (PublicNVR / PublicCamera / ...) types. mac and type are Optional because the public tree omits them on older firmware.

ProtectDeviceModel

Bases: ProtectModelWithId

set_name(name: str | None) -> None async

Sets name for the device

ProtectModel

Bases: ProtectBaseObject

Base class for UFP objects with a modelKey attr. Provides .from_unifi_dict() static helper method for automatically decoding a modelKey object into the correct UFP object and type

ProtectModelWithId

Bases: ProtectModel

emit_message(updated: dict[str, Any]) -> None async

Emits fake WS message for ProtectApiClient to process.

queue_update(callback: Callable[[], None]) -> None async

Queues a device update.

This allows aggregating devices updates so if multiple ones come in all at once, they can be combined in a single PATCH.

revert_changes(data_before_changes: dict[str, Any]) -> None

Reverts current changes to device and resets it back to initial state

save_device(data_before_changes: dict[str, Any], force_emit: bool = False, revert_on_fail: bool = True) -> None async

Generates a diff for unsaved changed on the device and sends them back to UFP

USE WITH CAUTION, updates all fields for the current object that have been changed. May have unexpected side effects.

Tested updates have been added a methods on applicable devices.


Text Only
1
force_emit: Emit a fake UFP WS message. Should only be use for when UFP does not properly emit a WS message

ProtectWSPayloadFormat

Bases: int, Enum

Websocket Payload formats.

PublicArmScheduleDict

Bases: TypedDict

Arm-profile schedule entry (write shape). Fields are cron expressions.

PublicBootstrap dataclass

In-memory cache of the Public Integration API resources.

All device dicts map id -> object. Empty by default; populated by :meth:ProtectApiClient.update_public.

Staleness on websocket reconnect. While the devices/events websocket is connected, incoming add/update/remove messages are merged into the cache. If the websocket drops and reconnects, any messages emitted during the gap are lost. :class:ProtectApiClient automatically schedules an :meth:~ProtectApiClient.update_public refresh on reconnect (the initial connect does not trigger a refresh).

alarm_hubs: dict[str, LinkStation] property

Subset of :attr:link_stations filtered to alarm hubs.

arm_mode: NvrArmMode | None property

Current arm-manager state. Shortcut for nvr.arm_mode.

Returns None when the NVR cache hasn't been primed yet, when the firmware does not expose the alarm manager, or when the alarm manager is set to global.

__post_init__() -> None

Validate cache bounds used by event eviction logic.

apply_fetch_result(attr: str, objs: list[ProtectModelWithId]) -> None

Merge fetched objects into self.<attr> without wholesale replace.

Used by :meth:ProtectApiClient.update_public so that add/ update/remove WS messages arriving concurrently with the HTTP fetch are not clobbered. IDs present in objs overwrite the cache entry; IDs absent from objs but present in the cache are removed.

get(model_type: ModelType, obj_id: str) -> ProtectModelWithId | None

Look up a cached device by model type and id.

get_device_mac(device_id: str) -> str | None

Resolve a device id to its mac across the public device stores.

process_devices_ws_message(api: ProtectApiClient, data: dict[str, Any]) -> tuple[ModelType | None, ProtectModelWithId | None, ProtectModelWithId | None]

Apply a public devices WS payload to the cache.

Back-compat façade over :meth:process_devices_ws_messages: returns the first expanded result's (model_type, new_obj, old_obj) 3-tuple, or (None, None, None) when nothing was produced. Callers that need per-device frames for bulk envelopes should use the plural form.

update messages carry partial diffs — only the changed fields. They are merged into the existing cached object via :meth:ProtectBaseObject.update_from_dict; reconstructing from a partial payload would fail strict validation for required fields.

process_devices_ws_messages(api: ProtectApiClient, data: dict[str, Any]) -> list[DeviceWSResult]

Apply a public devices WS frame to the cache, expanding bulk forms.

The bulk envelopes (devicesAdd / devicesBulkUpdate / devicesBulkRemove) share a single item whose id is a list of ids with one shared modelKey and payload. This fans that out to one :class:DeviceWSResult per id (each carrying a scalar-id item); a single-id frame yields a one-element list. An empty id array yields an empty list.

process_events_ws_message(api: ProtectApiClient, data: dict[str, Any]) -> EventsFrameResult

Apply a public events WS payload to the event cache.

Returns an :class:EventsFrameResult (a tuple-compatible NamedTuple of new_event, old_event, model_updates). new_event / old_event may be None; old_event is a pre-merge snapshot of the cached event taken before this frame is applied — update merges its partial diff into the cached object in place, so without the snapshot old and new would be the same mutated instance. The snapshot lets a consumer detect the open→closed transition (old.end is None and new.end is not None) and reject retransmits idempotently.

model_updates are devices-WS update messages for any camera whose derived detection booleans net-flipped over this frame — the first-class device-model outputs of processing the events frame. The api handler emits them through the standard devices channel with no knowledge that they originated from a detection event.

supports_device(model_type: ModelType) -> bool

Return whether model_type maps to a public device store.

PublicBridge

Bases: PublicDeviceModel

Public API bridge device.

ModelType.BRIDGE is already owned by the private :class:Bridge class in MODEL_TO_CLASS; this public counterpart is routed via a dedicated factory on :class:~uiprotect.data.public_bootstrap.PublicBootstrap instead.

PublicCamera

Bases: PublicDeviceModel

Public API camera device (GET /v1/cameras).

hdr_mode_display: Literal['auto', 'off', 'always'] property

HDR mode as shown in the Protect interface (inverse of hdr_type).

is_animal_currently_detected: bool property

Is an animal currently being detected.

is_animal_detection_on: bool property

Is animal smart detection enabled.

is_audio_currently_detected: bool property

Is an audio smart-detect event currently active.

is_baby_cry_currently_detected: bool property

Is a baby cry currently being detected.

is_baby_cry_detection_on: bool property

Is baby cry smart detection enabled.

is_bark_currently_detected: bool property

Is a bark currently being detected.

is_bark_detection_on: bool property

Is bark smart detection enabled.

is_car_alarm_currently_detected: bool property

Is a car alarm currently being detected.

is_car_alarm_detection_on: bool property

Is car alarm smart detection enabled.

is_car_horn_currently_detected: bool property

Is a car horn currently being detected.

is_car_horn_detection_on: bool property

Is car horn smart detection enabled.

is_cmonx_currently_detected: bool property

Is a CO alarm currently being detected.

is_co_detection_on: bool property

Is CO alarm smart detection enabled.

is_face_detection_on: bool property

Is face smart detection enabled.

is_glass_break_currently_detected: bool property

Is glass breaking currently being detected.

is_glass_break_detection_on: bool property

Is glass break smart detection enabled.

is_high_fps_enabled: bool property

Is the camera running in high-FPS video mode.

is_license_plate_detection_on: bool property

Is license plate smart detection enabled.

is_motion_detected: bool property

Is a motion event currently active.

is_package_detection_on: bool property

Is package smart detection enabled.

is_person_currently_detected: bool property

Is a person currently being detected.

is_person_detection_on: bool property

Is person smart detection enabled.

is_siren_currently_detected: bool property

Is a siren currently being detected.

is_siren_detection_on: bool property

Is siren smart detection enabled.

is_smart_currently_detected: bool property

Is a smart-detect event currently active.

is_smoke_currently_detected: bool property

Is a smoke alarm currently being detected.

is_smoke_detection_on: bool property

Is smoke alarm smart detection enabled.

is_speaking_currently_detected: bool property

Is speaking currently being detected.

is_speaking_detection_on: bool property

Is speaking smart detection enabled.

is_vehicle_currently_detected: bool property

Is a vehicle currently being detected.

is_vehicle_detection_on: bool property

Is vehicle smart detection enabled.

hardware_stream_qualities() -> list[ChannelQuality]

Stream qualities the camera hardware supports (not the server's available list).

set_animal_detection(enabled: bool) -> PublicCamera async

Toggle animal smart detection via the public API.

set_baby_cry_detection(enabled: bool) -> PublicCamera async

Toggle baby cry audio detection via the public API.

set_bark_detection(enabled: bool) -> PublicCamera async

Toggle bark audio detection via the public API.

set_burglar_detection(enabled: bool) -> PublicCamera async

Toggle burglar audio detection via the public API.

set_car_horn_detection(enabled: bool) -> PublicCamera async

Toggle car horn audio detection via the public API.

set_co_detection(enabled: bool) -> PublicCamera async

Toggle CO audio detection via the public API.

set_face_detection(enabled: bool) -> PublicCamera async

Toggle face smart detection via the public API.

set_flood_led(enabled: bool) -> PublicCamera async

Set the flood LED via the public API.

set_glass_break_detection(enabled: bool) -> PublicCamera async

Toggle glass break audio detection via the public API.

set_hdr_mode(mode: PublicHdrMode) -> PublicCamera async

Set HDR mode via the public API.

set_lcd_message(text_type: DoorbellMessageType, text: str | None = None, reset_at: datetime | None | DEFAULT_TYPE = DEFAULT) -> PublicCamera async

Set the doorbell LCD message via the public API.

text is required for CUSTOM_MESSAGE and IMAGE and must be omitted otherwise. reset_at controls when the message clears: omit for the NVR default, pass None for "forever", or a specific datetime.

set_license_plate_detection(enabled: bool) -> PublicCamera async

Toggle license plate smart detection via the public API.

set_mic_volume(level: int) -> PublicCamera async

Set microphone volume (1-100) via the public API.

set_osd_date(enabled: bool) -> PublicCamera async

Toggle the date overlay (OSD) via the public API.

Toggle the logo overlay (OSD) via the public API.

set_osd_name(enabled: bool) -> PublicCamera async

Toggle the name overlay (OSD) via the public API.

set_osd_nerd_mode(enabled: bool) -> PublicCamera async

Toggle the bitrate/debug overlay (OSD) via the public API.

set_osd_overlay_location(location: OsdOverlayLocation) -> PublicCamera async

Set the OSD overlay location via the public API.

set_package_detection(enabled: bool) -> PublicCamera async

Toggle package smart detection via the public API.

set_person_detection(enabled: bool) -> PublicCamera async

Toggle person smart detection via the public API.

set_siren_detection(enabled: bool) -> PublicCamera async

Toggle siren audio detection via the public API.

set_smoke_detection(enabled: bool) -> PublicCamera async

Toggle smoke audio detection via the public API.

set_speaking_detection(enabled: bool) -> PublicCamera async

Toggle speaking audio detection via the public API.

set_status_light(enabled: bool) -> PublicCamera async

Set the status LED via the public API.

set_vehicle_detection(enabled: bool) -> PublicCamera async

Toggle vehicle smart detection via the public API.

set_video_mode(mode: VideoMode) -> PublicCamera async

Set the video mode via the public API.

set_welcome_led(enabled: bool) -> PublicCamera async

Set the welcome LED via the public API.

PublicChime

Bases: PublicDeviceModel

Public API chime device (GET /v1/chimes).

set_repeat_times_for_camera(camera_id: str, value: int) -> PublicChime async

Set the ring repeat count for one paired camera via the public API.

set_ring_settings(ring_settings: list[PublicApiChimeRingSettingRequest]) -> PublicChime async

Replace the full per-camera ring settings via the public API.

set_volume_for_camera(camera_id: str, level: int) -> PublicChime async

Set the ring volume for one paired camera via the public API.

PublicDeviceModel

Bases: PublicIdentifiedModel

Shared base for dedicated public device models carrying mac / state.

PublicDoorbellCustomImage

Bases: ProtectBaseObject

A custom doorbell image entry (preview GIF + full sprite PNG).

PublicDoorbellSettings

Bases: ProtectBaseObject

Doorbell settings exposed by the Public Integration API (GET /v1/nvrs).

Intentionally separate from the private :class:~uiprotect.data.nvr.DoorbellSettings which carries additional private-API-only fields (allMessages, typed timedelta, etc.).

All fields have defaults because the doorbellSettings OpenAPI schema declares no required array — fields may be absent on older firmware or in partial WS update diffs.

PublicEvent

Bases: ProtectModelWithId

Event delivered over the Public Integration API events websocket.

unifi_dict_conversions() -> dict[str, object | Callable[[Any], Any]] cached classmethod

Parse the start / end wire timestamps into datetime.

PublicEventMetadata

Bases: ProtectBaseObject

Union of every public *Event metadata field, all optional.

unifi_dict(data: dict[str, Any] | None = None, exclude: set[str] | None = None) -> dict[str, Any]

Serialise, dropping None fields and re-wrapping metadata envelopes.

unifi_dict_to_dict(data: dict[str, Any]) -> dict[str, Any] classmethod

Collapse the {text|number: value} metadata envelopes to inner values.

PublicFile

Bases: ProtectBaseObject

Public API device asset file (/v1/files/{fileType}).

PublicFingerprintMetadata

Bases: ProtectBaseObject

fingerprint block of a fingerprintIdentified event (public spec).

PublicLight

Bases: PublicDeviceModel

Public API light device (GET /v1/lights).

set_duration(duration: timedelta) -> PublicLight async

Set how long the light stays on after motion (15s-900s) via the public API.

set_flood_light(enabled: bool) -> PublicLight async

Force the flood light on/off via the public API.

set_led_level(led_level: int) -> PublicLight async

Set the indicator LED brightness (1-6) via the public API.

set_light_mode(mode: LightModeType, enable_at: LightModeEnableType | None = None) -> PublicLight async

Set the lighting trigger mode (and optional schedule) via the public API.

set_light_settings(mode: LightModeType, enable_at: LightModeEnableType | None = None, duration: timedelta | None = None, sensitivity: int | None = None) -> PublicLight async

Update mode, schedule, duration and PIR sensitivity via the public API.

set_name(name: str) -> PublicLight async

Set the light name via the public API.

set_sensitivity(sensitivity: int) -> PublicLight async

Set PIR motion sensitivity (0-100) via the public API.

set_status_light(enabled: bool) -> PublicLight async

Toggle the status indicator LED via the public API.

PublicLiveview

Bases: ProtectModelWithId

Public API liveview.

owner is a flat userId string (the spec types it as $ref: userId, which is type: string) — not an embedded user object. layout is the number of slots the liveview contains (spec: number, 1..26); the field name matches the wire key exactly.

PublicLiveviewSlot

Bases: ProtectBaseObject

One slot in a public-API liveview (read shape).

PublicLiveviewSlotDict

Bases: TypedDict

Liveview slot (write shape).

PublicNVR

Bases: PublicIdentifiedModel

NVR device as exposed by the Public Integration API (GET /v1/nvrs).

This model reflects the public schema: id, modelKey, name, doorbellSettings, and optionally armMode / mac.

name is nullable — the API schema declares it as oneOf: [string, null].

mac is exposed on GET /v1/nvrs from Protect newer than 7.1 and is None on older firmware that omits the key (and absent from WS partial-update diffs).

doorbell_settings is None on older firmware that does not yet expose the doorbellSettings key, and is absent from WS partial-update diffs (which only require id + modelKey).

arm_mode is None when the firmware does not yet expose the alarm manager (older releases) and also None when the alarm manager is set to global (server returns armMode: null). WS device-update diffs that include armMode are handled automatically by :meth:~uiprotect.data.base.ProtectBaseObject.update_from_dict without any manual extraction.

PublicNfcMetadata

Bases: ProtectBaseObject

nfc block of an nfcCardScanned event (public spec).

PublicSensor

Bases: PublicDeviceModel

Public API sensor device (GET /v1/sensors).

has_feature_flags: bool property

Whether a capability map was reported; False means unavailable, not empty.

is_leak_detected: bool property

Whether a leak is detected on either the internal or external channel.

is_tampering_detected: bool property

Whether the tamper switch is currently triggered.

set_alarm(enabled: bool) -> PublicSensor async

Toggle the (audio) alarm detection setting via the public API.

set_arm_profile_ids(arm_profile_ids: list[str]) -> PublicSensor async

Set the arm-profile ids associated with the sensor via the public API.

set_custom_sensitivity_when_armed(enabled: bool) -> PublicSensor async

Toggle custom armed sensitivity via the public API.

set_glass_break_settings(*, is_enabled: bool | None = None, sensitivity: float | None = None, sensitivity_when_armed: float | None = None) -> PublicSensor async

Update glass-break detection settings via the public API.

set_glass_break_status(enabled: bool) -> PublicSensor async

Toggle glass-break detection via the public API.

set_humidity_settings(*, is_enabled: bool | None = None, low_threshold: float | None = None, high_threshold: float | None = None, margin: int | None = None) -> PublicSensor async

Update humidity alert settings via the public API.

set_humidity_status(enabled: bool) -> PublicSensor async

Toggle humidity alerts via the public API.

set_light_settings(*, is_enabled: bool | None = None, low_threshold: float | None = None, high_threshold: float | None = None, margin: int | None = None) -> PublicSensor async

Update light (lux) alert settings via the public API.

set_light_status(enabled: bool) -> PublicSensor async

Toggle light (lux) alerts via the public API.

set_motion_sensitivity(sensitivity: float) -> PublicSensor async

Set motion detection sensitivity via the public API.

set_motion_settings(*, is_enabled: bool | None = None, sensitivity: float | None = None, sensitivity_when_armed: float | None = None) -> PublicSensor async

Update motion detection settings via the public API.

set_motion_status(enabled: bool) -> PublicSensor async

Toggle motion detection via the public API.

set_name(name: str) -> PublicSensor async

Set the sensor name via the public API.

set_schedule_mode(mode: SensorScheduleMode) -> PublicSensor async

Set the arm-schedule mode via the public API.

set_temperature_settings(*, is_enabled: bool | None = None, low_threshold: float | None = None, high_threshold: float | None = None, margin: float | None = None) -> PublicSensor async

Update temperature alert settings via the public API.

set_temperature_status(enabled: bool) -> PublicSensor async

Toggle temperature alerts via the public API.

supports(capability: SensorFeatureCapability) -> bool

Whether the sensor advertises capability (False without a feature map).

PublicSensorFeatureCapability

Bases: ProtectBaseObject

One capability slice; channel_count defaults to 0 when the wire omits it.

PublicSensorFeatureFlags

Bases: ProtectBaseObject

Per-sensor capability map. An absent key means the capability is unsupported.

PublicSirenStatus

Bases: ProtectBaseObject

turn_off_at: datetime | None property

When the siren is expected to stop playing.

Returns None when the siren is idle — either because activated_at / duration are not set, or because is_active is False (e.g. after a manual stop, where the server may leave the timing fields populated). Derived from the websocket payload so no extra API call is needed — HA can compare against datetime.now(UTC) instead of maintaining its own timer.

PublicUlpUser

Bases: ProtectModelWithId

Public API UniFi Identity (ULP) user (read-only).

PublicUser

Bases: ProtectModelWithId

Public API Protect user (read-only).

PublicViewer

Bases: PublicDeviceModel

Public API viewer device.

ModelType.VIEWPORT is already owned by the private :class:Viewer class in MODEL_TO_CLASS; this public counterpart is routed via a dedicated factory on :class:~uiprotect.data.public_bootstrap.PublicBootstrap instead.

The wire field liveview is a flat liveviewId string (nullable); snake-cased to :attr:liveview_id via :meth:_get_unifi_remaps.

RTSPSStreams

Bases: ProtectBaseObject

RTSPS stream URLs for a camera.

get_active_stream_qualities() -> list[str]

Get list of currently active RTSPS stream quality levels (only those with stream URLs).

get_available_stream_qualities() -> list[str]

List available RTSPS quality keys from the server.

Returns raw strings; may include values not in :class:ChannelQuality.

get_inactive_stream_qualities() -> list[str]

Get list of inactive RTSPS stream quality levels (supported but not currently active).

get_stream_url(quality: str, srtp: bool = True) -> str | None

Get stream URL for a quality level; srtp=False strips ?enableSrtp.

Relay

Bases: PublicDeviceModel

Public API relay device.

Use :meth:__getitem__ (relay[output_id]) for "fail loud" lookup or :meth:get_output for the None-returning variant.

__getitem__(output_id: int) -> PublicRelayOutput

Return the output with the given id; raises :class:KeyError if unknown.

activate_output(output_id: int, state: Literal['on', 'off'] | None = None, pulse_duration_ms: int | None = None) -> None async

Activate / toggle a relay output channel.

get_output(output_id: int) -> PublicRelayOutput | None

Return the output with the given id, or None if not found.

RelayInputActionTrigger

Bases: UnknownValuesEnumMixin, StrEnum

Relay input action trigger condition (inputs[].actionTrigger field).

RelayInputActionType

Bases: UnknownValuesEnumMixin, StrEnum

Relay input action effect (inputs[].actionType field).

RelayInputState

Bases: UnknownValuesEnumMixin, StrEnum

State of a single relay input channel.

RelayOutputRebootState

Bases: UnknownValuesEnumMixin, StrEnum

State the relay output is set to after a reboot/power cycle (rebootState field).

RelayOutputState

Bases: UnknownValuesEnumMixin, StrEnum

State of a single relay output channel (state field).

RelayOutputType

Bases: UnknownValuesEnumMixin, StrEnum

Relay output device type (outputs[].type field).

RingSetting

Bases: ProtectBaseObject

Ring settings for a paired doorbell camera.

camera: Camera | None property

Paired Camera will always be none if no camera is paired.

to_api_dict(volume: int | None = None, repeat_times: int | None = None) -> PublicApiChimeRingSettingRequest

Convert to API dict format for Public API requests.


Text Only
1
2
3
volume: Override volume value. If None, uses current volume.
repeat_times: Override repeat-times value. If None, uses current
    repeat_times.

Text Only
1
Dict with cameraId, volume, repeatTimes, and optionally ringtoneId keys.

Sensor

Bases: ProtectAdoptableDeviceModel

camera: Camera | None property

Paired Camera will always be none if no camera is paired

clear_tamper() -> None async

Clears tamper status for sensor

remove_humidity_safe_range() -> None async

Removes the humidity safe range for the sensor

remove_light_safe_range() -> None async

Removes the light safe range for the sensor

remove_temperature_safe_range() -> None async

Removes the temperature safe range for the sensor

set_alarm_public(enabled: bool) -> None async

Toggle the (audio) alarm detection setting via public API.

set_alarm_status(enabled: bool) -> None async

Sets the alarm detection type for the sensor

set_arm_profile_ids_public(arm_profile_ids: list[str]) -> None async

Set the arm-profile ids associated with the sensor via public API.

set_custom_sensitivity_when_armed_public(enabled: bool) -> None async

Toggle custom armed sensitivity via public API.

set_glass_break_settings_public(*, is_enabled: bool | None = None, sensitivity: float | None = None, sensitivity_when_armed: float | None = None) -> None async

Update glass-break detection settings via public API.

set_glass_break_status_public(enabled: bool) -> None async

Toggle glass-break detection via public API.

set_humidity_safe_range(low: float, high: float) -> None async

Sets the humidity safe range for the sensor

set_humidity_settings_public(*, is_enabled: bool | None = None, low_threshold: float | None = None, high_threshold: float | None = None, margin: int | None = None) -> None async

Update humidity alert settings via public API.

set_humidity_status(enabled: bool) -> None async

Sets the humidity detection type for the sensor

set_humidity_status_public(enabled: bool) -> None async

Toggle humidity alerts via public API.

set_light_safe_range(low: float, high: float) -> None async

Sets the light safe range for the sensor

set_light_settings_public(*, is_enabled: bool | None = None, low_threshold: float | None = None, high_threshold: float | None = None, margin: int | None = None) -> None async

Update light (lux) alert settings via public API.

set_light_status(enabled: bool) -> None async

Sets the light detection type for the sensor

set_light_status_public(enabled: bool) -> None async

Toggle light (lux) alerts via public API.

set_motion_sensitivity(sensitivity: int) -> None async

Sets the motion sensitivity for the sensor

set_motion_sensitivity_public(sensitivity: float) -> None async

Set motion detection sensitivity via public API.

set_motion_settings_public(*, is_enabled: bool | None = None, sensitivity: float | None = None, sensitivity_when_armed: float | None = None) -> None async

Update motion detection settings via public API.

set_motion_status(enabled: bool) -> None async

Sets the motion detection type for the sensor

set_motion_status_public(enabled: bool) -> None async

Toggle motion detection via public API.

set_mount_type(mount_type: MountType) -> None async

Sets current mount type for sensor

set_name_public(name: str) -> None async

Set sensor name via public API.

set_paired_camera(camera: Camera | None) -> None async

Sets the camera paired with the sensor

set_schedule_mode_public(mode: SensorScheduleMode) -> None async

Set the arm-schedule mode via public API.

set_status_light(enabled: bool) -> None async

Sets the status indicator light for the sensor

set_temperature_safe_range(low: float, high: float) -> None async

Sets the temperature safe range for the sensor

set_temperature_settings_public(*, is_enabled: bool | None = None, low_threshold: float | None = None, high_threshold: float | None = None, margin: float | None = None) -> None async

Update temperature alert settings via public API.

set_temperature_status(enabled: bool) -> None async

Sets the temperature detection type for the sensor

set_temperature_status_public(enabled: bool) -> None async

Toggle temperature alerts via public API.

SensorAlarmType

Bases: UnknownValuesEnumMixin, StrEnum

Alarm sound of a sensorAlarm / alarmHub* event (metadata.alarmType.text).

SensorFeatureCapability

Bases: StrEnum

A capability a sensor can advertise in :class:PublicSensorFeatureFlags.

Siren

Bases: PublicDeviceModel

Public API siren device.

is_active: bool property

Whether the siren is currently playing.

The server does not emit a stop event when the siren finishes its timed run, so sirenStatus.isActive in the WS payload stays True until the next update. turn_off_at is only set while the server flag is true and the timing fields are populated, so a clock check against it catches the timed-expiry case. A manual stop clears the server flag and turn_off_at becomes None, falling back to the (now-false) server flag.

play(duration: int | SirenDuration | None = None) -> None async

Play the siren. duration may be a supported integer or :class:SirenDuration; defaults to 5 seconds.

stop() -> None async

Stop an active siren.

test_sound(volume: int | None = None) -> None async

Test the siren sound at the given volume.

SirenConnectionType

Bases: UnknownValuesEnumMixin, StrEnum

Public-API siren wireless connection type (connectionType field).

SirenDuration

Bases: int, Enum

Valid siren play durations in seconds (as accepted by the public API).

Speaker

Bases: PublicDeviceModel

Public API speaker device.

test_sound(volume: int | None = None) -> None async

Test the speaker sound at the given volume.

SpeakerMode

Bases: UnknownValuesEnumMixin, StrEnum

Public-API speaker mode (speakerState.mode field).

SpeakerStatus

Bases: UnknownValuesEnumMixin, StrEnum

Public-API speaker runtime status (speakerState.status field).

UlpUserStatus

Bases: UnknownValuesEnumMixin, StrEnum

Public-API UniFi Identity (ULP) user status (status field).

User

Bases: ProtectModelWithId

groups: list[Group] property

Groups the user is in

Will always be empty if the user only has read only access.

can(model: ModelType, node: PermissionNode, obj: ProtectModelWithId | None = None) -> bool

Checks if a user can do a specific action

VideoMode

Bases: UnknownValuesEnumMixin, StrEnum

Camera video pipeline mode; unknown wire values coerce to UNKNOWN.

Viewer

Bases: ProtectAdoptableDeviceModel

set_liveview(liveview: Liveview) -> None async

Set the liveview for this viewer.

.. deprecated:: Use :meth:ProtectApiClient.update_viewer_public instead; the public-API counterpart is feature-complete for renaming and liveview assignment.

set_liveview_public(liveview_id: str | None) -> None async

Set the viewer liveview via public API. Pass None to clear.

set_name_public(name: str) -> None async

Set viewer name via public API.

WSPacket

Class to handle a unifi protect websocket packet.

channel_id_for_quality(quality: ChannelQuality) -> int | None

Channel id for an RTSPS quality tier (inverse of quality_for_channel_id).

create_from_unifi_dict(data: dict[str, Any], api: ProtectApiClient | None = None, klass: type[ProtectModel] | None = None, model_type: ModelType | None = None) -> ProtectModel

Convert a UFP JSON dict to the correct Python class.

When model_type is provided (e.g. from WS action headers), modelKey will be synthesised if absent (Protect 7+).

Raises DataDecodeError if the model cannot be resolved.

quality_for_channel_id(channel_id: int) -> ChannelQuality | None

RTSPS quality tier for a channel id (0→HIGH, 1→MEDIUM, 2→LOW, 3→PACKAGE).

Enums and Types (uiprotect.data.types)

AlarmHubBatteryStatus

Bases: UnknownValuesEnumMixin, StrEnum

Alarm-hub backup-battery health (alarmHub.battery.batteryStatus field).

AlarmHubConnectionState

Bases: UnknownValuesEnumMixin, StrEnum

Alarm-hub backup-battery wiring state (alarmHub.battery.connection field).

AlarmHubCoverStatus

Bases: UnknownValuesEnumMixin, StrEnum

Alarm-hub tamper-cover status (alarmHub.cover.status field).

AlarmHubInputContactType

Bases: UnknownValuesEnumMixin, StrEnum

Alarm-hub input contact wiring (alarmHub.input[].type field).

AlarmHubInputStatus

Bases: UnknownValuesEnumMixin, StrEnum

Alarm-hub input zone status (alarmHub.input[].status field).

AlarmHubInputType

Bases: UnknownValuesEnumMixin, StrEnum

Alarm-hub input zone kind (alarmHub.input[].inputType field).

AlarmHubOutputStatus

Bases: UnknownValuesEnumMixin, StrEnum

Alarm-hub output channel status (alarmHub.output[].status field).

AssetFileType

Bases: UnknownValuesEnumMixin, StrEnum

Public-API device asset file kind (/v1/files/{fileType}).

ChannelQuality

Bases: UnknownValuesEnumMixin, StrEnum

RTSPS channel quality (qualities field on rtsps-stream endpoints).

DeviceState

Bases: UnknownValuesEnumMixin, StrEnum

Public-API device connection state (state field).

EventButtonType

Bases: UnknownValuesEnumMixin, StrEnum

Button of a sensorButtonPressed / alarmHubButtonPress event.

Sourced from metadata.button.text.

FixSizeOrderedDict

Bases: dict[KT, VT]

A fixed size ordered dict.

__init__(*args: Any, max_size: int = 0, **kwargs: Any) -> None

Create the FixSizeOrderedDict.

__setitem__(key: KT, value: VT) -> None

Set an update up to the max size.

FobAwayState

Bases: UnknownValuesEnumMixin, StrEnum

Key-fob presence/away state (awayState field).

FobButton

Bases: UnknownValuesEnumMixin, StrEnum

Key-fob button kinds (featureFlags.buttons items).

LiveviewCycleMode

Bases: UnknownValuesEnumMixin, StrEnum

Public-API liveview slot cycle mode (slots[].cycleMode field).

ModelType

Bases: UnknownValuesEnumMixin, StrEnum

devices_key() -> str

Return the devices key.

name() -> str

Return the name.

value() -> str

Return the value.

NvrArmModeStatus

Bases: UnknownValuesEnumMixin, StrEnum

Arm-manager status values embedded in the NVR armMode field.

OnOffState

Bases: UnknownValuesEnumMixin, StrEnum

Generic on/off wire state used by several alarm-hub fields.

OsdOverlayLocation

Bases: UnknownValuesEnumMixin, StrEnum

On-screen-display overlay location (osdSettings.overlayLocation).

Carries an UNKNOWN member so values added by newer firmware coerce to UNKNOWN instead of raising during Camera deserialization.

PermissionNode

Bases: UnknownValuesEnumMixin, StrEnum

name() -> str

Return the name.

value() -> str

Return the value.

ProtectWSPayloadFormat

Bases: int, Enum

Websocket Payload formats.

RelayInputActionTrigger

Bases: UnknownValuesEnumMixin, StrEnum

Relay input action trigger condition (inputs[].actionTrigger field).

RelayInputActionType

Bases: UnknownValuesEnumMixin, StrEnum

Relay input action effect (inputs[].actionType field).

RelayInputCircuitState

Bases: UnknownValuesEnumMixin, StrEnum

Relay input circuit state (relayInputChanged metadata.inputState.text).

RelayInputState

Bases: UnknownValuesEnumMixin, StrEnum

State of a single relay input channel.

RelayOutputRebootState

Bases: UnknownValuesEnumMixin, StrEnum

State the relay output is set to after a reboot/power cycle (rebootState field).

RelayOutputState

Bases: UnknownValuesEnumMixin, StrEnum

State of a single relay output channel (state field).

RelayOutputType

Bases: UnknownValuesEnumMixin, StrEnum

Relay output device type (outputs[].type field).

SensorAlarmType

Bases: UnknownValuesEnumMixin, StrEnum

Alarm sound of a sensorAlarm / alarmHub* event (metadata.alarmType.text).

SensorExtremeMetricType

Bases: UnknownValuesEnumMixin, StrEnum

Metric of a sensorExtremeValues event (metadata.sensorType.text).

SirenConnectionType

Bases: UnknownValuesEnumMixin, StrEnum

Public-API siren wireless connection type (connectionType field).

SirenDuration

Bases: int, Enum

Valid siren play durations in seconds (as accepted by the public API).

SmokeTestSource

Bases: UnknownValuesEnumMixin, StrEnum

Origin of a sensorSmokeTest event (flat metadata.source).

SpeakerMode

Bases: UnknownValuesEnumMixin, StrEnum

Public-API speaker mode (speakerState.mode field).

SpeakerStatus

Bases: UnknownValuesEnumMixin, StrEnum

Public-API speaker runtime status (speakerState.status field).

UlpUserStatus

Bases: UnknownValuesEnumMixin, StrEnum

Public-API UniFi Identity (ULP) user status (status field).

VideoMode

Bases: UnknownValuesEnumMixin, StrEnum

Camera video pipeline mode; unknown wire values coerce to UNKNOWN.

get_field_type(annotation: type[Any] | None) -> tuple[type | None, Any] cached

Extract the origin and type from an annotation.

Public Bootstrap (uiprotect.data.public_bootstrap)

UniFi Protect Public Integration API bootstrap.

This is an opt-in, separate cache for the Public Integration API. It is not populated by :meth:ProtectApiClient.update and does not touch the private :class:~uiprotect.data.bootstrap.Bootstrap in any way.

Prime/subscribe ordering is a library guarantee, not a caller obligation: update_public() buffers any public WS frame that arrives while it is priming and replays it onto the fresh snapshot before returning, so a subscriber that is already connected never loses an update to the prime window. Consumers may subscribe and prime in either order:

  • Typed (subscribe_devices / subscribe_events): deliver merged public models, so they require a primed cache and raise RuntimeError if it is missing. Use subscribe_devices_and_prime / subscribe_events_and_prime to subscribe and prime in one call — these connect the websocket before priming so the buffer catches every frame, making the prime-then-subscribe question moot.
  • Raw (subscribe_devices_websocket / subscribe_events_websocket): subscribe in any order relative to update_public(). Frames that land while priming are held and replayed once the snapshot is applied, so they reach subscribers with a merged new_obj instead of being dropped.

WS messages that arrive after priming are merged into the fresh cache normally. An update for an object still not in the cache after a replay is dropped — the cache catches up on the next update_public() / reconnect refresh.

WS messages carry partial diffs for update actions; the cache therefore merges updates into the existing in-memory object instead of reconstructing it from the partial payload. Only add messages are treated as full payloads.

DeviceWSResult dataclass

One expanded per-device outcome of a public devices WS frame.

EventsFrameResult

Bases: NamedTuple

Outputs of applying one public events-WS frame to the cache.

PublicBootstrap dataclass

In-memory cache of the Public Integration API resources.

All device dicts map id -> object. Empty by default; populated by :meth:ProtectApiClient.update_public.

Staleness on websocket reconnect. While the devices/events websocket is connected, incoming add/update/remove messages are merged into the cache. If the websocket drops and reconnects, any messages emitted during the gap are lost. :class:ProtectApiClient automatically schedules an :meth:~ProtectApiClient.update_public refresh on reconnect (the initial connect does not trigger a refresh).

alarm_hubs: dict[str, LinkStation] property

Subset of :attr:link_stations filtered to alarm hubs.

arm_mode: NvrArmMode | None property

Current arm-manager state. Shortcut for nvr.arm_mode.

Returns None when the NVR cache hasn't been primed yet, when the firmware does not expose the alarm manager, or when the alarm manager is set to global.

__post_init__() -> None

Validate cache bounds used by event eviction logic.

apply_fetch_result(attr: str, objs: list[ProtectModelWithId]) -> None

Merge fetched objects into self.<attr> without wholesale replace.

Used by :meth:ProtectApiClient.update_public so that add/ update/remove WS messages arriving concurrently with the HTTP fetch are not clobbered. IDs present in objs overwrite the cache entry; IDs absent from objs but present in the cache are removed.

get(model_type: ModelType, obj_id: str) -> ProtectModelWithId | None

Look up a cached device by model type and id.

get_device_mac(device_id: str) -> str | None

Resolve a device id to its mac across the public device stores.

process_devices_ws_message(api: ProtectApiClient, data: dict[str, Any]) -> tuple[ModelType | None, ProtectModelWithId | None, ProtectModelWithId | None]

Apply a public devices WS payload to the cache.

Back-compat façade over :meth:process_devices_ws_messages: returns the first expanded result's (model_type, new_obj, old_obj) 3-tuple, or (None, None, None) when nothing was produced. Callers that need per-device frames for bulk envelopes should use the plural form.

update messages carry partial diffs — only the changed fields. They are merged into the existing cached object via :meth:ProtectBaseObject.update_from_dict; reconstructing from a partial payload would fail strict validation for required fields.

process_devices_ws_messages(api: ProtectApiClient, data: dict[str, Any]) -> list[DeviceWSResult]

Apply a public devices WS frame to the cache, expanding bulk forms.

The bulk envelopes (devicesAdd / devicesBulkUpdate / devicesBulkRemove) share a single item whose id is a list of ids with one shared modelKey and payload. This fans that out to one :class:DeviceWSResult per id (each carrying a scalar-id item); a single-id frame yields a one-element list. An empty id array yields an empty list.

process_events_ws_message(api: ProtectApiClient, data: dict[str, Any]) -> EventsFrameResult

Apply a public events WS payload to the event cache.

Returns an :class:EventsFrameResult (a tuple-compatible NamedTuple of new_event, old_event, model_updates). new_event / old_event may be None; old_event is a pre-merge snapshot of the cached event taken before this frame is applied — update merges its partial diff into the cached object in place, so without the snapshot old and new would be the same mutated instance. The snapshot lets a consumer detect the open→closed transition (old.end is None and new.end is not None) and reject retransmits idempotently.

model_updates are devices-WS update messages for any camera whose derived detection booleans net-flipped over this frame — the first-class device-model outputs of processing the events frame. The api handler emits them through the standard devices channel with no knowledge that they originated from a detection event.

supports_device(model_type: ModelType) -> bool

Return whether model_type maps to a public device store.

Public Devices (uiprotect.data.public_devices)

UniFi Protect Public API (Integration) data models.

These models represent resources that are exposed only through the Public Integration API. They live in a separate module so that the existing private-API data models (in :mod:uiprotect.data.devices) are not affected and older Protect installations remain unaffected.

Fields the NVR is contractually required to return are modelled as required; only fields that are genuinely optional on the wire (bridge link, battery status on mains-powered devices, siren activation metadata while idle, ...) are Optional.

AlarmHubBattery

Bases: ProtectBaseObject

Backup battery status of an alarm hub (alarmHub.battery sub-schema).

The battery object declares no required array in the OpenAPI spec, and a real hub with the backup battery disconnected emits only connection (omitting charging/voltage/batteryStatus), so every field is optional.

AlarmHubCover

Bases: ProtectBaseObject

Tamper cover status of an alarm hub (alarmHub.cover sub-schema).

The cover object declares no required array in the OpenAPI spec, so both fields are optional.

AlarmHubInput

Bases: ProtectBaseObject

A single alarm-hub input zone (alarmHub.input[<id>] sub-schema).

AlarmHubOutput

Bases: ProtectBaseObject

A single alarm-hub output channel (alarmHub.output[<id>] sub-schema).

ArmProfile

Bases: ProtectBaseObject

Public API arm profile (local alarm manager).

Arm profiles are configuration objects, not devices — the /v1/arm-profiles payload has no modelKey. The class therefore inherits directly from :class:ProtectBaseObject and carries its own id field.

Fob

Bases: PublicDeviceModel

Public API key fob device.

LinkStation

Bases: PublicDeviceModel

Public API link station / alarm hub.

A single wire schema (modelKey: "linkstation") covers both the /v1/link-stations and /v1/alarm-hubs endpoints. The :attr:is_alarm_hub flag distinguishes the two; alarm_hub is only populated when :attr:is_alarm_hub is True.

alarm_hub_armed: OnOffState | None property

Return the typed armed flag, or None when the field is absent.

alarm_hub_battery: AlarmHubBattery | None property

Return the typed backup-battery status, or None when absent.

alarm_hub_cover: AlarmHubCover | None property

Return the typed tamper-cover status, or None when absent.

alarm_hub_inputs: dict[int, AlarmHubInput] property

Return input zones keyed by numeric id; non-integer keys are skipped.

alarm_hub_outputs: dict[int, AlarmHubOutput] property

Return output channels keyed by numeric id; non-integer keys are skipped.

set_name(name: str) -> LinkStation async

Rename via the matching endpoint for the device's role.

trigger_output(output_id: int, *, enable: bool | None = None, delay: int | None = None, duration: int | None = None) -> None async

Trigger an alarm-hub output channel. Raises if this is not an alarm hub.

unifi_dict_conversions() -> dict[str, object | Callable[[Any], Any]] cached classmethod

Parse the lastEvent epoch-ms wire value into datetime.

NvrArmMode

Bases: ProtectBaseObject

Current arm-manager state embedded in the NVR object (armMode field).

Returned by GET /v1/nvrs as part of the NVR payload. All fields that may legitimately be null on the wire are typed as Optional for forward-compatibility.

PublicArmScheduleDict

Bases: TypedDict

Arm-profile schedule entry (write shape). Fields are cron expressions.

PublicBridge

Bases: PublicDeviceModel

Public API bridge device.

ModelType.BRIDGE is already owned by the private :class:Bridge class in MODEL_TO_CLASS; this public counterpart is routed via a dedicated factory on :class:~uiprotect.data.public_bootstrap.PublicBootstrap instead.

PublicCamera

Bases: PublicDeviceModel

Public API camera device (GET /v1/cameras).

hdr_mode_display: Literal['auto', 'off', 'always'] property

HDR mode as shown in the Protect interface (inverse of hdr_type).

is_animal_currently_detected: bool property

Is an animal currently being detected.

is_animal_detection_on: bool property

Is animal smart detection enabled.

is_audio_currently_detected: bool property

Is an audio smart-detect event currently active.

is_baby_cry_currently_detected: bool property

Is a baby cry currently being detected.

is_baby_cry_detection_on: bool property

Is baby cry smart detection enabled.

is_bark_currently_detected: bool property

Is a bark currently being detected.

is_bark_detection_on: bool property

Is bark smart detection enabled.

is_car_alarm_currently_detected: bool property

Is a car alarm currently being detected.

is_car_alarm_detection_on: bool property

Is car alarm smart detection enabled.

is_car_horn_currently_detected: bool property

Is a car horn currently being detected.

is_car_horn_detection_on: bool property

Is car horn smart detection enabled.

is_cmonx_currently_detected: bool property

Is a CO alarm currently being detected.

is_co_detection_on: bool property

Is CO alarm smart detection enabled.

is_face_detection_on: bool property

Is face smart detection enabled.

is_glass_break_currently_detected: bool property

Is glass breaking currently being detected.

is_glass_break_detection_on: bool property

Is glass break smart detection enabled.

is_high_fps_enabled: bool property

Is the camera running in high-FPS video mode.

is_license_plate_detection_on: bool property

Is license plate smart detection enabled.

is_motion_detected: bool property

Is a motion event currently active.

is_package_detection_on: bool property

Is package smart detection enabled.

is_person_currently_detected: bool property

Is a person currently being detected.

is_person_detection_on: bool property

Is person smart detection enabled.

is_siren_currently_detected: bool property

Is a siren currently being detected.

is_siren_detection_on: bool property

Is siren smart detection enabled.

is_smart_currently_detected: bool property

Is a smart-detect event currently active.

is_smoke_currently_detected: bool property

Is a smoke alarm currently being detected.

is_smoke_detection_on: bool property

Is smoke alarm smart detection enabled.

is_speaking_currently_detected: bool property

Is speaking currently being detected.

is_speaking_detection_on: bool property

Is speaking smart detection enabled.

is_vehicle_currently_detected: bool property

Is a vehicle currently being detected.

is_vehicle_detection_on: bool property

Is vehicle smart detection enabled.

hardware_stream_qualities() -> list[ChannelQuality]

Stream qualities the camera hardware supports (not the server's available list).

set_animal_detection(enabled: bool) -> PublicCamera async

Toggle animal smart detection via the public API.

set_baby_cry_detection(enabled: bool) -> PublicCamera async

Toggle baby cry audio detection via the public API.

set_bark_detection(enabled: bool) -> PublicCamera async

Toggle bark audio detection via the public API.

set_burglar_detection(enabled: bool) -> PublicCamera async

Toggle burglar audio detection via the public API.

set_car_horn_detection(enabled: bool) -> PublicCamera async

Toggle car horn audio detection via the public API.

set_co_detection(enabled: bool) -> PublicCamera async

Toggle CO audio detection via the public API.

set_face_detection(enabled: bool) -> PublicCamera async

Toggle face smart detection via the public API.

set_flood_led(enabled: bool) -> PublicCamera async

Set the flood LED via the public API.

set_glass_break_detection(enabled: bool) -> PublicCamera async

Toggle glass break audio detection via the public API.

set_hdr_mode(mode: PublicHdrMode) -> PublicCamera async

Set HDR mode via the public API.

set_lcd_message(text_type: DoorbellMessageType, text: str | None = None, reset_at: datetime | None | DEFAULT_TYPE = DEFAULT) -> PublicCamera async

Set the doorbell LCD message via the public API.

text is required for CUSTOM_MESSAGE and IMAGE and must be omitted otherwise. reset_at controls when the message clears: omit for the NVR default, pass None for "forever", or a specific datetime.

set_license_plate_detection(enabled: bool) -> PublicCamera async

Toggle license plate smart detection via the public API.

set_mic_volume(level: int) -> PublicCamera async

Set microphone volume (1-100) via the public API.

set_osd_date(enabled: bool) -> PublicCamera async

Toggle the date overlay (OSD) via the public API.

Toggle the logo overlay (OSD) via the public API.

set_osd_name(enabled: bool) -> PublicCamera async

Toggle the name overlay (OSD) via the public API.

set_osd_nerd_mode(enabled: bool) -> PublicCamera async

Toggle the bitrate/debug overlay (OSD) via the public API.

set_osd_overlay_location(location: OsdOverlayLocation) -> PublicCamera async

Set the OSD overlay location via the public API.

set_package_detection(enabled: bool) -> PublicCamera async

Toggle package smart detection via the public API.

set_person_detection(enabled: bool) -> PublicCamera async

Toggle person smart detection via the public API.

set_siren_detection(enabled: bool) -> PublicCamera async

Toggle siren audio detection via the public API.

set_smoke_detection(enabled: bool) -> PublicCamera async

Toggle smoke audio detection via the public API.

set_speaking_detection(enabled: bool) -> PublicCamera async

Toggle speaking audio detection via the public API.

set_status_light(enabled: bool) -> PublicCamera async

Set the status LED via the public API.

set_vehicle_detection(enabled: bool) -> PublicCamera async

Toggle vehicle smart detection via the public API.

set_video_mode(mode: VideoMode) -> PublicCamera async

Set the video mode via the public API.

set_welcome_led(enabled: bool) -> PublicCamera async

Set the welcome LED via the public API.

PublicChime

Bases: PublicDeviceModel

Public API chime device (GET /v1/chimes).

set_repeat_times_for_camera(camera_id: str, value: int) -> PublicChime async

Set the ring repeat count for one paired camera via the public API.

set_ring_settings(ring_settings: list[PublicApiChimeRingSettingRequest]) -> PublicChime async

Replace the full per-camera ring settings via the public API.

set_volume_for_camera(camera_id: str, level: int) -> PublicChime async

Set the ring volume for one paired camera via the public API.

PublicDeviceModel

Bases: PublicIdentifiedModel

Shared base for dedicated public device models carrying mac / state.

PublicDoorbellCustomImage

Bases: ProtectBaseObject

A custom doorbell image entry (preview GIF + full sprite PNG).

PublicDoorbellSettings

Bases: ProtectBaseObject

Doorbell settings exposed by the Public Integration API (GET /v1/nvrs).

Intentionally separate from the private :class:~uiprotect.data.nvr.DoorbellSettings which carries additional private-API-only fields (allMessages, typed timedelta, etc.).

All fields have defaults because the doorbellSettings OpenAPI schema declares no required array — fields may be absent on older firmware or in partial WS update diffs.

PublicFile

Bases: ProtectBaseObject

Public API device asset file (/v1/files/{fileType}).

PublicIdentifiedModel

Bases: ProtectModelWithId

Public model carrying the optional device self-description (type / guid).

display_name: str property

Human-facing name, falling back name -> type (no market_name here).

type: str | None property

Alias for device_type mirroring the private tree's type field.

PublicLight

Bases: PublicDeviceModel

Public API light device (GET /v1/lights).

set_duration(duration: timedelta) -> PublicLight async

Set how long the light stays on after motion (15s-900s) via the public API.

set_flood_light(enabled: bool) -> PublicLight async

Force the flood light on/off via the public API.

set_led_level(led_level: int) -> PublicLight async

Set the indicator LED brightness (1-6) via the public API.

set_light_mode(mode: LightModeType, enable_at: LightModeEnableType | None = None) -> PublicLight async

Set the lighting trigger mode (and optional schedule) via the public API.

set_light_settings(mode: LightModeType, enable_at: LightModeEnableType | None = None, duration: timedelta | None = None, sensitivity: int | None = None) -> PublicLight async

Update mode, schedule, duration and PIR sensitivity via the public API.

set_name(name: str) -> PublicLight async

Set the light name via the public API.

set_sensitivity(sensitivity: int) -> PublicLight async

Set PIR motion sensitivity (0-100) via the public API.

set_status_light(enabled: bool) -> PublicLight async

Toggle the status indicator LED via the public API.

PublicLiveview

Bases: ProtectModelWithId

Public API liveview.

owner is a flat userId string (the spec types it as $ref: userId, which is type: string) — not an embedded user object. layout is the number of slots the liveview contains (spec: number, 1..26); the field name matches the wire key exactly.

PublicLiveviewSlot

Bases: ProtectBaseObject

One slot in a public-API liveview (read shape).

PublicLiveviewSlotDict

Bases: TypedDict

Liveview slot (write shape).

PublicNVR

Bases: PublicIdentifiedModel

NVR device as exposed by the Public Integration API (GET /v1/nvrs).

This model reflects the public schema: id, modelKey, name, doorbellSettings, and optionally armMode / mac.

name is nullable — the API schema declares it as oneOf: [string, null].

mac is exposed on GET /v1/nvrs from Protect newer than 7.1 and is None on older firmware that omits the key (and absent from WS partial-update diffs).

doorbell_settings is None on older firmware that does not yet expose the doorbellSettings key, and is absent from WS partial-update diffs (which only require id + modelKey).

arm_mode is None when the firmware does not yet expose the alarm manager (older releases) and also None when the alarm manager is set to global (server returns armMode: null). WS device-update diffs that include armMode are handled automatically by :meth:~uiprotect.data.base.ProtectBaseObject.update_from_dict without any manual extraction.

PublicSensor

Bases: PublicDeviceModel

Public API sensor device (GET /v1/sensors).

has_feature_flags: bool property

Whether a capability map was reported; False means unavailable, not empty.

is_leak_detected: bool property

Whether a leak is detected on either the internal or external channel.

is_tampering_detected: bool property

Whether the tamper switch is currently triggered.

set_alarm(enabled: bool) -> PublicSensor async

Toggle the (audio) alarm detection setting via the public API.

set_arm_profile_ids(arm_profile_ids: list[str]) -> PublicSensor async

Set the arm-profile ids associated with the sensor via the public API.

set_custom_sensitivity_when_armed(enabled: bool) -> PublicSensor async

Toggle custom armed sensitivity via the public API.

set_glass_break_settings(*, is_enabled: bool | None = None, sensitivity: float | None = None, sensitivity_when_armed: float | None = None) -> PublicSensor async

Update glass-break detection settings via the public API.

set_glass_break_status(enabled: bool) -> PublicSensor async

Toggle glass-break detection via the public API.

set_humidity_settings(*, is_enabled: bool | None = None, low_threshold: float | None = None, high_threshold: float | None = None, margin: int | None = None) -> PublicSensor async

Update humidity alert settings via the public API.

set_humidity_status(enabled: bool) -> PublicSensor async

Toggle humidity alerts via the public API.

set_light_settings(*, is_enabled: bool | None = None, low_threshold: float | None = None, high_threshold: float | None = None, margin: int | None = None) -> PublicSensor async

Update light (lux) alert settings via the public API.

set_light_status(enabled: bool) -> PublicSensor async

Toggle light (lux) alerts via the public API.

set_motion_sensitivity(sensitivity: float) -> PublicSensor async

Set motion detection sensitivity via the public API.

set_motion_settings(*, is_enabled: bool | None = None, sensitivity: float | None = None, sensitivity_when_armed: float | None = None) -> PublicSensor async

Update motion detection settings via the public API.

set_motion_status(enabled: bool) -> PublicSensor async

Toggle motion detection via the public API.

set_name(name: str) -> PublicSensor async

Set the sensor name via the public API.

set_schedule_mode(mode: SensorScheduleMode) -> PublicSensor async

Set the arm-schedule mode via the public API.

set_temperature_settings(*, is_enabled: bool | None = None, low_threshold: float | None = None, high_threshold: float | None = None, margin: float | None = None) -> PublicSensor async

Update temperature alert settings via the public API.

set_temperature_status(enabled: bool) -> PublicSensor async

Toggle temperature alerts via the public API.

supports(capability: SensorFeatureCapability) -> bool

Whether the sensor advertises capability (False without a feature map).

PublicSensorFeatureCapability

Bases: ProtectBaseObject

One capability slice; channel_count defaults to 0 when the wire omits it.

PublicSensorFeatureFlags

Bases: ProtectBaseObject

Per-sensor capability map. An absent key means the capability is unsupported.

PublicSirenStatus

Bases: ProtectBaseObject

turn_off_at: datetime | None property

When the siren is expected to stop playing.

Returns None when the siren is idle — either because activated_at / duration are not set, or because is_active is False (e.g. after a manual stop, where the server may leave the timing fields populated). Derived from the websocket payload so no extra API call is needed — HA can compare against datetime.now(UTC) instead of maintaining its own timer.

PublicUlpUser

Bases: ProtectModelWithId

Public API UniFi Identity (ULP) user (read-only).

PublicUser

Bases: ProtectModelWithId

Public API Protect user (read-only).

PublicViewer

Bases: PublicDeviceModel

Public API viewer device.

ModelType.VIEWPORT is already owned by the private :class:Viewer class in MODEL_TO_CLASS; this public counterpart is routed via a dedicated factory on :class:~uiprotect.data.public_bootstrap.PublicBootstrap instead.

The wire field liveview is a flat liveviewId string (nullable); snake-cased to :attr:liveview_id via :meth:_get_unifi_remaps.

RTSPSStreams

Bases: ProtectBaseObject

RTSPS stream URLs for a camera.

get_active_stream_qualities() -> list[str]

Get list of currently active RTSPS stream quality levels (only those with stream URLs).

get_available_stream_qualities() -> list[str]

List available RTSPS quality keys from the server.

Returns raw strings; may include values not in :class:ChannelQuality.

get_inactive_stream_qualities() -> list[str]

Get list of inactive RTSPS stream quality levels (supported but not currently active).

get_stream_url(quality: str, srtp: bool = True) -> str | None

Get stream URL for a quality level; srtp=False strips ?enableSrtp.

Relay

Bases: PublicDeviceModel

Public API relay device.

Use :meth:__getitem__ (relay[output_id]) for "fail loud" lookup or :meth:get_output for the None-returning variant.

__getitem__(output_id: int) -> PublicRelayOutput

Return the output with the given id; raises :class:KeyError if unknown.

activate_output(output_id: int, state: Literal['on', 'off'] | None = None, pulse_duration_ms: int | None = None) -> None async

Activate / toggle a relay output channel.

get_output(output_id: int) -> PublicRelayOutput | None

Return the output with the given id, or None if not found.

SensorFeatureCapability

Bases: StrEnum

A capability a sensor can advertise in :class:PublicSensorFeatureFlags.

Siren

Bases: PublicDeviceModel

Public API siren device.

is_active: bool property

Whether the siren is currently playing.

The server does not emit a stop event when the siren finishes its timed run, so sirenStatus.isActive in the WS payload stays True until the next update. turn_off_at is only set while the server flag is true and the timing fields are populated, so a clock check against it catches the timed-expiry case. A manual stop clears the server flag and turn_off_at becomes None, falling back to the (now-false) server flag.

play(duration: int | SirenDuration | None = None) -> None async

Play the siren. duration may be a supported integer or :class:SirenDuration; defaults to 5 seconds.

stop() -> None async

Stop an active siren.

test_sound(volume: int | None = None) -> None async

Test the siren sound at the given volume.

Speaker

Bases: PublicDeviceModel

Public API speaker device.

test_sound(volume: int | None = None) -> None async

Test the speaker sound at the given volume.

Events (uiprotect.events)

Public events contract for UniFi Protect.

EventChange

Bases: StrEnum

Lifecycle tag for a ProtectEvent dispatch.

ProtectEvent

Bases: BaseModel

Frozen public value type emitted by subscribe_events.

ProtectEventChannel

Bases: StrEnum

High-level grouping for public events.

UlpUserIdentity

Bases: BaseModel

ULP-cached identity attached to a credential event.

UnknownIdentity

Bases: BaseModel

Identity unresolvable from the cached public bootstrap.

Exceptions (uiprotect.exceptions)

ArmedModeError

Bases: BadRequest

Operation not available while the arm alarm is armed.

BadRequest

Bases: ClientError

Invalid request from API Client

ClientError

Bases: UnifiProtectError

Base Class for all other UniFi Protect client errors

DataDecodeError

Bases: UnifiProtectError

Exception raised when trying to decode a UniFi Protect object

GlobalAlarmManagerError

Bases: BadRequest

Operation not available when global alarm manager is enabled.

Invalid

Bases: ClientError

Invalid return from Authorization Request.

NotAuthorized

Bases: PermissionError, BadRequest

Wrong username, password or permission error.

NvrError

Bases: ClientError

Other error.

PublicOnlyModeError

Bases: BadRequest

Private-API operation attempted on a public-only (API-key-only) client.

StreamError

Bases: UnifiProtectError

Exception raised when trying to stream content

UnifiProtectError

Bases: Exception

Base class for all other UniFi Protect errors

WSDecodeError

Bases: UnifiProtectError

Exception raised when decoding Websocket packet

WSEncodeError

Bases: UnifiProtectError

Exception raised when encoding Websocket packet

Stream (uiprotect.stream)

Audio streaming utilities for UniFi Protect cameras using PyAV.

CodecConfig

Bases: NamedTuple

Audio codec configuration for talkback streaming.

Attributes:

Name Type Description
encoder str

PyAV/libav encoder name (e.g., "aac", "libopus").

format str

Output container format (e.g., "adts", "rtp").

TalkbackSession dataclass

Talkback session configuration from the UniFi Protect public API.

Attributes:

Name Type Description
url str

Streaming URL (UDP or RTP, e.g., "rtp://192.168.1.1:7004").

codec str

Audio codec name ("aac", "opus", or "vorbis").

sampling_rate int

Audio sampling rate in Hz.

host: str property

Get hostname from talkback URL.

port: int property

Get port from talkback URL, defaults to 7004.

__post_init__() -> None

Parse URL on initialization.

from_unifi_dict(**data: object) -> TalkbackSession classmethod

Create from UniFi API response.

Parameters:

Name Type Description Default
**data object

Raw API response fields (url, codec, samplingRate).

{}

Returns:

Type Description
TalkbackSession

Configured TalkbackSession instance.

TalkbackStream

Stream audio to a UniFi Protect camera's speaker using PyAV.

This class handles audio transcoding and UDP streaming to camera speakers. It runs the actual streaming in a separate thread to avoid blocking the event loop.

Example
Python
stream = TalkbackStream(camera, "/path/to/audio.wav", session)
await stream.run_until_complete()

is_running: bool property

Check if the stream is currently running.

__aenter__() -> Self async

Start streaming when entering async context.

__aexit__(exc_type: type[BaseException] | None, exc_val: BaseException | None, exc_tb: object) -> None async

Stop streaming when exiting async context.

__init__(camera: Camera, content_url: str, session: TalkbackSession | None = None) -> None

Initialize talkback stream.

Parameters:

Name Type Description Default
camera Camera

Camera device to stream audio to.

required
content_url str

URL or file path of audio source.

required
session TalkbackSession | None

Optional talkback session from public API.

None

Raises:

Type Description
BadRequest

If camera does not have a speaker.

run_until_complete() -> None async

Run the stream until it completes naturally.

start() -> None async

Start the audio stream.

stop() -> None async

Stop the audio stream gracefully and wait for completion.

Utils (uiprotect.utils)

clamp_value(value: float, step_size: float) -> float

Clamps value to multiples of step size.

convert_smart_audio_types(items: Iterable[str]) -> list[SmartDetectAudioType]

Converts list of str into SmartDetectAudioType. Any unknown values will be ignored and logged.

convert_smart_types(items: Iterable[str]) -> list[SmartDetectObjectType]

Converts list of str into SmartDetectObjectType. Any unknown values will be ignored and logged.

convert_to_datetime(source_time: float | str | datetime | None) -> datetime | None cached

Converts timestamp to datetime object

convert_unifi_data(value: Any, field: FieldInfo) -> Any

Converts value from UFP data into pydantic field class

convert_video_modes(items: Iterable[str]) -> list[VideoMode]

Converts list of str into VideoMode. Any unknown values will be ignored and logged.

Decode a token cookie if it is still valid.

format_datetime(dt: datetime | None, default: str | None = None) -> str | None

Formats a datetime object in a consistent format

format_duration(duration: timedelta) -> str

Formats a timedelta as a string.

format_host_for_url(host: IPv4Address | IPv6Address | str) -> str

Format host for URLs. IPv6 addresses are wrapped in brackets.

from_js_time(num: float | str | datetime) -> datetime

Converts Javascript timestamp or ISO-8601 string to Python datetime

get_local_timezone() -> tzinfo

Gets Olson timezone name for localizing datetimes

get_nested_attr(attrs: tuple[str, ...], obj: Any) -> Any

Fetch a nested attribute.

get_nested_attr_as_bool(attrs: tuple[str, ...], obj: Any) -> bool

Fetch a nested attribute as a bool.

get_top_level_attr_as_bool(attr: str, obj: Any) -> Any

Fetch a top level attribute as a bool.

ip_from_host(host: str) -> IPv4Address | IPv6Address async

Resolve hostname to IP address (IPv4 or IPv6).

Raises:

Type Description
ValueError

If host cannot be resolved to IP address

is_debug() -> bool cached

Returns if debug ENV is on (True)

local_datetime(dt: datetime | None = None) -> datetime

Returns datetime in local timezone

make_enabled_getter(ufp_enabled: str) -> Callable[[T], bool]

Return a function to get a value from a Protect device.

make_required_getter(ufp_required_field: str) -> Callable[[T], bool]

Return a function to get a value from a Protect device.

make_value_getter(ufp_value: str) -> Callable[[T], Any]

Return a function to get a value from a Protect device.

normalize_mac(mac: str) -> str cached

Normalize MAC address.

pybool_to_json_bool(value: bool) -> str

Convert a Python bool to a JSON boolean string ('true'/'false').

run_async(callback: Coroutine[Any, Any, T]) -> T

Run async coroutine.

serialize_coord(coord: CoordType) -> int | float

Serializes UFP zone coordinate

serialize_dict(data: dict[str, Any], levels: int = -1) -> dict[str, Any]

Serializes UFP data dict

serialize_list(items: Iterable[Any], levels: int = -1) -> list[Any]

Serializes UFP data list

serialize_point(point: tuple[CoordType, CoordType]) -> list[int | float]

Serializes UFP zone coordinate point

serialize_unifi_obj(value: Any, levels: int = -1) -> Any

Serializes UFP data

set_debug() -> None

Sets ENV variable for UFP_DEBUG to on (True)

set_no_debug() -> None

Sets ENV variable for UFP_DEBUG to off (False)

to_camel_case(name: str) -> str

Converts string to camelCase

to_js_time(dt: datetime | int | None) -> int | None

Python
to_js_time(dt: datetime | int) -> int
Python
to_js_time(dt: None) -> None

Converts Python datetime to Javascript timestamp

to_ms(duration: timedelta | None) -> int | None

Converts python timedelta to Milliseconds

to_snake_case(name: str) -> str cached

Converts string to snake_case

Websocket (uiprotect.websocket)

UniFi Protect Websockets.

Websocket

UniFi Protect Websocket manager.

is_connected: bool property

Return if the websocket connection is open.

__init__(get_url: Callable[[], URL], auth_callback: AuthCallbackType, update_bootstrap: UpdateBootstrapCallbackType, get_session: GetSessionCallbackType, subscription: Callable[[WSMessage], None], state_callback: Callable[[WebsocketState], None], *, timeout: float = 30.0, backoff: int = 10, auth_failed_backoff: int = 120, verify: bool = True, receive_timeout: float | None = None, heartbeat: float | None = None) -> None

Init Websocket.

reset_auth_failure() -> None

Clear the auth-failure backoff and wake the reconnect loop.

Call after installing a fresh credential (e.g. a new API key) so a websocket parked on the long auth_failed_backoff retries at once.

start() -> None

Start the websocket.

stop() -> None

Disconnect the websocket.

wait_closed() -> None async

Wait for the websocket to close.