unifi-protect
Version:
A complete implementation of the UniFi Protect API.
115 lines (114 loc) • 6.53 kB
TypeScript
/**
* Utilities to help decode packets from the UniFi Protect realtime events API.
*
* UniFi OS update events data packets are used to provide a realtime stream of updates to Protect. It differs from the system events API in that the system events API
* appears to be shared across other applications (Network, Access, etc.) while the updates events API appears to only be utilized by Protect and not shared by other
* applications, although the protocol is shared.
*
* So how does it all work? Cameras continuously stream updates to the UniFi Protect controller containing things like camera health, statistics, and, crucially for us,
* events such as motion and doorbell ring. A complete update packet is composed of four frames:
*
* ```
* ----------------
* | Header Frame | (8 bytes)
* ----------------
* | Action Frame |
* ----------------
* | Header Frame | (8 bytes)
* ----------------
* | Data Frame |
* ----------------
* ```
*
* The header frame is required overhead since websockets provide only a transport medium. It's purpose is to tell us what's coming in the frame that follows.
*
* The action frame identifies what the action and category that the update contains:
*
* | Property | Description |
* |-------------|----------------------------------------------------------------------------------|
* | action | What action is being taken. Known actions are `add` and `update`. |
* | id | The identifier for the device we're updating. |
* | modelKey | The device model category that we're updating. |
* | newUpdateId | A new UUID generated on a per-update basis. This can be safely ignored it seems. |
*
* The final part of the update packet is the data frame. The data frame can be three different types of data - although in practice, I've only seen JSONs come across.
* Those types are:
*
* | Payload Type | Description |
* |--------------|------------------------------------------------------------------------------------------------------------|
* | 1 | JSON. For update actions that are not events, this is always a subset of the configuration bootstrap JSON. |
* | 2 | A UTF8-encoded string |
* | 3 | Node Buffer |
*
* Some tips:
*
* - `update` actions are always tied to the following modelKeys: camera, event, nvr, and user.
*
* - `add` actions are always tied to the `event` modelKey and indicate the beginning of an event item in the Protect events list. A subsequent `update` action is sent
* signaling the end of the event capture, and it's confidence score for motion detection.
*
* - The above is NOT the same thing as motion detection. If you want to detect motion, you should watch the `update` action for `camera` modelKeys, and look for a JSON
* that updates lastMotion. For doorbell rings, lastRing. The Protect events list is useful for the Protect app, but it's of limited utility to HomeKit, and it's slow
* = relative to looking for lastMotion that is. If you want true realtime updates, you want to look at the `update` action.
*
* - JSONs are only payload type that seems to be sent, although the protocol is designed to accept all three.
*
* - With the exception of update actions with a modelKey of event, JSONs are always a subset of the bootstrap JSON, indexed off of modelKey. So for a modelKey of camera,
* the data payload is always a subset of {@link ProtectTypes.ProtectCameraConfigInterface | ProtectCameraConfigInterface}.
*
* @module ProtectApiEvents
*/
import { Nullable } from "./protect-types.js";
import { ProtectLogging } from "./protect-logging.js";
/**
* UniFi Protect event packet.
*
* @param header - Protect event header.
* @param payload - Protect event payload.
*
* @remarks A UniFi Protect event packet represents a realtime event update from a UniFi Protect controller. There are two components to each packet, a `header` and
* a `payload`. The `header` contains information about which Protect device and what action category it belongs to. The `payload` contains the detailed information
* related to the device and action specified in the header.
*/
export type ProtectEventPacket = {
header: ProtectEventHeader;
payload: unknown;
};
/**
* UniFi Protect event header.
*
* @param header - Protect event header.
* @param payload - Protect event payload.
*
* @remarks A UniFi Protect event packet represents a realtime event update from a UniFi Protect controller. There are two components to each packet, a `header` and
* a `payload`. The `header` contains information about which Protect device and what action category it belongs to and can contain arbitrary information, though has
* a few properties that are always present (`action`, `id`, `modelKey`, and `newUpdateId`). The `payload` contains the detailed information related to the device and
* action specified in the header.
*/
export type ProtectEventHeader = {
action: string;
id: string;
modelKey: string;
newUpdateId: string;
[key: string]: boolean | number | object | string;
};
/**
* UniFi Protect event utility class that provides functions for decoding realtime event API packet frames.
*/
export declare class ProtectApiEvents {
/** @internal */
constructor();
/**
* Decode a UniFi Protect event packet.
*
* @param log - Logging functions to use.
* @param packet - Input packet to decode.
*
* @remarks A UniFi Protect event packet is an encoded representation of state updates that occur in a UniFi Protect controller. This utility function takes an
* encoded packet as an input, and decodes it into an event header and payload that can be acted upon. An example of it's use is in {@link ProtectApi} where, once
* successfully logged into the Protect controller, events are generated automatically and can be accessed by listening to `message` events emitted by
* {@link ProtectApi}.
*/
static decodePacket(log: ProtectLogging, packet: Buffer): Nullable<ProtectEventPacket>;
private static decodeFrame;
}