homebridge-unifi-protect 5.5.4 → 6.0.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.
Files changed (79) hide show
  1. package/README.md +3 -3
  2. package/config.schema.json +17 -16
  3. package/dist/index.d.ts +3 -0
  4. package/dist/index.js +6 -6
  5. package/dist/index.js.map +1 -1
  6. package/dist/protect-camera.d.ts +58 -0
  7. package/dist/protect-camera.js +367 -246
  8. package/dist/protect-camera.js.map +1 -1
  9. package/dist/protect-device.d.ts +48 -0
  10. package/dist/protect-device.js +189 -0
  11. package/dist/protect-device.js.map +1 -0
  12. package/dist/protect-doorbell.d.ts +22 -0
  13. package/dist/protect-doorbell.js +75 -64
  14. package/dist/protect-doorbell.js.map +1 -1
  15. package/dist/protect-ffmpeg-record.d.ts +15 -0
  16. package/dist/protect-ffmpeg-record.js +48 -34
  17. package/dist/protect-ffmpeg-record.js.map +1 -1
  18. package/dist/protect-ffmpeg-stream.d.ts +15 -0
  19. package/dist/protect-ffmpeg-stream.js +22 -12
  20. package/dist/protect-ffmpeg-stream.js.map +1 -1
  21. package/dist/protect-ffmpeg.d.ts +42 -0
  22. package/dist/protect-ffmpeg.js +49 -58
  23. package/dist/protect-ffmpeg.js.map +1 -1
  24. package/dist/protect-light.d.ts +13 -0
  25. package/dist/protect-light.js +63 -40
  26. package/dist/protect-light.js.map +1 -1
  27. package/dist/protect-liveviews.d.ts +17 -0
  28. package/dist/protect-liveviews.js +117 -101
  29. package/dist/protect-liveviews.js.map +1 -1
  30. package/dist/protect-mqtt.d.ts +19 -0
  31. package/dist/protect-mqtt.js +26 -35
  32. package/dist/protect-mqtt.js.map +1 -1
  33. package/dist/protect-nvr-events.d.ts +30 -0
  34. package/dist/protect-nvr-events.js +168 -431
  35. package/dist/protect-nvr-events.js.map +1 -1
  36. package/dist/protect-nvr-systeminfo.d.ts +15 -0
  37. package/dist/protect-nvr-systeminfo.js +43 -49
  38. package/dist/protect-nvr-systeminfo.js.map +1 -1
  39. package/dist/protect-nvr.d.ts +48 -0
  40. package/dist/protect-nvr.js +327 -359
  41. package/dist/protect-nvr.js.map +1 -1
  42. package/dist/protect-options.d.ts +39 -0
  43. package/dist/protect-options.js +172 -6
  44. package/dist/protect-options.js.map +1 -1
  45. package/dist/protect-platform.d.ts +17 -0
  46. package/dist/protect-platform.js +17 -30
  47. package/dist/protect-platform.js.map +1 -1
  48. package/dist/protect-record.d.ts +33 -0
  49. package/dist/protect-record.js +130 -126
  50. package/dist/protect-record.js.map +1 -1
  51. package/dist/protect-rtp.d.ts +29 -0
  52. package/dist/protect-rtp.js +133 -16
  53. package/dist/protect-rtp.js.map +1 -1
  54. package/dist/protect-securitysystem.d.ts +18 -0
  55. package/dist/protect-securitysystem.js +105 -109
  56. package/dist/protect-securitysystem.js.map +1 -1
  57. package/dist/protect-sensor.d.ts +28 -0
  58. package/dist/protect-sensor.js +79 -97
  59. package/dist/protect-sensor.js.map +1 -1
  60. package/dist/protect-stream.d.ts +41 -0
  61. package/dist/protect-stream.js +298 -156
  62. package/dist/protect-stream.js.map +1 -1
  63. package/dist/protect-timeshift.d.ts +30 -0
  64. package/dist/protect-timeshift.js +65 -48
  65. package/dist/protect-timeshift.js.map +1 -1
  66. package/dist/protect-types.d.ts +50 -0
  67. package/dist/protect-types.js +22 -0
  68. package/dist/protect-types.js.map +1 -0
  69. package/dist/protect-viewer.d.ts +17 -0
  70. package/dist/protect-viewer.js +41 -47
  71. package/dist/protect-viewer.js.map +1 -1
  72. package/dist/settings.d.ts +22 -0
  73. package/dist/settings.js +30 -35
  74. package/dist/settings.js.map +1 -1
  75. package/homebridge-ui/public/index.html +715 -0
  76. package/homebridge-ui/server.js +156 -0
  77. package/package.json +14 -15
  78. package/dist/protect-accessory.js +0 -184
  79. package/dist/protect-accessory.js.map +0 -1
@@ -1,66 +1,74 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ProtectCamera = void 0;
4
- /* Copyright(C) 2019-2022, HJD (https://github.com/hjdhjd). All rights reserved.
5
- *
6
- * protect-camera.ts: Camera device class for UniFi Protect.
7
- */
8
- const protect_accessory_1 = require("./protect-accessory");
9
- const settings_1 = require("./settings");
10
- const protect_stream_1 = require("./protect-stream");
11
- class ProtectCamera extends protect_accessory_1.ProtectAccessory {
12
- // Configure a camera accessory for HomeKit.
13
- async configureDevice() {
14
- var _a, _b, _c;
1
+ import { PLATFORM_NAME, PLUGIN_NAME, PROTECT_HOMEKIT_IDR_INTERVAL, PROTECT_SNAPSHOT_CACHE_REFRESH_INTERVAL } from "./settings.js";
2
+ import { ProtectDevice } from "./protect-device.js";
3
+ import { ProtectReservedNames } from "./protect-types.js";
4
+ import { ProtectStreamingDelegate } from "./protect-stream.js";
5
+ export class ProtectCamera extends ProtectDevice {
6
+ // Create an instance.
7
+ constructor(nvr, device, accessory) {
8
+ super(nvr, accessory);
15
9
  this.isDoorbellConfigured = false;
16
- this.isHksv = false;
10
+ this.hasHksv = false;
11
+ this.hasHwAccel = false;
12
+ this.isDeleted = false;
17
13
  this.isRinging = false;
18
14
  this.isVideoConfigured = false;
15
+ this.packageCamera = null;
16
+ this.rtspEntries = [];
19
17
  this.rtspQuality = {};
20
- this.smartDetectTypes = [];
21
- // Save the device object before we wipeout the context.
22
- const device = this.accessory.context.device;
23
- // Default to enabling camera motion detection.
24
- let detectMotion = true;
25
- // Save the motion sensor switch state before we wipeout the context.
26
- if (this.accessory.context.detectMotion !== undefined) {
27
- detectMotion = this.accessory.context.detectMotion;
28
- }
18
+ this.ufp = device;
19
+ this.configureHints();
20
+ void this.configureDevice();
21
+ }
22
+ // Configure device-specific settings for this device.
23
+ configureHints() {
24
+ // Configure our parent's hints.
25
+ super.configureHints();
26
+ // Configure our device-class specific hints.
27
+ this.hints.hardwareTranscoding = this.nvr.optionEnabled(this.ufp, "Video.Transcode.Hardware", false);
28
+ this.hints.ledStatus = this.ufp.featureFlags.hasLedStatus && this.nvr.optionEnabled(this.ufp, "Device.StatusLed", false);
29
+ this.hints.logDoorbell = this.nvr.optionEnabled(this.ufp, "Log.Doorbell", false);
30
+ this.hints.logHksv = this.nvr.optionEnabled(this.ufp, "Log.HKSV");
31
+ this.hints.probesize = 16384;
32
+ this.hints.timeshift = this.nvr.optionEnabled(this.ufp, "Video.HKSV.TimeshiftBuffer");
33
+ this.hints.transcode = this.nvr.optionEnabled(this.ufp, "Video.Transcode", false);
34
+ this.hints.transcodeHighLatency = this.nvr.optionEnabled(this.ufp, "Video.Transcode.HighLatency");
35
+ this.hints.twoWayAudio = this.ufp.hasSpeaker && this.nvr.optionEnabled(this.ufp, "Audio") && this.nvr.optionEnabled(this.ufp, "Audio.TwoWay");
36
+ return true;
37
+ }
38
+ // Configure a camera accessory for HomeKit.
39
+ async configureDevice() {
29
40
  // Default to disabling the dynamic bitrate setting.
30
41
  let dynamicBitrate = false;
31
42
  // Save the dynamic bitrate switch state before we wipeout the context.
32
- if (this.accessory.context.dynamicBitrate !== undefined) {
43
+ if ("dynamicBitrate" in this.accessory.context) {
33
44
  dynamicBitrate = this.accessory.context.dynamicBitrate;
34
45
  }
35
46
  // Default to enabling HKSV recording.
36
47
  let hksvRecording = true;
37
48
  // Save the HKSV recording switch state before we wipeout the context.
38
- if (this.accessory.context.hksvRecording !== undefined) {
49
+ if ("hksvRecording" in this.accessory.context) {
39
50
  hksvRecording = this.accessory.context.hksvRecording;
40
51
  }
41
52
  // Clean out the context object in case it's been polluted somehow.
42
53
  this.accessory.context = {};
43
- this.accessory.context.device = device;
44
- this.accessory.context.nvr = (_a = this.nvr.nvrApi.bootstrap) === null || _a === void 0 ? void 0 : _a.nvr.mac;
45
- this.accessory.context.detectMotion = detectMotion;
46
54
  this.accessory.context.dynamicBitrate = dynamicBitrate;
47
55
  this.accessory.context.hksvRecording = hksvRecording;
56
+ this.accessory.context.mac = this.ufp.mac;
57
+ this.accessory.context.nvr = this.nvr.ufp.mac;
48
58
  // Inform the user if we have enabled the dynamic bitrate setting.
49
- if ((_b = this.nvr) === null || _b === void 0 ? void 0 : _b.optionEnabled(this.accessory.context.device, "Video.DynamicBitrate", false)) {
50
- this.log.info("%s: Dynamic streaming bitrate adjustment on the UniFi Protect controller enabled.", this.name());
59
+ if (this.nvr.optionEnabled(this.ufp, "Video.DynamicBitrate", false)) {
60
+ this.log.info("Dynamic streaming bitrate adjustment on the UniFi Protect controller enabled.");
51
61
  }
52
62
  // If the camera supports it, check to see if we have smart motion events enabled.
53
- if (device.featureFlags.hasSmartDetect && ((_c = this.nvr) === null || _c === void 0 ? void 0 : _c.optionEnabled(device, "Motion.SmartDetect", false))) {
63
+ if (this.ufp.featureFlags.hasSmartDetect && this.nvr.optionEnabled(this.ufp, "Motion.SmartDetect", false)) {
54
64
  // We deal with smart motion detection options here and save them on the ProtectCamera instance because
55
65
  // we're trying to optimize and reduce the number of feature option lookups we do in realtime, when possible.
56
66
  // Reading a stream of constant events and having to perform a string comparison through a list of options multiple
57
67
  // times a second isn't an ideal use of CPU cycles, even if you have plenty of them to spare. Instead, we perform
58
68
  // that lookup once, here, and set the appropriate option booleans for faster lookup and use later in event
59
69
  // detection.
60
- // Check for the smart motion detection object types that UniFi Protect supports.
61
- this.smartDetectTypes = device.featureFlags.smartDetectTypes.filter(x => { var _a; return (_a = this.nvr) === null || _a === void 0 ? void 0 : _a.optionEnabled(device, "Motion.SmartDetect." + x); });
62
70
  // Inform the user of what smart detection object types we're configured for.
63
- this.log.info("%s: Smart motion detection enabled%s.", this.name(), this.smartDetectTypes.length ? ": " + this.smartDetectTypes.join(", ") : "");
71
+ this.log.info("Smart motion detection enabled%s.", this.ufp.featureFlags.smartDetectTypes.length ? ": " + this.ufp.featureFlags.smartDetectTypes.join(", ") : "");
64
72
  }
65
73
  // Configure accessory information.
66
74
  this.configureInfo();
@@ -72,13 +80,15 @@ class ProtectCamera extends protect_accessory_1.ProtectAccessory {
72
80
  this.configureMotionTrigger();
73
81
  // Configure smart motion contact sensors.
74
82
  this.configureMotionSmartSensor();
75
- // Configure two-way audio support.
76
- this.configureTwoWayAudio();
77
83
  // Configure HomeKit Secure Video suport.
78
84
  this.configureHksv();
79
85
  this.configureHksvRecordingSwitch();
80
86
  // Configure our video stream.
81
87
  await this.configureVideoStream();
88
+ // Configure our snapshot updates.
89
+ void this.configureSnapshotUpdates();
90
+ // Configure our package camera.
91
+ this.configurePackageCamera();
82
92
  // Configure our camera details.
83
93
  this.configureCameraDetails();
84
94
  // Configure our bitrate switch.
@@ -87,41 +97,88 @@ class ProtectCamera extends protect_accessory_1.ProtectAccessory {
87
97
  this.configureNvrRecordingSwitch();
88
98
  // Configure the doorbell trigger.
89
99
  this.configureDoorbellTrigger();
100
+ // Listen for events.
101
+ this.nvr.events.on("updateEvent." + this.ufp.id, this.listeners["updateEvent." + this.ufp.id] = this.eventHandler.bind(this));
102
+ if (this.ufp.featureFlags.hasSmartDetect && this.nvr.optionEnabled(this.ufp, "Motion.SmartDetect", false)) {
103
+ this.nvr.events.on("addEvent." + this.ufp.id, this.listeners["addEvent." + this.ufp.id] = this.smartMotionEventHandler.bind(this));
104
+ }
90
105
  return true;
91
106
  }
107
+ // Cleanup after ourselves if we're being deleted.
108
+ cleanup() {
109
+ super.cleanup();
110
+ this.isDeleted = true;
111
+ }
112
+ // Handle camera-related events.
113
+ eventHandler(packet) {
114
+ const payload = packet.payload;
115
+ // Update the package camera, if we have one.
116
+ if (this.packageCamera) {
117
+ this.packageCamera.ufp = Object.assign({}, this.ufp, { name: this.ufp.name + " Package Camera" });
118
+ }
119
+ // Process any RTSP stream updates.
120
+ if (payload.channels) {
121
+ void this.configureVideoStream();
122
+ }
123
+ // Process motion events.
124
+ if (payload.isMotionDetected && payload.lastMotion) {
125
+ // We only want to process the motion event if we have the right payload, and either HKSV recording is enabled, or
126
+ // HKSV recording is disabled and we have smart motion events disabled since We handle those elsewhere.
127
+ if (this.stream.hksv?.isRecording || (!this.stream.hksv?.isRecording && !this.ufp.featureFlags.smartDetectTypes.length)) {
128
+ this.nvr.events.motionEventHandler(this, payload.lastMotion);
129
+ }
130
+ }
131
+ // Process ring events.
132
+ if (payload.lastRing) {
133
+ this.nvr.events.doorbellEventHandler(this, payload.lastRing);
134
+ }
135
+ // Process camera details updates:
136
+ // - camera status light.
137
+ // - camera recording settings.
138
+ if ((payload.ledSettings && ("isEnabled" in payload.ledSettings)) || (payload.recordingSettings && ("mode" in payload.recordingSettings))) {
139
+ this.updateDevice();
140
+ }
141
+ }
142
+ // Handle smart motion detection events.
143
+ smartMotionEventHandler(packet) {
144
+ const payload = packet.payload;
145
+ // We're only interested in smart motion detection events.
146
+ if ((packet.header.modelKey !== "event") || (payload.type !== "smartDetectZone") || !payload.smartDetectTypes.length) {
147
+ return;
148
+ }
149
+ // Process the motion event.
150
+ this.nvr.events.motionEventHandler(this, payload.start, payload.smartDetectTypes);
151
+ }
92
152
  // Configure discrete smart motion contact sensors for HomeKit.
93
153
  configureMotionSmartSensor() {
94
- var _a, _b, _c, _d, _e, _f;
95
- const device = this.accessory.context.device;
154
+ // If we don't have smart motion detection, we're done.
155
+ if (!this.ufp.featureFlags.hasSmartDetect) {
156
+ return false;
157
+ }
96
158
  // Check for object-centric contact sensors that are no longer enabled and remove them.
97
- for (const objectService of this.accessory.services.filter(x => { var _a; return (_a = x.subtype) === null || _a === void 0 ? void 0 : _a.startsWith(protect_accessory_1.ProtectReservedNames.CONTACT_MOTION_SMARTDETECT + "."); })) {
159
+ for (const objectService of this.accessory.services.filter(x => x.subtype?.startsWith(ProtectReservedNames.CONTACT_MOTION_SMARTDETECT + "."))) {
98
160
  // If we have motion sensors as well as object contact sensors enabled, and we have this object type enabled on this camera, we're good here.
99
- if (((_a = this.nvr) === null || _a === void 0 ? void 0 : _a.optionEnabled(device, "Motion.Sensor")) &&
100
- ((_b = this.nvr) === null || _b === void 0 ? void 0 : _b.optionEnabled(device, "Motion.SmartDetect.ObjectSensors", false))) {
161
+ if (this.nvr.optionEnabled(this.ufp, "Motion.SmartDetect.ObjectSensors", false)) {
101
162
  continue;
102
163
  }
103
164
  // We don't have this contact sensor enabled, remove it.
104
165
  this.accessory.removeService(objectService);
105
- this.log.info("%s: Disabling smart motion contact sensor: %s.", this.name(), (_c = objectService.subtype) === null || _c === void 0 ? void 0 : _c.slice(((_d = objectService.subtype) === null || _d === void 0 ? void 0 : _d.indexOf(".")) + 1));
106
- }
107
- // Have we disabled motion sensors? If so, we're done.
108
- if (!((_e = this.nvr) === null || _e === void 0 ? void 0 : _e.optionEnabled(device, "Motion.Sensor"))) {
109
- return false;
166
+ this.log.info("Disabling smart motion contact sensor: %s.", objectService.subtype?.slice(objectService.subtype?.indexOf(".") + 1));
110
167
  }
111
168
  // Have we enabled discrete contact sensors for specific object types? If not, we're done here.
112
- if (!((_f = this.nvr) === null || _f === void 0 ? void 0 : _f.optionEnabled(device, "Motion.SmartDetect.ObjectSensors", false))) {
169
+ if (!this.nvr.optionEnabled(this.ufp, "Motion.SmartDetect.ObjectSensors", false)) {
113
170
  return false;
114
171
  }
115
172
  // Add individual contact sensors for each object detection type, if needed.
116
- for (const smartDetectType of device.featureFlags.smartDetectTypes) {
173
+ for (const smartDetectType of this.ufp.featureFlags.smartDetectTypes) {
117
174
  // See if we already have this contact sensor configured.
118
- let contactService = this.accessory.getServiceById(this.hap.Service.ContactSensor, protect_accessory_1.ProtectReservedNames.CONTACT_MOTION_SMARTDETECT + "." + smartDetectType);
175
+ let contactService = this.accessory.getServiceById(this.hap.Service.ContactSensor, ProtectReservedNames.CONTACT_MOTION_SMARTDETECT + "." + smartDetectType);
119
176
  // If not, let's add it.
120
177
  if (!contactService) {
121
- contactService = new this.hap.Service.ContactSensor(this.accessory.displayName + " " + smartDetectType.charAt(0).toUpperCase() + smartDetectType.slice(1), protect_accessory_1.ProtectReservedNames.CONTACT_MOTION_SMARTDETECT + "." + smartDetectType);
178
+ contactService = new this.hap.Service.ContactSensor(this.accessory.displayName + " " + smartDetectType.charAt(0).toUpperCase() + smartDetectType.slice(1), ProtectReservedNames.CONTACT_MOTION_SMARTDETECT + "." + smartDetectType);
122
179
  // Something went wrong, we're done here.
123
180
  if (!contactService) {
124
- this.log.error("%s: Unable to add smart motion contact sensor for %s detection.", this.name(), smartDetectType);
181
+ this.log.error("Unable to add smart motion contact sensor for %s detection.", smartDetectType);
125
182
  return false;
126
183
  }
127
184
  // Finally, add it to the camera.
@@ -130,17 +187,15 @@ class ProtectCamera extends protect_accessory_1.ProtectAccessory {
130
187
  // Initialize the sensor.
131
188
  contactService.updateCharacteristic(this.hap.Characteristic.ContactSensorState, false);
132
189
  }
133
- this.log.info("%s: Smart motion contact sensor%s enabled: %s.", this.name(), device.featureFlags.smartDetectTypes.length > 1 ? "s" : "", device.featureFlags.smartDetectTypes.join(", "));
190
+ this.log.info("Smart motion contact sensor%s enabled: %s.", this.ufp.featureFlags.smartDetectTypes.length > 1 ? "s" : "", this.ufp.featureFlags.smartDetectTypes.join(", "));
134
191
  return true;
135
192
  }
136
193
  // Configure a switch to manually trigger a motion sensor event for HomeKit.
137
194
  configureMotionTrigger() {
138
- var _a, _b, _c;
139
195
  // Find the switch service, if it exists.
140
- let triggerService = this.accessory.getServiceById(this.hap.Service.Switch, protect_accessory_1.ProtectReservedNames.SWITCH_MOTION_TRIGGER);
196
+ let triggerService = this.accessory.getServiceById(this.hap.Service.Switch, ProtectReservedNames.SWITCH_MOTION_TRIGGER);
141
197
  // Motion triggers are disabled by default and primarily exist for automation purposes.
142
- if (!((_a = this.nvr) === null || _a === void 0 ? void 0 : _a.optionEnabled(this.accessory.context.device, "Motion.Sensor")) ||
143
- !((_b = this.nvr) === null || _b === void 0 ? void 0 : _b.optionEnabled(this.accessory.context.device, "Motion.Trigger", false))) {
198
+ if (!this.nvr.optionEnabled(this.ufp, "Motion.Trigger", false)) {
144
199
  if (triggerService) {
145
200
  this.accessory.removeService(triggerService);
146
201
  }
@@ -148,63 +203,63 @@ class ProtectCamera extends protect_accessory_1.ProtectAccessory {
148
203
  }
149
204
  // Add the switch to the camera, if needed.
150
205
  if (!triggerService) {
151
- triggerService = new this.hap.Service.Switch(this.accessory.displayName + " Motion Trigger", protect_accessory_1.ProtectReservedNames.SWITCH_MOTION_TRIGGER);
206
+ triggerService = new this.hap.Service.Switch(this.accessory.displayName + " Motion Trigger", ProtectReservedNames.SWITCH_MOTION_TRIGGER);
152
207
  if (!triggerService) {
153
- this.log.error("%s: Unable to add motion sensor trigger.", this.name());
208
+ this.log.error("Unable to add motion sensor trigger.");
154
209
  return false;
155
210
  }
156
211
  this.accessory.addService(triggerService);
157
212
  }
158
213
  const motionService = this.accessory.getService(this.hap.Service.MotionSensor);
159
- const switchService = this.accessory.getServiceById(this.hap.Service.Switch, protect_accessory_1.ProtectReservedNames.SWITCH_MOTION_SENSOR);
214
+ const switchService = this.accessory.getServiceById(this.hap.Service.Switch, ProtectReservedNames.SWITCH_MOTION_SENSOR);
160
215
  // Activate or deactivate motion detection.
161
- (_c = triggerService
162
- .getCharacteristic(this.hap.Characteristic.On)) === null || _c === void 0 ? void 0 : _c.onGet(() => {
163
- return (motionService === null || motionService === void 0 ? void 0 : motionService.getCharacteristic(this.hap.Characteristic.MotionDetected).value) === true;
164
- }).onSet((value) => {
216
+ triggerService
217
+ .getCharacteristic(this.hap.Characteristic.On)
218
+ ?.onGet(() => {
219
+ return motionService?.getCharacteristic(this.hap.Characteristic.MotionDetected).value === true;
220
+ })
221
+ .onSet((value) => {
165
222
  if (value) {
166
223
  // Check to see if motion events are disabled.
167
224
  if (switchService && !switchService.getCharacteristic(this.hap.Characteristic.On).value) {
168
225
  setTimeout(() => {
169
- triggerService === null || triggerService === void 0 ? void 0 : triggerService.updateCharacteristic(this.hap.Characteristic.On, false);
226
+ triggerService?.updateCharacteristic(this.hap.Characteristic.On, false);
170
227
  }, 50);
171
228
  }
172
229
  else {
173
230
  // Trigger the motion event.
174
- this.nvr.events.motionEventHandler(this.accessory, Date.now());
175
- this.log.info("%s: Motion event triggered.", this.name());
231
+ this.nvr.events.motionEventHandler(this, Date.now());
232
+ this.log.info("Motion event triggered.");
176
233
  }
177
234
  }
178
235
  else {
179
236
  // If the motion sensor is still on, we should be as well.
180
- if (motionService === null || motionService === void 0 ? void 0 : motionService.getCharacteristic(this.hap.Characteristic.MotionDetected).value) {
237
+ if (motionService?.getCharacteristic(this.hap.Characteristic.MotionDetected).value) {
181
238
  setTimeout(() => {
182
- triggerService === null || triggerService === void 0 ? void 0 : triggerService.updateCharacteristic(this.hap.Characteristic.On, true);
239
+ triggerService?.updateCharacteristic(this.hap.Characteristic.On, true);
183
240
  }, 50);
184
241
  }
185
242
  }
186
243
  });
187
244
  // Initialize the switch.
188
245
  triggerService.updateCharacteristic(this.hap.Characteristic.On, false);
189
- this.log.info("%s: Enabling motion sensor automation trigger.", this.name());
246
+ this.log.info("Enabling motion sensor automation trigger.");
190
247
  return true;
191
248
  }
192
249
  // Configure a switch to manually trigger a doorbell ring event for HomeKit.
193
250
  configureDoorbellTrigger() {
194
- var _a, _b;
195
- const camera = this.accessory.context.device;
196
251
  // Find the switch service, if it exists.
197
- let triggerService = this.accessory.getServiceById(this.hap.Service.Switch, protect_accessory_1.ProtectReservedNames.SWITCH_DOORBELL_TRIGGER);
252
+ let triggerService = this.accessory.getServiceById(this.hap.Service.Switch, ProtectReservedNames.SWITCH_DOORBELL_TRIGGER);
198
253
  // See if we have a doorbell service configured.
199
254
  let doorbellService = this.accessory.getService(this.hap.Service.Doorbell);
200
255
  // Doorbell switches are disabled by default and primarily exist for automation purposes.
201
- if (!((_a = this.nvr) === null || _a === void 0 ? void 0 : _a.optionEnabled(this.accessory.context.device, "Doorbell.Trigger", false))) {
256
+ if (!this.nvr.optionEnabled(this.ufp, "Doorbell.Trigger", false)) {
202
257
  if (triggerService) {
203
258
  this.accessory.removeService(triggerService);
204
259
  }
205
260
  // Since we aren't enabling the doorbell trigger on this camera, remove the doorbell service if the camera
206
261
  // isn't actually doorbell-capable hardware.
207
- if (!camera.featureFlags.hasChime && doorbellService) {
262
+ if (!this.ufp.featureFlags.hasChime && doorbellService) {
208
263
  this.accessory.removeService(doorbellService);
209
264
  }
210
265
  return false;
@@ -218,41 +273,43 @@ class ProtectCamera extends protect_accessory_1.ProtectAccessory {
218
273
  }
219
274
  // Now find the doorbell service.
220
275
  if (!(doorbellService = this.accessory.getService(this.hap.Service.Doorbell))) {
221
- this.log.error("%s: Unable to find the doorbell service.", this.name());
276
+ this.log.error("Unable to find the doorbell service.");
222
277
  return false;
223
278
  }
224
279
  }
225
280
  // Add the switch to the camera, if needed.
226
281
  if (!triggerService) {
227
- triggerService = new this.hap.Service.Switch(this.accessory.displayName + " Doorbell Trigger", protect_accessory_1.ProtectReservedNames.SWITCH_DOORBELL_TRIGGER);
282
+ triggerService = new this.hap.Service.Switch(this.accessory.displayName + " Doorbell Trigger", ProtectReservedNames.SWITCH_DOORBELL_TRIGGER);
228
283
  if (!triggerService) {
229
- this.log.error("%s: Unable to add the doorbell trigger.", this.name());
284
+ this.log.error("Unable to add the doorbell trigger.");
230
285
  return false;
231
286
  }
232
287
  this.accessory.addService(triggerService);
233
288
  }
234
289
  // Trigger the doorbell.
235
- (_b = triggerService
236
- .getCharacteristic(this.hap.Characteristic.On)) === null || _b === void 0 ? void 0 : _b.onGet(() => {
290
+ triggerService
291
+ .getCharacteristic(this.hap.Characteristic.On)
292
+ ?.onGet(() => {
237
293
  return this.isRinging;
238
- }).onSet((value) => {
294
+ })
295
+ .onSet((value) => {
239
296
  if (value) {
240
297
  // Trigger the motion event.
241
- this.nvr.events.doorbellEventHandler(this.accessory, Date.now());
242
- this.log.info("%s: Doorbell ring event triggered.", this.name());
298
+ this.nvr.events.doorbellEventHandler(this, Date.now());
299
+ this.log.info("Doorbell ring event triggered.");
243
300
  }
244
301
  else {
245
302
  // If the doorbell ring event is still going, we should be as well.
246
303
  if (this.isRinging) {
247
304
  setTimeout(() => {
248
- triggerService === null || triggerService === void 0 ? void 0 : triggerService.updateCharacteristic(this.hap.Characteristic.On, true);
305
+ triggerService?.updateCharacteristic(this.hap.Characteristic.On, true);
249
306
  }, 50);
250
307
  }
251
308
  }
252
309
  });
253
310
  // Initialize the switch.
254
311
  triggerService.updateCharacteristic(this.hap.Characteristic.On, false);
255
- this.log.info("%s: Enabling doorbell automation trigger.", this.name());
312
+ this.log.info("Enabling doorbell automation trigger.");
256
313
  return true;
257
314
  }
258
315
  // Configure the doorbell service for HomeKit.
@@ -268,7 +325,7 @@ class ProtectCamera extends protect_accessory_1.ProtectAccessory {
268
325
  if (!doorbellService) {
269
326
  doorbellService = new this.hap.Service.Doorbell(this.accessory.displayName);
270
327
  if (!doorbellService) {
271
- this.log.error("%s: Unable to add doorbell.", this.name());
328
+ this.log.error("Unable to add doorbell.");
272
329
  return false;
273
330
  }
274
331
  this.accessory.addService(doorbellService);
@@ -277,78 +334,68 @@ class ProtectCamera extends protect_accessory_1.ProtectAccessory {
277
334
  this.isDoorbellConfigured = true;
278
335
  return true;
279
336
  }
280
- // Configure two-way audio support for HomeKit.
281
- configureTwoWayAudio() {
282
- var _a, _b;
283
- // Identify twoway-capable devices.
284
- if (!this.accessory.context.device.hasSpeaker) {
285
- return this.twoWayAudio = false;
286
- }
287
- // Enabled by default unless disabled by the user.
288
- return this.twoWayAudio = ((_a = this.nvr) === null || _a === void 0 ? void 0 : _a.optionEnabled(this.accessory.context.device, "Audio")) &&
289
- ((_b = this.nvr) === null || _b === void 0 ? void 0 : _b.optionEnabled(this.accessory.context.device, "Audio.TwoWay"));
290
- }
291
337
  // Configure additional camera-specific characteristics for HomeKit.
292
338
  configureCameraDetails() {
293
- var _a;
294
339
  // Find the service, if it exists.
295
- const service = this.accessory.getService(this.hap.Service.CameraOperatingMode);
296
- // Grab our device context.
297
- const device = this.accessory.context.device;
298
- // Turn the status light on or off.
299
- if (device.featureFlags.hasLedStatus) {
300
- (_a = service === null || service === void 0 ? void 0 : service.getCharacteristic(this.hap.Characteristic.CameraOperatingModeIndicator)) === null || _a === void 0 ? void 0 : _a.onGet(() => {
301
- var _a;
302
- return ((_a = this.accessory.context.device.ledSettings) === null || _a === void 0 ? void 0 : _a.isEnabled) === true;
303
- }).onSet(async (value) => {
340
+ const statusLedService = this.accessory.getService(this.hap.Service.CameraOperatingMode);
341
+ // Have we enabled the camera status LED?
342
+ if (this.hints.ledStatus && statusLedService) {
343
+ // Turn the status light on or off.
344
+ statusLedService.getCharacteristic(this.hap.Characteristic.CameraOperatingModeIndicator)
345
+ ?.onGet(() => {
346
+ return this.ufp.ledSettings?.isEnabled === true;
347
+ })
348
+ .onSet(async (value) => {
304
349
  const ledState = value === true;
305
350
  // Update the status light in Protect.
306
- const newDevice = await this.nvr.nvrApi.updateCamera(this.accessory.context.device, { ledSettings: { isEnabled: ledState } });
351
+ const newDevice = await this.nvr.ufpApi.updateDevice(this.ufp, { ledSettings: { isEnabled: ledState } });
307
352
  if (!newDevice) {
308
- this.log.error("%s: Unable to turn the status light %s. Please ensure this username has the Administrator role in UniFi Protect.", this.name(), ledState ? "on" : "off");
353
+ this.log.error("Unable to turn the status light %s. Please ensure this username has the Administrator role in UniFi Protect.", ledState ? "on" : "off");
309
354
  return;
310
355
  }
311
- // Set the context to our updated device configuration.
312
- this.accessory.context.device = newDevice;
356
+ // Update our internal view of the device configuration.
357
+ this.ufp = newDevice;
313
358
  });
314
359
  // Initialize the status light state.
315
- service === null || service === void 0 ? void 0 : service.updateCharacteristic(this.hap.Characteristic.CameraOperatingModeIndicator, device.ledSettings.isEnabled === true);
360
+ statusLedService.updateCharacteristic(this.hap.Characteristic.CameraOperatingModeIndicator, this.ufp.ledSettings.isEnabled === true);
361
+ }
362
+ else if (statusLedService) {
363
+ // Remove the camera status light if we have it.
364
+ const statusLight = statusLedService.getCharacteristic(this.hap.Characteristic.CameraOperatingModeIndicator);
365
+ if (statusLight) {
366
+ statusLedService.removeCharacteristic(statusLight);
367
+ }
316
368
  }
317
369
  return true;
318
370
  }
319
371
  // Configure a camera accessory for HomeKit.
320
372
  async configureVideoStream() {
321
- var _a, _b;
322
- const bootstrap = this.nvr.nvrApi.bootstrap;
323
- let device = this.accessory.context.device;
324
- const nvr = this.nvr;
325
- const nvrApi = this.nvr.nvrApi;
326
373
  const rtspEntries = [];
327
374
  // No channels exist on this camera or we don't have access to the bootstrap configuration.
328
- if (!(device === null || device === void 0 ? void 0 : device.channels) || !bootstrap) {
375
+ if (!this.ufp.channels) {
329
376
  return false;
330
377
  }
331
378
  // Enable RTSP on the camera if needed and get the list of RTSP streams we have ultimately configured.
332
- device = (_a = await nvrApi.enableRtsp(device)) !== null && _a !== void 0 ? _a : device;
379
+ this.ufp = await this.nvr.ufpApi.enableRtsp(this.ufp) ?? this.ufp;
333
380
  // Figure out which camera channels are RTSP-enabled, and user-enabled.
334
- const cameraChannels = device.channels.filter(x => x.isRtspEnabled && nvr.optionEnabled(device, "Video.Stream." + x.name));
381
+ const cameraChannels = this.ufp.channels.filter(x => x.isRtspEnabled && this.nvr.optionEnabled(this.ufp, "Video.Stream." + x.name));
335
382
  // Make sure we've got a HomeKit compatible IDR frame interval. If not, let's take care of that.
336
- let idrChannels = cameraChannels.filter(x => x.idrInterval !== settings_1.PROTECT_HOMEKIT_IDR_INTERVAL);
383
+ let idrChannels = cameraChannels.filter(x => x.idrInterval !== PROTECT_HOMEKIT_IDR_INTERVAL);
337
384
  if (idrChannels.length) {
338
385
  // Edit the channel map.
339
386
  idrChannels = idrChannels.map(x => {
340
- x.idrInterval = settings_1.PROTECT_HOMEKIT_IDR_INTERVAL;
387
+ x.idrInterval = PROTECT_HOMEKIT_IDR_INTERVAL;
341
388
  return x;
342
389
  });
343
- device = (_b = await nvrApi.updateCamera(device, { channels: idrChannels })) !== null && _b !== void 0 ? _b : device;
344
- this.accessory.context.device = device;
390
+ this.ufp = await this.nvr.ufpApi.updateDevice(this.ufp, { channels: idrChannels }) ?? this.ufp;
345
391
  }
346
392
  // Set the camera and shapshot URLs.
347
- const cameraUrl = "rtsps://" + nvr.nvrAddress + ":" + bootstrap.nvr.ports.rtsps.toString() + "/";
348
- this.snapshotUrl = nvrApi.camerasUrl() + "/" + device.id + "/snapshot";
393
+ const cameraUrl = "rtsps://" + this.nvr.nvrOptions.address + ":" + this.nvr.ufp.ports.rtsps.toString() + "/";
394
+ this.snapshotUrl = this.nvr.ufpApi.getApiEndpoint(this.ufp.modelKey) + "/" + this.ufp.id + "/snapshot";
349
395
  // No RTSP streams are available that meet our criteria - we're done.
350
396
  if (!cameraChannels.length) {
351
- this.log.info("%s: No RTSP stream profiles have been configured for this camera. %s", this.name(), "Enable at least one RTSP stream profile in the UniFi Protect webUI to resolve this issue or " +
397
+ this.log.info("No RTSP stream profiles have been configured for this camera. " +
398
+ "Enable at least one RTSP stream profile in the UniFi Protect webUI to resolve this issue or " +
352
399
  "assign the Administrator role to the user configured for this plugin to allow it to automatically configure itself.");
353
400
  return false;
354
401
  }
@@ -368,8 +415,13 @@ class ProtectCamera extends protect_accessory_1.ProtectAccessory {
368
415
  // 3840x2160@30 (4k).
369
416
  // 1920x1080@30 (1080p).
370
417
  // 1280x720@30 (720p).
418
+ // 320x240@30 (Apple Watch).
371
419
  // 320x240@15 (Apple Watch).
372
- for (const entry of [[3840, 2160, 30], [1920, 1080, 30], [1280, 720, 30], [320, 240, 15]]) {
420
+ // 320x180@30 (Apple Watch).
421
+ for (const entry of [
422
+ [3840, 2160, 30], [1920, 1080, 30], [1280, 960, 30], [1280, 720, 30], [1024, 768, 30], [640, 480, 30],
423
+ [640, 360, 30], [480, 360, 30], [480, 270, 30], [320, 240, 30], [320, 240, 15], [320, 180, 30]
424
+ ]) {
373
425
  // We already have this resolution in our list.
374
426
  if (rtspEntries.some(x => (x.resolution[0] === entry[0]) && (x.resolution[1] === entry[1]) && (x.resolution[2] === entry[2]))) {
375
427
  continue;
@@ -391,70 +443,104 @@ class ProtectCamera extends protect_accessory_1.ProtectAccessory {
391
443
  return true;
392
444
  }
393
445
  // Inform users about our RTSP entry mapping, if we're debugging.
394
- if (nvr.optionEnabled(device, "Debug.Video.Startup", false)) {
446
+ if (this.nvr.optionEnabled(this.ufp, "Debug.Video.Startup", false)) {
395
447
  for (const entry of this.rtspEntries) {
396
- this.log.info("%s: Mapping resolution: %s.", this.name(), this.getResolution(entry.resolution) + " => " + entry.name);
448
+ this.log.info("Mapping resolution: %s.", this.getResolution(entry.resolution) + " => " + entry.name);
397
449
  }
398
450
  }
399
451
  // Check for explicit RTSP profile preferences.
400
452
  for (const rtspProfile of ["LOW", "MEDIUM", "HIGH"]) {
401
453
  // Check to see if the user has requested a specific streaming profile for this camera.
402
- if (nvr.optionEnabled(device, "Video.Stream.Only." + rtspProfile, false)) {
454
+ if (this.nvr.optionEnabled(this.ufp, "Video.Stream.Only." + rtspProfile, false)) {
403
455
  this.rtspQuality.StreamingDefault = rtspProfile;
404
456
  }
405
457
  // Check to see if the user has requested a specific recording profile for this camera.
406
- if (nvr.optionEnabled(device, "Video.HKSV.Recording.Only." + rtspProfile, false)) {
458
+ if (this.nvr.optionEnabled(this.ufp, "Video.HKSV.Record.Only." + rtspProfile, false)) {
407
459
  this.rtspQuality.RecordingDefault = rtspProfile;
408
460
  }
409
461
  }
410
462
  // Inform the user if we've set a streaming default.
411
463
  if (this.rtspQuality.StreamingDefault) {
412
- this.log.info("%s: Video streaming configured to use only: %s.", this.name(), this.rtspQuality.StreamingDefault.charAt(0) + this.rtspQuality.StreamingDefault.slice(1).toLowerCase());
464
+ this.log.info("Video streaming configured to use only: %s.", this.rtspQuality.StreamingDefault.charAt(0) + this.rtspQuality.StreamingDefault.slice(1).toLowerCase());
413
465
  }
414
466
  // Inform the user if we've set a recording default.
415
467
  if (this.rtspQuality.RecordingDefault) {
416
- this.log.info("%s: HomeKit Secure Video event recording configured to use only: %s.", this.name(), this.rtspQuality.RecordingDefault.charAt(0) + this.rtspQuality.RecordingDefault.slice(1).toLowerCase());
468
+ this.log.info("HomeKit Secure Video event recording configured to use only: %s.", this.rtspQuality.RecordingDefault.charAt(0) + this.rtspQuality.RecordingDefault.slice(1).toLowerCase());
417
469
  }
418
470
  // Configure the video stream with our resolutions.
419
- this.stream = new protect_stream_1.ProtectStreamingDelegate(this, this.rtspEntries.map(x => x.resolution));
471
+ this.stream = new ProtectStreamingDelegate(this, this.rtspEntries.map(x => x.resolution));
472
+ if (this.hasHwAccel) {
473
+ this.log.info("Hardware accelerated transcoding enabled.");
474
+ }
420
475
  // Fire up the controller and inform HomeKit about it.
421
476
  this.accessory.configureController(this.stream.controller);
422
477
  this.isVideoConfigured = true;
423
478
  return true;
424
479
  }
425
- // Configure HomeKit Secure Video support.
426
- configureHksv() {
427
- var _a, _b, _c, _d;
428
- const device = this.accessory.context.device;
429
- // If we've explicitly disabled HomeKit Secure Video support, we're done.
430
- if (!((_a = this.nvr) === null || _a === void 0 ? void 0 : _a.optionEnabled(this.accessory.context.device, "Video.HKSV", true))) {
431
- this.log.info("%s: HomeKit Secure Video support disabled.", this.name());
432
- return false;
480
+ // Configure a periodic refresh of our snapshot images.
481
+ async configureSnapshotUpdates() {
482
+ for (;;) {
483
+ // If we've removed the device, make sure we stop refreshing.
484
+ if (this.isDeleted) {
485
+ return true;
486
+ }
487
+ // Refresh our snapshot cache.
488
+ // eslint-disable-next-line no-await-in-loop
489
+ await this.stream.getSnapshot(undefined, false);
490
+ // Sleep for 59 seconds.
491
+ // eslint-disable-next-line no-await-in-loop
492
+ await this.nvr.sleep(PROTECT_SNAPSHOT_CACHE_REFRESH_INTERVAL * 1000);
433
493
  }
434
- // HomeKit Secure Video support requires an enabled motion sensor. If one isn't enabled, we're done.
435
- if (!((_b = this.nvr) === null || _b === void 0 ? void 0 : _b.optionEnabled(device, "Motion.Sensor"))) {
436
- this.log.info("%s: Disabling HomeKit Secure Video support. You must enable motion sensor support in order to use HomeKit Secure Video.", this.name());
494
+ return true;
495
+ }
496
+ // Configure a package camera, if one exists.
497
+ configurePackageCamera() {
498
+ // First, confirm the device has a package camera.
499
+ if (!this.ufp.featureFlags.hasPackageCamera) {
437
500
  return false;
438
501
  }
439
- this.isHksv = true;
440
- this.log.info("%s: HomeKit Secure Video support enabled.", this.name());
502
+ // If we've already setup the package camera, we're done.
503
+ if (this.packageCamera) {
504
+ return true;
505
+ }
506
+ // Generate a UUID for the package camera.
507
+ const uuid = this.hap.uuid.generate(this.ufp.mac + ".PackageCamera");
508
+ // Let's find it if we've already created it.
509
+ let packageCameraAccessory = this.platform.accessories.find((x) => x.UUID === uuid) ?? null;
510
+ // We can't find the accessory. Let's create it.
511
+ if (!packageCameraAccessory) {
512
+ // We will use the NVR MAC address + ".NVRSystemInfo" to create our UUID. That should provide the guaranteed uniqueness we need.
513
+ packageCameraAccessory = new this.api.platformAccessory(this.accessory.displayName + " Package Camera", uuid);
514
+ if (!packageCameraAccessory) {
515
+ this.log.error("Unable to create the package camera accessory.");
516
+ return false;
517
+ }
518
+ // Register this accessory with homebridge and add it to the platform accessory array so we can track it.
519
+ this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [packageCameraAccessory]);
520
+ this.platform.accessories.push(packageCameraAccessory);
521
+ }
522
+ // Now create the package camera accessory. We do want to modify the camera name to ensure things look pretty.
523
+ this.packageCamera = new ProtectPackageCamera(this.nvr, Object.assign({}, this.ufp, { name: this.ufp.name + " Package Camera" }), packageCameraAccessory);
524
+ return true;
525
+ }
526
+ // Configure HomeKit Secure Video support.
527
+ configureHksv() {
528
+ this.hasHksv = true;
441
529
  // If we have smart motion events enabled, let's warn the user that things will not work quite the way they expect.
442
- if (device.featureFlags.hasSmartDetect && ((_c = this.nvr) === null || _c === void 0 ? void 0 : _c.optionEnabled(device, "Motion.SmartDetect", false))) {
443
- this.log.info("%s: WARNING: Smart motion detection and HomeKit Secure Video provide overlapping functionality. " +
530
+ if (this.ufp.featureFlags.hasSmartDetect && this.nvr.optionEnabled(this.ufp, "Motion.SmartDetect", false)) {
531
+ this.log.info("WARNING: Smart motion detection and HomeKit Secure Video provide overlapping functionality. " +
444
532
  "Only HomeKit Secure Video, when event recording is enabled in the Home app, will be used to trigger motion event notifications for this camera." +
445
- (((_d = this.nvr) === null || _d === void 0 ? void 0 : _d.optionEnabled(device, "Motion.SmartDetect.ObjectSensors", false)) ?
446
- " Smart motion contact sensors will continue to function using telemetry from UniFi Protect." : ""), this.name());
533
+ (this.nvr.optionEnabled(this.ufp, "Motion.SmartDetect.ObjectSensors", false) ?
534
+ " Smart motion contact sensors will continue to function using telemetry from UniFi Protect." : ""));
447
535
  }
448
536
  return true;
449
537
  }
450
538
  // Configure a switch to manually enable or disable HKSV recording for a camera.
451
539
  configureHksvRecordingSwitch() {
452
- var _a, _b, _c;
453
540
  // Find the switch service, if it exists.
454
- let switchService = this.accessory.getServiceById(this.hap.Service.Switch, protect_accessory_1.ProtectReservedNames.SWITCH_HKSV_RECORDING);
541
+ let switchService = this.accessory.getServiceById(this.hap.Service.Switch, ProtectReservedNames.SWITCH_HKSV_RECORDING);
455
542
  // If we don't have HKSV or the HKSV recording switch enabled, disable it and we're done.
456
- if (!((_a = this.nvr) === null || _a === void 0 ? void 0 : _a.optionEnabled(this.accessory.context.device, "Video.HKSV")) ||
457
- !((_b = this.nvr) === null || _b === void 0 ? void 0 : _b.optionEnabled(this.accessory.context.device, "Video.HKSV.Recording.Switch", false))) {
543
+ if (!this.nvr.optionEnabled(this.ufp, "Video.HKSV.Recording.Switch", false)) {
458
544
  if (switchService) {
459
545
  this.accessory.removeService(switchService);
460
546
  }
@@ -464,35 +550,36 @@ class ProtectCamera extends protect_accessory_1.ProtectAccessory {
464
550
  }
465
551
  // Add the switch to the camera, if needed.
466
552
  if (!switchService) {
467
- switchService = new this.hap.Service.Switch(this.accessory.displayName + " HKSV Recording", protect_accessory_1.ProtectReservedNames.SWITCH_HKSV_RECORDING);
553
+ switchService = new this.hap.Service.Switch(this.accessory.displayName + " HKSV Recording", ProtectReservedNames.SWITCH_HKSV_RECORDING);
468
554
  if (!switchService) {
469
- this.log.error("%s: Unable to add the HomeKit Secure Video recording switch.", this.name());
555
+ this.log.error("Unable to add the HomeKit Secure Video recording switch.");
470
556
  return false;
471
557
  }
472
558
  this.accessory.addService(switchService);
473
559
  }
474
560
  // Activate or deactivate HKSV recording.
475
- (_c = switchService
476
- .getCharacteristic(this.hap.Characteristic.On)) === null || _c === void 0 ? void 0 : _c.onGet(() => {
561
+ switchService
562
+ .getCharacteristic(this.hap.Characteristic.On)
563
+ ?.onGet(() => {
477
564
  return this.accessory.context.hksvRecording;
478
- }).onSet((value) => {
565
+ })
566
+ .onSet((value) => {
479
567
  if (this.accessory.context.hksvRecording !== value) {
480
- this.log.info("%s: HomeKit Secure Video event recording has been %s.", this.name(), value === true ? "enabled" : "disabled");
568
+ this.log.info("HomeKit Secure Video event recording has been %s.", value === true ? "enabled" : "disabled");
481
569
  }
482
570
  this.accessory.context.hksvRecording = value === true;
483
571
  });
484
572
  // Initialize the switch.
485
573
  switchService.updateCharacteristic(this.hap.Characteristic.On, this.accessory.context.hksvRecording);
486
- this.log.info("%s: Enabling HomeKit Secure Video recording switch.", this.name());
574
+ this.log.info("Enabling HomeKit Secure Video recording switch.");
487
575
  return true;
488
576
  }
489
577
  // Configure a switch to manually enable or disable dynamic bitrate capabilities for a camera.
490
578
  configureDynamicBitrateSwitch() {
491
- var _a, _b;
492
579
  // Find the switch service, if it exists.
493
- let switchService = this.accessory.getServiceById(this.hap.Service.Switch, protect_accessory_1.ProtectReservedNames.SWITCH_DYNAMIC_BITRATE);
580
+ let switchService = this.accessory.getServiceById(this.hap.Service.Switch, ProtectReservedNames.SWITCH_DYNAMIC_BITRATE);
494
581
  // If we don't want a dynamic bitrate switch, disable it and we're done.
495
- if (!((_a = this.nvr) === null || _a === void 0 ? void 0 : _a.optionEnabled(this.accessory.context.device, "Video.DynamicBitrate.Switch", false))) {
582
+ if (!this.nvr.optionEnabled(this.ufp, "Video.DynamicBitrate.Switch", false)) {
496
583
  if (switchService) {
497
584
  this.accessory.removeService(switchService);
498
585
  }
@@ -502,62 +589,62 @@ class ProtectCamera extends protect_accessory_1.ProtectAccessory {
502
589
  }
503
590
  // Add the switch to the camera, if needed.
504
591
  if (!switchService) {
505
- switchService = new this.hap.Service.Switch(this.accessory.displayName + " Dynamic Bitrate", protect_accessory_1.ProtectReservedNames.SWITCH_DYNAMIC_BITRATE);
592
+ switchService = new this.hap.Service.Switch(this.accessory.displayName + " Dynamic Bitrate", ProtectReservedNames.SWITCH_DYNAMIC_BITRATE);
506
593
  if (!switchService) {
507
- this.log.error("%s: Unable to add the dynamic bitrate switch.", this.name());
594
+ this.log.error("Unable to add the dynamic bitrate switch.");
508
595
  return false;
509
596
  }
510
597
  this.accessory.addService(switchService);
511
598
  }
512
599
  // Activate or deactivate dynamic bitrate for this device.
513
- (_b = switchService
514
- .getCharacteristic(this.hap.Characteristic.On)) === null || _b === void 0 ? void 0 : _b.onGet(() => {
600
+ switchService
601
+ .getCharacteristic(this.hap.Characteristic.On)
602
+ ?.onGet(() => {
515
603
  return this.accessory.context.dynamicBitrate;
516
- }).onSet(async (value) => {
604
+ })
605
+ .onSet(async (value) => {
517
606
  if (this.accessory.context.dynamicBitrate === value) {
518
607
  return;
519
608
  }
520
609
  // We're enabling dynamic bitrate for this device.
521
610
  if (value) {
522
611
  this.accessory.context.dynamicBitrate = true;
523
- this.log.info("%s: Dynamic streaming bitrate adjustment on the UniFi Protect controller enabled.", this.name());
612
+ this.log.info("Dynamic streaming bitrate adjustment on the UniFi Protect controller enabled.");
524
613
  return;
525
614
  }
526
615
  // We're disabling dynamic bitrate for this device.
527
- const device = this.accessory.context.device;
528
- const updatedChannels = device.channels;
616
+ const updatedChannels = this.ufp.channels;
529
617
  // Update the channels JSON.
530
618
  for (const channel of updatedChannels) {
531
619
  channel.bitrate = channel.maxBitrate;
532
620
  }
533
621
  // Send the channels JSON to Protect.
534
- const newDevice = await this.nvrApi.updateCamera(device, { channels: updatedChannels });
622
+ const newDevice = await this.nvr.ufpApi.updateDevice(this.ufp, { channels: updatedChannels });
535
623
  // We failed.
536
624
  if (!newDevice) {
537
- this.log.error("%s: Unable to set the streaming bitrate to %s.", this.name(), value);
625
+ this.log.error("Unable to set the streaming bitrate to %s.", value);
538
626
  }
539
627
  else {
540
- this.accessory.context.device = newDevice;
628
+ this.ufp = newDevice;
541
629
  }
542
630
  this.accessory.context.dynamicBitrate = false;
543
- this.log.info("%s: Dynamic streaming bitrate adjustment on the UniFi Protect controller disabled.", this.name());
631
+ this.log.info("Dynamic streaming bitrate adjustment on the UniFi Protect controller disabled.");
544
632
  });
545
633
  // Initialize the switch.
546
634
  switchService.updateCharacteristic(this.hap.Characteristic.On, this.accessory.context.dynamicBitrate);
547
- this.log.info("%s: Enabling the dynamic streaming bitrate adjustment switch.", this.name());
635
+ this.log.info("Enabling the dynamic streaming bitrate adjustment switch.");
548
636
  return true;
549
637
  }
550
638
  // Configure a series of switches to manually enable or disable recording on the UniFi Protect controller for a camera.
551
639
  configureNvrRecordingSwitch() {
552
- var _a, _b;
553
640
  const switchesEnabled = [];
554
641
  // The Protect controller supports three modes for recording on a camera: always, detections, and never. We create switches for each of the modes.
555
- for (const ufpRecordingSwitchType of [protect_accessory_1.ProtectReservedNames.SWITCH_UFP_RECORDING_ALWAYS, protect_accessory_1.ProtectReservedNames.SWITCH_UFP_RECORDING_DETECTIONS, protect_accessory_1.ProtectReservedNames.SWITCH_UFP_RECORDING_NEVER]) {
642
+ for (const ufpRecordingSwitchType of [ProtectReservedNames.SWITCH_UFP_RECORDING_ALWAYS, ProtectReservedNames.SWITCH_UFP_RECORDING_DETECTIONS, ProtectReservedNames.SWITCH_UFP_RECORDING_NEVER]) {
556
643
  const ufpRecordingSetting = ufpRecordingSwitchType.slice(ufpRecordingSwitchType.lastIndexOf(".") + 1);
557
644
  // Find the switch service, if it exists.
558
645
  let switchService = this.accessory.getServiceById(this.hap.Service.Switch, ufpRecordingSwitchType);
559
646
  // If we don't have the feature option enabled, disable the switch and we're done.
560
- if (!((_a = this.nvr) === null || _a === void 0 ? void 0 : _a.optionEnabled(this.accessory.context.device, "Nvr.Recording.Switch", false))) {
647
+ if (!this.nvr.optionEnabled(this.ufp, "Nvr.Recording.Switch", false)) {
561
648
  if (switchService) {
562
649
  this.accessory.removeService(switchService);
563
650
  }
@@ -567,17 +654,18 @@ class ProtectCamera extends protect_accessory_1.ProtectAccessory {
567
654
  if (!switchService) {
568
655
  switchService = new this.hap.Service.Switch(this.accessory.displayName + " UFP Recording " + ufpRecordingSetting.charAt(0).toUpperCase() + ufpRecordingSetting.slice(1), ufpRecordingSwitchType);
569
656
  if (!switchService) {
570
- this.log.error("%s: Unable to add the UniFi Protect recording switches.", this.name());
657
+ this.log.error("Unable to add the UniFi Protect recording switches.");
571
658
  continue;
572
659
  }
573
660
  this.accessory.addService(switchService);
574
661
  }
575
662
  // Activate or deactivate the appropriate recording mode on the Protect controller.
576
- (_b = switchService
577
- .getCharacteristic(this.hap.Characteristic.On)) === null || _b === void 0 ? void 0 : _b.onGet(() => {
578
- return this.accessory.context.device.recordingSettings.mode === ufpRecordingSetting;
579
- }).onSet(async (value) => {
580
- var _a;
663
+ switchService
664
+ .getCharacteristic(this.hap.Characteristic.On)
665
+ ?.onGet(() => {
666
+ return this.ufp.recordingSettings.mode === ufpRecordingSetting;
667
+ })
668
+ .onSet(async (value) => {
581
669
  // We only want to do something if we're being activated. Turning off the switch would really be an undefined state given that
582
670
  // there are three different settings one can choose from. Instead, we do nothing and leave it to the user to choose what state
583
671
  // they really want to set.
@@ -588,124 +676,107 @@ class ProtectCamera extends protect_accessory_1.ProtectAccessory {
588
676
  return;
589
677
  }
590
678
  // Set our recording mode.
591
- const device = this.accessory.context.device;
592
- device.recordingSettings.mode = ufpRecordingSetting;
679
+ this.ufp.recordingSettings.mode = ufpRecordingSetting;
593
680
  // Tell Protect about it.
594
- const newDevice = await this.nvr.nvrApi.updateCamera(device, { recordingSettings: device.recordingSettings });
681
+ const newDevice = await this.nvr.ufpApi.updateDevice(this.ufp, { recordingSettings: this.ufp.recordingSettings });
595
682
  if (!newDevice) {
596
- this.log.error("%s: Unable to set the UniFi Protect recording mode to %s.", this.name(), ufpRecordingSetting);
683
+ this.log.error("Unable to set the UniFi Protect recording mode to %s.", ufpRecordingSetting);
597
684
  return false;
598
685
  }
599
686
  // Save our updated device context.
600
- this.accessory.context.device = newDevice;
687
+ this.ufp = newDevice;
601
688
  // Update all the other recording switches.
602
- for (const otherUfpSwitch of [protect_accessory_1.ProtectReservedNames.SWITCH_UFP_RECORDING_ALWAYS, protect_accessory_1.ProtectReservedNames.SWITCH_UFP_RECORDING_DETECTIONS, protect_accessory_1.ProtectReservedNames.SWITCH_UFP_RECORDING_NEVER]) {
689
+ for (const otherUfpSwitch of [ProtectReservedNames.SWITCH_UFP_RECORDING_ALWAYS, ProtectReservedNames.SWITCH_UFP_RECORDING_DETECTIONS, ProtectReservedNames.SWITCH_UFP_RECORDING_NEVER]) {
603
690
  // Don't update ourselves a second time.
604
691
  if (ufpRecordingSwitchType === otherUfpSwitch) {
605
692
  continue;
606
693
  }
607
694
  // Update the other recording switches.
608
- (_a = this.accessory.getServiceById(this.hap.Service.Switch, otherUfpSwitch)) === null || _a === void 0 ? void 0 : _a.updateCharacteristic(this.hap.Characteristic.On, false);
695
+ this.accessory.getServiceById(this.hap.Service.Switch, otherUfpSwitch)?.updateCharacteristic(this.hap.Characteristic.On, false);
609
696
  }
610
697
  // Inform the user, and we're done.
611
- this.log.info("%s: UniFi Protect recording mode set to %s.", this.name(), ufpRecordingSetting);
698
+ this.log.info("UniFi Protect recording mode set to %s.", ufpRecordingSetting);
612
699
  });
613
700
  // Initialize the recording switch state.
614
- switchService.updateCharacteristic(this.hap.Characteristic.On, this.accessory.context.device.recordingSettings.mode === ufpRecordingSetting);
701
+ switchService.updateCharacteristic(this.hap.Characteristic.On, this.ufp.recordingSettings.mode === ufpRecordingSetting);
615
702
  switchesEnabled.push(ufpRecordingSetting);
616
703
  }
617
704
  if (switchesEnabled.length) {
618
- this.log.info("%s: Enabling UniFi Protect recording switches: %s.", this.name(), switchesEnabled.join(", "));
705
+ this.log.info("Enabling UniFi Protect recording switches: %s.", switchesEnabled.join(", "));
619
706
  }
620
707
  return true;
621
708
  }
622
709
  // Configure MQTT capabilities of this camera.
623
710
  configureMqtt() {
624
- var _a, _b;
625
- const bootstrap = this.nvr.nvrApi.bootstrap;
626
- const device = this.accessory.context.device;
627
711
  // Return the RTSP URLs when requested.
628
- (_a = this.nvr.mqtt) === null || _a === void 0 ? void 0 : _a.subscribe(this.accessory, "rtsp/get", (message) => {
629
- var _a;
712
+ this.nvr.mqtt?.subscribe(this.accessory, "rtsp/get", (message) => {
630
713
  const value = message.toString();
631
714
  // When we get the right message, we trigger the snapshot request.
632
- if ((value === null || value === void 0 ? void 0 : value.toLowerCase()) !== "true") {
715
+ if (value?.toLowerCase() !== "true") {
633
716
  return;
634
717
  }
635
718
  const urlInfo = {};
636
719
  // Grab all the available RTSP channels.
637
- for (const channel of device.channels) {
638
- if (!bootstrap || !channel.isRtspEnabled) {
720
+ for (const channel of this.ufp.channels) {
721
+ if (!channel.isRtspEnabled) {
639
722
  continue;
640
723
  }
641
- urlInfo[channel.name] = "rtsps://" + bootstrap.nvr.host + ":" + bootstrap.nvr.ports.rtsp.toString() + "/" + channel.rtspAlias + "?enableSrtp";
724
+ urlInfo[channel.name] = "rtsps://" + this.nvr.ufp.host + ":" + this.nvr.ufp.ports.rtsp.toString() + "/" + channel.rtspAlias + "?enableSrtp";
642
725
  }
643
- (_a = this.nvr.mqtt) === null || _a === void 0 ? void 0 : _a.publish(this.accessory, "rtsp", JSON.stringify(urlInfo));
644
- this.log.info("%s: RTSP information published via MQTT.", this.name());
726
+ this.nvr.mqtt?.publish(this.accessory, "rtsp", JSON.stringify(urlInfo));
727
+ this.log.info("RTSP information published via MQTT.");
645
728
  });
646
729
  // Trigger snapshots when requested.
647
- (_b = this.nvr.mqtt) === null || _b === void 0 ? void 0 : _b.subscribe(this.accessory, "snapshot/trigger", (message) => {
648
- var _a;
730
+ this.nvr.mqtt?.subscribe(this.accessory, "snapshot/trigger", (message) => {
649
731
  const value = message.toString();
650
732
  // When we get the right message, we trigger the snapshot request.
651
- if ((value === null || value === void 0 ? void 0 : value.toLowerCase()) !== "true") {
733
+ if (value?.toLowerCase() !== "true") {
652
734
  return;
653
735
  }
654
- void ((_a = this.stream) === null || _a === void 0 ? void 0 : _a.handleSnapshotRequest());
655
- this.log.info("%s: Snapshot triggered via MQTT.", this.name());
736
+ void this.stream?.handleSnapshotRequest();
737
+ this.log.info("Snapshot triggered via MQTT.");
656
738
  });
657
739
  return true;
658
740
  }
659
741
  // Refresh camera-specific characteristics.
660
742
  updateDevice() {
661
- var _a, _b, _c;
662
- // Grab our device context.
663
- const device = this.accessory.context.device;
664
743
  // Update the camera state.
665
- (_a = this.accessory.getService(this.hap.Service.MotionSensor)) === null || _a === void 0 ? void 0 : _a.updateCharacteristic(this.hap.Characteristic.StatusActive, device.state === "CONNECTED");
666
- // Find the service, if it exists.
667
- const service = this.accessory.getService(this.hap.Service.CameraOperatingMode);
744
+ this.accessory.getService(this.hap.Service.MotionSensor)?.updateCharacteristic(this.hap.Characteristic.StatusActive, this.ufp.state === "CONNECTED");
668
745
  // Check to see if this device has a status light.
669
- if (device.featureFlags.hasLedStatus) {
670
- service === null || service === void 0 ? void 0 : service.updateCharacteristic(this.hap.Characteristic.CameraOperatingModeIndicator, device.ledSettings.isEnabled === true);
746
+ if (this.hints.ledStatus) {
747
+ this.accessory.getService(this.hap.Service.CameraOperatingMode)?.
748
+ updateCharacteristic(this.hap.Characteristic.CameraOperatingModeIndicator, this.ufp.ledSettings.isEnabled === true);
671
749
  }
672
750
  // Check for updates to the recording state, if we have the switches configured.
673
- if ((_b = this.nvr) === null || _b === void 0 ? void 0 : _b.optionEnabled(device, "Nvr.Recording.Switch", false)) {
751
+ if (this.nvr.optionEnabled(this.ufp, "Nvr.Recording.Switch", false)) {
674
752
  // Update all the switch states.
675
- for (const ufpRecordingSwitchType of [protect_accessory_1.ProtectReservedNames.SWITCH_UFP_RECORDING_ALWAYS, protect_accessory_1.ProtectReservedNames.SWITCH_UFP_RECORDING_DETECTIONS, protect_accessory_1.ProtectReservedNames.SWITCH_UFP_RECORDING_NEVER]) {
753
+ for (const ufpRecordingSwitchType of [ProtectReservedNames.SWITCH_UFP_RECORDING_ALWAYS, ProtectReservedNames.SWITCH_UFP_RECORDING_DETECTIONS, ProtectReservedNames.SWITCH_UFP_RECORDING_NEVER]) {
676
754
  const ufpRecordingSetting = ufpRecordingSwitchType.slice(ufpRecordingSwitchType.lastIndexOf(".") + 1);
677
755
  // Update state based on the recording mode.
678
- (_c = this.accessory.getServiceById(this.hap.Service.Switch, ufpRecordingSwitchType)) === null || _c === void 0 ? void 0 : _c.updateCharacteristic(this.hap.Characteristic.On, ufpRecordingSetting === device.recordingSettings.mode);
756
+ this.accessory.getServiceById(this.hap.Service.Switch, ufpRecordingSwitchType)?.
757
+ updateCharacteristic(this.hap.Characteristic.On, ufpRecordingSetting === this.ufp.recordingSettings.mode);
679
758
  }
680
759
  }
681
760
  return true;
682
761
  }
683
762
  // Get the current bitrate for a specific camera channel.
684
763
  getBitrate(channelId) {
685
- var _a;
686
- // Grab the device JSON.
687
- const device = this.accessory.context.device;
688
764
  // Find the right channel.
689
- const channel = device.channels.find(x => x.id === channelId);
690
- return (_a = channel === null || channel === void 0 ? void 0 : channel.bitrate) !== null && _a !== void 0 ? _a : -1;
765
+ const channel = this.ufp.channels.find(x => x.id === channelId);
766
+ return channel?.bitrate ?? -1;
691
767
  }
692
768
  // Set the bitrate for a specific camera channel.
693
769
  async setBitrate(channelId, value) {
694
- var _a, _b, _c;
695
770
  // If we've disabled the ability to set the bitrate dynamically, silently fail. We prioritize switches over the global
696
771
  // setting here, in case the user enabled both, using the principle that the most specific setting always wins. If the
697
772
  // user has both the global setting and the switch enabled, the switch setting will take precedence.
698
- if ((!this.accessory.context.dynamicBitrate &&
699
- !((_a = this.nvr) === null || _a === void 0 ? void 0 : _a.optionEnabled(this.accessory.context.device, "Video.DynamicBitrate", false))) ||
700
- (!this.accessory.context.dynamicBitrate &&
701
- ((_b = this.nvr) === null || _b === void 0 ? void 0 : _b.optionEnabled(this.accessory.context.device, "Video.DynamicBitrate", false)) &&
702
- ((_c = this.nvr) === null || _c === void 0 ? void 0 : _c.optionEnabled(this.accessory.context.device, "Video.DynamicBitrate.Switch", false)))) {
773
+ if ((!this.accessory.context.dynamicBitrate && !this.nvr.optionEnabled(this.ufp, "Video.DynamicBitrate", false)) ||
774
+ (!this.accessory.context.dynamicBitrate && this.nvr.optionEnabled(this.ufp, "Video.DynamicBitrate", false) &&
775
+ this.nvr.optionEnabled(this.ufp, "Video.DynamicBitrate.Switch", false))) {
703
776
  return true;
704
777
  }
705
- // Grab the device JSON.
706
- const device = this.accessory.context.device;
707
778
  // Find the right channel.
708
- const channel = device.channels.find(x => x.id === channelId);
779
+ const channel = this.ufp.channels.find(x => x.id === channelId);
709
780
  // No channel, we're done.
710
781
  if (!channel) {
711
782
  return false;
@@ -717,18 +788,17 @@ class ProtectCamera extends protect_accessory_1.ProtectAccessory {
717
788
  // Make sure the requested bitrate fits within the constraints of what this channel can do.
718
789
  channel.bitrate = Math.min(channel.maxBitrate, Math.max(channel.minBitrate, value));
719
790
  // Tell Protect about it.
720
- const newDevice = await this.nvr.nvrApi.updateCamera(device, { channels: device.channels });
791
+ const newDevice = await this.nvr.ufpApi.updateDevice(this.ufp, { channels: this.ufp.channels });
721
792
  if (!newDevice) {
722
- this.log.error("%s: Unable to set the streaming bitrate to %s.", this.name(), value);
793
+ this.log.error("Unable to set the streaming bitrate to %s.", value);
723
794
  return false;
724
795
  }
725
796
  // Save our updated device context.
726
- this.accessory.context.device = newDevice;
797
+ this.ufp = newDevice;
727
798
  return true;
728
799
  }
729
800
  // Find an RTSP configuration for a given target resolution.
730
801
  findRtspEntry(width, height, camera, address, rtspEntries, defaultStream = this.rtspQuality.StreamingDefault) {
731
- var _a, _b;
732
802
  // No RTSP entries to choose from, we're done.
733
803
  if (!rtspEntries || !rtspEntries.length) {
734
804
  return null;
@@ -753,12 +823,12 @@ class ProtectCamera extends protect_accessory_1.ProtectAccessory {
753
823
  }
754
824
  // If it's set to none, we default to our normal lookup logic.
755
825
  if (this.rtspQuality[address] !== "None") {
756
- return (_a = rtspEntries.find(x => x.channel.name.toUpperCase() === this.rtspQuality[address])) !== null && _a !== void 0 ? _a : null;
826
+ return rtspEntries.find(x => x.channel.name.toUpperCase() === this.rtspQuality[address]) ?? null;
757
827
  }
758
828
  }
759
829
  // Second, we check to see if we've set an explicit preference for stream quality.
760
830
  if (defaultStream) {
761
- return (_b = rtspEntries.find(x => x.channel.name.toUpperCase() === defaultStream)) !== null && _b !== void 0 ? _b : null;
831
+ return rtspEntries.find(x => x.channel.name.toUpperCase() === defaultStream) ?? null;
762
832
  }
763
833
  // See if we have a match for our desired resolution on the camera. We ignore FPS - HomeKit clients seem
764
834
  // to be able to handle it just fine.
@@ -827,5 +897,56 @@ class ProtectCamera extends protect_accessory_1.ProtectAccessory {
827
897
  return resolution[0].toString() + "x" + resolution[1].toString() + "@" + resolution[2].toString() + "fps";
828
898
  }
829
899
  }
830
- exports.ProtectCamera = ProtectCamera;
900
+ // Package camera class.
901
+ export class ProtectPackageCamera extends ProtectCamera {
902
+ // Configure the package camera.
903
+ async configureDevice() {
904
+ this.hints.probesize = 20480; //10240;
905
+ // this.hints.transcode = this.nvr.optionEnabled(this.ufp, "Video.Transcode", false);
906
+ // this.hints.transcode = true;
907
+ this.hasHksv = false;
908
+ this.isRinging = false;
909
+ // Clean out the context object in case it's been polluted somehow.
910
+ this.accessory.context = {};
911
+ this.accessory.context.nvr = this.nvr.ufp.mac;
912
+ this.accessory.context.packageCamera = true;
913
+ // Configure accessory information.
914
+ this.configureInfo();
915
+ // Set the snapshot URL.
916
+ this.snapshotUrl = this.nvr.ufpApi.getApiEndpoint(this.ufp.modelKey) + "/" + this.ufp.id + "/package-snapshot";
917
+ // Configure the video stream with our required resolutions. No, package cameras don't really support any of these resolutions, but they're required
918
+ // by HomeKit in order to stream video.
919
+ this.stream = new ProtectStreamingDelegate(this, [[3840, 2160, 30], [1920, 1080, 30], [1280, 960, 30], [1280, 720, 30], [1024, 768, 30], [640, 480, 30],
920
+ [640, 360, 30], [480, 360, 30], [480, 270, 30], [320, 240, 30], [320, 240, 15], [320, 180, 30]]);
921
+ // Fire up the controller and inform HomeKit about it.
922
+ this.accessory.configureController(this.stream.controller);
923
+ // Periodically refresh our snapshot cache.
924
+ void this.configureSnapshotUpdates();
925
+ // We're done.
926
+ return Promise.resolve(true);
927
+ }
928
+ // Make our RTSP stream findable.
929
+ findRtsp() {
930
+ const channel = this.ufp.channels.find(x => x.name === "Package Camera");
931
+ if (!channel) {
932
+ return null;
933
+ }
934
+ return {
935
+ channel: channel,
936
+ name: channel.name,
937
+ resolution: [channel.width, channel.height, channel.fps],
938
+ url: "rtsps://" + this.nvr.nvrOptions.address + ":" + this.nvr.ufp.ports.rtsps.toString() + "/" + channel.rtspAlias + "?enableSrtp"
939
+ };
940
+ }
941
+ // Get the current bitrate for a specific camera channel.
942
+ getBitrate(channelId) {
943
+ // Find the right channel.
944
+ const channel = this.ufp.channels.find(x => x.id === channelId);
945
+ return channel?.bitrate ?? -1;
946
+ }
947
+ // Set the bitrate for a specific camera channel.
948
+ setBitrate() {
949
+ return Promise.resolve(true);
950
+ }
951
+ }
831
952
  //# sourceMappingURL=protect-camera.js.map