forked from eu-evops/homebridge-hikvision
/
HikvisionApi.ts
129 lines (113 loc) · 4.23 KB
/
HikvisionApi.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
import https from 'https';
import Axios, { AxiosResponse, AxiosRequestConfig } from 'axios';
import { AxiosDigest } from 'axios-digest';
import xml2js, { Parser } from 'xml2js';
import highland from 'highland';
import { PlatformConfig } from 'homebridge';
export interface HikVisionNvrApiConfiguration extends PlatformConfig {
host: string
port: Number
secure: boolean
ignoreInsecureTls: boolean
username: string
password: string
debugFfmpeg: boolean
}
export class HikvisionApi {
private _http?: AxiosDigest
private _parser?: Parser
constructor(config: HikVisionNvrApiConfiguration) {
const _axios = Axios.create({
baseURL: `http${config.secure ? 's' : ''}://${config.host}:${config.port}`,
httpsAgent: new https.Agent({
rejectUnauthorized: !config.ignoreInsecureTls
})
});
this._http = new AxiosDigest(config.username, config.password, _axios);
this._parser = new Parser({ explicitArray: false })
}
/*
"DeviceInfo": {
"$": {
"version": "2.0",
"xmlns": "http://www.isapi.org/ver20/XMLSchema"
},
"deviceName": "Network Video Recorder",
"deviceID": "48443030-3637-3534-3837-f84dfcf8ef1c",
"model": "DS-7608NI-I2/8P",
"serialNumber": "DS-7608NI-I2/8P0820190316CCRRD00675487WCVU",
"macAddress": "f8:4d:fc:f8:ef:1c",
"firmwareVersion": "V4.22.005",
"firmwareReleasedDate": "build 191208",
"encoderVersion": "V5.0",
"encoderReleasedDate": "build 191208",
"deviceType": "NVR",
"telecontrolID": "255"
}
*/
public async getSystemInfo() {
return this._getResponse('/ISAPI/System/deviceInfo');
}
async getCameras() {
const channels = await this._getResponse('/ISAPI/ContentMgmt/InputProxy/channels');
const channelStatus = await this._getResponse('/ISAPI/ContentMgmt/InputProxy/channels/status');
for (let i = 0; i < channels.InputProxyChannelList.InputProxyChannel.length; i++) {
const channel = channels.InputProxyChannelList.InputProxyChannel[i];
try {
channel.capabilities = await this._getResponse(`/ISAPI/ContentMgmt/StreamingProxy/channels/${channel.id}01/capabilities`);
} catch {
console.log(`Error getting cabailities for channel ${channel.id}`);
}
}
return channels.InputProxyChannelList.InputProxyChannel.map((channel: { status: any; id: any; name: string }) => {
channel.status = channelStatus.InputProxyChannelStatusList.InputProxyChannelStatus.find((cs: { id: any; }) => {
return cs.id === channel.id;
});
return channel;
}).filter((camera: { status: { online: string; }; }) => camera.status.online === 'true');
}
async startMonitoringEvents(callback: (value: any) => any) {
const xmlParser = new xml2js.Parser({
explicitArray: false,
});
/*
EventNotificationAlert: {
'$': { version: '2.0', xmlns: 'http://www.isapi.org/ver20/XMLSchema' },
ipAddress: '10.0.1.186',
portNo: '80',
protocolType: 'HTTP',
macAddress: 'f8:4d:fc:f8:ef:1c',
dynChannelID: '1',
channelID: '1',
dateTime: '2020-02-19T18:44:4400:00',
activePostCount: '1',
eventType: 'fielddetection',
eventState: 'active',
eventDescription: 'fielddetection alarm',
channelName: 'Front door',
DetectionRegionList: { DetectionRegionEntry: [Object] }
}
*/
const url = `/ISAPI/Event/notification/alertStream`
// TODO: what do we do if we lose our connection to the NVR? Don't we need to re-connect?
this.get(url, {
responseType: 'stream',
headers: {}
}).then(response => {
highland(response!.data)
.map((chunk: any) => chunk.toString('utf8'))
.filter(text => text.match(/<\?xml/))
.map(text => text.replace(/[\s\S]*<\?xml/gmi, '<?xml'))
.map(xmlText => xmlParser.parseStringPromise(xmlText))
.each(promise => promise.then(callback));
});
}
async get(url: string, config?: AxiosRequestConfig): Promise<AxiosResponse | undefined> {
return this._http?.get(url, config);
}
private async _getResponse(path: string) {
const response = await this._http?.get(path);
const responseJson = await this._parser?.parseStringPromise(response?.data);
return responseJson;
}
}