Skip to content

Manager

System-level services: CoreManager (plugin-to-plugin RPC, FFmpeg, signed requests), DeviceManager (cameras, discovered cameras), DownloadManager (one-shot download tokens).

camera_ui_sdk.manager

CoreManagerEvent

Bases: TypedDict

Core manager event payload.

The host currently publishes one event type, cloudAccountChanged. Subscribe via coreManager.onEvent to react to it.

type instance-attribute

type: str

Event type identifier (e.g. cloudAccountChanged).

data instance-attribute

data: Any

Event-specific data payload. Shape depends on the event type.

AssistantAskImage

Bases: TypedDict

One picture of an assistant request.

AssistantAskRequest

Bases: TypedDict

One completion request to the assistant model the admin assigned to this plugin.

AssistantAskResult

Bases: TypedDict

Answer of CoreManager.assistantAsk: text (and json when a schema was given) or the reason it did not run.

AssistantAccess

Bases: TypedDict

Whether this plugin may use the assistant model, and what the assigned model can do.

SensorHistoryEntry

Bases: TypedDict

One recorded change of one sensor property.

PluginCallOptions

Bases: TypedDict

How the calls of a proxy from CoreManager.connectToPlugin wait for an answer.

timeoutMs instance-attribute

timeoutMs: NotRequired[int]

Timeout of each attempt in milliseconds; omitted or zero keeps the default.

noRetry instance-attribute

noRetry: NotRequired[bool]

Fail a call at once when no process serves the method, instead of retrying for about 3.5 s.

CoreManager

Bases: Protocol

Core manager interface for system-level operations.

Provides access to cross-cutting services like the FFmpeg binary path, server addresses, the cloud server id, inter-plugin lookup, and a stream of core system events.

Accessed via api.coreManager in plugins.

Example
ffmpeg_path = await api.coreManager.getFFmpegPath()
addresses = await api.coreManager.getServerAddresses()


def on_event(e):
    if e["type"] == "cloudAccountChanged":
        print("Cloud account state:", e["data"])


api.coreManager.onEvent.subscribe(on_event)

onEvent property

onEvent: Observable[CoreManagerEvent]

Observable for core manager events (e.g. cloud account changes).

Example
api.coreManager.onEvent.subscribe(lambda e: print(e["type"], e["data"]))

connectToPlugin async

connectToPlugin(pluginName: str, options: PluginCallOptions | None = None) -> BasePlugin | None

Connect to another plugin by name. Proxies are cached per plugin and options and share one connection per plugin.

Parameters:

Name Type Description Default
pluginName str

Name of the plugin to connect to

required
options PluginCallOptions | None

Timeout and retry for the calls of the returned proxy

None

Returns:

Type Description
BasePlugin | None

Plugin instance or None if not found. Cast to specific interface as needed.

Example
clip = await api.coreManager.connectToPlugin("CLIP Plugin", {"noRetry": True})
get_text_embeddings = getattr(clip, "getTextEmbeddings", None)
if get_text_embeddings is not None:
    try:
        embeddings = await get_text_embeddings("a red car")
    except Exception:
        pass  # stopped, or no getTextEmbeddings

assistantAsk async

assistantAsk(request: AssistantAskRequest) -> AssistantAskResult

Ask the assistant model for one completion.

The admin decides under Settings, Assistant which plugins may use the model and which entry they get; the key never reaches the plugin.

Parameters:

Name Type Description Default
request AssistantAskRequest

Prompt, optional system text, pictures and output schema. timeoutMs defaults to 45 s and is capped at 300 s.

required

Returns:

Type Description
AssistantAskResult

The answer, or ok: False with the reason when the plugin is not allowed or the call failed.

Example

answer = await api.coreManager.assistantAsk({ "system": "Answer with one word.", "prompt": "Is there a person in this picture?", "images": [{"data": jpeg, "mimeType": "image/jpeg"}], }) if answer["ok"]: print(answer["text"])

assistantAccess async

assistantAccess() -> AssistantAccess

Check whether this plugin may use the assistant model and what the assigned entry can do.

Subscribe to the assistantModelChanged event to learn about changes while running.

Returns:

Type Description
AssistantAccess

Access flag, model id and picture support.

getFFmpegPath async

getFFmpegPath() -> str

Get the FFmpeg executable path.

Returns:

Type Description
str

Path to FFmpeg binary

getServerAddresses async

getServerAddresses() -> list[str]

Get server addresses (IP addresses the server is listening on). A plugin running on a worker gets the addresses selected for that worker, empty when none are selected.

Returns:

Type Description
list[str]

List of server addresses

getCloudServerId async

getCloudServerId() -> str

Get the cloud server identity this server is registered as.

Returns the cloud server_id from the active cloud pairing, or an empty string when the server is not connected to the cloud.

Returns:

Type Description
str

Cloud server id, or an empty string if not paired

getRestoreGeneration async

getRestoreGeneration() -> str

Get the id of the last restore on this server.

It changes every time a backup is restored or a restore is undone and is empty before the first one. A plugin that keeps credentials for an outside service compares it with the id it saw when storing them: a different one means they came back with a backup and may be outdated.

Returns:

Type Description
str

Restore id, or an empty string before the first restore

getInstanceId async

getInstanceId() -> str

Get the id of this camera.ui installation.

A copy of the server made from a backup gets a new id, while a move or an undone restore keeps it. A plugin that announces itself on the network under a fixed identity compares it with the id it saw before: a different one means it now runs on a copy and must not reuse that identity.

Servers older than 2.4.0 do not know the call and reject it.

Returns:

Type Description
str

Installation id

getPluginsByInterface async

getPluginsByInterface(interfaceName: PluginInterface) -> list[PluginInfo]

Get all installed, enabled plugins that implement a specific interface.

Plugins the admin disabled are excluded. A returned plugin may still be starting up or may have crashed, so a call into one can fail.

Parameters:

Name Type Description Default
interfaceName PluginInterface

Plugin interface name (e.g., 'ClipDetection')

required

Returns:

Type Description
list[PluginInfo]

List of plugin info dicts with id, name, contract

SensorManager

Bases: Protocol

Read access to the host's sensor registry, via api.sensorManager.

Sensors are never created here: a camera's own sensors go through camera.addSensor(), standalone sensors exist only once the user adopted them from a SensorDiscoveryProvider.

getSensorHistory async

getSensorHistory(sensorIds: list[str], start: int, end: int) -> list[SensorHistoryEntry]

Get what a set of sensors did during a window of time.

Returns every recorded change between start and end, and for each property also the value it already had when the window opened, because a door that was open the whole time says as much as one that opened halfway through. Entries come back oldest first.

The history is a short tail, not an archive: it is coalesced to one entry per second and capped per sensor, so a window far in the past may be gone.

Parameters:

Name Type Description Default
sensorIds list[str]

Sensors to read

required
start int

Start of the window, in milliseconds

required
end int

End of the window, in milliseconds

required

Returns:

Type Description
list[SensorHistoryEntry]

Recorded changes, oldest first

Example
changes = await api.sensorManager.getSensorHistory([contact_id], event_start, event_end)
opened = [c for c in changes if c["property"] == "detected" and c["value"] is True]

DeviceManager

Bases: Protocol

Device manager interface for camera operations. Provides methods to push discovered cameras and get camera devices.

Accessed via api.deviceManager in plugins.

Example
# Get a camera by ID or name
camera = await api.deviceManager.getCamera("Front Door")

# Push discovered cameras (for cloud-based discovery)
discovered = await fetch_cameras_from_cloud()
await api.deviceManager.pushDiscoveredCameras(discovered)

pushDiscoveredCameras async

pushDiscoveredCameras(cameras: list[DiscoveredCamera]) -> None

Push discovered cameras to the backend. Use this when cameras are discovered asynchronously (e.g., after cloud login). Cameras become visible in the UI without waiting for the next poll. Only available for CameraController and CameraAndSensorProvider plugins.

Parameters:

Name Type Description Default
cameras list[DiscoveredCamera]

List of discovered cameras to push

required

getCamera async

getCamera(cameraIdOrName: str) -> CameraDevice | None

Get a camera by ID or name.

Parameters:

Name Type Description Default
cameraIdOrName str

Camera ID or name

required

Returns:

Type Description
CameraDevice | None

Camera device or None if not found

DiscoveredCamera

Bases: TypedDict

Discovered camera from a discovery provider.

Represents a camera found during network scanning or cloud lookup that can be adopted into the system. Push these via deviceManager.pushDiscoveredCameras so the user can pick them in the UI without waiting for the next discovery poll.

id instance-attribute

id: str

Unique, stable identifier for this discovered camera (used for deduplication).

name instance-attribute

name: str

Display name shown in the UI adoption list.

manufacturer instance-attribute

manufacturer: NotRequired[str]

Camera manufacturer label (optional).

model instance-attribute

model: NotRequired[str]

Camera model label (optional).

address instance-attribute

address: NotRequired[str]

Network address (IP or hostname) shown in the UI to disambiguate same-model cameras.

DiscoveredSensor

Bases: TypedDict

A sensor a plugin can offer for adoption (see SensorDiscoveryProvider).

id instance-attribute

id: str

The source's stable identity for this sensor, never its address: a Home Assistant entity-registry id, an MQTT unique_id, a vendor device id. It becomes the sensor's nativeId, and a sensor keeps its record, assignments and history for as long as this id stays the same. Using a mutable address (a Home Assistant entity_id) here turns every rename at the source into an orphan plus a new sensor.

address instance-attribute

address: NotRequired[str]

Current address at the source (e.g. a Home Assistant entity id), shown next to the name.

name instance-attribute

name: str

Display name shown in the UI adoption list.

type instance-attribute

type: SensorType

Sensor type the plugin would register the sensor as.

room instance-attribute

room: NotRequired[str]

Room or area label from the source system (optional).

manufacturer instance-attribute

manufacturer: NotRequired[str]

Manufacturer label (optional).

model instance-attribute

model: NotRequired[str]

Model label (optional).

AdoptedSensor

Bases: TypedDict

A sensor the user adopted; what the host hands a SensorDiscoveryProvider to build its runtime sensor from.

id instance-attribute

id: str

Persistent registry id, the sensor's id once bound.

nativeId instance-attribute

nativeId: str

The DiscoveredSensor.id the adoption used.

address instance-attribute

address: NotRequired[str]

Last known address at the source, if any.

name instance-attribute

name: str

Name at adoption time; the user may have renamed the sensor since.

type instance-attribute

type: SensorType

Sensor type the plugin offered it as.

CreateDownloadOptions

Bases: TypedDict

Options for creating a download.

filePath instance-attribute

filePath: str

Absolute path to the file on disk, inside the plugin's storage folder (api.storagePath).

filename instance-attribute

filename: NotRequired[str]

Filename for Content-Disposition header (defaults to basename of filePath).

mimeType instance-attribute

mimeType: NotRequired[str]

MIME type for Content-Type header (defaults to application/octet-stream).

ttlMs instance-attribute

ttlMs: NotRequired[int]

Time-to-live in milliseconds (defaults to 10 minutes).

cleanup instance-attribute

cleanup: NotRequired[Literal['never', 'on-expiry', 'on-download']]

When the file on disk is deleted (registry always expires at TTL).

  • never (default): file persists; caller manages it.
  • on-expiry: deleted at TTL. Can be fetched N times during the window, the right mode for notification images that fan out to multiple devices or recipients.
  • on-download: deleted after first successful download OR on TTL, whichever first. One-shot mode for things like backup exports.

CreateStreamDownloadOptions

Bases: CreateDownloadOptions

Options for creating a streaming download (progressive file tailing).

markerPath instance-attribute

markerPath: str

Path to a marker file that signals export is still in progress, inside the plugin's storage folder.

DownloadToken

Bases: TypedDict

Token returned after registering a download.

token instance-attribute

token: str

Unique download token.

url instance-attribute

url: str

In-app, same-origin URL: /api/download/<token>. Use for callers already authenticated against this server.

publicUrl instance-attribute

publicUrl: str

Externally-reachable, session-less URL the server publishes for out-of-band fetchers (push-notification image attachments, FCM / APNs payloads, share recipients). Shape: <externalUrl>/api/download/<token>, where the token is the auth. Empty string when the server has no external URL configured (LAN-only deployments); fall back to url for in-app callers.

expiresAt instance-attribute

expiresAt: int

Unix timestamp (ms) when the token expires.

DownloadManager

Bases: Protocol

Download manager interface for token-based file downloads.

Plugins register a file and get back a token URL. No JWT is involved, the token itself is the auth.

Accessed via api.downloadManager in plugins.

Example
result = await api.downloadManager.createDownload(
    {
        "filePath": f"{api.storagePath}/export.mp4",
        "filename": "recording.mp4",
        "mimeType": "video/mp4",
        "ttlMs": 600000,
        "cleanup": "on-download",
    }
)
token, url = result["token"], result["url"]

createDownload async

createDownload(options: CreateDownloadOptions) -> DownloadToken

Register a file for download and get a token-based URL.

Parameters:

Name Type Description Default
options CreateDownloadOptions

Download options

required

Returns:

Type Description
DownloadToken

Token, URL, and expiry information

createStreamDownload async

createStreamDownload(options: CreateStreamDownloadOptions) -> DownloadToken

Register a streaming file for progressive download.

The file is tailed during writing; the marker file signals completion.

Parameters:

Name Type Description Default
options CreateStreamDownloadOptions

Streaming download options (includes markerPath)

required

Returns:

Type Description
DownloadToken

Token, URL, and expiry information

deleteDownload async

deleteDownload(token: str) -> None

Remove a download token and optionally delete the file.

Parameters:

Name Type Description Default
token str

The download token to remove

required

NotificationManager

Bases: Protocol

Notification manager interface for publishing notifications into the host.

Plugins call publish to ask the host to fan a Notification out to every installed Notifier-plugin and the in-app UI. The host applies user settings (master toggle, per-source toggle, quiet hours) and the publishing plugin's declared capabilities; calls from plugins without :attr:PluginCapability.PublishNotifications are silently dropped.

Accessed via api.notificationManager in plugins.

Example
await api.notificationManager.publish(
    {
        "title": "Camera offline",
        "body": "Front Door stopped recording",
        "severity": Severity.Warn,
        "deepLink": "/cameras/front-door",
        "data": {"cameraId": "front-door"},
    }
)

publish async

publish(notification: Notification) -> None

Send a notification to the host for fan-out to every installed Notifier-plugin and the in-app UI.

Resolves once the publish was handed to the transport. Downstream delivery is async and failures there never propagate back here.

Parameters:

Name Type Description Default
notification Notification

Notification payload to publish.

required