homebridge-unifi-protect 6.18.1 → 6.20.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 (111) hide show
  1. package/dist/devices/index.d.ts +11 -0
  2. package/dist/devices/index.js +16 -0
  3. package/dist/devices/index.js.map +1 -0
  4. package/dist/{protect-camera-package.js → devices/protect-camera-package.js} +2 -4
  5. package/dist/devices/protect-camera-package.js.map +1 -0
  6. package/dist/{protect-camera.d.ts → devices/protect-camera.d.ts} +2 -5
  7. package/dist/{protect-camera.js → devices/protect-camera.js} +119 -210
  8. package/dist/devices/protect-camera.js.map +1 -0
  9. package/dist/{protect-chime.d.ts → devices/protect-chime.d.ts} +4 -1
  10. package/dist/devices/protect-chime.js +180 -0
  11. package/dist/devices/protect-chime.js.map +1 -0
  12. package/dist/{protect-device.d.ts → devices/protect-device.d.ts} +12 -5
  13. package/dist/{protect-device.js → devices/protect-device.js} +159 -109
  14. package/dist/devices/protect-device.js.map +1 -0
  15. package/dist/{protect-doorbell.d.ts → devices/protect-doorbell.d.ts} +1 -1
  16. package/dist/{protect-doorbell.js → devices/protect-doorbell.js} +50 -83
  17. package/dist/devices/protect-doorbell.js.map +1 -0
  18. package/dist/{protect-light.d.ts → devices/protect-light.d.ts} +1 -1
  19. package/dist/{protect-light.js → devices/protect-light.js} +34 -44
  20. package/dist/devices/protect-light.js.map +1 -0
  21. package/dist/{protect-liveviews.d.ts → devices/protect-liveviews.d.ts} +1 -1
  22. package/dist/{protect-liveviews.js → devices/protect-liveviews.js} +11 -21
  23. package/dist/devices/protect-liveviews.js.map +1 -0
  24. package/dist/{protect-nvr-systeminfo.d.ts → devices/protect-nvr-systeminfo.d.ts} +1 -1
  25. package/dist/{protect-nvr-systeminfo.js → devices/protect-nvr-systeminfo.js} +3 -9
  26. package/dist/devices/protect-nvr-systeminfo.js.map +1 -0
  27. package/dist/{protect-securitysystem.d.ts → devices/protect-securitysystem.d.ts} +2 -3
  28. package/dist/{protect-securitysystem.js → devices/protect-securitysystem.js} +32 -59
  29. package/dist/devices/protect-securitysystem.js.map +1 -0
  30. package/dist/{protect-sensor.d.ts → devices/protect-sensor.d.ts} +3 -2
  31. package/dist/devices/protect-sensor.js +402 -0
  32. package/dist/devices/protect-sensor.js.map +1 -0
  33. package/dist/{protect-viewer.d.ts → devices/protect-viewer.d.ts} +1 -1
  34. package/dist/{protect-viewer.js → devices/protect-viewer.js} +21 -28
  35. package/dist/devices/protect-viewer.js.map +1 -0
  36. package/dist/ffmpeg/index.d.ts +6 -0
  37. package/dist/ffmpeg/index.js +11 -0
  38. package/dist/ffmpeg/index.js.map +1 -0
  39. package/dist/{protect-ffmpeg-codecs.d.ts → ffmpeg/protect-ffmpeg-codecs.d.ts} +1 -1
  40. package/dist/ffmpeg/protect-ffmpeg-codecs.js.map +1 -0
  41. package/dist/{protect-ffmpeg-exec.d.ts → ffmpeg/protect-ffmpeg-exec.d.ts} +5 -2
  42. package/dist/{protect-ffmpeg-exec.js → ffmpeg/protect-ffmpeg-exec.js} +13 -1
  43. package/dist/ffmpeg/protect-ffmpeg-exec.js.map +1 -0
  44. package/dist/{protect-ffmpeg-options.d.ts → ffmpeg/protect-ffmpeg-options.d.ts} +1 -1
  45. package/dist/{protect-ffmpeg-options.js → ffmpeg/protect-ffmpeg-options.js} +1 -1
  46. package/dist/ffmpeg/protect-ffmpeg-options.js.map +1 -0
  47. package/dist/{protect-ffmpeg-record.d.ts → ffmpeg/protect-ffmpeg-record.d.ts} +1 -1
  48. package/dist/{protect-ffmpeg-record.js → ffmpeg/protect-ffmpeg-record.js} +7 -3
  49. package/dist/ffmpeg/protect-ffmpeg-record.js.map +1 -0
  50. package/dist/{protect-ffmpeg-stream.d.ts → ffmpeg/protect-ffmpeg-stream.d.ts} +1 -1
  51. package/dist/ffmpeg/protect-ffmpeg-stream.js.map +1 -0
  52. package/dist/{protect-ffmpeg.d.ts → ffmpeg/protect-ffmpeg.d.ts} +3 -3
  53. package/dist/ffmpeg/protect-ffmpeg.js.map +1 -0
  54. package/dist/{protect-nvr-events.d.ts → protect-events.d.ts} +3 -4
  55. package/dist/{protect-nvr-events.js → protect-events.js} +4 -4
  56. package/dist/protect-events.js.map +1 -0
  57. package/dist/protect-mqtt.d.ts +3 -2
  58. package/dist/protect-mqtt.js +30 -6
  59. package/dist/protect-mqtt.js.map +1 -1
  60. package/dist/protect-nvr.d.ts +4 -8
  61. package/dist/protect-nvr.js +82 -129
  62. package/dist/protect-nvr.js.map +1 -1
  63. package/dist/protect-options.js +7 -5
  64. package/dist/protect-options.js.map +1 -1
  65. package/dist/protect-platform.d.ts +1 -1
  66. package/dist/protect-platform.js +1 -1
  67. package/dist/protect-platform.js.map +1 -1
  68. package/dist/protect-record.d.ts +4 -2
  69. package/dist/protect-record.js +37 -34
  70. package/dist/protect-record.js.map +1 -1
  71. package/dist/protect-snapshot.d.ts +21 -0
  72. package/dist/protect-snapshot.js +200 -0
  73. package/dist/protect-snapshot.js.map +1 -0
  74. package/dist/protect-stream.d.ts +3 -7
  75. package/dist/protect-stream.js +7 -86
  76. package/dist/protect-stream.js.map +1 -1
  77. package/dist/protect-timeshift.d.ts +3 -2
  78. package/dist/protect-timeshift.js +31 -30
  79. package/dist/protect-timeshift.js.map +1 -1
  80. package/dist/protect-types.d.ts +5 -6
  81. package/dist/protect-types.js +8 -0
  82. package/dist/protect-types.js.map +1 -1
  83. package/dist/settings.d.ts +3 -6
  84. package/dist/settings.js +6 -12
  85. package/dist/settings.js.map +1 -1
  86. package/homebridge-ui/public/index.html +2 -0
  87. package/package.json +12 -12
  88. package/dist/protect-camera-package.js.map +0 -1
  89. package/dist/protect-camera.js.map +0 -1
  90. package/dist/protect-chime.js +0 -108
  91. package/dist/protect-chime.js.map +0 -1
  92. package/dist/protect-device.js.map +0 -1
  93. package/dist/protect-doorbell.js.map +0 -1
  94. package/dist/protect-ffmpeg-codecs.js.map +0 -1
  95. package/dist/protect-ffmpeg-exec.js.map +0 -1
  96. package/dist/protect-ffmpeg-options.js.map +0 -1
  97. package/dist/protect-ffmpeg-record.js.map +0 -1
  98. package/dist/protect-ffmpeg-stream.js.map +0 -1
  99. package/dist/protect-ffmpeg.js.map +0 -1
  100. package/dist/protect-light.js.map +0 -1
  101. package/dist/protect-liveviews.js.map +0 -1
  102. package/dist/protect-nvr-events.js.map +0 -1
  103. package/dist/protect-nvr-systeminfo.js.map +0 -1
  104. package/dist/protect-securitysystem.js.map +0 -1
  105. package/dist/protect-sensor.js +0 -449
  106. package/dist/protect-sensor.js.map +0 -1
  107. package/dist/protect-viewer.js.map +0 -1
  108. /package/dist/{protect-camera-package.d.ts → devices/protect-camera-package.d.ts} +0 -0
  109. /package/dist/{protect-ffmpeg-codecs.js → ffmpeg/protect-ffmpeg-codecs.js} +0 -0
  110. /package/dist/{protect-ffmpeg-stream.js → ffmpeg/protect-ffmpeg-stream.js} +0 -0
  111. /package/dist/{protect-ffmpeg.js → ffmpeg/protect-ffmpeg.js} +0 -0
@@ -1,5 +1,5 @@
1
1
  import { ProtectBase } from "./protect-device.js";
2
- import { ProtectReservedNames } from "./protect-types.js";
2
+ import { ProtectReservedNames } from "../protect-types.js";
3
3
  export class ProtectSecuritySystem extends ProtectBase {
4
4
  accessory;
5
5
  isAlarmTriggered;
@@ -46,21 +46,13 @@ export class ProtectSecuritySystem extends ProtectBase {
46
46
  // Configure MQTT capabilities for the security system.
47
47
  configureMqtt() {
48
48
  // Get the current status of the security system.
49
- this.nvr.mqtt?.subscribe(this.accessory, "securitysystem/get", (message) => {
50
- const value = message.toString().toLowerCase();
51
- // When we get the right message, we return the state of the security system.
52
- if (value !== "true") {
53
- return;
54
- }
55
- // Publish the current status of the security system.
56
- this.publishSecurityState();
57
- this.log.info("Security system status published via MQTT.");
49
+ this.nvr.mqtt?.subscribeGet(this.accessory, "securitysystem", "security system state", () => {
50
+ return this.currentSecuritySystemState;
58
51
  });
59
52
  // Set the security system state.
60
- this.nvr.mqtt?.subscribe(this.accessory, "securitysystem/set", (message) => {
53
+ this.nvr.mqtt?.subscribeSet(this.accessory, "securitysystem", "security system state", (value) => {
61
54
  const SecuritySystemCurrentState = this.hap.Characteristic.SecuritySystemCurrentState;
62
55
  const SecuritySystemTargetState = this.hap.Characteristic.SecuritySystemTargetState;
63
- const value = message.toString().toLowerCase();
64
56
  let alarmState;
65
57
  let targetState;
66
58
  // Map the request to our security states.
@@ -87,34 +79,32 @@ export class ProtectSecuritySystem extends ProtectBase {
87
79
  break;
88
80
  default:
89
81
  // The user sent a bad value. Ignore it and we're done.
90
- this.log.error("Unable to process MQTT security system setting: %s.", message.toString());
82
+ this.log.error("Unable to process MQTT security system setting: %s.", value);
91
83
  return;
92
84
  }
93
85
  // The security alarm gets handled differently than the other state settings.
94
86
  if (targetState === SecuritySystemCurrentState.ALARM_TRIGGERED) {
95
87
  this.setSecurityAlarm(alarmState);
96
- this.log.info("Security alarm %s via MQTT.", alarmState ? "triggered" : "reset");
97
88
  return;
98
89
  }
99
90
  // Set the security state, and we're done.
100
91
  this.accessory.getService(this.hap.Service.SecuritySystem)?.updateCharacteristic(SecuritySystemTargetState, targetState);
101
92
  this.setSecurityState(targetState);
102
- this.log.info("Security system state set via MQTT: %s.", value.charAt(0).toUpperCase() + value.slice(1));
103
93
  });
104
94
  return true;
105
95
  }
106
96
  // Configure the security system for HomeKit.
107
97
  configureSecuritySystem() {
108
98
  // Find any existing security system service.
109
- let securityService = this.accessory.getService(this.hap.Service.SecuritySystem);
99
+ let service = this.accessory.getService(this.hap.Service.SecuritySystem);
110
100
  // Add the security system service, if needed.
111
- if (!securityService) {
112
- securityService = new this.hap.Service.SecuritySystem(this.accessory.displayName);
113
- if (!securityService) {
101
+ if (!service) {
102
+ service = new this.hap.Service.SecuritySystem(this.accessory.displayName);
103
+ if (!service) {
114
104
  this.log.error("Unable to add security system.");
115
105
  return false;
116
106
  }
117
- this.accessory.addService(securityService);
107
+ this.accessory.addService(service);
118
108
  }
119
109
  const SecuritySystemCurrentState = this.hap.Characteristic.SecuritySystemCurrentState;
120
110
  const SecuritySystemTargetState = this.hap.Characteristic.SecuritySystemTargetState;
@@ -135,8 +125,10 @@ export class ProtectSecuritySystem extends ProtectBase {
135
125
  break;
136
126
  }
137
127
  // Handlers to get our current state, and initialize on startup.
138
- securityService.updateCharacteristic(SecuritySystemCurrentState, this.accessory.context.securityState)
139
- .getCharacteristic(SecuritySystemCurrentState)?.onGet(this.getSecurityState.bind(this));
128
+ service.updateCharacteristic(SecuritySystemCurrentState, this.accessory.context.securityState)
129
+ .getCharacteristic(SecuritySystemCurrentState)?.onGet(() => {
130
+ return this.isAlarmTriggered ? this.hap.Characteristic.SecuritySystemCurrentState.ALARM_TRIGGERED : this.accessory.context.securityState;
131
+ });
140
132
  // Handlers for triggering a change in the security system state.
141
133
  this.accessory.getService(this.hap.Service.SecuritySystem)?.getCharacteristic(SecuritySystemTargetState).onSet(this.setSecurityState.bind(this));
142
134
  // Set the initial state after we have setup our handlers above. This way, when we startup, we
@@ -211,33 +203,16 @@ export class ProtectSecuritySystem extends ProtectBase {
211
203
  getCharacteristic(this.hap.Characteristic.SecuritySystemTargetState).setProps({ validValues: availableSecurityStates });
212
204
  return true;
213
205
  }
214
- // Publish the security system state to MQTT.
215
- publishSecurityState() {
216
- const SecuritySystemCurrentState = this.hap.Characteristic.SecuritySystemCurrentState;
217
- let state;
218
- switch (this.accessory.context.securityState) {
219
- case SecuritySystemCurrentState.STAY_ARM:
220
- state = "Home";
221
- break;
222
- case SecuritySystemCurrentState.AWAY_ARM:
223
- state = "Away";
224
- break;
225
- case SecuritySystemCurrentState.NIGHT_ARM:
226
- state = "Night";
227
- break;
228
- case SecuritySystemCurrentState.ALARM_TRIGGERED:
229
- state = "Alarm";
230
- break;
231
- case SecuritySystemCurrentState.DISARMED:
232
- default:
233
- state = "Off";
234
- break;
235
- }
236
- this.nvr.mqtt?.publish(this.accessory, "securitysystem", this.isAlarmTriggered ? "Alarm" : state);
237
- }
238
- // Get the current security system state.
239
- getSecurityState() {
240
- return this.isAlarmTriggered ? this.hap.Characteristic.SecuritySystemCurrentState.ALARM_TRIGGERED : this.accessory.context.securityState;
206
+ // Utility to translate security system states.
207
+ get currentSecuritySystemState() {
208
+ const securitySystemCurrentState = {
209
+ [this.hap.Characteristic.SecuritySystemCurrentState.ALARM_TRIGGERED]: "Alarm",
210
+ [this.hap.Characteristic.SecuritySystemCurrentState.AWAY_ARM]: "Away",
211
+ [this.hap.Characteristic.SecuritySystemCurrentState.DISARMED]: "Off",
212
+ [this.hap.Characteristic.SecuritySystemCurrentState.NIGHT_ARM]: "Night",
213
+ [this.hap.Characteristic.SecuritySystemCurrentState.STAY_ARM]: "Home"
214
+ };
215
+ return this.isAlarmTriggered ? "Alarm" : securitySystemCurrentState[this.accessory.context.securityState] ?? "Off";
241
216
  }
242
217
  // Change the security system state, and enable or disable motion detection accordingly.
243
218
  setSecurityState(value) {
@@ -250,9 +225,8 @@ export class ProtectSecuritySystem extends ProtectBase {
250
225
  if (!liveviews) {
251
226
  return;
252
227
  }
253
- // We have three different states which can be triggered (aside from disarming).
254
- // Those states are home, away, and night. We use this as a convenient way to easily enable or disable motion detection
255
- // on a Protect controller and effectively give us scene-type functionality in a nice way.
228
+ // We have three different states which can be triggered (aside from disarming). Those states are home, away, and night. We use this as a convenient way to easily
229
+ // enable or disable motion detection on a Protect controller and effectively give us scene-type functionality in a nice way.
256
230
  switch (value) {
257
231
  case SecuritySystemTargetState.STAY_ARM:
258
232
  newState = SecuritySystemCurrentState.STAY_ARM;
@@ -274,9 +248,8 @@ export class ProtectSecuritySystem extends ProtectBase {
274
248
  newState = SecuritySystemCurrentState.DISARMED;
275
249
  break;
276
250
  }
277
- // Get the complete list of cameras in the liveview we're interested in. This cryptic line grabs the list
278
- // of liveviews that have the name we're interested in (turns out, you can define multiple liveviews in Protect
279
- // with the same name...who knew!), and then create a single list containing all of the cameras found.
251
+ // Get the complete list of cameras in the liveview we're interested in. This cryptic line grabs the list of liveviews that have the name we're interested in (turns
252
+ // out, you can define multiple liveviews in Protect with the same name...who knew!), and then create a single list containing all of the cameras found.
280
253
  const targetCameraIds = liveviews.filter(view => view.name.toLowerCase() === viewScene).map(view => view.slots.map(slots => slots.cameras)).flat(2);
281
254
  // We don't have a liveview for this state and we aren't disarming - update state for the user and we're done.
282
255
  if (newState !== SecuritySystemCurrentState.DISARMED && !targetCameraIds.length) {
@@ -294,8 +267,8 @@ export class ProtectSecuritySystem extends ProtectBase {
294
267
  continue;
295
268
  }
296
269
  let targetState = false;
297
- // If we're disarming, then all Protect cameras will disable motion detection in HomeKit. Otherwise,
298
- // check to see if this is one of the cameras we want to turn on motion detection for.
270
+ // If we're disarming, then all Protect cameras will disable motion detection in HomeKit. Otherwise, check to see if this is one of the cameras we want to turn on
271
+ // motion detection for.
299
272
  if (((newState !== SecuritySystemCurrentState.DISARMED) ||
300
273
  ((newState === SecuritySystemCurrentState.DISARMED) && targetCameraIds.length)) && targetCameraIds.some(thisCameraId => thisCameraId === targetUfp?.id)) {
301
274
  targetState = true;
@@ -320,7 +293,7 @@ export class ProtectSecuritySystem extends ProtectBase {
320
293
  this.accessory.getService(this.hap.Service.Switch)?.updateCharacteristic(this.hap.Characteristic.On, this.isAlarmTriggered);
321
294
  }
322
295
  // Publish to MQTT, if configured.
323
- this.publishSecurityState();
296
+ this.nvr.mqtt?.publish(this.accessory, "securitysystem", this.currentSecuritySystemState);
324
297
  }
325
298
  // Set the security alarm.
326
299
  setSecurityAlarm(value) {
@@ -335,7 +308,7 @@ export class ProtectSecuritySystem extends ProtectBase {
335
308
  // Update the security alarm state.
336
309
  this.accessory.getService(this.hap.Service.Switch)?.updateCharacteristic(this.hap.Characteristic.On, this.isAlarmTriggered);
337
310
  // Publish to MQTT, if configured.
338
- this.publishSecurityState();
311
+ this.nvr.mqtt?.publish(this.accessory, "securitysystem", this.currentSecuritySystemState);
339
312
  }
340
313
  }
341
314
  //# sourceMappingURL=protect-securitysystem.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"protect-securitysystem.js","sourceRoot":"","sources":["../../src/devices/protect-securitysystem.ts"],"names":[],"mappings":"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"}
@@ -1,8 +1,9 @@
1
1
  import { PlatformAccessory } from "homebridge";
2
2
  import { ProtectSensorConfig } from "unifi-protect";
3
3
  import { ProtectDevice } from "./protect-device.js";
4
- import { ProtectNvr } from "./protect-nvr.js";
4
+ import { ProtectNvr } from "../protect-nvr.js";
5
5
  export declare class ProtectSensor extends ProtectDevice {
6
+ private enabledSensors;
6
7
  private lastAlarm;
7
8
  private lastContact;
8
9
  private lastLeak;
@@ -10,7 +11,7 @@ export declare class ProtectSensor extends ProtectDevice {
10
11
  constructor(nvr: ProtectNvr, device: ProtectSensorConfig, accessory: PlatformAccessory);
11
12
  private configureDevice;
12
13
  private configureBatteryService;
13
- updateDevice(isInitialized?: boolean): string[];
14
+ private updateDevice;
14
15
  private configureAlarmSoundSensor;
15
16
  private configureAmbientLightSensor;
16
17
  private configureContactSensor;
@@ -0,0 +1,402 @@
1
+ import { ProtectDevice } from "./protect-device.js";
2
+ import { ProtectReservedNames } from "../protect-types.js";
3
+ export class ProtectSensor extends ProtectDevice {
4
+ enabledSensors;
5
+ lastAlarm;
6
+ lastContact;
7
+ lastLeak;
8
+ ufp;
9
+ // Create an instance.
10
+ constructor(nvr, device, accessory) {
11
+ super(nvr, accessory);
12
+ this.enabledSensors = [];
13
+ this.ufp = device;
14
+ this.configureHints();
15
+ this.configureDevice();
16
+ }
17
+ // Initialize and configure the sensor accessory for HomeKit.
18
+ configureDevice() {
19
+ // Clean out the context object in case it's been polluted somehow.
20
+ this.accessory.context = {};
21
+ this.accessory.context.mac = this.ufp.mac;
22
+ this.accessory.context.nvr = this.nvr.ufp.mac;
23
+ // Configure accessory information.
24
+ this.configureInfo();
25
+ // Configure the battery status.
26
+ this.configureBatteryService();
27
+ // Configure the sensor services that have been enabled.
28
+ this.updateDevice(false);
29
+ // Configure MQTT services.
30
+ this.configureMqtt();
31
+ // Listen for events.
32
+ this.nvr.events.on("updateEvent." + this.ufp.id, this.listeners["updateEvent." + this.ufp.id] = this.eventHandler.bind(this));
33
+ return true;
34
+ }
35
+ // Update battery status information for HomeKit.
36
+ configureBatteryService() {
37
+ // Acquire the service.
38
+ const service = this.acquireService(this.hap.Service.Battery);
39
+ // Fail gracefully.
40
+ if (!service) {
41
+ this.log.error("Unable to add the battery service.");
42
+ return false;
43
+ }
44
+ // Retrieve the current battery status when requested.
45
+ service.getCharacteristic(this.hap.Characteristic.StatusLowBattery)?.onGet(() => {
46
+ return this.ufp.batteryStatus?.percentage ?? 0;
47
+ });
48
+ service.getCharacteristic(this.hap.Characteristic.StatusLowBattery)?.onGet(() => {
49
+ return this.ufp.batteryStatus?.isLow ?? false;
50
+ });
51
+ // Initialize the battery state.
52
+ this.updateBatteryStatus();
53
+ return true;
54
+ }
55
+ // Update accessory services and characteristics.
56
+ updateDevice(isInitialized = true) {
57
+ const currentEnabledSensors = [];
58
+ // Update the battery status for the accessory.
59
+ this.updateBatteryStatus();
60
+ // Configure the alarm sound sensor.
61
+ if (this.configureAlarmSoundSensor()) {
62
+ currentEnabledSensors.push("alarm sound");
63
+ }
64
+ // Configure the ambient light sensor.
65
+ if (this.configureAmbientLightSensor()) {
66
+ currentEnabledSensors.push("ambient light");
67
+ }
68
+ // Configure the contact sensor.
69
+ if (this.configureContactSensor()) {
70
+ currentEnabledSensors.push("contact");
71
+ }
72
+ // Configure the humidity sensor.
73
+ if (this.configureHumiditySensor()) {
74
+ currentEnabledSensors.push("humidity");
75
+ }
76
+ // Configure the alarm sound sensor.
77
+ if (this.configureLeakSensor()) {
78
+ currentEnabledSensors.push("leak");
79
+ }
80
+ // Configure the motion sensor.
81
+ if (this.configureMotionSensor(this.ufp.motionSettings?.isEnabled, isInitialized)) {
82
+ // Sensor accessories also support battery, connection, and tamper status...we need to handle those ourselves.
83
+ const motionService = this.accessory.getService(this.hap.Service.MotionSensor);
84
+ if (motionService) {
85
+ // Update the state characteristics.
86
+ this.configureStateCharacteristics(motionService);
87
+ }
88
+ currentEnabledSensors.push("motion sensor");
89
+ }
90
+ // Configure the occupancy sensor.
91
+ this.configureOccupancySensor(this.ufp.motionSettings?.isEnabled, isInitialized);
92
+ // Configure the temperature sensor.
93
+ if (this.configureTemperatureSensor()) {
94
+ currentEnabledSensors.push("temperature");
95
+ }
96
+ // Inform the user if we've had a change.
97
+ if (this.enabledSensors.join(" ") !== currentEnabledSensors.join(" ")) {
98
+ this.enabledSensors = currentEnabledSensors;
99
+ // Inform the user what we're enabling on startup.
100
+ if (this.enabledSensors.length) {
101
+ this.log.info("Enabled sensor%s: %s.", this.enabledSensors.length > 1 ? "s" : "", this.enabledSensors.join(", "));
102
+ }
103
+ else {
104
+ this.log.info("No sensors enabled.");
105
+ }
106
+ }
107
+ }
108
+ // Configure the alarm sound sensor for HomeKit.
109
+ configureAlarmSoundSensor() {
110
+ // Validate whether we should have this service enabled.
111
+ if (!this.validService(this.hap.Service.ContactSensor, () => {
112
+ // Have we disabled the sensor?
113
+ if (!this.ufp.alarmSettings?.isEnabled) {
114
+ return false;
115
+ }
116
+ return true;
117
+ }, ProtectReservedNames.CONTACT_SENSOR_ALARM_SOUND)) {
118
+ return false;
119
+ }
120
+ // Acquire the service.
121
+ const service = this.acquireService(this.hap.Service.ContactSensor, this.accessoryName + " Alarm Sound", ProtectReservedNames.CONTACT_SENSOR_ALARM_SOUND);
122
+ // Fail gracefully.
123
+ if (!service) {
124
+ this.log.error("Unable to add alarm sound contact sensor.");
125
+ return false;
126
+ }
127
+ // Retrieve the current contact sensor state when requested.
128
+ service.getCharacteristic(this.hap.Characteristic.ContactSensorState)?.onGet(() => {
129
+ return this.alarmDetected;
130
+ });
131
+ // Update the sensor.
132
+ service.updateCharacteristic(this.hap.Characteristic.ContactSensorState, this.alarmDetected);
133
+ // Update the state characteristics.
134
+ this.configureStateCharacteristics(service);
135
+ return true;
136
+ }
137
+ // Configure the ambient light sensor for HomeKit.
138
+ configureAmbientLightSensor() {
139
+ // Validate whether we should have this service enabled.
140
+ if (!this.validService(this.hap.Service.LightSensor, () => {
141
+ // Have we disabled the sensor?
142
+ if (!this.ufp.lightSettings?.isEnabled) {
143
+ return false;
144
+ }
145
+ return true;
146
+ })) {
147
+ return false;
148
+ }
149
+ // Acquire the service.
150
+ const service = this.acquireService(this.hap.Service.LightSensor);
151
+ // Fail gracefully.
152
+ if (!service) {
153
+ this.log.error("Unable to add ambient light sensor.");
154
+ return false;
155
+ }
156
+ // Retrieve the current light level when requested.
157
+ service.getCharacteristic(this.hap.Characteristic.CurrentAmbientLightLevel)?.onGet(() => {
158
+ // The minimum value for ambient light in HomeKit is 0.0001. I have no idea why...but it is. Honor it.
159
+ return this.ambientLight >= 0.0001 ? this.ambientLight : 0.0001;
160
+ });
161
+ // Update the sensor. The minimum value for ambient light in HomeKit is 0.0001. I have no idea why...but it is. Honor it.
162
+ service.updateCharacteristic(this.hap.Characteristic.CurrentAmbientLightLevel, this.ambientLight >= 0.0001 ? this.ambientLight : 0.0001);
163
+ // Update the state characteristics.
164
+ this.configureStateCharacteristics(service);
165
+ return true;
166
+ }
167
+ // Configure the contact sensor for HomeKit.
168
+ configureContactSensor() {
169
+ // Validate whether we should have this service enabled.
170
+ if (!this.validService(this.hap.Service.ContactSensor, () => {
171
+ // Have we disabled the sensor or are we configured as a leak sensor?
172
+ if (!this.ufp.mountType || (this.ufp.mountType === "leak") || (this.ufp.mountType === "none")) {
173
+ return false;
174
+ }
175
+ return true;
176
+ }, ProtectReservedNames.CONTACT_SENSOR)) {
177
+ return false;
178
+ }
179
+ // Acquire the service.
180
+ const service = this.acquireService(this.hap.Service.ContactSensor, undefined, ProtectReservedNames.CONTACT_SENSOR);
181
+ // Fail gracefully.
182
+ if (!service) {
183
+ this.log.error("Unable to add contact sensor.");
184
+ return false;
185
+ }
186
+ // Retrieve the current contact sensor state when requested.
187
+ service.getCharacteristic(this.hap.Characteristic.ContactSensorState)?.onGet(() => {
188
+ return this.contact;
189
+ });
190
+ // Update the sensor.
191
+ service.updateCharacteristic(this.hap.Characteristic.ContactSensorState, this.contact);
192
+ // Update the state characteristics.
193
+ this.configureStateCharacteristics(service);
194
+ return true;
195
+ }
196
+ // Configure the humidity sensor for HomeKit.
197
+ configureHumiditySensor() {
198
+ // Validate whether we should have this service enabled.
199
+ if (!this.validService(this.hap.Service.HumiditySensor, () => {
200
+ // Have we disabled the sensor?
201
+ if (!this.ufp.humiditySettings?.isEnabled) {
202
+ return false;
203
+ }
204
+ return true;
205
+ })) {
206
+ return false;
207
+ }
208
+ // Acquire the service.
209
+ const service = this.acquireService(this.hap.Service.HumiditySensor);
210
+ // Fail gracefully.
211
+ if (!service) {
212
+ this.log.error("Unable to add humidity sensor.");
213
+ return false;
214
+ }
215
+ // Retrieve the current humidity when requested.
216
+ service.getCharacteristic(this.hap.Characteristic.CurrentRelativeHumidity)?.onGet(() => {
217
+ return this.humidity < 0 ? 0 : this.humidity;
218
+ });
219
+ // Update the sensor.
220
+ service.updateCharacteristic(this.hap.Characteristic.CurrentRelativeHumidity, this.humidity < 0 ? 0 : this.humidity);
221
+ // Update the state characteristics.
222
+ this.configureStateCharacteristics(service);
223
+ return true;
224
+ }
225
+ // Configure the leak sensor for HomeKit.
226
+ configureLeakSensor() {
227
+ // Validate whether we should have this service enabled.
228
+ if (!this.validService(this.hap.Service.LeakSensor, () => {
229
+ // Have we disabled the leak sensor?
230
+ if (this.ufp.mountType !== "leak") {
231
+ return false;
232
+ }
233
+ return true;
234
+ })) {
235
+ return false;
236
+ }
237
+ // Acquire the service.
238
+ const service = this.acquireService(this.hap.Service.LeakSensor);
239
+ // Fail gracefully.
240
+ if (!service) {
241
+ this.log.error("Unable to add leak sensor.");
242
+ return false;
243
+ }
244
+ // Retrieve the current contact sensor state when requested.
245
+ service.getCharacteristic(this.hap.Characteristic.LeakDetected)?.onGet(() => {
246
+ return this.leakDetected;
247
+ });
248
+ // Update the sensor.
249
+ service.updateCharacteristic(this.hap.Characteristic.LeakDetected, this.leakDetected);
250
+ // Update the state characteristics.
251
+ this.configureStateCharacteristics(service);
252
+ return true;
253
+ }
254
+ // Configure the temperature sensor for HomeKit.
255
+ configureTemperatureSensor() {
256
+ // Validate whether we should have this service enabled.
257
+ if (!this.validService(this.hap.Service.TemperatureSensor, () => {
258
+ // Have we disabled the sensor?
259
+ if (!this.ufp.temperatureSettings?.isEnabled) {
260
+ return false;
261
+ }
262
+ return true;
263
+ })) {
264
+ return false;
265
+ }
266
+ // Acquire the service.
267
+ const service = this.acquireService(this.hap.Service.TemperatureSensor);
268
+ // Fail gracefully.
269
+ if (!service) {
270
+ this.log.error("Unable to add humidity sensor.");
271
+ return false;
272
+ }
273
+ // Retrieve the current temperature when requested.
274
+ service.getCharacteristic(this.hap.Characteristic.CurrentTemperature)?.onGet(() => {
275
+ return this.temperature < 0 ? 0 : this.temperature;
276
+ });
277
+ // Update the sensor.
278
+ service.updateCharacteristic(this.hap.Characteristic.CurrentTemperature, this.temperature < 0 ? 0 : this.temperature);
279
+ // Update the state characteristics.
280
+ this.configureStateCharacteristics(service);
281
+ return true;
282
+ }
283
+ // Configure the active connection status in HomeKit.
284
+ configureActiveStatus(service) {
285
+ // Retrieve the current connection status when requested.
286
+ service.getCharacteristic(this.hap.Characteristic.StatusActive)?.onGet(() => {
287
+ return this.isOnline;
288
+ });
289
+ // Update the current connection status.
290
+ service.updateCharacteristic(this.hap.Characteristic.StatusActive, this.isOnline);
291
+ return true;
292
+ }
293
+ // Update the battery status in HomeKit.
294
+ updateBatteryStatus() {
295
+ // Find the battery service, if it exists.
296
+ const batteryService = this.accessory.getService(this.hap.Service.Battery);
297
+ // Update the battery status.
298
+ batteryService?.updateCharacteristic(this.hap.Characteristic.BatteryLevel, this.ufp.batteryStatus?.percentage ?? 0);
299
+ batteryService?.updateCharacteristic(this.hap.Characteristic.StatusLowBattery, this.ufp.batteryStatus?.isLow);
300
+ return true;
301
+ }
302
+ // Configure the tamper status in HomeKit.
303
+ configureTamperedStatus(service) {
304
+ // Retrieve the current tamper status when requested.
305
+ service.getCharacteristic(this.hap.Characteristic.StatusTampered)?.onGet(() => {
306
+ return this.ufp.tamperingDetectedAt !== null;
307
+ });
308
+ // Update the tamper status.
309
+ service.updateCharacteristic(this.hap.Characteristic.StatusTampered, this.ufp.tamperingDetectedAt !== null);
310
+ return true;
311
+ }
312
+ // Configure the additional state characteristics in HomeKit.
313
+ configureStateCharacteristics(service) {
314
+ // Update the active connection status.
315
+ this.configureActiveStatus(service);
316
+ // Update the tamper status.
317
+ this.configureTamperedStatus(service);
318
+ return true;
319
+ }
320
+ // Get the current alarm alert detection information.
321
+ get alarmDetected() {
322
+ // Return true if we are not null, meaning the alarm has sounded.
323
+ const value = this.ufp.alarmTriggeredAt !== null;
324
+ // Save the state change and publish to MQTT.
325
+ if (value !== this.lastAlarm) {
326
+ this.lastAlarm = value;
327
+ this.publish("alarm", value.toString());
328
+ this.log.info("Alarm %sdetected.", value ? "" : "no longer ");
329
+ }
330
+ return value;
331
+ }
332
+ // Get the current ambient light information.
333
+ get ambientLight() {
334
+ return this.ufp.stats.light.value ?? -1;
335
+ }
336
+ // Get the current contact sensor information.
337
+ get contact() {
338
+ // Save the state change and publish to MQTT.
339
+ if (this.ufp.isOpened !== this.lastContact) {
340
+ this.lastContact = this.ufp.isOpened;
341
+ this.publish("contact", this.ufp.isOpened.toString());
342
+ }
343
+ return this.ufp.isOpened;
344
+ }
345
+ // Get the current humidity information.
346
+ get humidity() {
347
+ return this.ufp.stats.humidity.value ?? -1;
348
+ }
349
+ // Get the current leak sensor information.
350
+ get leakDetected() {
351
+ // Return true if we are not null, meaning a leak has been detected.
352
+ const value = this.ufp.leakDetectedAt !== null;
353
+ // If it's our first run, just save the state and we're done if we don't have a leak. If we do have a leak, make sure we inform the user.
354
+ if ((this.lastLeak === undefined) && !value) {
355
+ this.lastLeak = value;
356
+ return value;
357
+ }
358
+ // Save the state change and publish to MQTT.
359
+ if (value !== this.lastLeak) {
360
+ this.lastLeak = value;
361
+ this.publish("leak", value.toString());
362
+ this.log.info("Leak %sdetected.", value ? "" : "no longer ");
363
+ }
364
+ return value;
365
+ }
366
+ // Get the current temperature information.
367
+ get temperature() {
368
+ return this.ufp.stats.temperature.value ?? -1;
369
+ }
370
+ // Configure MQTT capabilities for sensors.
371
+ configureMqtt() {
372
+ this.subscribeGet("alarm", "alarm detected", () => {
373
+ return this.alarmDetected.toString();
374
+ });
375
+ this.subscribeGet("ambientlight", "ambient light", () => {
376
+ return this.ambientLight.toString();
377
+ });
378
+ this.subscribeGet("contact", "contact sensor", () => {
379
+ return this.contact.toString();
380
+ });
381
+ this.subscribeGet("humidity", "humidity", () => {
382
+ return this.humidity.toString();
383
+ });
384
+ this.subscribeGet("leak", "leak detected", () => {
385
+ return this.leakDetected.toString();
386
+ });
387
+ this.subscribeGet("temperature", "temperature", () => {
388
+ return this.temperature.toString();
389
+ });
390
+ }
391
+ // Handle sensor-related events.
392
+ eventHandler(packet) {
393
+ const payload = packet.payload;
394
+ // It's a motion event - process it accordingly.
395
+ if (payload.motionDetectedAt) {
396
+ this.nvr.events.motionEventHandler(this);
397
+ }
398
+ // Process it.
399
+ this.updateDevice();
400
+ }
401
+ }
402
+ //# sourceMappingURL=protect-sensor.js.map