ts-onvif
Version:
Client to ONVIF devices
240 lines (239 loc) • 10.6 kB
TypeScript
/**
* Events ver10 module
* @author Andrew D.Laptev <a.d.laptev@gmail.com>
* @see https://www.onvif.org/specs/core/ONVIF-Core-Specification.pdf
* @see https://www.onvif.org/ver10/events/wsdl/event.wsdl
*/
import { Onvif } from './onvif';
import { AddEventBroker, Capabilities, CreatePullPointSubscription, DeleteEventBroker, EventBrokerConfig, GetEventBrokers, GetEventPropertiesResponse, PullMessages } from './interfaces/event';
import { CommonDuration } from './utils';
import { AnyURI } from './interfaces/basics';
import { ItemList } from './interfaces/onvif';
import { EventEmitter } from 'events';
import { Agent as HttpsAgent } from 'https';
import { Agent as HttpAgent } from 'http';
interface TerminationTimeResponse {
currentTime: Date;
terminationTime: Date;
}
/** ONVIF topic expression dialects from WS-Topics and [event.wsdl](https://www.onvif.org/ver10/events/wsdl/event.wsdl). */
export type TopicExpressionDialect = 'http://www.onvif.org/ver10/tev/topicExpression/ConcreteSet' | 'http://docs.oasis-open.org/wsn/t-1/TopicExpression/Concrete' | 'http://docs.oasis-open.org/wsn/t-1/TopicExpression/Full' | 'http://docs.oasis-open.org/wsn/t-1/TopicExpression/Simple';
/**
* Popular ONVIF topic expressions (`tns1` = `http://www.onvif.org/ver10/topics`).
* Subtree patterns ending with `//.` are defined in ONVIF Core 9.6.3.
*/
export type OnvifTopicExpression = 'tns1:RuleEngine/CellMotionDetector/Motion' | 'tns1:RuleEngine/LineDetector/Crossed' | 'tns1:RuleEngine/FieldDetector/ObjectsInside' | 'tns1:RuleEngine/TamperDetector/Tamper' | 'tns1:RuleEngine/LineDetector//.' | 'tns1:RuleEngine/FieldDetector//.' | 'tns1:RuleEngine//.' | 'tns1:VideoSource/MotionAlarm' | 'tns1:VideoSource/GlobalSceneChange' | 'tns1:VideoSource/ImageTooDark/ImagingService' | 'tns1:VideoSource/ImageTooBright/ImagingService' | 'tns1:VideoSource/ImageTooBlurry/ImagingService' | 'tns1:VideoSource/ImageTooNoisy/ImagingService' | 'tns1:VideoAnalytics//.' | 'tns1:VideoAnalytics/tnsanalytics:CellMotionDetector' | 'tns1:Device/Trigger/DigitalInput' | 'tns1:Device/Trigger/Relay' | 'tns1:Device/HardwareFailure/StorageFailure' | 'tns1:Device/HardwareFailure/FanFailure' | 'tns1:Device/HardwareFailure/PowerSupplyFailure' | 'tns1:Device/HardwareFailure/TemperatureCritical' | 'tns1:Monitoring/ProcessorUsage' | 'tns1:Monitoring/OperatingTime/LastReset' | 'tns1:Monitoring/OperatingTime/LastReboot' | 'tns1:Monitoring/OperatingTime/LastClockSynchronization' | 'tns1:RecordingConfig/RecordingJobState' | 'tns1:RecordingConfig/TrackConfiguration' | 'tns1:Media/ConfigurationChanged' | 'tns1:Media/ProfileChanged'
/** Vendor-specific topics, e.g. `tns1:RuleEngine/MyRuleDetector/FaceDetect` */
| 'tns1:RuleEngine/PeopleDetector/People' | (string & {});
export interface TopicExpression {
dialect: TopicExpressionDialect;
expression: OnvifTopicExpression;
}
export interface PullPointSubscriptionFilter {
topicExpression?: TopicExpression[];
/** XPath for message content filtering (ItemFilter dialect). */
messageContent?: string;
}
export interface CreatePullPointSubscriptionExtended extends Omit<CreatePullPointSubscription, 'filter' | 'initialTerminationTime'> {
filter?: PullPointSubscriptionFilter;
/** Initial termination time. */
initialTerminationTime?: CommonDuration;
}
export interface PullMessagesResponse {
/** The date and time when the messages have been delivered by the web server to the client. */
currentTime: Date;
/** Date time when the PullPoint will be shut down without further pull requests. */
terminationTime: Date;
/** List of messages. This list shall be empty in case of a timeout. */
notificationMessage: NotificationMessage[];
}
export interface NotificationMessage {
topic: Topic;
subscriptionReference?: {
address?: any;
};
producerReference?: {
address?: any;
};
message: {
message: EventMessage;
};
}
export interface Topic {
_: OnvifTopicExpression;
dialect?: TopicExpressionDialect;
}
export interface EventMessage {
utcTime: Date;
propertyOperation?: PropertyOperation;
source?: ItemList;
key?: ItemList;
data?: ItemList;
}
export type PropertyOperation = 'Initialized' | 'Changed' | 'Deleted';
export interface PullPointSubscription {
subscriptionReference: {
address: AnyURI;
referenceParameters?: {
subscriptionId: string;
};
};
currentTime: Date;
terminationTime: Date;
}
interface StatusResponse {
currentTime: Date;
terminationTime: Date;
}
interface SubscribeOptions {
/** URL of the event service */
url: string;
/** Subscription duration in milliseconds */
terminationTime?: CommonDuration;
/** Renew subscription after the termination time */
renew?: boolean;
/** Filter */
filter?: PullPointSubscriptionFilter;
}
/**
* Events service
*/
export default class Events {
private readonly onvif;
agent: HttpsAgent | HttpAgent;
globalSubscription: Subscription;
constructor(onvif: Onvif);
private createAgent;
/**
* Drop in-flight PullMessages sockets (long-poll up to PULL_TIMEOUT) so unsubscribe
* does not leave Happytime / cameras stuck with an open request.
*/
resetAgent(): void;
/**
* The WS-BaseNotification specification defines a set of OPTIONAL WS-ResouceProperties. This specification does not
* require the implementation of the WS-ResourceProperty interface. Instead, the subsequent direct interface shall be
* implemented by an ONVIF compliant device in order to provide information about the FilterDialects, Schema files
* and topics supported by the device.
*/
getEventProperties(): Promise<GetEventPropertiesResponse>;
getServiceCapabilities(): Promise<Capabilities>;
static filterToBuild(filter?: PullPointSubscriptionFilter): Record<string, unknown> | undefined;
/**
* This method returns a PullPointSubscription that can be polled using PullMessages. This message contains the same
* elements as the SubscriptionRequest of the WS-BaseNotification without the ConsumerReference.
* If no Filter is specified the pullpoint notifies all occurring events to the client.
* This method is mandatory.
*/
createPullPointSubscription(options?: CreatePullPointSubscriptionExtended): Promise<PullPointSubscription>;
private static eventBrokerToBuild;
addEventBroker({ eventBroker }: AddEventBroker): Promise<void>;
deleteEventBroker({ address }: DeleteEventBroker): Promise<void>;
getEventBrokers({ address }?: GetEventBrokers): Promise<EventBrokerConfig[]>;
/**
* Subscribe to events using WS-BaseNotification producer
* @param options
*/
subscribe(options: SubscribeOptions): Promise<PullPointSubscription>;
/**
* Unsubscribe from WS-BaseNotification push events
*/
unsubscribe(subscription: PullPointSubscription): Promise<void>;
/**
* Renew for WS-BaseNotification push event
* @param subscription
* @param terminationTime time in milliseconds
*/
renew(subscription: PullPointSubscription, terminationTime: CommonDuration): Promise<StatusResponse>;
/**
* Get status for WS-BaseNotification push events
*/
getStatus(subscription: PullPointSubscription): Promise<StatusResponse>;
}
interface SubscriptionEvents {
data: [msg: NotificationMessage];
error: [error: NodeJS.ErrnoException];
connectionError: [error: NodeJS.ErrnoException];
}
/**
* Subscription to events class
* @event data - emitted when event is received
* @event error - emitted when error occurs
* @example
* ```ts
* const sub = new Subscription(cam, 'pullPoint', {
* filter: {
* topicExpression: [
* {
* expression: 'tns1:RuleEngine/PeopleDetector/People',
* dialect: 'http://www.onvif.org/ver10/tev/topicExpression/ConcreteSet',
* },
* ],
* },
* });
* sub.on('data', console.log);
* await sub.subscribe();
* ```
*/
export declare class Subscription extends EventEmitter<SubscriptionEvents> {
private readonly onvif;
subscription?: PullPointSubscription;
private readonly messageLimit;
eventReconnectMs: number;
private readonly options;
/**
* Event received from subscription
* @event
* @param msg Notification message
*/
data: (msg: NotificationMessage) => void;
/**
* Any subscription error
* @event
* @param error Error object
*/
error: (error: NodeJS.ErrnoException) => void;
connectionError: (error: NodeJS.ErrnoException) => void;
constructor(onvif: Onvif, options?: CreatePullPointSubscriptionExtended);
/** When false, in-flight pull loops must not renew or auto-resubscribe. */
private pulling;
subscribe(): Promise<void>;
/**
* Loop events from the subscription
*/
eventPull(): Promise<void>;
/**
* Pull messages from the subscription
* @param options
*/
pullMessages(options?: PullMessages): Promise<PullMessagesResponse>;
/**
* Properties inform a client about property creation, changes and deletion in a uniform way. When a client wants to
* synchronize its properties with the properties of the device, it can request a synchronization point which repeats
* the current status of all properties to which a client has subscribed. The PropertyOperation of all produced
* notifications is set to “Initialized”. The Synchronization Point is requested directly from the SubscriptionManager
* which was returned in either the SubscriptionResponse or in the CreatePullPointSubscriptionResponse. The property
* update is transmitted via the notification transportation of the notification interface. This method is mandatory.
*/
setSynchronizationPoint(): Promise<void>;
/**
* Renew the subscription
*/
renew(): Promise<TerminationTimeResponse>;
/**
* The device shall provide the following Unsubscribe command for all SubscriptionManager endpoints returned
* by the CreatePullPointSubscription command.
* This command shall terminate the lifetime of a pull point.
*/
unsubscribe(): Promise<void>;
/**
* Restart the event request with an increasing interval when the connection to the device is refused
* @private
*/
private restartEventRequest;
/**
* Get params for concrete subscription
* @private
*/
private getSubscriptionUrlAndHeaders;
}
export {};