homebridge-unifi-protect 6.7.0 → 6.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +1 -1
- package/README.md +1 -1
- package/config.schema.json +0 -24
- package/dist/protect-camera-package.d.ts +9 -0
- package/dist/protect-camera-package.js +120 -0
- package/dist/protect-camera-package.js.map +1 -0
- package/dist/protect-camera.d.ts +5 -12
- package/dist/protect-camera.js +48 -139
- package/dist/protect-camera.js.map +1 -1
- package/dist/protect-device.d.ts +10 -4
- package/dist/protect-device.js +82 -13
- package/dist/protect-device.js.map +1 -1
- package/dist/protect-doorbell.d.ts +4 -0
- package/dist/protect-doorbell.js +54 -0
- package/dist/protect-doorbell.js.map +1 -1
- package/dist/protect-ffmpeg-codecs.js +5 -4
- package/dist/protect-ffmpeg-codecs.js.map +1 -1
- package/dist/protect-ffmpeg-options.d.ts +2 -2
- package/dist/protect-ffmpeg-options.js +199 -149
- package/dist/protect-ffmpeg-options.js.map +1 -1
- package/dist/protect-ffmpeg-record.js +1 -1
- package/dist/protect-ffmpeg-record.js.map +1 -1
- package/dist/protect-ffmpeg.d.ts +3 -3
- package/dist/protect-ffmpeg.js.map +1 -1
- package/dist/protect-light.js +2 -0
- package/dist/protect-light.js.map +1 -1
- package/dist/protect-nvr-events.js +34 -31
- package/dist/protect-nvr-events.js.map +1 -1
- package/dist/protect-nvr-systeminfo.js +1 -1
- package/dist/protect-nvr-systeminfo.js.map +1 -1
- package/dist/protect-nvr.d.ts +2 -3
- package/dist/protect-nvr.js +22 -101
- package/dist/protect-nvr.js.map +1 -1
- package/dist/protect-options.d.ts +4 -3
- package/dist/protect-options.js +87 -87
- package/dist/protect-options.js.map +1 -1
- package/dist/protect-platform.js +3 -13
- package/dist/protect-platform.js.map +1 -1
- package/dist/protect-record.js +7 -6
- package/dist/protect-record.js.map +1 -1
- package/dist/protect-sensor.d.ts +6 -3
- package/dist/protect-sensor.js +67 -13
- package/dist/protect-sensor.js.map +1 -1
- package/dist/protect-stream.d.ts +2 -2
- package/dist/protect-stream.js +18 -27
- package/dist/protect-stream.js.map +1 -1
- package/dist/protect-timeshift.d.ts +1 -1
- package/dist/protect-timeshift.js +2 -2
- package/dist/protect-timeshift.js.map +1 -1
- package/dist/protect-viewer.d.ts +2 -1
- package/dist/protect-viewer.js +12 -0
- package/dist/protect-viewer.js.map +1 -1
- package/homebridge-ui/public/index.html +426 -36
- package/homebridge-ui/server.js +12 -12
- package/package.json +8 -8
package/LICENSE.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Internet Systems Consortium License
|
|
2
2
|
===================================
|
|
3
3
|
|
|
4
|
-
Copyright (c) `2017-
|
|
4
|
+
Copyright (c) `2017-2023`, `HJD https://github.com/hjdhjd`
|
|
5
5
|
|
|
6
6
|
Permission to use, copy, modify, and/or distribute this software for any purpose
|
|
7
7
|
with or without fee is hereby granted, provided that the above copyright notice
|
package/README.md
CHANGED
|
@@ -136,6 +136,6 @@ You can use your Ubiquiti account credentials, though 2FA is not currently suppo
|
|
|
136
136
|
This is mostly of interest to the true developer nerds amongst us.
|
|
137
137
|
|
|
138
138
|
[](https://github.com/hjdhjd/homebridge-unifi-protect/blob/main/LICENSE.md)
|
|
139
|
-
[](https://github.com/hjdhjd/homebridge-unifi-protect/actions?query=workflow%3A%22Continuous+Integration%22)
|
|
140
140
|
[](https://libraries.io/npm/homebridge-unifi-protect)
|
|
141
141
|
[](https://github.com/hjdhjd/homebridge-unifi-protect/commits/master)
|
package/config.schema.json
CHANGED
|
@@ -143,28 +143,6 @@
|
|
|
143
143
|
}
|
|
144
144
|
},
|
|
145
145
|
|
|
146
|
-
"occupancyDuration": {
|
|
147
|
-
|
|
148
|
-
"type": "integer",
|
|
149
|
-
"title": "Occupancy Event Duration (seconds)",
|
|
150
|
-
"required": false,
|
|
151
|
-
"minimum": 60,
|
|
152
|
-
"maximum": 3600,
|
|
153
|
-
"placeholder": "e.g. 300",
|
|
154
|
-
"description": "Duration of time to wait without receiving a motion event to determine when occupancy is no longer detected. Default: 300."
|
|
155
|
-
},
|
|
156
|
-
|
|
157
|
-
"motionDuration": {
|
|
158
|
-
|
|
159
|
-
"type": "integer",
|
|
160
|
-
"title": "Motion Event Duration (seconds)",
|
|
161
|
-
"required": false,
|
|
162
|
-
"minimum": 5,
|
|
163
|
-
"maximum": 300,
|
|
164
|
-
"placeholder": "e.g. 10",
|
|
165
|
-
"description": "Duration of a single motion event, before allowing a new motion event. Setting this too low will potentially cause a lot of excess notifications. Default: 10."
|
|
166
|
-
},
|
|
167
|
-
|
|
168
146
|
"ringDuration": {
|
|
169
147
|
|
|
170
148
|
"type": "integer",
|
|
@@ -318,8 +296,6 @@
|
|
|
318
296
|
"videoProcessor",
|
|
319
297
|
"videoEncoder",
|
|
320
298
|
"verboseFfmpeg",
|
|
321
|
-
"motionDuration",
|
|
322
|
-
"occupancyDuration",
|
|
323
299
|
"ringDuration"
|
|
324
300
|
]
|
|
325
301
|
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { ProtectCamera, RtspEntry } from "./protect-camera.js";
|
|
2
|
+
export declare class ProtectCameraPackage extends ProtectCamera {
|
|
3
|
+
protected configureDevice(): Promise<boolean>;
|
|
4
|
+
get id(): string;
|
|
5
|
+
findRtsp(): RtspEntry | null;
|
|
6
|
+
findRecordingRtsp(): RtspEntry | null;
|
|
7
|
+
getBitrate(channelId: number): number;
|
|
8
|
+
setBitrate(): Promise<boolean>;
|
|
9
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/* Copyright(C) 2019-2023, HJD (https://github.com/hjdhjd). All rights reserved.
|
|
2
|
+
*
|
|
3
|
+
* protect-camera-package.ts: Package camera device class for UniFi Protect.
|
|
4
|
+
*/
|
|
5
|
+
import { ProtectCamera } from "./protect-camera.js";
|
|
6
|
+
import { ProtectStreamingDelegate } from "./protect-stream.js";
|
|
7
|
+
// Package camera class. To avoid circular dependencies, this has to be declared in the same file as ProtectCamera, given the ProtectCamera class references it.
|
|
8
|
+
export class ProtectCameraPackage extends ProtectCamera {
|
|
9
|
+
// Configure the package camera.
|
|
10
|
+
async configureDevice() {
|
|
11
|
+
// Get our parent camera.
|
|
12
|
+
const parentCamera = this.nvr.deviceLookup(this.ufp.id);
|
|
13
|
+
this.hasHksv = true;
|
|
14
|
+
this.hints.probesize = 32768;
|
|
15
|
+
if (parentCamera) {
|
|
16
|
+
this.hints.timeshift = parentCamera.hints.timeshift;
|
|
17
|
+
this.hints.hardwareDecoding = parentCamera.hints.hardwareDecoding;
|
|
18
|
+
this.hints.hardwareTranscoding = parentCamera.hints.hardwareTranscoding;
|
|
19
|
+
this.hints.logHksv = parentCamera.hints.logHksv;
|
|
20
|
+
}
|
|
21
|
+
// Clean out the context object in case it's been polluted somehow.
|
|
22
|
+
this.accessory.context = {};
|
|
23
|
+
// Inherit our HKSV and motion awareness states from our parent camera.
|
|
24
|
+
this.accessory.context.hksvRecording = parentCamera?.accessory.context.hksvRecording;
|
|
25
|
+
this.accessory.context.detectMotion = parentCamera?.accessory.context.detectMotion;
|
|
26
|
+
// We explicitly avoid adding the MAC address of the camera - that's reserved for real Protect devices, not synthetic ones we create.
|
|
27
|
+
this.accessory.context.nvr = this.nvr.ufp.mac;
|
|
28
|
+
this.accessory.context.packageCamera = this.ufp.mac;
|
|
29
|
+
// Configure accessory information.
|
|
30
|
+
this.configureInfo();
|
|
31
|
+
// Configure the motion sensor.
|
|
32
|
+
this.configureMotionSensor();
|
|
33
|
+
// Set the snapshot URL.
|
|
34
|
+
this.snapshotUrl = this.nvr.ufpApi.getApiEndpoint(this.ufp.modelKey) + "/" + this.ufp.id + "/package-snapshot";
|
|
35
|
+
let hkResolutions = [];
|
|
36
|
+
const validResolutions = [this.findRtsp()?.resolution ?? [1600, 1200, 2]];
|
|
37
|
+
// Ensure we have mandatory resolutions required by HomeKit, as well as special support for Apple TV and Apple Watch, while respecting aspect ratios.
|
|
38
|
+
// We use the frame rate of the first entry, which should be our highest resolution option that's native to the camera as the upper bound for frame rate.
|
|
39
|
+
//
|
|
40
|
+
// Our supported resolutions range from 4K through 320p...even for package cameras.
|
|
41
|
+
if ((validResolutions[0][0] / validResolutions[0][1]) === (16 / 9)) {
|
|
42
|
+
hkResolutions = [
|
|
43
|
+
[3840, 2160, 15], [2560, 1440, 15],
|
|
44
|
+
[1920, 1080, 15], [1280, 720, 15],
|
|
45
|
+
[640, 360, 15], [480, 270, 15],
|
|
46
|
+
[320, 180, 15]
|
|
47
|
+
];
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
hkResolutions = [
|
|
51
|
+
[3840, 2880, 15], [2560, 1920, 15],
|
|
52
|
+
[1920, 1440, 15], [1280, 960, 15],
|
|
53
|
+
[640, 480, 15], [480, 360, 15],
|
|
54
|
+
[320, 240, 15]
|
|
55
|
+
];
|
|
56
|
+
}
|
|
57
|
+
// Validate and add our entries to the list of what we make available to HomeKit.
|
|
58
|
+
for (const entry of hkResolutions) {
|
|
59
|
+
// This resolution is larger than the highest resolution on the camera, natively. We make an exception for
|
|
60
|
+
// 1080p and 720p resolutions since HomeKit explicitly requires them.
|
|
61
|
+
if ((entry[0] >= validResolutions[0][0]) && ![1920, 1280].includes(entry[0])) {
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
// We already have this resolution in our list.
|
|
65
|
+
if (validResolutions.some(x => (x[0] === entry[0]) && (x[1] === entry[1]) && (x[2] === entry[2]))) {
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
validResolutions.push(entry);
|
|
69
|
+
}
|
|
70
|
+
// Inform users about our RTSP entry mapping, if we're debugging.
|
|
71
|
+
if (this.nvr.optionEnabled(this.ufp, "Debug.Video.Startup", false)) {
|
|
72
|
+
for (const entry of validResolutions) {
|
|
73
|
+
this.log.info("Mapping resolution: %s.", this.getResolution(entry) + " => " + this.getResolution(validResolutions[0]));
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
// Configure the video stream with our required resolutions. No, package cameras don't really support any of these resolutions, but they're required
|
|
77
|
+
// by HomeKit in order to stream video.
|
|
78
|
+
this.stream = new ProtectStreamingDelegate(this, validResolutions);
|
|
79
|
+
// Fire up the controller and inform HomeKit about it.
|
|
80
|
+
this.accessory.configureController(this.stream.controller);
|
|
81
|
+
// Periodically refresh our snapshot cache.
|
|
82
|
+
void this.configureSnapshotUpdates();
|
|
83
|
+
// We're done.
|
|
84
|
+
return Promise.resolve(true);
|
|
85
|
+
}
|
|
86
|
+
// Return a unique identifier for package cameras based on the parent device's MAC address.
|
|
87
|
+
get id() {
|
|
88
|
+
return this.ufp.mac + ".PackageCamera";
|
|
89
|
+
}
|
|
90
|
+
// Make our RTSP stream findable.
|
|
91
|
+
findRtsp() {
|
|
92
|
+
const channel = this.ufp.channels.find(x => x.name === "Package Camera");
|
|
93
|
+
if (!channel) {
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
// Return the information we need for package camera channel access.
|
|
97
|
+
return {
|
|
98
|
+
channel: channel,
|
|
99
|
+
lens: this.ufp.lenses[0].id,
|
|
100
|
+
name: this.getResolution([channel.width, channel.height, channel.fps]) + " (" + channel.name + ")",
|
|
101
|
+
resolution: [channel.width, channel.height, channel.fps],
|
|
102
|
+
url: "rtsps://" + this.nvr.nvrOptions.address + ":" + this.nvr.ufp.ports.rtsps.toString() + "/" + channel.rtspAlias + "?enableSrtp"
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
// Return a recording RTSP configuration for HKSV.
|
|
106
|
+
findRecordingRtsp() {
|
|
107
|
+
return this.findRtsp();
|
|
108
|
+
}
|
|
109
|
+
// Get the current bitrate for a specific camera channel.
|
|
110
|
+
getBitrate(channelId) {
|
|
111
|
+
// Find the right channel.
|
|
112
|
+
const channel = this.ufp.channels.find(x => x.id === channelId);
|
|
113
|
+
return channel?.bitrate ?? -1;
|
|
114
|
+
}
|
|
115
|
+
// Set the bitrate for a specific camera channel.
|
|
116
|
+
setBitrate() {
|
|
117
|
+
return Promise.resolve(true);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
//# sourceMappingURL=protect-camera-package.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"protect-camera-package.js","sourceRoot":"","sources":["../src/protect-camera-package.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,aAAa,EAAa,MAAM,qBAAqB,CAAC;AAC/D,OAAO,EAAE,wBAAwB,EAAE,MAAM,qBAAqB,CAAC;AAG/D,gKAAgK;AAChK,MAAM,OAAO,oBAAqB,SAAQ,aAAa;IAErD,gCAAgC;IACtB,KAAK,CAAC,eAAe;QAE7B,yBAAyB;QACzB,MAAM,YAAY,GAAG,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAExD,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QACpB,IAAI,CAAC,KAAK,CAAC,SAAS,GAAG,KAAK,CAAC;QAE7B,IAAG,YAAY,EAAE;YAEf,IAAI,CAAC,KAAK,CAAC,SAAS,GAAG,YAAY,CAAC,KAAK,CAAC,SAAS,CAAC;YACpD,IAAI,CAAC,KAAK,CAAC,gBAAgB,GAAG,YAAY,CAAC,KAAK,CAAC,gBAAgB,CAAC;YAClE,IAAI,CAAC,KAAK,CAAC,mBAAmB,GAAG,YAAY,CAAC,KAAK,CAAC,mBAAmB,CAAC;YACxE,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,YAAY,CAAC,KAAK,CAAC,OAAO,CAAC;SACjD;QAED,mEAAmE;QACnE,IAAI,CAAC,SAAS,CAAC,OAAO,GAAG,EAAE,CAAC;QAE5B,uEAAuE;QACvE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,aAAa,GAAG,YAAY,EAAE,SAAS,CAAC,OAAO,CAAC,aAAwB,CAAC;QAChG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,YAAY,GAAG,YAAY,EAAE,SAAS,CAAC,OAAO,CAAC,YAAuB,CAAC;QAE9F,qIAAqI;QACrI,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC;QAC9C,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;QAEpD,mCAAmC;QACnC,IAAI,CAAC,aAAa,EAAE,CAAC;QAErB,+BAA+B;QAC/B,IAAI,CAAC,qBAAqB,EAAE,CAAC;QAE7B,wBAAwB;QACxB,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,cAAc,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,GAAG,mBAAmB,CAAC;QAE/G,IAAI,aAAa,GAAiB,EAAE,CAAC;QACrC,MAAM,gBAAgB,GAAiB,CAAE,IAAI,CAAC,QAAQ,EAAE,EAAE,UAAU,IAAI,CAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAE,CAAE,CAAC;QAE5F,qJAAqJ;QACrJ,yJAAyJ;QACzJ,EAAE;QACF,mFAAmF;QACnF,IAAG,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE;YAEjE,aAAa,GAAG;gBAEd,CAAE,IAAI,EAAE,IAAI,EAAE,EAAE,CAAE,EAAE,CAAE,IAAI,EAAE,IAAI,EAAE,EAAE,CAAE;gBACtC,CAAE,IAAI,EAAE,IAAI,EAAE,EAAE,CAAC,EAAE,CAAE,IAAI,EAAE,GAAG,EAAE,EAAE,CAAE;gBACpC,CAAE,GAAG,EAAE,GAAG,EAAE,EAAE,CAAE,EAAE,CAAE,GAAG,EAAE,GAAG,EAAE,EAAE,CAAE;gBAClC,CAAE,GAAG,EAAE,GAAG,EAAE,EAAE,CAAE;aACjB,CAAC;SACH;aAAM;YAEL,aAAa,GAAG;gBAEd,CAAE,IAAI,EAAE,IAAI,EAAE,EAAE,CAAE,EAAE,CAAE,IAAI,EAAE,IAAI,EAAE,EAAE,CAAE;gBACtC,CAAE,IAAI,EAAE,IAAI,EAAE,EAAE,CAAE,EAAE,CAAE,IAAI,EAAE,GAAG,EAAE,EAAE,CAAE;gBACrC,CAAE,GAAG,EAAE,GAAG,EAAE,EAAE,CAAE,EAAE,CAAE,GAAG,EAAE,GAAG,EAAE,EAAE,CAAE;gBAClC,CAAE,GAAG,EAAE,GAAG,EAAE,EAAE,CAAE;aACjB,CAAC;SACH;QAED,iFAAiF;QACjF,KAAI,MAAM,KAAK,IAAI,aAAa,EAAE;YAEhC,0GAA0G;YAC1G,qEAAqE;YACrE,IAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAE,IAAI,EAAE,IAAI,CAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE;gBAE7E,SAAS;aACV;YAED,+CAA+C;YAC/C,IAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;gBAEhG,SAAS;aACV;YAED,gBAAgB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;SAC9B;QAED,iEAAiE;QACjE,IAAG,IAAI,CAAC,GAAG,CAAC,aAAa,CAAC,IAAI,CAAC,GAAG,EAAE,qBAAqB,EAAE,KAAK,CAAC,EAAE;YAEjE,KAAI,MAAM,KAAK,IAAI,gBAAgB,EAAE;gBAEnC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,yBAAyB,EAAE,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,GAAG,MAAM,GAAG,IAAI,CAAC,aAAa,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;aACxH;SACF;QAED,oJAAoJ;QACpJ,uCAAuC;QACvC,IAAI,CAAC,MAAM,GAAG,IAAI,wBAAwB,CAAC,IAAI,EAAE,gBAAgB,CAAC,CAAC;QAEnE,sDAAsD;QACtD,IAAI,CAAC,SAAS,CAAC,mBAAmB,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;QAE3D,2CAA2C;QAC3C,KAAK,IAAI,CAAC,wBAAwB,EAAE,CAAC;QAErC,cAAc;QACd,OAAO,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/B,CAAC;IAED,2FAA2F;IAC3F,IAAW,EAAE;QAEX,OAAO,IAAI,CAAC,GAAG,CAAC,GAAG,GAAG,gBAAgB,CAAC;IACzC,CAAC;IAED,iCAAiC;IAC1B,QAAQ;QAEb,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,gBAAgB,CAAC,CAAC;QAEzE,IAAG,CAAC,OAAO,EAAE;YAEX,OAAO,IAAI,CAAC;SACb;QAED,oEAAoE;QACpE,OAAO;YAEL,OAAO,EAAE,OAAO;YAChB,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE;YAC3B,IAAI,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,GAAG,GAAG;YAClG,UAAU,EAAE,CAAE,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,CAAE;YAC1D,GAAG,EAAG,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,OAAO,GAAG,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,EAAE,GAAG,GAAG,GAAG,OAAO,CAAC,SAAS,GAAG,aAAa;SACrI,CAAC;IACJ,CAAC;IAED,kDAAkD;IAC3C,iBAAiB;QAEtB,OAAO,IAAI,CAAC,QAAQ,EAAE,CAAC;IACzB,CAAC;IAED,yDAAyD;IAClD,UAAU,CAAC,SAAiB;QAEjC,0BAA0B;QAC1B,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,SAAS,CAAC,CAAC;QAEhE,OAAO,OAAO,EAAE,OAAO,IAAI,CAAC,CAAC,CAAC;IAChC,CAAC;IAED,iDAAiD;IAC1C,UAAU;QAEf,OAAO,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/B,CAAC;CACF"}
|
package/dist/protect-camera.d.ts
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
import { PlatformAccessory } from "homebridge";
|
|
1
|
+
import { PlatformAccessory, Resolution } from "homebridge";
|
|
2
2
|
import { ProtectCameraChannelConfig, ProtectCameraConfig, ProtectEventPacket } from "unifi-protect";
|
|
3
3
|
import { ProtectDevice } from "./protect-device.js";
|
|
4
4
|
import { ProtectNvr } from "./protect-nvr.js";
|
|
5
5
|
import { ProtectStreamingDelegate } from "./protect-stream.js";
|
|
6
6
|
export interface RtspEntry {
|
|
7
7
|
channel: ProtectCameraChannelConfig;
|
|
8
|
+
lens?: number;
|
|
8
9
|
name: string;
|
|
9
|
-
resolution:
|
|
10
|
+
resolution: Resolution;
|
|
10
11
|
url: string;
|
|
11
12
|
}
|
|
12
13
|
export declare class ProtectCamera extends ProtectDevice {
|
|
@@ -15,7 +16,6 @@ export declare class ProtectCamera extends ProtectDevice {
|
|
|
15
16
|
private isDoorbellConfigured;
|
|
16
17
|
isRinging: boolean;
|
|
17
18
|
private isVideoConfigured;
|
|
18
|
-
packageCamera: ProtectPackageCamera | null;
|
|
19
19
|
private rtspEntries;
|
|
20
20
|
private rtspQuality;
|
|
21
21
|
snapshotUrl: string;
|
|
@@ -33,7 +33,6 @@ export declare class ProtectCamera extends ProtectDevice {
|
|
|
33
33
|
private configureCameraDetails;
|
|
34
34
|
private configureVideoStream;
|
|
35
35
|
protected configureSnapshotUpdates(): Promise<boolean>;
|
|
36
|
-
private configurePackageCamera;
|
|
37
36
|
private configureHksv;
|
|
38
37
|
private configureHksvRecordingSwitch;
|
|
39
38
|
private configureDynamicBitrateSwitch;
|
|
@@ -43,14 +42,8 @@ export declare class ProtectCamera extends ProtectDevice {
|
|
|
43
42
|
getBitrate(channelId: number): number;
|
|
44
43
|
setBitrate(channelId: number, value: number): Promise<boolean>;
|
|
45
44
|
private findRtspEntry;
|
|
46
|
-
findRtsp(width: number, height: number,
|
|
45
|
+
findRtsp(width: number, height: number, rtspEntries?: RtspEntry[], constrainPixels?: number): RtspEntry | null;
|
|
47
46
|
findRecordingRtsp(width: number, height: number, rtspEntries?: RtspEntry[]): RtspEntry | null;
|
|
48
47
|
private sortByResolutions;
|
|
49
|
-
|
|
50
|
-
}
|
|
51
|
-
export declare class ProtectPackageCamera extends ProtectCamera {
|
|
52
|
-
protected configureDevice(): Promise<boolean>;
|
|
53
|
-
findRtsp(): RtspEntry | null;
|
|
54
|
-
getBitrate(channelId: number): number;
|
|
55
|
-
setBitrate(): Promise<boolean>;
|
|
48
|
+
protected getResolution(resolution: Resolution): string;
|
|
56
49
|
}
|
package/dist/protect-camera.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { PROTECT_HOMEKIT_IDR_INTERVAL, PROTECT_SNAPSHOT_CACHE_REFRESH_INTERVAL } from "./settings.js";
|
|
2
2
|
import { ProtectDevice } from "./protect-device.js";
|
|
3
3
|
import { ProtectReservedNames } from "./protect-types.js";
|
|
4
4
|
import { ProtectStreamingDelegate } from "./protect-stream.js";
|
|
@@ -11,7 +11,6 @@ export class ProtectCamera extends ProtectDevice {
|
|
|
11
11
|
this.isDeleted = false;
|
|
12
12
|
this.isRinging = false;
|
|
13
13
|
this.isVideoConfigured = false;
|
|
14
|
-
this.packageCamera = null;
|
|
15
14
|
this.rtspEntries = [];
|
|
16
15
|
this.rtspQuality = {};
|
|
17
16
|
this.ufp = device;
|
|
@@ -29,7 +28,7 @@ export class ProtectCamera extends ProtectDevice {
|
|
|
29
28
|
this.hints.logDoorbell = this.hasFeature("Log.Doorbell");
|
|
30
29
|
this.hints.logHksv = this.hasFeature("Log.HKSV");
|
|
31
30
|
this.hints.probesize = 16384;
|
|
32
|
-
this.hints.smartDetect = this.hasFeature("Motion.SmartDetect");
|
|
31
|
+
this.hints.smartDetect = this.ufp.featureFlags.hasSmartDetect && this.hasFeature("Motion.SmartDetect");
|
|
33
32
|
this.hints.timeshift = this.hasFeature("Video.HKSV.TimeshiftBuffer");
|
|
34
33
|
this.hints.transcode = this.hasFeature("Video.Transcode");
|
|
35
34
|
this.hints.transcodeHighLatency = this.hasFeature("Video.Transcode.HighLatency");
|
|
@@ -67,8 +66,8 @@ export class ProtectCamera extends ProtectDevice {
|
|
|
67
66
|
if (this.hasFeature("Video.DynamicBitrate")) {
|
|
68
67
|
this.log.info("Dynamic streaming bitrate adjustment on the UniFi Protect controller enabled.");
|
|
69
68
|
}
|
|
70
|
-
//
|
|
71
|
-
if (this.
|
|
69
|
+
// Check to see if we have smart motion events enabled on a supported camera.
|
|
70
|
+
if (this.hints.smartDetect) {
|
|
72
71
|
// We deal with smart motion detection options here and save them on the ProtectCamera instance because
|
|
73
72
|
// we're trying to optimize and reduce the number of feature option lookups we do in realtime, when possible.
|
|
74
73
|
// Reading a stream of constant events and having to perform a string comparison through a list of options multiple
|
|
@@ -95,8 +94,6 @@ export class ProtectCamera extends ProtectDevice {
|
|
|
95
94
|
await this.configureVideoStream();
|
|
96
95
|
// Configure our snapshot updates.
|
|
97
96
|
void this.configureSnapshotUpdates();
|
|
98
|
-
// Configure our package camera.
|
|
99
|
-
this.configurePackageCamera();
|
|
100
97
|
// Configure our camera details.
|
|
101
98
|
this.configureCameraDetails();
|
|
102
99
|
// Configure our bitrate switch.
|
|
@@ -107,7 +104,7 @@ export class ProtectCamera extends ProtectDevice {
|
|
|
107
104
|
this.configureDoorbellTrigger();
|
|
108
105
|
// Listen for events.
|
|
109
106
|
this.nvr.events.on("updateEvent." + this.ufp.id, this.listeners["updateEvent." + this.ufp.id] = this.eventHandler.bind(this));
|
|
110
|
-
if (this.
|
|
107
|
+
if (this.hints.smartDetect) {
|
|
111
108
|
this.nvr.events.on("addEvent." + this.ufp.id, this.listeners["addEvent." + this.ufp.id] = this.smartMotionEventHandler.bind(this));
|
|
112
109
|
}
|
|
113
110
|
return true;
|
|
@@ -124,10 +121,6 @@ export class ProtectCamera extends ProtectDevice {
|
|
|
124
121
|
// Handle camera-related events.
|
|
125
122
|
eventHandler(packet) {
|
|
126
123
|
const payload = packet.payload;
|
|
127
|
-
// Update the package camera, if we have one.
|
|
128
|
-
if (this.packageCamera) {
|
|
129
|
-
this.packageCamera.ufp = Object.assign({}, this.ufp, { name: this.ufp.name + " Package Camera" });
|
|
130
|
-
}
|
|
131
124
|
// Process any RTSP stream updates.
|
|
132
125
|
if (payload.channels) {
|
|
133
126
|
void this.configureVideoStream();
|
|
@@ -146,9 +139,10 @@ export class ProtectCamera extends ProtectDevice {
|
|
|
146
139
|
this.nvr.events.doorbellEventHandler(this, payload.lastRing);
|
|
147
140
|
}
|
|
148
141
|
// Process camera details updates:
|
|
142
|
+
// - availability state.
|
|
149
143
|
// - camera status light.
|
|
150
144
|
// - camera recording settings.
|
|
151
|
-
if ((payload.ledSettings && ("isEnabled" in payload.ledSettings)) || (payload.recordingSettings && ("mode" in payload.recordingSettings))) {
|
|
145
|
+
if (payload.state || (payload.ledSettings && ("isEnabled" in payload.ledSettings)) || (payload.recordingSettings && ("mode" in payload.recordingSettings))) {
|
|
152
146
|
this.updateDevice();
|
|
153
147
|
}
|
|
154
148
|
}
|
|
@@ -341,7 +335,7 @@ export class ProtectCamera extends ProtectDevice {
|
|
|
341
335
|
// Enable RTSP on the camera if needed and get the list of RTSP streams we have ultimately configured.
|
|
342
336
|
this.ufp = await this.nvr.ufpApi.enableRtsp(this.ufp) ?? this.ufp;
|
|
343
337
|
// Figure out which camera channels are RTSP-enabled, and user-enabled.
|
|
344
|
-
|
|
338
|
+
let cameraChannels = this.ufp.channels.filter(x => x.isRtspEnabled && this.hasFeature("Video.Stream." + x.name));
|
|
345
339
|
// Make sure we've got a HomeKit compatible IDR frame interval. If not, let's take care of that.
|
|
346
340
|
let idrChannels = cameraChannels.filter(x => x.idrInterval !== PROTECT_HOMEKIT_IDR_INTERVAL);
|
|
347
341
|
if (idrChannels.length) {
|
|
@@ -355,6 +349,8 @@ export class ProtectCamera extends ProtectDevice {
|
|
|
355
349
|
// Set the camera and shapshot URLs.
|
|
356
350
|
const cameraUrl = "rtsps://" + (this.nvr.nvrOptions.overrideAddress ?? this.ufp.connectionHost) + ":" + this.nvr.ufp.ports.rtsps.toString() + "/";
|
|
357
351
|
this.snapshotUrl = this.nvr.ufpApi.getApiEndpoint(this.ufp.modelKey) + "/" + this.ufp.id + "/snapshot";
|
|
352
|
+
// Filter out any package camera entries.
|
|
353
|
+
cameraChannels = cameraChannels.filter(x => x.name !== "Package Camera");
|
|
358
354
|
// No RTSP streams are available that meet our criteria - we're done.
|
|
359
355
|
if (!cameraChannels.length) {
|
|
360
356
|
this.log.info("No RTSP stream profiles have been configured for this camera. " +
|
|
@@ -377,29 +373,45 @@ export class ProtectCamera extends ProtectDevice {
|
|
|
377
373
|
}
|
|
378
374
|
// Sort the list of resolutions, from high to low.
|
|
379
375
|
rtspEntries.sort(this.sortByResolutions.bind(this));
|
|
380
|
-
|
|
381
|
-
//
|
|
382
|
-
//
|
|
383
|
-
//
|
|
384
|
-
//
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
376
|
+
let validResolutions = [];
|
|
377
|
+
// Next, ensure we have mandatory resolutions required by HomeKit, as well as special support for Apple TV and Apple Watch, while respecting aspect ratios.
|
|
378
|
+
// We use the frame rate of the first entry, which should be our highest resolution option that's native to the camera as the upper bound for frame rate.
|
|
379
|
+
//
|
|
380
|
+
// Our supported resolutions range from 4K through 320p.
|
|
381
|
+
if ((rtspEntries[0].resolution[0] / rtspEntries[0].resolution[1]) === (16 / 9)) {
|
|
382
|
+
validResolutions = [
|
|
383
|
+
[3840, 2160, 30], [2560, 1440, 30],
|
|
384
|
+
[1920, 1080, 30], [1280, 720, 30],
|
|
385
|
+
[640, 360, 30], [480, 270, 30],
|
|
386
|
+
[320, 180, 30]
|
|
387
|
+
];
|
|
388
|
+
}
|
|
389
|
+
else {
|
|
390
|
+
validResolutions = [
|
|
391
|
+
[3840, 2880, 30], [2560, 1920, 30],
|
|
392
|
+
[1920, 1440, 30], [1280, 960, 30],
|
|
393
|
+
[640, 480, 30], [480, 360, 30],
|
|
394
|
+
[320, 240, 30]
|
|
395
|
+
];
|
|
396
|
+
}
|
|
397
|
+
// Validate and add our entries to the list of what we make available to HomeKit. We map these resolutions to the channels we have available to us on the camera.
|
|
398
|
+
for (const entry of validResolutions) {
|
|
399
|
+
// This resolution is larger than the highest resolution on the camera, natively. We make an exception for
|
|
400
|
+
// 1080p and 720p resolutions since HomeKit explicitly requires them.
|
|
401
|
+
if ((entry[0] >= rtspEntries[0].resolution[0]) && ![1920, 1280].includes(entry[0])) {
|
|
394
402
|
continue;
|
|
395
403
|
}
|
|
396
404
|
// Find the closest RTSP match for this resolution.
|
|
397
|
-
const foundRtsp = this.findRtsp(entry[0], entry[1],
|
|
405
|
+
const foundRtsp = this.findRtsp(entry[0], entry[1], rtspEntries);
|
|
398
406
|
if (!foundRtsp) {
|
|
399
407
|
continue;
|
|
400
408
|
}
|
|
401
|
-
//
|
|
402
|
-
rtspEntries.
|
|
409
|
+
// We already have this resolution in our list.
|
|
410
|
+
if (rtspEntries.some(x => (x.resolution[0] === entry[0]) && (x.resolution[1] === entry[1]) && (x.resolution[2] === foundRtsp.channel.fps))) {
|
|
411
|
+
continue;
|
|
412
|
+
}
|
|
413
|
+
// Add the resolution to the list of supported resolutions, but use the selected camera channel's native frame rate.
|
|
414
|
+
rtspEntries.push({ channel: foundRtsp.channel, name: foundRtsp.name, resolution: [entry[0], entry[1], foundRtsp.channel.fps], url: foundRtsp.url });
|
|
403
415
|
// Since we added resolutions to the list, resort resolutions, from high to low.
|
|
404
416
|
rtspEntries.sort(this.sortByResolutions.bind(this));
|
|
405
417
|
}
|
|
@@ -488,41 +500,11 @@ export class ProtectCamera extends ProtectDevice {
|
|
|
488
500
|
}
|
|
489
501
|
return true;
|
|
490
502
|
}
|
|
491
|
-
// Configure a package camera, if one exists.
|
|
492
|
-
configurePackageCamera() {
|
|
493
|
-
// First, confirm the device has a package camera.
|
|
494
|
-
if (!this.ufp.featureFlags.hasPackageCamera) {
|
|
495
|
-
return false;
|
|
496
|
-
}
|
|
497
|
-
// If we've already setup the package camera, we're done.
|
|
498
|
-
if (this.packageCamera) {
|
|
499
|
-
return true;
|
|
500
|
-
}
|
|
501
|
-
// Generate a UUID for the package camera.
|
|
502
|
-
const uuid = this.hap.uuid.generate(this.ufp.mac + ".PackageCamera");
|
|
503
|
-
// Let's find it if we've already created it.
|
|
504
|
-
let packageCameraAccessory = this.platform.accessories.find((x) => x.UUID === uuid) ?? null;
|
|
505
|
-
// We can't find the accessory. Let's create it.
|
|
506
|
-
if (!packageCameraAccessory) {
|
|
507
|
-
// We will use the NVR MAC address + ".NVRSystemInfo" to create our UUID. That should provide the guaranteed uniqueness we need.
|
|
508
|
-
packageCameraAccessory = new this.api.platformAccessory(this.accessory.displayName + " Package Camera", uuid);
|
|
509
|
-
if (!packageCameraAccessory) {
|
|
510
|
-
this.log.error("Unable to create the package camera accessory.");
|
|
511
|
-
return false;
|
|
512
|
-
}
|
|
513
|
-
// Register this accessory with homebridge and add it to the platform accessory array so we can track it.
|
|
514
|
-
this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [packageCameraAccessory]);
|
|
515
|
-
this.platform.accessories.push(packageCameraAccessory);
|
|
516
|
-
}
|
|
517
|
-
// Now create the package camera accessory. We do want to modify the camera name to ensure things look pretty.
|
|
518
|
-
this.packageCamera = new ProtectPackageCamera(this.nvr, Object.assign({}, this.ufp, { name: this.ufp.name + " Package Camera" }), packageCameraAccessory);
|
|
519
|
-
return true;
|
|
520
|
-
}
|
|
521
503
|
// Configure HomeKit Secure Video support.
|
|
522
504
|
configureHksv() {
|
|
523
505
|
this.hasHksv = true;
|
|
524
506
|
// If we have smart motion events enabled, let's warn the user that things will not work quite the way they expect.
|
|
525
|
-
if (this.
|
|
507
|
+
if (this.hints.smartDetect) {
|
|
526
508
|
this.log.info("WARNING: Smart motion detection and HomeKit Secure Video provide overlapping functionality. " +
|
|
527
509
|
"Only HomeKit Secure Video, when event recording is enabled in the Home app, will be used to trigger motion event notifications for this camera." +
|
|
528
510
|
(this.hasFeature("Motion.SmartDetect.ObjectSensors") ? " Smart motion contact sensors will continue to function using telemetry from UniFi Protect." : ""));
|
|
@@ -800,34 +782,11 @@ export class ProtectCamera extends ProtectDevice {
|
|
|
800
782
|
return true;
|
|
801
783
|
}
|
|
802
784
|
// Find an RTSP configuration for a given target resolution.
|
|
803
|
-
findRtspEntry(width, height,
|
|
785
|
+
findRtspEntry(width, height, rtspEntries, defaultStream = this.rtspQuality.StreamingDefault) {
|
|
804
786
|
// No RTSP entries to choose from, we're done.
|
|
805
787
|
if (!rtspEntries || !rtspEntries.length) {
|
|
806
788
|
return null;
|
|
807
789
|
}
|
|
808
|
-
// First, we check to see if we've set an explicit preference for the target address.
|
|
809
|
-
if (address) {
|
|
810
|
-
// If we don't have this address cached, look it up and cache it.
|
|
811
|
-
if (!this.rtspQuality[address]) {
|
|
812
|
-
// Check to see if there's an explicit preference set and cache the result.
|
|
813
|
-
if (this.hasFeature("Video.Stream.Only.Low", address, true)) {
|
|
814
|
-
this.rtspQuality[address] = "LOW";
|
|
815
|
-
}
|
|
816
|
-
else if (this.hasFeature("Video.Stream.Only.Medium", address, true)) {
|
|
817
|
-
this.rtspQuality[address] = "MEDIUM";
|
|
818
|
-
}
|
|
819
|
-
else if (this.hasFeature("Video.Stream.Only.High", address, true)) {
|
|
820
|
-
this.rtspQuality[address] = "HIGH";
|
|
821
|
-
}
|
|
822
|
-
else {
|
|
823
|
-
this.rtspQuality[address] = "None";
|
|
824
|
-
}
|
|
825
|
-
}
|
|
826
|
-
// If it's set to none, we default to our normal lookup logic.
|
|
827
|
-
if (this.rtspQuality[address] !== "None") {
|
|
828
|
-
return rtspEntries.find(x => x.channel.name.toUpperCase() === this.rtspQuality[address]) ?? null;
|
|
829
|
-
}
|
|
830
|
-
}
|
|
831
790
|
// Second, we check to see if we've set an explicit preference for stream quality.
|
|
832
791
|
if (defaultStream) {
|
|
833
792
|
defaultStream = defaultStream.toUpperCase();
|
|
@@ -853,16 +812,16 @@ export class ProtectCamera extends ProtectDevice {
|
|
|
853
812
|
return rtspEntries.find(x => width >= x.resolution[0]) ?? rtspEntries[rtspEntries.length - 1];
|
|
854
813
|
}
|
|
855
814
|
// Find a streaming RTSP configuration for a given target resolution.
|
|
856
|
-
findRtsp(width, height,
|
|
815
|
+
findRtsp(width, height, rtspEntries = this.rtspEntries, constrainPixels = 0) {
|
|
857
816
|
// If we've imposed a constraint on the maximum dimensions of what we want due to a hardware limitation, filter out those entries.
|
|
858
817
|
if (constrainPixels) {
|
|
859
818
|
rtspEntries = rtspEntries.filter(x => (x.channel.width * x.channel.height) <= constrainPixels);
|
|
860
819
|
}
|
|
861
|
-
return this.findRtspEntry(width, height,
|
|
820
|
+
return this.findRtspEntry(width, height, rtspEntries);
|
|
862
821
|
}
|
|
863
822
|
// Find a recording RTSP configuration for a given target resolution.
|
|
864
823
|
findRecordingRtsp(width, height, rtspEntries = this.rtspEntries) {
|
|
865
|
-
return this.findRtspEntry(width, height,
|
|
824
|
+
return this.findRtspEntry(width, height, rtspEntries, this.rtspQuality.RecordingDefault ?? this.stream.ffmpegOptions.recordingDefaultChannel);
|
|
866
825
|
}
|
|
867
826
|
// Utility function for sorting by resolution.
|
|
868
827
|
sortByResolutions(a, b) {
|
|
@@ -894,54 +853,4 @@ export class ProtectCamera extends ProtectDevice {
|
|
|
894
853
|
return resolution[0].toString() + "x" + resolution[1].toString() + "@" + resolution[2].toString() + "fps";
|
|
895
854
|
}
|
|
896
855
|
}
|
|
897
|
-
// Package camera class.
|
|
898
|
-
export class ProtectPackageCamera extends ProtectCamera {
|
|
899
|
-
// Configure the package camera.
|
|
900
|
-
async configureDevice() {
|
|
901
|
-
this.hints.probesize = 32768;
|
|
902
|
-
this.hasHksv = false;
|
|
903
|
-
// Clean out the context object in case it's been polluted somehow.
|
|
904
|
-
this.accessory.context = {};
|
|
905
|
-
// We explicitly avoid adding the MAC address of the camera - that's reserved for real Protect devices, not synthetic ones we create.
|
|
906
|
-
this.accessory.context.nvr = this.nvr.ufp.mac;
|
|
907
|
-
this.accessory.context.packageCamera = this.ufp.mac;
|
|
908
|
-
// Configure accessory information.
|
|
909
|
-
this.configureInfo();
|
|
910
|
-
// Set the snapshot URL.
|
|
911
|
-
this.snapshotUrl = this.nvr.ufpApi.getApiEndpoint(this.ufp.modelKey) + "/" + this.ufp.id + "/package-snapshot";
|
|
912
|
-
// Configure the video stream with our required resolutions. No, package cameras don't really support any of these resolutions, but they're required
|
|
913
|
-
// by HomeKit in order to stream video.
|
|
914
|
-
this.stream = new ProtectStreamingDelegate(this, [[3840, 2160, 30], [1920, 1080, 30], [1280, 960, 30], [1280, 720, 30], [1024, 768, 30], [640, 480, 30],
|
|
915
|
-
[640, 360, 30], [480, 360, 30], [480, 270, 30], [320, 240, 30], [320, 240, 15], [320, 180, 30]]);
|
|
916
|
-
// Fire up the controller and inform HomeKit about it.
|
|
917
|
-
this.accessory.configureController(this.stream.controller);
|
|
918
|
-
// Periodically refresh our snapshot cache.
|
|
919
|
-
void this.configureSnapshotUpdates();
|
|
920
|
-
// We're done.
|
|
921
|
-
return Promise.resolve(true);
|
|
922
|
-
}
|
|
923
|
-
// Make our RTSP stream findable.
|
|
924
|
-
findRtsp() {
|
|
925
|
-
const channel = this.ufp.channels.find(x => x.name === "Package Camera");
|
|
926
|
-
if (!channel) {
|
|
927
|
-
return null;
|
|
928
|
-
}
|
|
929
|
-
return {
|
|
930
|
-
channel: channel,
|
|
931
|
-
name: channel.name,
|
|
932
|
-
resolution: [channel.width, channel.height, channel.fps],
|
|
933
|
-
url: "rtsps://" + this.nvr.nvrOptions.address + ":" + this.nvr.ufp.ports.rtsps.toString() + "/" + channel.rtspAlias + "?enableSrtp"
|
|
934
|
-
};
|
|
935
|
-
}
|
|
936
|
-
// Get the current bitrate for a specific camera channel.
|
|
937
|
-
getBitrate(channelId) {
|
|
938
|
-
// Find the right channel.
|
|
939
|
-
const channel = this.ufp.channels.find(x => x.id === channelId);
|
|
940
|
-
return channel?.bitrate ?? -1;
|
|
941
|
-
}
|
|
942
|
-
// Set the bitrate for a specific camera channel.
|
|
943
|
-
setBitrate() {
|
|
944
|
-
return Promise.resolve(true);
|
|
945
|
-
}
|
|
946
|
-
}
|
|
947
856
|
//# sourceMappingURL=protect-camera.js.map
|