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.
- package/dist/devices/index.d.ts +11 -0
- package/dist/devices/index.js +16 -0
- package/dist/devices/index.js.map +1 -0
- package/dist/{protect-camera-package.js → devices/protect-camera-package.js} +2 -4
- package/dist/devices/protect-camera-package.js.map +1 -0
- package/dist/{protect-camera.d.ts → devices/protect-camera.d.ts} +2 -5
- package/dist/{protect-camera.js → devices/protect-camera.js} +119 -210
- package/dist/devices/protect-camera.js.map +1 -0
- package/dist/{protect-chime.d.ts → devices/protect-chime.d.ts} +4 -1
- package/dist/devices/protect-chime.js +180 -0
- package/dist/devices/protect-chime.js.map +1 -0
- package/dist/{protect-device.d.ts → devices/protect-device.d.ts} +12 -5
- package/dist/{protect-device.js → devices/protect-device.js} +159 -109
- package/dist/devices/protect-device.js.map +1 -0
- package/dist/{protect-doorbell.d.ts → devices/protect-doorbell.d.ts} +1 -1
- package/dist/{protect-doorbell.js → devices/protect-doorbell.js} +50 -83
- package/dist/devices/protect-doorbell.js.map +1 -0
- package/dist/{protect-light.d.ts → devices/protect-light.d.ts} +1 -1
- package/dist/{protect-light.js → devices/protect-light.js} +34 -44
- package/dist/devices/protect-light.js.map +1 -0
- package/dist/{protect-liveviews.d.ts → devices/protect-liveviews.d.ts} +1 -1
- package/dist/{protect-liveviews.js → devices/protect-liveviews.js} +11 -21
- package/dist/devices/protect-liveviews.js.map +1 -0
- package/dist/{protect-nvr-systeminfo.d.ts → devices/protect-nvr-systeminfo.d.ts} +1 -1
- package/dist/{protect-nvr-systeminfo.js → devices/protect-nvr-systeminfo.js} +3 -9
- package/dist/devices/protect-nvr-systeminfo.js.map +1 -0
- package/dist/{protect-securitysystem.d.ts → devices/protect-securitysystem.d.ts} +2 -3
- package/dist/{protect-securitysystem.js → devices/protect-securitysystem.js} +32 -59
- package/dist/devices/protect-securitysystem.js.map +1 -0
- package/dist/{protect-sensor.d.ts → devices/protect-sensor.d.ts} +3 -2
- package/dist/devices/protect-sensor.js +402 -0
- package/dist/devices/protect-sensor.js.map +1 -0
- package/dist/{protect-viewer.d.ts → devices/protect-viewer.d.ts} +1 -1
- package/dist/{protect-viewer.js → devices/protect-viewer.js} +21 -28
- package/dist/devices/protect-viewer.js.map +1 -0
- package/dist/ffmpeg/index.d.ts +6 -0
- package/dist/ffmpeg/index.js +11 -0
- package/dist/ffmpeg/index.js.map +1 -0
- package/dist/{protect-ffmpeg-codecs.d.ts → ffmpeg/protect-ffmpeg-codecs.d.ts} +1 -1
- package/dist/ffmpeg/protect-ffmpeg-codecs.js.map +1 -0
- package/dist/{protect-ffmpeg-exec.d.ts → ffmpeg/protect-ffmpeg-exec.d.ts} +5 -2
- package/dist/{protect-ffmpeg-exec.js → ffmpeg/protect-ffmpeg-exec.js} +13 -1
- package/dist/ffmpeg/protect-ffmpeg-exec.js.map +1 -0
- package/dist/{protect-ffmpeg-options.d.ts → ffmpeg/protect-ffmpeg-options.d.ts} +1 -1
- package/dist/{protect-ffmpeg-options.js → ffmpeg/protect-ffmpeg-options.js} +1 -1
- package/dist/ffmpeg/protect-ffmpeg-options.js.map +1 -0
- package/dist/{protect-ffmpeg-record.d.ts → ffmpeg/protect-ffmpeg-record.d.ts} +1 -1
- package/dist/{protect-ffmpeg-record.js → ffmpeg/protect-ffmpeg-record.js} +7 -3
- package/dist/ffmpeg/protect-ffmpeg-record.js.map +1 -0
- package/dist/{protect-ffmpeg-stream.d.ts → ffmpeg/protect-ffmpeg-stream.d.ts} +1 -1
- package/dist/ffmpeg/protect-ffmpeg-stream.js.map +1 -0
- package/dist/{protect-ffmpeg.d.ts → ffmpeg/protect-ffmpeg.d.ts} +3 -3
- package/dist/ffmpeg/protect-ffmpeg.js.map +1 -0
- package/dist/{protect-nvr-events.d.ts → protect-events.d.ts} +3 -4
- package/dist/{protect-nvr-events.js → protect-events.js} +4 -4
- package/dist/protect-events.js.map +1 -0
- package/dist/protect-mqtt.d.ts +3 -2
- package/dist/protect-mqtt.js +30 -6
- package/dist/protect-mqtt.js.map +1 -1
- package/dist/protect-nvr.d.ts +4 -8
- package/dist/protect-nvr.js +82 -129
- package/dist/protect-nvr.js.map +1 -1
- package/dist/protect-options.js +7 -5
- package/dist/protect-options.js.map +1 -1
- package/dist/protect-platform.d.ts +1 -1
- package/dist/protect-platform.js +1 -1
- package/dist/protect-platform.js.map +1 -1
- package/dist/protect-record.d.ts +4 -2
- package/dist/protect-record.js +37 -34
- package/dist/protect-record.js.map +1 -1
- package/dist/protect-snapshot.d.ts +21 -0
- package/dist/protect-snapshot.js +200 -0
- package/dist/protect-snapshot.js.map +1 -0
- package/dist/protect-stream.d.ts +3 -7
- package/dist/protect-stream.js +7 -86
- package/dist/protect-stream.js.map +1 -1
- package/dist/protect-timeshift.d.ts +3 -2
- package/dist/protect-timeshift.js +31 -30
- package/dist/protect-timeshift.js.map +1 -1
- package/dist/protect-types.d.ts +5 -6
- package/dist/protect-types.js +8 -0
- package/dist/protect-types.js.map +1 -1
- package/dist/settings.d.ts +3 -6
- package/dist/settings.js +6 -12
- package/dist/settings.js.map +1 -1
- package/homebridge-ui/public/index.html +2 -0
- package/package.json +12 -12
- package/dist/protect-camera-package.js.map +0 -1
- package/dist/protect-camera.js.map +0 -1
- package/dist/protect-chime.js +0 -108
- package/dist/protect-chime.js.map +0 -1
- package/dist/protect-device.js.map +0 -1
- package/dist/protect-doorbell.js.map +0 -1
- package/dist/protect-ffmpeg-codecs.js.map +0 -1
- package/dist/protect-ffmpeg-exec.js.map +0 -1
- package/dist/protect-ffmpeg-options.js.map +0 -1
- package/dist/protect-ffmpeg-record.js.map +0 -1
- package/dist/protect-ffmpeg-stream.js.map +0 -1
- package/dist/protect-ffmpeg.js.map +0 -1
- package/dist/protect-light.js.map +0 -1
- package/dist/protect-liveviews.js.map +0 -1
- package/dist/protect-nvr-events.js.map +0 -1
- package/dist/protect-nvr-systeminfo.js.map +0 -1
- package/dist/protect-securitysystem.js.map +0 -1
- package/dist/protect-sensor.js +0 -449
- package/dist/protect-sensor.js.map +0 -1
- package/dist/protect-viewer.js.map +0 -1
- /package/dist/{protect-camera-package.d.ts → devices/protect-camera-package.d.ts} +0 -0
- /package/dist/{protect-ffmpeg-codecs.js → ffmpeg/protect-ffmpeg-codecs.js} +0 -0
- /package/dist/{protect-ffmpeg-stream.js → ffmpeg/protect-ffmpeg-stream.js} +0 -0
- /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 "
|
|
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?.
|
|
50
|
-
|
|
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?.
|
|
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.",
|
|
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
|
|
99
|
+
let service = this.accessory.getService(this.hap.Service.SecuritySystem);
|
|
110
100
|
// Add the security system service, if needed.
|
|
111
|
-
if (!
|
|
112
|
-
|
|
113
|
-
if (!
|
|
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(
|
|
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
|
-
|
|
139
|
-
.getCharacteristic(SecuritySystemCurrentState)?.onGet(
|
|
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
|
-
//
|
|
215
|
-
|
|
216
|
-
const
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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.
|
|
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.
|
|
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 "
|
|
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
|
|
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
|