ts-onvif
Version:
Client to ONVIF devices
574 lines (573 loc) • 17.1 kB
TypeScript
/**
* Onvif module
* @author Andrew D.Laptev <a.d.laptev@gmail.com>
* @see https://www.onvif.org/wp-content/uploads/2022/07/ONVIF_Device_Feature_Discovery_Specification_21.12.pdf
*/
import { EventEmitter } from 'events';
import { SecureContextOptions } from 'tls';
import { Agent as HttpsAgent, RequestOptions } from 'https';
import http, { Agent as HttpAgent } from 'http';
import { OnvifResponse } from './utils';
import Device from './device';
import type Media from './media';
import type Media2 from './media2';
import type PTZ from './ptz';
import { Capabilities, Profile, SystemDateTime } from './interfaces/onvif';
import { GetDeviceInformationResponse, SetSystemDateAndTime } from './interfaces/devicemgmt';
import { ReferenceToken } from './interfaces/common';
import Events, { NotificationMessage } from './events';
import type Replay from './replay';
import type Imaging from './imaging';
import type Recording from './recording';
import type DoorControl from './doorcontrol';
import type AccessControl from './accesscontrol';
import type Credential from './credential';
import type AccessRules from './accessrules';
import type Schedule from './schedule';
import type Provisioning from './provisioning';
import type AdvancedSecurity from './advancedsecurity';
import type Thermal from './thermal';
import type Analytics from './analytics';
import type DeviceIO from './deviceio';
import type Display from './display';
import type ActionEngine from './actionengine';
import type Search from './search';
import type AnalyticsDevice from './analyticsdevice';
import type Receiver from './receiver';
/**
* Cam constructor options
*/
export interface OnvifOptions {
/** Set true if using `https` protocol, defaults to false. */
useSecure?: boolean;
/** Set options for https like ca, cert, ciphers, rejectUnauthorized, secureOptions, secureProtocol, etc. */
secureOptions?: SecureContextOptions;
/** Use WS-Security SOAP headers */
useWSSecurity?: boolean;
hostname: string;
username?: string;
password?: string;
port?: number;
path?: string;
timeout?: number;
urn?: string;
/** Supports things like https://www.npmjs.com/package/proxy-agent which provide SOCKS5 and other connections. */
agent?: HttpsAgent | HttpAgent | boolean;
/** Force using hostname and port from constructor for the services (ex.: for proxying), defaults to false. */
preserveAddress?: boolean;
/** Set false if the camera should not connect automatically, defaults false. */
autoConnect?: boolean;
}
export interface OnvifServices {
ptz?: URL;
analytics?: URL;
analyticsdevice?: URL;
device?: URL;
deviceIO?: URL;
display?: URL;
events?: URL;
imaging?: URL;
media2?: URL;
media?: URL;
receiver?: URL;
recording?: URL;
replay?: URL;
doorcontrol?: URL;
accesscontrol?: URL;
credential?: URL;
accessrules?: URL;
schedule?: URL;
provisioning?: URL;
advancedsecurity?: URL;
thermal?: URL;
actionengine?: URL;
search?: URL;
[key: string]: URL | undefined;
}
export interface OnvifRequestOptions extends Omit<RequestOptions, 'headers'> {
headers?: http.OutgoingHttpHeaders;
/** Name of service (ptz, media, etc) */
service?: keyof OnvifServices;
/** SOAP body */
body: Record<string, any>;
/** Defines another url to request */
url?: URL;
/** Make request to PTZ uri or not */
ptz?: boolean;
/** Timeout for pull-point event requests */
timeout?: number;
/** Additional SOAP-headers */
soapHeaders?: Record<string, any>;
/** Tags that should be forced to be arrays */
array?: string[];
/** Values of these tags will be in xml2js format */
rawXML?: string[];
}
export interface OnvifRawRequestOptions extends Omit<OnvifRequestOptions, 'body'> {
/** SOAP body */
body: string;
}
/**
* Information about active video source
*/
export interface ActiveSource {
sourceToken: ReferenceToken;
/**
* Media profile token
*/
profileToken: ReferenceToken;
videoSourceConfigurationToken: ReferenceToken;
videoSourceToken: ReferenceToken;
encoding?: string;
width?: number;
height?: number;
fps?: number;
bitrate?: number;
ptz?: {
name: string;
token: ReferenceToken;
};
}
export interface SetSystemDateAndTimeExtended extends SetSystemDateAndTime {
/**
* Javascript Date object to use instead of UTCDateTime
*/
dateTime?: Date;
/**
* The TZ format is specified by POSIX, please refer to POSIX 1003.1 section 8.3
* Example: Europe, Paris TZ=CET-1CEST,M3.5.0/2,M10.5.0/3
* CET = designation for standard time when daylight saving is not in force
* -1 = offset in hours = negative so 1 hour east of Greenwich meridian
* CEST = designation when daylight saving is in force ("Central European Summer Time")
* , = no offset number between code and comma, so default to one hour ahead for daylight saving
* M3.5.0 = when daylight saving starts = the last Sunday in March (the "5th" week means the last in the month)
* /2, = the local time when the switch occurs = 2 a.m. in this case
* M10.5.0 = when daylight saving ends = the last Sunday in October.
* /3, = the local time when the switch occurs = 3 a.m. in this case
*/
timezone?: string;
}
export interface SystemDateTimeExtended extends SystemDateTime {
/**
* Javascript Date object to use instead of UTCDateTime
*/
dateTime: Date;
}
interface OnvifEvents {
[Onvif.EVENT]: [msg: NotificationMessage];
[Onvif.ERROR]: [error: Error];
[Onvif.CONNECT]: [];
[Onvif.RAW_REQUEST]: [xml: string, requestOptions: http.RequestOptions];
[Onvif.REQUEST_BODY]: [body: string];
[Onvif.RAW_RESPONSE]: [xml: string];
[Onvif.WARN]: [error: Error];
[Onvif.EVENTS_ERROR]: [error: Error];
newListener: [event: string, listener: (...args: any[]) => void];
removeListener: [event: string, listener: (...args: any[]) => void];
}
export declare class Onvif extends EventEmitter<OnvifEvents> {
/**
* Indicates raw xml response from device.
* @event rawResponse
* @example
* ```typescript
* onvif.on('rawResponse', (xml) => { console.log('<- response was', xml); });
* ```
*/
static readonly RAW_RESPONSE = "rawResponse";
/**
* Indicates raw xml request to device.
* @event rawRequest
* @example
* ```typescript
* onvif.on('rawRequest', (xml) => { console.log('-> request was', xml); });
* ```
*/
static readonly RAW_REQUEST = "rawRequest";
/**
* Shows body of request
* @event
*/
static readonly REQUEST_BODY = "requestBody";
/**
* Indicates any errors except events errors
* @event error
* @example
* ```typescript
* onvif.on('error', console.error);
* ```
*/
static readonly ERROR = "error";
/**
* Indicates events errors
* @event eventsError
* @example
* ```typescript
* onvif.on('eventsError', console.error);
* ```
*/
static readonly EVENTS_ERROR = "eventsError";
/**
* Indicates any event from Onvif device.
* @event event
* @example
* ```typescript
* onvif.on('event', (msg) => { console.log(new Date().toLocaleTimeString(), 'new event', msg); });
* ```
*/
static readonly EVENT = "event";
/**
* Indicates any warnings
* @event warn
* @example
* ```typescript
* onvif.on('warn', console.warn);
* ```
*/
static readonly WARN = "warn";
/**
* Indicates successfully connection
* @event connect
* @example
* ```typescript
* onvif.on('connect', () => console.log('connected!'));
* ```
*/
static readonly CONNECT = "connect";
/**
* Core device namespace for device v1.0 methods
* @example
* ```typescript
* const date = await onvif.device.getSystemDateAndTime();
* console.log(date.toLocaleString());
* ```
*/
readonly device: Device;
/**
* Media namespace for media v1.0 methods
* @example
* ```typescript
* const profiles = await onvif.media.getProfiles();
* console.log(profiles);
* ```
*/
readonly media: Media;
/**
* Media2 namespace for media2 v1.0 methods
* @example
* ```typescript
* const profiles = await onvif.media2.getProfiles();
* console.log(profiles);
* ```
*/
readonly media2: Media2;
/**
* PTZ namespace for ptz v1.0 methods
* @example
* ```typescript
* const ptz = await onvif.ptz.getPTZStatus();
* console.log(ptz);
* ```
*/
readonly ptz: PTZ;
/**
* Events namespace for events v1.0 methods
* @example
* ```typescript
* onvif.on('event', (msg) => { console.log('-> request was', xml); });
* ```
*/
readonly events: Events;
/**
* Replay namespace for replay v1.0 methods
* @example
* ```typescript
* const replay = await onvif.replay.getReplayConfiguration();
* console.log(replay);
* ```
*/
readonly replay: Replay;
/**
* Imaging namespace for imaging v1.0 methods
* @example
* ```typescript
* const imaging = await onvif.imaging.getImagingSettings();
* console.log(imaging);
* ```
*/
readonly imaging: Imaging;
/**
* Recording namespace for recording v1.0 methods
* @example
* ```typescript
* const recording = await onvif.recording.getRecordingConfiguration();
* console.log(recording);
* ```
*/
readonly recording: Recording;
/**
* DoorControl namespace for doorcontrol v1.0 methods
* @example
* ```typescript
* const doorControl = await onvif.doorControl.getDoorControlConfiguration();
* console.log(doorControl);
* ```
*/
readonly doorControl: DoorControl;
/**
* AccessControl namespace for accesscontrol v1.0 methods
* @example
* ```typescript
* const list = await onvif.accessControl.getAccessPointInfoList();
* console.log(list);
* ```
*/
readonly accessControl: AccessControl;
/**
* Credential namespace for credential v1.0 methods
* @example
* ```typescript
* const list = await onvif.credential.getCredentialInfoList();
* console.log(list);
* ```
*/
readonly credential: Credential;
/**
* AccessRules namespace for accessrules v1.0 methods
* @example
* ```typescript
* const list = await onvif.accessRules.getAccessProfileInfoList();
* console.log(list);
* ```
*/
readonly accessRules: AccessRules;
/**
* Schedule namespace for schedule v1.0 methods
* @example
* ```typescript
* const list = await onvif.schedule.getScheduleInfoList();
* console.log(list);
* ```
*/
readonly schedule: Schedule;
/**
* Provisioning namespace for provisioning v1.0 methods
* @example
* ```typescript
* const caps = await onvif.provisioning.getServiceCapabilities();
* console.log(caps);
* ```
*/
readonly provisioning: Provisioning;
/**
* AdvancedSecurity namespace for advancedsecurity v1.0 methods
* @example
* ```typescript
* const caps = await onvif.advancedSecurity.getServiceCapabilities();
* console.log(caps);
* ```
*/
readonly advancedSecurity: AdvancedSecurity;
/**
* Thermal namespace for thermal v1.0 methods
* @example
* ```typescript
* const thermal = await onvif.thermal.getConfigurations();
* console.log(thermal);
* ```
*/
readonly thermal: Thermal;
/**
* Analytics namespace for analytics v1.0 methods
* @example
* ```typescript
* const analytics = await onvif.analytics.getAnalyticsConfiguration();
* console.log(analytics);
* ```
*/
readonly analytics: Analytics;
/**
* DeviceIO namespace for deviceio v1.0 methods
* @example
* ```typescript
* const deviceIO = await onvif.deviceIO.getDeviceIOConfiguration();
* console.log(deviceIO);
* ```
*/
readonly deviceIO: DeviceIO;
/**
* Display namespace for display v1.0 methods
* @example
* ```typescript
* const display = await onvif.display.getDisplayConfiguration();
* console.log(display);
* ```
*/
readonly display: Display;
/**
* ActionEngine namespace for actionengine v1.0 methods
* @example
* ```typescript
* const actionEngine = await onvif.actionEngine.getActionEngineConfiguration();
* console.log(actionEngine);
* ```
*/
readonly actionEngine: ActionEngine;
/**
* Search namespace for search v1.0 methods
* @example
* ```typescript
* const summary = await onvif.search.getRecordingSummary();
* console.log(summary);
* ```
*/
readonly search: Search;
/**
* AnalyticsDevice namespace for analytics device v1.0 methods
* @example
* ```typescript
* const controls = await onvif.analyticsDevice.getAnalyticsEngineControls();
* console.log(controls);
* ```
*/
readonly analyticsDevice: AnalyticsDevice;
/**
* Receiver namespace for receiver v1.0 methods
* @example
* ```typescript
* const receivers = await onvif.receiver.getReceivers();
* console.log(receivers);
* ```
*/
readonly receiver: Receiver;
/**
* Indicates if the device is using secure connection
*/
readonly useSecure: boolean;
/**
* Secure options for the connection
*/
secureOptions: SecureContextOptions;
/**
* Use WS-Security for the connection (this is the default and adds security headers in the SOAP messages)
*/
useWSSecurity: boolean;
/**
* Nonce for the connection
*/
private nc;
/**
* Hostname of the ONVIF device
*/
hostname: string;
/**
* Username for the connection
*/
username?: string;
/**
* Password for the connection
*/
password?: string;
/**
* Port for the connection
*/
port: number;
/**
* Path for the connection
*/
path: string;
timeout: number;
agent: HttpsAgent | HttpAgent | boolean;
preserveAddress: boolean;
uri: OnvifServices;
private timeShift?;
capabilities: Capabilities;
defaultProfiles: Profile[];
defaultProfile?: Profile;
private activeSources;
activeSource?: ActiveSource;
readonly urn?: string;
deviceInformation?: GetDeviceInformationResponse;
constructor(options: OnvifOptions);
envelopeBody(body: Record<string, any>): {
$: {
'xmlns:xsi': string;
'xmlns:xsd': string;
};
};
/**
* Envelope header for all SOAP messages
* @param options
* @private
*/
envelopeHeader(options?: OnvifRequestOptions): {
Security?: {
$: {
's:mustUnderstand': string;
xmlns: string;
};
UsernameToken: {
Username: string | undefined;
Password: {
$: {
Type: string;
};
_: string;
};
Nonce: {
$: {
EncodingType: string;
};
_: string;
};
Created: {
$: {
xmlns: string;
};
_: string;
};
};
} | undefined;
};
private passwordDigest;
private rawRequest;
private digestAuth;
request(options: OnvifRequestOptions): OnvifResponse;
private parseChallenge;
private updateNC;
/**
* Parse url with an eye on `preserveAddress` property
* @param address
* @private
*/
parseUrl(address: string): URL;
/**
* Receive date and time from cam
*/
getSystemDateAndTime(): Promise<SystemDateTimeExtended>;
/**
* Receive only date and time from cam (old behaviour, returns only Date object)
*/
getOnlySystemDateAndTime(): Promise<Date>;
/**
* Add time shift to use with ONVIF timestamps
* @param data
* @private
*/
private setupSystemDateAndTime;
/**
* Set the device system date and time
* Supports two possible date and time values: UTCDateTime(ONVIF types) or dateTime(js Date-object, preferred)
*/
setSystemDateAndTime(options: SetSystemDateAndTimeExtended): Promise<SystemDateTimeExtended>;
/**
* Check and find out video configuration for device
* @private
*/
private getActiveSources;
/**
* Connect to the camera and fill device information properties
*/
connect(): Promise<this>;
}
export {};