homebridge-ecobee-security 0.7.0 → 0.7.1
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/CHANGELOG.md +9 -0
- package/README.md +5 -2
- package/lib/security.js +23 -8
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.7.1
|
|
4
|
+
|
|
5
|
+
- Keypad unlock: the plugin now reads ecobee's current state first and only disarms when the system
|
|
6
|
+
is armed, arming or alarming. A disarm sent while it was already off was followed by ecobee camera
|
|
7
|
+
activity alerts.
|
|
8
|
+
- An intrusion incident only shows as **Alarm triggered** while the system is armed. ecobee also
|
|
9
|
+
opens one for a camera activity alert while the system is off, which briefly showed as an alarm in
|
|
10
|
+
the Home app (and counted as one for security holds). Smoke alarms still show at any time.
|
|
11
|
+
|
|
3
12
|
## 0.7.0
|
|
4
13
|
|
|
5
14
|
- New setting **Disarm when a door is unlocked with its keypad** (`keypadDisarm`, off by default,
|
package/README.md
CHANGED
|
@@ -92,8 +92,9 @@ node <plugin folder>/bin/ecobee-login.js --browser # website sign-in
|
|
|
92
92
|
exit delay (0 by default). Off needs no PIN.
|
|
93
93
|
- **Changes from elsewhere** (ecobee app, keypad, ecobee automations) show up within 10 s, about
|
|
94
94
|
as fast as in the ecobee app (it polls too), and quickly after an exit delay ends.
|
|
95
|
-
- **Alarm triggered** while ecobee lists an open incident
|
|
96
|
-
|
|
95
|
+
- **Alarm triggered** while ecobee lists an open incident: a smoke alarm at any time, an intrusion
|
|
96
|
+
only while armed (ecobee also opens one for a camera activity alert while the system is off; that
|
|
97
|
+
isn't shown as an alarm). See `alarmTrigger` above for when it starts showing. Disarming clears it. Every change in the incident list is logged.
|
|
97
98
|
- **Siri:** asking for Home or for Stay mode both set Home (ecobee's Stay).
|
|
98
99
|
- **Night** is only offered with `offerNight`; ecobee has no Night mode of its own.
|
|
99
100
|
- After three failed reads in a row the accessory shows a fault; reads back off up to 5 minutes.
|
|
@@ -111,6 +112,8 @@ schedules, expiry), so the plugin needs no codes of its own.
|
|
|
111
112
|
unlocked (HomeKit's Lock Last Known Action), for example homebridge-nest-accfactory's Nest × Yale
|
|
112
113
|
locks. The settings page lists the locks found; untick the ones that shouldn't disarm. Locks
|
|
113
114
|
paired to Apple Home directly (not through Homebridge) can't be seen.
|
|
115
|
+
- **Only when armed:** the plugin checks ecobee's current state first and sends nothing if the system
|
|
116
|
+
is already off.
|
|
114
117
|
- **Only keypad unlocks** count: not the app, Siri, automations, a key or the thumb turn. Any code
|
|
115
118
|
that opens the lock disarms, yours included.
|
|
116
119
|
- **Speed:** the plugin checks the locks every second; the disarm reaches ecobee about as fast as
|
package/lib/security.js
CHANGED
|
@@ -73,7 +73,7 @@ export class SecuritySystem {
|
|
|
73
73
|
this.alarmAfterEntryDelay = alarmAfterEntryDelay;
|
|
74
74
|
// Extra exit-delay time for robots heading back to their base when Away is armed (ms).
|
|
75
75
|
this.returnWait = Math.max(0, returnWait) * 1000;
|
|
76
|
-
this.
|
|
76
|
+
this.openIncidents = [];
|
|
77
77
|
this.firstSeen = new Map();
|
|
78
78
|
|
|
79
79
|
const { Service, Characteristic } = api.hap;
|
|
@@ -259,8 +259,17 @@ export class SecuritySystem {
|
|
|
259
259
|
}
|
|
260
260
|
}
|
|
261
261
|
|
|
262
|
+
/**
|
|
263
|
+
* Open incidents that are alarms: smoke always, intrusions only while armed. ecobee also opens an
|
|
264
|
+
* intrusion incident for a camera activity alert while the system is off; that isn't an alarm.
|
|
265
|
+
*/
|
|
266
|
+
get incidents() {
|
|
267
|
+
const armed = [ArmedState.STAY, ArmedState.AWAY].includes(this.monitoring?.armedState);
|
|
268
|
+
return this.openIncidents.filter(i => i.detectedSmokeAlarm || armed);
|
|
269
|
+
}
|
|
270
|
+
|
|
262
271
|
noteIncidents(incidents) {
|
|
263
|
-
this.
|
|
272
|
+
this.openIncidents = incidents.filter(i => !CLOSED_INCIDENT.test(i.status ?? ''));
|
|
264
273
|
const summary = JSON.stringify(incidents);
|
|
265
274
|
if (summary !== this.incidentSummary) {
|
|
266
275
|
if (incidents.length || this.incidentSummary !== undefined) {
|
|
@@ -270,8 +279,8 @@ export class SecuritySystem {
|
|
|
270
279
|
}
|
|
271
280
|
// ecobee's incidents carry no time we read, so the entry delay counts from when we first saw one.
|
|
272
281
|
const now = Date.now();
|
|
273
|
-
const ids = new Set(this.
|
|
274
|
-
this.
|
|
282
|
+
const ids = new Set(this.openIncidents.map(i => i.id));
|
|
283
|
+
this.openIncidents.forEach(i => this.firstSeen.has(i.id) || this.firstSeen.set(i.id, now));
|
|
275
284
|
[...this.firstSeen.keys()].filter(id => !ids.has(id)).forEach(id => this.firstSeen.delete(id));
|
|
276
285
|
}
|
|
277
286
|
|
|
@@ -388,9 +397,8 @@ export class SecuritySystem {
|
|
|
388
397
|
|
|
389
398
|
|
|
390
399
|
/**
|
|
391
|
-
* A door was unlocked with its keypad: disarm, like Nest Guard with a Nest × Yale lock.
|
|
392
|
-
*
|
|
393
|
-
* Retried once, since a missed disarm means an alarm.
|
|
400
|
+
* A door was unlocked with its keypad: disarm, like Nest Guard with a Nest × Yale lock. Retried
|
|
401
|
+
* once, since a missed disarm means an alarm.
|
|
394
402
|
*/
|
|
395
403
|
keypadDisarm(lock) {
|
|
396
404
|
return this.serial(async () => {
|
|
@@ -398,6 +406,13 @@ export class SecuritySystem {
|
|
|
398
406
|
this.log.info(`${lock} was unlocked during the ${this.holders().join(' and ')} hold; it won't be put back to Away.`);
|
|
399
407
|
this.dropHold();
|
|
400
408
|
}
|
|
409
|
+
// Only disarm what's armed: a disarm sent while ecobee is already off isn't a no-op for ecobee
|
|
410
|
+
// (camera activity alerts followed it), so read the live state first. Can't read it: disarm anyway.
|
|
411
|
+
if (await this.refresh() && this.monitoring?.armedState === ArmedState.DISARMED
|
|
412
|
+
&& !this.monitoring.delayedArmedState?.desiredArmedState) {
|
|
413
|
+
this.log.info(`${lock} was unlocked with its keypad; the security system is already off.`);
|
|
414
|
+
return;
|
|
415
|
+
}
|
|
401
416
|
try {
|
|
402
417
|
await this.arm(Hk.DISARMED, `${lock} unlocked with its keypad`);
|
|
403
418
|
} catch {
|
|
@@ -552,7 +567,7 @@ export class SecuritySystem {
|
|
|
552
567
|
this.apply(home);
|
|
553
568
|
return true;
|
|
554
569
|
} catch (error) {
|
|
555
|
-
this.log.warn(`Could not read the security state
|
|
570
|
+
this.log.warn(`Could not read the security state (${error.message}).`);
|
|
556
571
|
return false;
|
|
557
572
|
}
|
|
558
573
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "homebridge-ecobee-security",
|
|
3
3
|
"displayName": "ecobee Smart Security",
|
|
4
|
-
"version": "0.7.
|
|
4
|
+
"version": "0.7.1",
|
|
5
5
|
"description": "ecobee Smart Security as a HomeKit security system: arm Stay / Away, disarm, alarm state (unofficial, ecobee cloud)",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "index.js",
|