Plugin API¶
Core plugin lifecycle: BasePlugin, the manifest contract, optional interfaces (discovery, notifier, detection).
camera_ui_sdk.plugin ¶
APIListener
module-attribute
¶
Listener for plugin lifecycle events. Coroutine functions are awaited.
AssistantToolProperty
module-attribute
¶
AssistantToolProperty = AssistantToolStringProperty | AssistantToolNumberProperty | AssistantToolBooleanProperty | AssistantToolArrayProperty | AssistantToolObjectProperty
Property schema of a tool input: the JSON Schema draft-07 subset every supported model provider accepts unchanged.
AssistantModelChunk
module-attribute
¶
AssistantModelChunk = AssistantModelTextChunk | AssistantModelToolCallChunk | AssistantModelUsageChunk | AssistantModelDoneChunk
A piece of the answer: text, a tool call, token counts, or the end.
AssistantModelContent
module-attribute
¶
Part of a message: text or an image.
PROTOCOL_LEVEL
module-attribute
¶
Compatibility level of the plugin surface: the plugin-facing API and the
plugin wire protocol. Bumped only on breaking changes, never for additive
features. The CLI stamps the level a plugin was built against into its
bundle (cameraui.protocolLevel in the bundle package.json); the server
compares that stamp with its own level and refuses to start plugins outside
its supported range.
PythonVersion
module-attribute
¶
Python interpreter major.minor version a Python plugin requires. The host ensures a matching interpreter exists in its venv pool before launching the plugin; Node and Go plugins ignore this field.
PluginInterfaces
module-attribute
¶
PluginInterfaces = MotionDetectionInterface | ObjectDetectionInterface | AudioDetectionInterface | FaceDetectionInterface | LicensePlateDetectionInterface | ClassifierDetectionInterface | ClipDetectionInterface | PersonEmbeddingInterface | SegmentationInterface | DiscoveryProvider | AssistantToolProvider
Union of all optional plugin interfaces.
OAuthStatus
module-attribute
¶
Lifecycle phase of an OAuth provider connection, carried in OAuthState.status.
API_EVENT ¶
Bases: Enum
Lifecycle events emitted on the PluginAPI EventEmitter.
Plugins subscribe with api.on(API_EVENT.X, handler) to react to
host-driven phase changes.
FINISH_LAUNCHING
class-attribute
instance-attribute
¶
Emitted once after every assigned camera is wired up and configureCameras() returned. Start timers and warm-ups here.
SHUTDOWN
class-attribute
instance-attribute
¶
Emitted when the host tears the plugin down. Release files, sockets, timers and child processes now.
PluginAPI ¶
Bases: Protocol
The PluginAPI is injected into the plugin at runtime and exposes the
system services the plugin is allowed to talk to. It also acts as an
EventEmitter for plugin lifecycle events (see :class:API_EVENT).
Example
coreManager
property
¶
System-level operations: the FFmpeg path and the server addresses used for media URLs (HTTP/RTSP).
deviceManager
property
¶
Owns the camera devices assigned to this plugin and publishes camera-state changes.
sensorManager
property
¶
Registers standalone sensors: entities of their own, persisted across restarts, assignable to cameras by the user.
downloadManager
property
¶
Mints token-protected download URLs for files the plugin exposes to the UI (clip exports, snapshots).
notificationManager
property
¶
Publishes notifications to every installed notifier and the in-app UI. Requires :attr:PluginCapability.PublishNotifications.
storagePath
property
¶
Absolute path to the plugin's writable storage directory, created and cleaned up by the host.
on ¶
Subscribe to a lifecycle event. Returns self for chaining.
once ¶
Subscribe to a lifecycle event for one delivery only. Returns self for chaining.
off ¶
Remove a previously registered listener (alias of :meth:removeListener).
removeListener ¶
Remove a previously registered listener.
removeAllListeners ¶
Remove every listener for event, or every listener when no event is given.
AssistantToolArrayProperty ¶
Bases: TypedDict
Array argument of a tool input.
description
instance-attribute
¶
What the argument means, written for the model.
AssistantToolBooleanProperty ¶
AssistantToolContext ¶
Bases: TypedDict
Who is asking and in which language. Passed to every tool call; the host
has already enforced adminOnly and approval, the fields are
information.
language
instance-attribute
¶
BCP 47 language tag of the conversation, for localized text results.
timezone
instance-attribute
¶
IANA time zone of the user, for parsing and formatting times.
threadId
instance-attribute
¶
ID of the conversation the tool is called from. Absent for scheduled runs and MCP clients.
AssistantToolImage ¶
Bases: TypedDict
An image a tool returns alongside its text. Forwarded to the model only
when the instance allows images to leave the machine, so content should
still describe what the image shows.
AssistantToolNumberProperty ¶
Bases: TypedDict
Numeric argument of a tool input.
description
instance-attribute
¶
What the argument means, written for the model.
AssistantToolObjectProperty ¶
AssistantToolProvider ¶
Bases: Protocol
Implemented by plugins that list PluginInterface.AssistantTools in
their contract. The host asks for the tool list once after the plugin is
ready and dispatches calls by name.
Example
class MyPlugin(BasePlugin):
async def assistantTools(self) -> list[AssistantToolSpec]:
return [query_events]
async def callAssistantTool(
self, name: str, input: dict[str, Any], ctx: AssistantToolContext
) -> AssistantToolResult:
if name == "query_events":
return {"content": await self.store.query(input["from"], input["to"])}
return {"error": f"Unknown tool {name}"}
assistantTools
async
¶
List the tools this plugin offers. Called once per plugin start.
Returns:
| Type | Description |
|---|---|
list[AssistantToolSpec]
|
The tool specs, empty when the plugin currently has none. |
callAssistantTool
async
¶
callAssistantTool(name: str, input: dict[str, Any], ctx: AssistantToolContext) -> AssistantToolResult
Run one tool. Validate input against the declared schema, the
host does not.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Tool name as declared in |
required |
input
|
dict[str, Any]
|
Parsed arguments the model produced. |
required |
ctx
|
AssistantToolContext
|
Who is asking and in which language. |
required |
Returns:
| Type | Description |
|---|---|
AssistantToolResult
|
Text, JSON or images for the model, or an |
AssistantToolReference ¶
Bases: TypedDict
Something in the app a tool result points at. The chat renders it as a button that opens the matching view: the recording player for an event, the episode player for an episode, the camera page for a camera, or a download button for a file the download manager serves.
kind
instance-attribute
¶
What the id names.
label
instance-attribute
¶
Short label for the button, for example the camera name and time.
cameraId
instance-attribute
¶
Camera the event belongs to, required for event.
timestamp
instance-attribute
¶
Start of the event or episode in milliseconds since the epoch, required for event.
url
instance-attribute
¶
Download path from the download manager, required for download; the chat shows a download button labelled with label.
AssistantToolResult ¶
Bases: TypedDict
Result of a tool call. Return error for problems the model can repair
by asking differently (unknown camera, empty range); raise only for
failures that should end the run.
content
instance-attribute
¶
Text or JSON the model reads. The host serializes JSON.
images
instance-attribute
¶
Images to show and, when allowed, to send to the model.
references
instance-attribute
¶
Things the chat should offer to open, at most a handful per result.
error
instance-attribute
¶
User-level problem the model may repair. Replaces content.
AssistantToolSchema ¶
Bases: TypedDict
Input schema of a tool: always an object schema. The model fills the
properties, the host passes them to callAssistantTool as parsed JSON.
AssistantToolSpec ¶
Bases: TypedDict
One tool a plugin offers to the assistant. The host prefixes name
with the plugin name, so names only have to be unique within the plugin.
Example
query_events = define_assistant_tool(
{
"name": "query_events",
"description": "List recorded events for a time range, optionally filtered by camera and label.",
"inputSchema": {
"type": "object",
"properties": {
"from": {
"type": "string",
"format": "date-time",
"description": "Start of the range, ISO 8601",
},
"to": {
"type": "string",
"format": "date-time",
"description": "End of the range, ISO 8601",
},
"camera": {"type": "string", "description": "Camera name, all cameras when omitted"},
},
"required": ["from", "to"],
},
}
)
description
instance-attribute
¶
What the tool does and when to use it, written for the model. One or two sentences, name units and defaults.
inputSchema
instance-attribute
¶
Object schema of the arguments (see :class:AssistantToolSchema).
approval
instance-attribute
¶
The user confirms every call before it runs. Set it on anything that changes state.
adminOnly
instance-attribute
¶
Hidden from users without the admin role.
timeoutMs
instance-attribute
¶
Time the host waits for callAssistantTool, in milliseconds. Default 60000.
lazy
instance-attribute
¶
Offered through tool discovery instead of on every turn. Use for rarely needed tools.
AssistantToolStringProperty ¶
AssistantModelContext ¶
AssistantModelDoneChunk ¶
Bases: TypedDict
End of the answer, yielded exactly once.
AssistantModelImage ¶
Bases: TypedDict
Image part of a message. Arrives only for a model whose spec says
vision, and only when the instance allows pictures to reach the model.
AssistantModelMessage ¶
AssistantModelProvider ¶
Bases: Protocol
Implemented by plugins that list PluginInterface.AssistantModels in
their contract. Such a plugin is a bridge to a model the host cannot reach
itself: one without an HTTP API, one behind an unusual authentication, or
one that lives on the machine the plugin runs on. The plugin holds no
conversation state, every request carries the whole conversation.
Example
class ApplePlugin(BasePlugin):
async def assistantModels(self) -> list[AssistantModelSpec]:
return [
{
"id": "apple-on-device",
"name": "Apple on-device",
"contextTokens": 8192,
"vision": True,
"toolCalling": True,
"structuredOutput": True,
}
]
async def assistantGenerate(
self, request: AssistantModelRequest, ctx: AssistantModelContext
) -> AsyncIterator[AssistantModelChunk]:
async for delta in self.session.stream(request, ctx["timeoutMs"]):
yield {"type": "text", "delta": delta}
yield {"type": "done", "finish": "stop"}
assistantModels
async
¶
List the models this plugin offers. Called after the plugin is ready and whenever the settings page is opened.
Returns:
| Type | Description |
|---|---|
list[AssistantModelSpec]
|
The specs, empty while the plugin has no usable model (no hardware, |
list[AssistantModelSpec]
|
no permission yet). |
assistantModelStatus
async
¶
Report whether the models can answer right now. The host asks before it offers them and while the settings page is open, so a model that is still downloading shows up as busy instead of missing. Leave it out when the models are usable as soon as the plugin runs.
Returns:
| Type | Description |
|---|---|
AssistantModelStatus
|
Readiness, with a line and a progress while it loads. |
assistantGenerate ¶
assistantGenerate(request: AssistantModelRequest, ctx: AssistantModelContext) -> AsyncIterator[AssistantModelChunk]
Answer one request. The host reads chunks until done, then either
returns the text to the user or runs the tool calls and asks again with
their results in messages.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
request
|
AssistantModelRequest
|
Conversation, tools and schema for this answer. |
required |
ctx
|
AssistantModelContext
|
Who asks, in which language, and how long the host waits. |
required |
Returns:
| Type | Description |
|---|---|
AsyncIterator[AssistantModelChunk]
|
The answer in pieces. |
AssistantModelRequest ¶
Bases: TypedDict
One request to a plugin model: the conversation so far plus what the model may do with it.
messages
instance-attribute
¶
The conversation, oldest first. The host has already trimmed it to contextTokens.
tools
instance-attribute
¶
Tools the model may call. Empty when the run allows none.
outputSchema
instance-attribute
¶
JSON Schema the answer has to match. Only set for models whose spec says structuredOutput.
maxOutputTokens
instance-attribute
¶
Upper bound for the answer in tokens, when the host has one.
AssistantModelSpec ¶
Bases: TypedDict
One model a plugin offers to the assistant. The user picks it under Settings, Assistant like any other model; the host never sees a key or an endpoint of it.
Example
id
instance-attribute
¶
Model id, unique within the plugin and stable across restarts: the settings store it.
contextTokens
instance-attribute
¶
Hard context limit of the model in tokens. The host plans prompt, tools and history with it.
vision
instance-attribute
¶
The model reads images. Without it the host sends text only.
toolCalling
instance-attribute
¶
The model calls tools. Without it the assistant answers from the conversation alone.
structuredOutput
instance-attribute
¶
The model honors a JSON schema. Without it the host asks for free text and parses defensively.
toolRouting
instance-attribute
¶
The host picks the tools for a question with a short call of its own and puts only those in front of the model. For a small model that calls the tools it sees but does not work through a catalog of fifty.
note
instance-attribute
¶
One line shown next to the model, for example where it runs or what it costs.
AssistantModelStatus ¶
Bases: TypedDict
Whether the plugin can answer right now. A model that has to be
downloaded or loaded first reports ready: False with a line the settings
page shows, and a progress while it knows one.
AssistantModelText ¶
AssistantModelTextChunk ¶
AssistantModelTool ¶
Bases: TypedDict
A tool the model may call in this request.
AssistantModelToolCall ¶
Bases: TypedDict
A tool call: which tool with which arguments.
arguments
instance-attribute
¶
Arguments as parsed JSON, matching the tool's input schema.
AssistantModelToolCallChunk ¶
AssistantModelUsageChunk ¶
PluginCapability ¶
Bases: StrEnum
Permission a plugin requests so it can call a host-provided system feature. Each capability gates one outgoing SDK call. Calls without the matching capability are rejected by the host.
PublishNotifications
class-attribute
instance-attribute
¶
Allows api.notificationManager.publish. Without it the host drops published notifications and logs an error.
PluginContract ¶
Bases: TypedDict
Manifest contract a plugin declares so the host knows what it does and what it needs at load time. Validated before the plugin is started.
name
instance-attribute
¶
Stable, unique identifier: registry key, log prefix and storage namespace.
provides
instance-attribute
¶
Sensor types the plugin produces. Empty for hubs and pure camera-controllers, required for sensor providers.
consumes
instance-attribute
¶
Sensor types the plugin reads from other plugins (e.g. a face plugin consuming camera video frames).
interfaces
instance-attribute
¶
Capability flags the plugin implements (see :class:PluginInterface).
capabilities
instance-attribute
¶
Permissions the plugin requests to call host system features (see :class:PluginCapability).
pythonVersion
instance-attribute
¶
Required Python interpreter version for Python plugins. Ignored by Node and Go plugins.
dependencies
instance-attribute
¶
Extra dependencies installed into the plugin's runtime (Go module paths, PyPI or npm names).
PluginInfo ¶
Bases: TypedDict
Lightweight handle identifying an installed plugin, used in RPC payloads and managers to refer to the plugin without shipping its full state.
running
instance-attribute
¶
True while the plugin's process is started; set by getPluginsByInterface.
PluginInterface ¶
Bases: StrEnum
Capability flags a plugin advertises in its contract.
The host uses these to decide which RPC handlers to wire up and which UI affordances to show.
MotionDetection
class-attribute
instance-attribute
¶
Implements MotionDetectionInterface (video-based motion detection).
ObjectDetection
class-attribute
instance-attribute
¶
Implements ObjectDetectionInterface (e.g. person, vehicle, animal).
AudioDetection
class-attribute
instance-attribute
¶
Implements AudioDetectionInterface (event/keyword audio detection).
FaceDetection
class-attribute
instance-attribute
¶
Implements FaceDetectionInterface (face localisation + embeddings). Matching against enrolled faces happens in the NVR.
LicensePlateDetection
class-attribute
instance-attribute
¶
Implements LicensePlateDetectionInterface (plate localisation + OCR).
ClassifierDetection
class-attribute
instance-attribute
¶
Implements ClassifierDetectionInterface (generic image classification emitting attribute/label pairs).
ClipDetection
class-attribute
instance-attribute
¶
Implements ClipDetectionInterface (CLIP image and text embeddings used for semantic search).
FaceEmbedding
class-attribute
instance-attribute
¶
Implements FaceEmbeddingInterface (turns a face crop into a vector). Matching against enrolled faces happens in the NVR.
PersonEmbedding
class-attribute
instance-attribute
¶
Implements PersonEmbeddingInterface (turns the crop of a person into a vector of their appearance). Searching happens in the NVR.
Segmentation
class-attribute
instance-attribute
¶
Implements SegmentationInterface (outlines the object at a box in a picture).
DiscoveryProvider
class-attribute
instance-attribute
¶
Implements DiscoveryProvider (network scan + adoption). Only valid for camera-controlling roles.
SensorDiscovery
class-attribute
instance-attribute
¶
Implements SensorDiscoveryProvider (external sensor inventory the user adopts from).
NVR
class-attribute
instance-attribute
¶
Implements NVRInterface (events and recordings). Exactly one plugin per host fills this role at runtime.
Notifier
class-attribute
instance-attribute
¶
Implements NotifierInterface, so the NotificationManager can dispatch notifications to this plugin.
OAuthCapable
class-attribute
instance-attribute
¶
Implements the OAuthCapable base interface plus at least one of the flow sub-interfaces below.
OAuthDeviceFlow
class-attribute
instance-attribute
¶
Implements OAuthDeviceFlowCapable (RFC 8628 Device Authorization Grant).
OAuthAuthCodeFlow
class-attribute
instance-attribute
¶
Implements OAuthAuthCodeFlowCapable (Authorization Code Flow + PKCE).
OAuthClientCredentials
class-attribute
instance-attribute
¶
Implements OAuthClientCredentialsCapable (user-supplied client_id + client_secret).
AssistantTools
class-attribute
instance-attribute
¶
Implements AssistantToolProvider, so the assistant can offer the plugin's tools to the model.
AssistantModels
class-attribute
instance-attribute
¶
Implements AssistantModelProvider, so its models appear in the assistant settings.
PluginRole ¶
Bases: StrEnum
Role a plugin plays in the system. The role decides which lifecycle hooks the host invokes and which contract validations apply.
Hub
class-attribute
instance-attribute
¶
Cross-camera aggregator (smart-home bridge, recorder). Owns no cameras and provides no sensors.
SensorProvider
class-attribute
instance-attribute
¶
Adds sensors to cameras owned by other plugins, for example a detector running on foreign video frames.
CameraController
class-attribute
instance-attribute
¶
Manages cameras and their media streams: stream URLs, PTZ, snapshots. Provides no sensors for foreign cameras.
CameraAndSensorProvider
class-attribute
instance-attribute
¶
Manages cameras and exposes sensors, on its own cameras and, with consumes set, on foreign ones.
Service
class-attribute
instance-attribute
¶
Serves camera.ui itself, for example with a language model. Touches no cameras and no sensors, and is never assigned to one.
AudioDetectionInterface ¶
Bases: Protocol
Implemented by plugins that perform audio event or keyword detection.
testAudioDetection
async
¶
testAudioDetection(audio_data: bytes, metadata: AudioMetadata, config: dict[str, Any]) -> AudioDetectionPluginResponse | None
Run detection on an audio buffer captured by the UI test panel; metadata carries the input MIME type.
detectAudio
async
¶
detectAudio(audio: AudioFrameData, config: dict[str, Any] | None = None) -> AudioDetectionPluginResponse | None
Run detection on a pre-decoded audio frame. Called from automation / benchmark pipelines.
audioDetectionSettings
async
¶
Return the JSON schema used to render the audio-detection settings form in the UI, or None for no schema.
AudioDetectionPluginResponse ¶
Bases: TypedDict
Result of an audio detection run.
AudioMetadata ¶
Bases: TypedDict
Audio metadata passed to audio detector test methods.
mimeType
instance-attribute
¶
Container format of the audio buffer.
BasePlugin ¶
Bases: ABC, Generic[StorageT]
Base class every plugin extends.
It wires up the three dependencies the host injects (logger, PluginAPI, DeviceStorage) and declares the lifecycle methods the host calls on the plugin.
The host calls :meth:configureCameras once at startup with every camera
already assigned to this plugin, then :meth:onCameraAdded /
:meth:onCameraReleased as the user adds or removes cameras at runtime.
StorageT types storage.values so plugin code gets autocompletion
for its own settings shape.
Example
class MyPlugin(BasePlugin[MyStorageValues]):
async def configureCameras(self, cameras: list[CameraDevice]) -> None:
self.model_path = self.storage.values.get("model_path")
for camera in cameras:
await self.onCameraAdded(camera)
async def onCameraAdded(self, camera: CameraDevice) -> None:
self.state[camera.id] = await self.attach(camera)
async def onCameraReleased(self, camera_id: str) -> None:
self.state.pop(camera_id, None)
storage_schema
property
¶
Override to register a JSON schema for the plugin-level settings form rendered in the UI. Default: no schema.
configureCameras
abstractmethod
async
¶
Called once on startup with every camera already assigned to this plugin. Attach handlers, open vendor sessions, warm up models here. Raising aborts plugin startup.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
cameras
|
list[CameraDevice]
|
Cameras already assigned to this plugin. |
required |
onCameraAdded
abstractmethod
async
¶
Called whenever a camera is assigned to this plugin at runtime,
after a discovery adoption (:meth:DiscoveryProvider.onAdoptCamera)
or after the user re-assigns an existing camera. Set up the same
per-camera state as in :meth:configureCameras.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
camera
|
CameraDevice
|
The camera device that was added. |
required |
onCameraReleased
abstractmethod
async
¶
Called when a camera is unassigned from this plugin or deleted from the system. Release per-camera resources (sessions, timers, decoders) before returning.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
cameraId
|
str
|
ID of the camera that was released. |
required |
configureSensors
async
¶
Called once on startup with every sensor this plugin may consume:
sensors whose type is listed in contract.consumes and that are
exposed. Each sensor carries type, assignedCameraIds and
connected, so consumers decide rendering purely from that data.
Optional, only bridge plugins override it.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
sensors
|
list[SensorLike]
|
Consumable sensors known at startup. |
required |
onSensorAdded
async
¶
Called when a sensor enters this plugin's consumable view at runtime: it was created, became exposed, or its type became consumable.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
sensor
|
SensorLike
|
The sensor that appeared. |
required |
onSensorReleased
async
¶
Called when a sensor permanently leaves the consumable view: it
was deleted or unexposed. Plugin connectivity does NOT fire this,
watch sensor.onConnectedChanged for that.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
sensorId
|
str
|
Persistent id of the sensor that left. |
required |
ClassifierDetectionInterface ¶
Bases: Protocol
Implemented by plugins that run a generic image classifier and emit attribute/label pairs (e.g. weather, scene, activity).
testClassifierDetection
async
¶
testClassifierDetection(image_data: bytes, metadata: ImageMetadata, config: dict[str, Any]) -> ClassifierDetectionPluginResponse | None
Run classification on a single image captured by the UI test panel and return the result for preview rendering.
detectClassifications
async
¶
detectClassifications(frame: VideoFrameData, config: dict[str, Any] | None = None) -> ClassifierDetectionPluginResponse | None
Run classification on a pre-decoded video frame.
classifierDetectionSettings
async
¶
Return the JSON schema for the classifier-detection settings form in the UI, or None for no schema.
ClassifierDetectionPluginResponse ¶
ClipDetectionInterface ¶
Bases: Protocol
Implemented by plugins that generate CLIP image and text embeddings used for semantic search over recorded events.
testClipEmbedding
async
¶
testClipEmbedding(image_data: bytes, metadata: ImageMetadata, config: dict[str, Any]) -> ClipDetectionPluginResponse | None
Run the CLIP image branch on a single image captured by the UI test panel.
detectClipEmbedding
async
¶
detectClipEmbedding(frame: VideoFrameData, config: dict[str, Any] | None = None) -> ClipDetectionPluginResponse | None
Run the CLIP image branch on a pre-decoded video frame.
embedImages
async
¶
embedImages(images: list[bytes], config: dict[str, Any] | None = None) -> list[ClipDetectionPluginResponse | None]
Run the CLIP image branch over a batch of encoded images (JPEG/PNG).
One result per input in the same order, None where decoding or embedding failed. Meant for re-indexing stored images after an embedding-model change.
getTextEmbedding
async
¶
Run the CLIP text branch and return a vector usable for semantic-search queries against stored image embeddings.
getTextEmbeddings
async
¶
Run the CLIP text branch once per embedding space the plugin can currently serve.
The configured search model comes first. Lets semantic search also cover embeddings produced by an older model during a transition.
clipSettings
async
¶
Return the JSON schema for the CLIP settings form in the UI, or None for no schema.
ClipDetectionPluginResponse ¶
Bases: TypedDict
Result of a CLIP image embedding run.
embeddings
instance-attribute
¶
Embedding vectors generated for the input.
embeddingModel
instance-attribute
¶
Model that produced the embeddings; consumers must not mix models.
scoreBand
instance-attribute
¶
[floor, ceiling] of raw text-image cosine scores for this model; consumers map scores to a 0..1 relevance scale and treat a missing band as score 0.
ClipTextEmbeddingResult ¶
Bases: TypedDict
Result of a CLIP text embedding request.
DiscoveryProvider ¶
Bases: Protocol
Implemented by plugins that can scan the network for new cameras and adopt them. Only plugins with a camera-controlling role (CameraController or CameraAndSensorProvider) are queried for discovery.
onDiscoverCameras
async
¶
Scan the network and return the cameras the plugin can offer for adoption. Called by the host on demand (UI rescan button) or on a polling schedule.
Returns:
| Type | Description |
|---|---|
list[DiscoveredCamera]
|
Cameras currently discoverable by this plugin. |
onGetCameraSettings
async
¶
Return a JSON schema describing the form fields (credentials, transport options, ...) the user must fill in to adopt this discovered camera.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
camera
|
DiscoveredCamera
|
The discovered camera the user is about to adopt. |
required |
Returns:
| Type | Description |
|---|---|
list[JsonSchemaWithoutCallbacks]
|
Schema for the adoption form. |
onAdoptCamera
async
¶
Probe the device with the user-provided settings and return the
camera configuration the host should persist. The host then creates
the camera and invokes :meth:BasePlugin.onCameraAdded on the plugin.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
camera
|
DiscoveredCamera
|
The discovered camera being adopted. |
required |
cameraSettings
|
dict[str, object]
|
Values entered into the adoption form. |
required |
Returns:
| Type | Description |
|---|---|
CameraConfig
|
Final camera configuration for the host to persist. |
FaceDetectionInterface ¶
Bases: Protocol
Implemented by plugins that locate faces and emit per-face embeddings. The NVR owns matching against enrolled faces, the plugin only emits raw detections and embeddings.
testFaceDetection
async
¶
testFaceDetection(image_data: bytes, metadata: ImageMetadata, config: dict[str, Any]) -> FaceDetectionPluginResponse | None
Run face detection on a single image captured by the UI test panel and return the result for preview rendering.
A number in config["threshold"] is the lowest confidence to return, without it the plugin's default applies.
detectFaces
async
¶
detectFaces(frame: VideoFrameData, config: dict[str, Any] | None = None) -> FaceDetectionPluginResponse | None
Run face detection on a pre-decoded video frame.
faceDetectionSettings
async
¶
Return the JSON schema for the face-detection settings form in the UI, or None for no schema.
FaceDetectionPluginResponse ¶
FaceEmbeddingInterface ¶
Bases: Protocol
Implemented by plugins that turn a face crop into an embedding vector.
Split from face detection so the two can run on different hosts: locating a face is cheap, embedding it is not.
embedFaceImages
async
¶
embedFaceImages(images: list[bytes], config: dict[str, Any] | None = None, landmarks: list[list[Point] | None] | None = None) -> list[FaceEmbeddingPluginResponse | None]
Embed a batch of encoded images (JPEG/PNG), each showing one face.
One result per input in the same order. An empty embedding means the
picture holds no face this model can use, None that the plugin could not run
at all: the caller may drop such a picture, so the two must not be mixed up.
Meant for re-embedding stored pictures after an embedding-model change.
landmarks holds the points an earlier result returned for the same picture,
one entry per image: with them the face is not searched again.
faceEmbeddingSettings
async
¶
Return the JSON schema for the face-embedding settings form in the UI, or None for no schema.
FaceEmbeddingPluginResponse ¶
Bases: TypedDict
Result of a face embedding run on a single image.
embedding
instance-attribute
¶
Embedding vector for the face, empty when no face could be embedded.
embeddingModel
instance-attribute
¶
Model that produced the embedding; consumers must not mix models.
landmarks
instance-attribute
¶
The five points the face was aligned on, in 0 - 1 of the input image: right eye, left eye, nose, right and left mouth corner.
quality
instance-attribute
¶
How sure the model is that those points sit on a face (0 - 1).
ImageMetadata ¶
LicensePlateDetectionInterface ¶
Bases: Protocol
Implemented by plugins that locate license plates and run OCR on them.
testLicensePlateDetection
async
¶
testLicensePlateDetection(image_data: bytes, metadata: ImageMetadata, config: dict[str, Any]) -> LicensePlateDetectionPluginResponse | None
Run detection on a single image captured by the UI test panel and return the result for preview rendering.
A number in config["threshold"] is the lowest confidence to return, without it the plugin's default applies.
detectLicensePlates
async
¶
detectLicensePlates(frame: VideoFrameData, config: dict[str, Any] | None = None) -> LicensePlateDetectionPluginResponse | None
Run detection on a pre-decoded video frame.
licensePlateDetectionSettings
async
¶
Return the JSON schema for the license-plate-detection settings form in the UI, or None for no schema.
LicensePlateDetectionPluginResponse ¶
MotionDetectionInterface ¶
Bases: Protocol
Implemented by plugins that perform video-based motion detection. The
host invokes :meth:testMotionDetection from the UI test panel and
:meth:detectMotion from automation / benchmark pipelines.
testMotionDetection
async
¶
testMotionDetection(video_data: bytes, config: dict[str, Any]) -> MotionDetectionPluginResponse | None
Run detection on a raw video buffer captured by the UI test panel and return the result for preview rendering.
detectMotion
async
¶
detectMotion(frames: list[VideoFrameData], config: dict[str, Any] | None = None) -> MotionDetectionPluginResponse | None
Run detection on already-decoded frames, supplied by automation / benchmark pipelines to avoid re-encoding.
motionDetectionSettings
async
¶
Return the JSON schema used to render the motion-detection settings form in the UI, or None for no schema.
MotionDetectionPluginResponse ¶
Bases: TypedDict
Result of a motion detection run.
videoData
instance-attribute
¶
Annotated re-encoded clip for the UI test panel, when the plugin renders one.
ObjectDetectionInterface ¶
Bases: Protocol
Implemented by plugins that perform object detection (person, vehicle, animal, ...).
testObjectDetection
async
¶
testObjectDetection(image_data: bytes, metadata: ImageMetadata, config: dict[str, Any]) -> ObjectDetectionPluginResponse | None
Run detection on a single image captured by the UI test panel; metadata carries the image dimensions.
A number in config["threshold"] is the lowest confidence to return, without it the plugin's default applies.
detectObjects
async
¶
detectObjects(frame: VideoFrameData, config: dict[str, Any] | None = None) -> ObjectDetectionPluginResponse | None
Run detection on a pre-decoded video frame. Called from automation / benchmark pipelines.
objectDetectionSettings
async
¶
Return the JSON schema used to render the object-detection settings form in the UI, or None for no schema.
ObjectDetectionPluginResponse ¶
PersonEmbeddingInterface ¶
Bases: Protocol
Implemented by plugins that turn the crop of a person into a vector of their appearance.
The NVR stores and searches the vectors, the plugin only emits them.
embedPersonImages
async
¶
embedPersonImages(images: list[bytes], config: dict[str, Any] | None = None) -> list[PersonEmbeddingPluginResponse | None]
Embed a batch of encoded images (JPEG/PNG), each showing one person cut tight around their box.
One result per input in the same order. An empty embedding means the
picture could not be used, None that the plugin could not run at all. Meant for
searching by a picture the user picked.
personEmbeddingSettings
async
¶
Return the JSON schema for the person-embedding settings form in the UI, or None for no schema.
PersonEmbeddingPluginResponse ¶
Bases: TypedDict
Result of a person embedding run on a single image.
SegmentationImage ¶
SegmentationInterface ¶
Bases: Protocol
Implemented by plugins that outline objects: a mask that separates an object from its background.
The frame-based side is the segmenter sensor.
segmentImages
async
¶
segmentImages(images: list[SegmentationImage], config: dict[str, Any] | None = None) -> list[SegmentationPluginResponse | None]
Outline the object at box in each picture.
One result per input in the same order, None when the plugin could not run
at all. config holds the values of the segmentation settings form.
segmentationSettings
async
¶
Return the JSON schema for the segmentation settings form in the UI, or None for no schema.
SegmentationPluginResponse ¶
Bases: TypedDict
Result of a segmentation run on a single image.
mask
instance-attribute
¶
The object's outline, missing when the model found no object at the box.
SensorDiscoveryProvider ¶
Bases: Protocol
Implemented by sensor-providing plugins that face an external inventory
(Home Assistant entities, vendor accessories) the user picks from instead
of the plugin importing everything. Declare PluginInterface.SensorDiscovery
in the contract.
The host owns the adoption: it lists what the plugin discovers, creates the sensor record when the user adopts, hands the plugin its adopted sensors on every start and tells it when the user deletes one. The plugin keeps no list of its own.
Identity is the source's stable id (DiscoveredSensor.id), never an
address; the same id means the same sensor across restarts and renames.
onDiscoverSensors
async
¶
Return every sensor the source currently offers. The host drops the ones already adopted, the plugin does not filter. Called on demand (Sensors page, rescan) and on a polling schedule while the page is open.
Returns:
| Type | Description |
|---|---|
list[DiscoveredSensor]
|
Sensors currently discoverable by this plugin. |
configureAdoptedSensors
async
¶
Called once at startup, right after configureCameras(), with every
sensor the user adopted from this plugin. Build and return one runtime
sensor per record, always, from the record's type and name alone; the
host binds each returned sensor to its record by nativeId. Report
what the source looks like on the sensor itself (setSourceState,
setAddress) as soon as you know: a record the source no longer has
gets setSourceState("removed"), it is never dropped here.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
sensors
|
list[AdoptedSensor]
|
The adopted sensors of this plugin. |
required |
Returns:
| Type | Description |
|---|---|
list[Sensor[Any, Any, Any]]
|
One runtime sensor per adopted record. |
onSensorAdopted
async
¶
The user adopted a discovered sensor and the host created its record.
Build and return the runtime sensor for it, same as one entry of
configureAdoptedSensors().
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
sensor
|
AdoptedSensor
|
The adopted sensor. |
required |
Returns:
| Type | Description |
|---|---|
Sensor[Any, Any, Any]
|
The runtime sensor to bind to the record. |
onSensorUnadopted
async
¶
The user deleted an adopted sensor. The host has already unbound the runtime sensor; drop whatever the plugin still holds for it. The entity shows up as discovered again on the next scan.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
nativeId
|
str
|
The |
required |
ServicePlugin ¶
Bases: BasePlugin[StorageT]
Base class for a plugin with the role :attr:PluginRole.Service: it
serves camera.ui itself and never touches cameras, so the camera lifecycle
hooks are already implemented as no-ops.
Example
Notification ¶
Bases: TypedDict
Payload published via api.notificationManager.publish or routed by
the host. Plugins fill the user-visible fields; the host stamps the
message id, timestamp and source identifier on receive.
subtitle
instance-attribute
¶
Optional second bold line, honoured natively on iOS; other notifiers may fold it into the body.
severity
instance-attribute
¶
Drives DND / Critical-Alerts behaviour and Quiet-Hours bypass. Defaults to :attr:Severity.Info.
tag
instance-attribute
¶
Collapse-key (e.g. motion:cam-1). The host replaces an older entry
with the same tag in the in-app list. Delivery is not throttled: every
publish is sent. Notifiers may map it to a platform collapse-id.
thumbnail
instance-attribute
¶
Optional inline JPEG attached to the notification.
imageUrl
instance-attribute
¶
Publicly-fetchable URL to a rich image (e.g. a detection snapshot).
Preferred over inline thumbnail bytes when a URL is available; empty
renders text-only.
videoUrl
instance-attribute
¶
Publicly-fetchable URL to a short MP4 clip. Notifiers that can render
video (iOS attachments) prefer it over imageUrl; everything else
ignores it, so always send the image alongside. Keep clips small: the
receiving phone downloads inside a tight OS budget.
deepLink
instance-attribute
¶
Router-relative path for mobile / web tap-handlers (e.g. /cameras/cam-1). No host, no scheme.
data
instance-attribute
¶
Plugin-specific context (cameraId, eventId, plugin-defined keys), string values only.
adminOnly
instance-attribute
¶
Restricts delivery to users with the master or admin role. Use it for
operational alerts (camera offline, disk full, plugin failures) so they
don't reach guests the instance is merely shared with. Defaults to
False.
silent
instance-attribute
¶
Delivers without sound, vibration or badge increment: meant for publishes
that replace an earlier notification with the same tag (e.g. a richer
description superseding the initial alert). The banner still updates.
Ignored when severity is :attr:Severity.Critical. Defaults to
False.
NotifierDevice ¶
Bases: TypedDict
A push-target managed by a notifier plugin (one phone, one chat, ...).
Devices are owned by the plugin that registered them; the manager queries plugins for their device list rather than maintaining a shared registry.
NotifierInterface ¶
Bases: Protocol
Implemented by plugins that deliver notifications.
The NotificationManager invokes these methods over RPC. Plugins own their device storage, the manager never persists devices itself.
get_devices
async
¶
Return the devices this notifier knows for the given users, each
carrying its ownerUserId. Return [] when the notifier is
unavailable (e.g. invalid license). Called often, keep it cheap.
get_device
async
¶
Return a single device by id, or None if not found.
send_notification
async
¶
Deliver a notification to the given devices in one call. Errors are logged, a failing notifier never aborts the fan-out.
register_device
async
¶
Create a new device. input is plugin-specific JSON the manager forwards opaquely.
revoke_device
async
¶
Permanently remove a device. Called when the user revokes it through their notifier-specific UI.
update_device
async
¶
Mutate name / active on an existing device. Return None if the id isn't ours so the manager can probe the next plugin.
notificationSettings
async
¶
Return the JSON schema used to render the notifier's settings form in the UI, or None for no schema.
Severity ¶
Bases: StrEnum
Classifies how urgent a Notification is.
Notifiers map this to platform-specific delivery characteristics; the
host bypasses user-configured Quiet Hours for Critical.
Info
class-attribute
instance-attribute
¶
Standard notification, default delivery (sound + banner).
Warn
class-attribute
instance-attribute
¶
Heightened attention; notifiers may use a different sound or colour.
Critical
class-attribute
instance-attribute
¶
Highest-priority delivery on supporting notifiers; bypasses Quiet Hours.
OAuthAuthCodeFlowCapable ¶
Bases: OAuthCapable, Protocol
Implemented by plugins that use the Authorization Code Flow with PKCE.
The host opens the auth URL and forwards the IdP redirect's code+state to
completeAuthCodeFlow.
OAuthCapable ¶
Bases: Protocol
Base interface every OAuth-capable plugin implements, alongside at least one flow sub-interface. IdP-agnostic: the plugin brings its own endpoint config and knows nothing about the host's internals.
getOAuthMetadata
async
¶
Return IdP display info, scope descriptions and the implemented flow sub-interfaces.
getOAuthState
async
¶
Return a snapshot of the current lifecycle state; the host polls this to mirror progress.
disconnect
async
¶
Revoke the current grant at the IdP and clear stored tokens.
OAuthClientCredentialsCapable ¶
Bases: OAuthCapable, Protocol
Implemented by plugins that authenticate with a user-supplied client_id + client_secret (no user redirect). The plugin validates by fetching a token immediately.
configureClientCredentials
async
¶
Store the supplied credentials and fetch an initial token to validate them.
OAuthDeviceFlowCapable ¶
Bases: OAuthCapable, Protocol
Implemented by plugins whose IdP supports the RFC 8628 Device
Authorization Grant. The plugin polls the IdP internally; the host only
polls getOAuthState to mirror progress.
OAuthMetadata ¶
Bases: TypedDict
Informational data the host renders in the connect dialog.
idpDisplayName
instance-attribute
¶
Human name of the identity provider, e.g. cameraui.com, Spotify.
scopeDescriptions
instance-attribute
¶
Maps each scope to a human-readable description.
supportedFlows
instance-attribute
¶
Flow sub-interfaces the plugin implements, so the host knows which affordance to render.
OAuthProviderConfig ¶
Bases: TypedDict
Points the plugin's OAuth manager at an identity provider.
preset
instance-attribute
¶
Built-in IdP endpoint set, e.g. cameraui.com. When unset, the explicit endpoints are used.
deviceAuthUrl
instance-attribute
¶
Device-authorization endpoint (used when preset is unset).
authUrl
instance-attribute
¶
Authorization endpoint (used when preset is unset).
tokenUrl
instance-attribute
¶
Token endpoint (used when preset is unset).
revokeUrl
instance-attribute
¶
Revocation endpoint (used when preset is unset).
OAuthProviderDeclaration ¶
Bases: TypedDict
One provider a plugin integrates with. A single-provider plugin declares exactly one.
OAuthState ¶
Bases: TypedDict
Snapshot of a provider connection's lifecycle. Lives in the plugin and
is the source of truth for both the host UI and downstream plugin code
that needs a token. The host polls it via getOAuthState while a flow
runs.
userCode
instance-attribute
¶
Device-flow user code shown to the user (set while awaiting_user).
verificationUri
instance-attribute
¶
Device-flow verification URI the user opens (set while awaiting_user).
verificationUriComplete
instance-attribute
¶
Verification URI with the user code embedded, rendered as a QR code.
authUrl
instance-attribute
¶
Authorization-code-flow URL the browser must open (set while awaiting_user).
userEmail
instance-attribute
¶
Connected account email (set while connected).
connectedAt
instance-attribute
¶
Unix timestamp the grant was established (set while connected).
scopesGranted
instance-attribute
¶
Scopes granted by the IdP (set while connected).
errorCode
instance-attribute
¶
OAuth error code (set while error): access_denied | expired_token | server_error.
errorMessage
instance-attribute
¶
Human-readable error detail (set while error).
define_assistant_tool ¶
Identity helper that types a tool spec, so a typo in a property type is a type-check error instead of a runtime surprise.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
spec
|
AssistantToolSpec
|
The tool spec. |
required |
Returns:
| Type | Description |
|---|---|
AssistantToolSpec
|
The same spec, unchanged. |
Example
set_favorite = define_assistant_tool(
{
"name": "set_favorite",
"description": "Mark or unmark a recorded event as favorite.",
"inputSchema": {
"type": "object",
"properties": {"eventId": {"type": "string"}, "favorite": {"type": "boolean"}},
"required": ["eventId", "favorite"],
},
"approval": True,
}
)
can_create_cameras ¶
Report whether the plugin can create cameras (role is CameraController or CameraAndSensorProvider). Used to gate camera-creating operations such as DiscoveryProvider adoption.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
contract
|
PluginContract
|
Plugin contract to inspect. |
required |
Returns:
| Type | Description |
|---|---|
bool
|
True if the plugin may create cameras. |
can_provide_sensors_to_any_cameras ¶
Report whether the plugin is allowed to add sensors to cameras owned by other plugins (true for SensorProvider and CameraAndSensorProvider). Hub and pure CameraController plugins only see their own cameras.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
contract
|
PluginContract
|
Plugin contract to inspect. |
required |
Returns:
| Type | Description |
|---|---|
bool
|
True if the plugin may attach sensors to any camera. |
get_contract_validation_errors ¶
Check the structural validity of an unknown contract object: required fields present, enum values inside the accepted sets. Returns one human-readable error per problem found, empty when the contract is valid.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
contract
|
object
|
Untrusted candidate contract (e.g. parsed manifest JSON). |
required |
Returns:
| Type | Description |
|---|---|
list[str]
|
Error messages, empty if the contract is valid. |
has_capability ¶
Report whether the plugin requested the given capability.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
contract
|
PluginContract
|
Plugin contract to inspect. |
required |
cap
|
PluginCapability
|
Capability to check (e.g. :attr: |
required |
Returns:
| Type | Description |
|---|---|
bool
|
True if |
has_interface ¶
Report whether the plugin implements the given capability.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
contract
|
PluginContract
|
Plugin contract to inspect. |
required |
iface
|
PluginInterface
|
Interface to check (e.g. :attr: |
required |
Returns:
| Type | Description |
|---|---|
bool
|
True if |
is_hub ¶
Report whether the plugin's role is Hub (a cross-camera aggregator such as a smart-home bridge or recorder, which owns no cameras of its own).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
contract
|
PluginContract
|
Plugin contract to inspect. |
required |
Returns:
| Type | Description |
|---|---|
bool
|
True if the role is :attr: |
is_service ¶
Report whether the plugin only serves camera.ui itself (role Service), which means it never appears in a camera's plugin list.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
contract
|
PluginContract
|
Plugin contract to inspect. |
required |
Returns:
| Type | Description |
|---|---|
bool
|
True if the role is :attr: |
validate_contract_consistency ¶
Enforce role-specific consistency rules on top of the structural check (e.g. SensorProvider plugins must declare at least one provided sensor; Hub plugins cannot expose sensors). Raises on the first violation.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
contract
|
PluginContract
|
Already-structurally-valid contract. |
required |
plugin_name
|
str | None
|
Optional plugin name; used to prefix error messages. |
None
|
Raises:
| Type | Description |
|---|---|
ValueError
|
When the contract violates a role-specific rule. |