homebridge-verisure 1.14.1 → 1.16.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/CHANGELOG.md +18 -0
- package/README.md +7 -3
- package/bin/verisure +4 -3
- package/config.schema.json +44 -0
- package/lib/accessories/alarm.js +1 -1
- package/lib/accessories/contactsensor.js +1 -1
- package/lib/accessories/doorlock.js +50 -7
- package/lib/accessories/verisure.js +2 -2
- package/lib/platform.js +41 -18
- package/package.json +13 -7
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,21 @@
|
|
|
1
|
+
## 1.16.0 (Aug 27, 2022)
|
|
2
|
+
|
|
3
|
+
### Plugin
|
|
4
|
+
|
|
5
|
+
* Added config options for door lock; auto-lock and volume.
|
|
6
|
+
|
|
7
|
+
## 1.15.0 (Jan 11, 2022)
|
|
8
|
+
|
|
9
|
+
### Plugin
|
|
10
|
+
|
|
11
|
+
* Added config option for installations to initiate.
|
|
12
|
+
|
|
13
|
+
## 1.14.2 (Jan 4, 2022)
|
|
14
|
+
|
|
15
|
+
### Plugin
|
|
16
|
+
|
|
17
|
+
* Initiate gracefully, to not affect other plugins.
|
|
18
|
+
|
|
1
19
|
## 1.14.1 (Oct 8, 2021)
|
|
2
20
|
|
|
3
21
|
### Dependencies
|
package/README.md
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
# homebridge-verisure
|
|
2
2
|
|
|
3
|
-
[](https://github.com/homebridge/homebridge/wiki/Verified-Plugins)
|
|
4
|
+
|
|
5
|
+
[](https://snyk.io/)
|
|
4
6
|
|
|
5
7
|
[](https://github.com/ptz0n/homebridge-verisure/actions?query=workflow%3ATest)
|
|
6
8
|
|
|
@@ -51,6 +53,7 @@ your array (list) of enabled platform plugins. Example config:
|
|
|
51
53
|
"token": "vid=topSecretToken",
|
|
52
54
|
"alarmCode": "0000",
|
|
53
55
|
"doorCode": "000000",
|
|
56
|
+
"installations": ["Alias"],
|
|
54
57
|
"pollInterval": 60
|
|
55
58
|
}
|
|
56
59
|
]
|
|
@@ -61,16 +64,17 @@ your array (list) of enabled platform plugins. Example config:
|
|
|
61
64
|
* __`token`__ Required string for accounts with MFA enabled.
|
|
62
65
|
* `alarmCode` Optional string containing your security system alarm code.
|
|
63
66
|
* `doorCode` Optional string containing your door lock code.
|
|
67
|
+
* `installations` Optional array for filtering installations based on Verisure alias. Defaults to `[]`
|
|
64
68
|
* `pollInterval` Optional integer containing poll interval in seconds. Defaults to `60`.
|
|
65
69
|
|
|
66
70
|
### Multi-factor authentication
|
|
67
71
|
|
|
68
72
|
> [Verisure] MFA is enabled for user. Please see README.
|
|
69
73
|
|
|
70
|
-
In 2021 Verisure started enrolling MFA which requires you to obtain a long lived token. This token is used instead of a `password` in your config and will need to be renewed yearly. After installing the plugin, run `npx verisure` in your terminal and copy the output values into your config.
|
|
74
|
+
In 2021 Verisure started enrolling MFA which requires you to obtain a long lived token. This token is used instead of a `password` in your config and will need to be renewed yearly. After installing the plugin, run `npx homebridge-verisure` in your terminal and copy the output values into your config.
|
|
71
75
|
|
|
72
76
|
```bash
|
|
73
|
-
$ npx verisure
|
|
77
|
+
$ npx homebridge-verisure
|
|
74
78
|
✔ What is your login email? · foo@bar.com
|
|
75
79
|
✔ What is your password? · ********************
|
|
76
80
|
|
package/bin/verisure
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
/* eslint-disable no-console */
|
|
2
3
|
|
|
3
4
|
const { prompt, Password } = require('enquirer');
|
|
4
5
|
|
|
@@ -25,7 +26,7 @@ const run = async () => {
|
|
|
25
26
|
await verisure.getToken();
|
|
26
27
|
|
|
27
28
|
if (!verisure.getCookie('vid')) {
|
|
28
|
-
console.log(
|
|
29
|
+
console.log('\n', 'One-time code sent.', '\n');
|
|
29
30
|
|
|
30
31
|
const { code } = await prompt({
|
|
31
32
|
type: 'input',
|
|
@@ -37,13 +38,13 @@ const run = async () => {
|
|
|
37
38
|
await verisure.getToken(code.trim());
|
|
38
39
|
}
|
|
39
40
|
|
|
40
|
-
console.log(
|
|
41
|
+
console.log('\n', 'Your config is ready.', '\n');
|
|
41
42
|
|
|
42
43
|
console.log(JSON.stringify({
|
|
43
44
|
platform: 'verisure',
|
|
44
45
|
name: 'Verisure',
|
|
45
46
|
email,
|
|
46
|
-
token: verisure.getCookie('vid')
|
|
47
|
+
token: verisure.getCookie('vid'),
|
|
47
48
|
}, null, 2));
|
|
48
49
|
};
|
|
49
50
|
|
package/config.schema.json
CHANGED
|
@@ -18,16 +18,27 @@
|
|
|
18
18
|
"token": {
|
|
19
19
|
"title": "Token",
|
|
20
20
|
"type": "string",
|
|
21
|
+
"placeholder": "vid=topSecretToken",
|
|
21
22
|
"required": false
|
|
22
23
|
},
|
|
23
24
|
"alarmCode": {
|
|
24
25
|
"title": "Alarm Code",
|
|
25
26
|
"type": "string",
|
|
27
|
+
"placeholder": "0000",
|
|
26
28
|
"required": false
|
|
27
29
|
},
|
|
28
30
|
"doorCode": {
|
|
29
31
|
"title": "Door Code",
|
|
30
32
|
"type": "string",
|
|
33
|
+
"placeholder": "000000",
|
|
34
|
+
"required": false
|
|
35
|
+
},
|
|
36
|
+
"installations": {
|
|
37
|
+
"title": "Installations",
|
|
38
|
+
"type": "array",
|
|
39
|
+
"items": {
|
|
40
|
+
"type": "string"
|
|
41
|
+
},
|
|
31
42
|
"required": false
|
|
32
43
|
},
|
|
33
44
|
"pollInterval": {
|
|
@@ -35,9 +46,42 @@
|
|
|
35
46
|
"type": "integer",
|
|
36
47
|
"default": 60,
|
|
37
48
|
"required": false
|
|
49
|
+
},
|
|
50
|
+
"showAutoLockSwitch": {
|
|
51
|
+
"title": "Show Auto-lock switch",
|
|
52
|
+
"type": "boolean",
|
|
53
|
+
"default": true
|
|
54
|
+
},
|
|
55
|
+
"showAudioSwitch": {
|
|
56
|
+
"title": "Show audio switch",
|
|
57
|
+
"type": "boolean",
|
|
58
|
+
"default": true
|
|
59
|
+
},
|
|
60
|
+
"audioOffValue": {
|
|
61
|
+
"title": "Audio off Value",
|
|
62
|
+
"type": "string",
|
|
63
|
+
"default": "SILENCE",
|
|
64
|
+
"oneOf": [
|
|
65
|
+
{ "title": "Silence", "enum": ["SILENCE"] },
|
|
66
|
+
{ "title": "Low", "enum": ["LOW"] }
|
|
67
|
+
],
|
|
68
|
+
"required": true,
|
|
69
|
+
"functionBody": "return model.showAudioSwitch === true;"
|
|
70
|
+
},
|
|
71
|
+
"audioOnValue": {
|
|
72
|
+
"title": "Audio on Value",
|
|
73
|
+
"type": "string",
|
|
74
|
+
"default": "HIGH",
|
|
75
|
+
"oneOf": [
|
|
76
|
+
{ "title": "Low", "enum": ["LOW"] },
|
|
77
|
+
{ "title": "High", "enum": ["HIGH"] }
|
|
78
|
+
],
|
|
79
|
+
"required": true,
|
|
80
|
+
"functionBody": "return model.showAudioSwitch === true;"
|
|
38
81
|
}
|
|
39
82
|
}
|
|
40
83
|
},
|
|
41
84
|
"form": null,
|
|
42
85
|
"display": null
|
|
86
|
+
|
|
43
87
|
}
|
package/lib/accessories/alarm.js
CHANGED
|
@@ -15,7 +15,7 @@ class ContactSensor extends VerisureAccessory {
|
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
getCurrentSensorState(callback) {
|
|
18
|
-
this.log('Getting current sensor state.');
|
|
18
|
+
this.log('Getting current sensor state.', 'debug');
|
|
19
19
|
|
|
20
20
|
this.installation.getOverview()
|
|
21
21
|
.then((overview) => overview.doorWindow.doorWindowDevice
|
|
@@ -8,6 +8,7 @@ class DoorLock extends VerisureAccessory {
|
|
|
8
8
|
|
|
9
9
|
this.doorCode = this.platformConfig.doorCode;
|
|
10
10
|
this.switchName = VerisureAccessory.getUniqueAccessoryName(`Auto-lock (${this.config.area})`);
|
|
11
|
+
this.audioName = VerisureAccessory.getUniqueAccessoryName(`Audio (${this.config.area})`);
|
|
11
12
|
this.configUrl = `/device/${this.serialNumber}/doorlockconfig`;
|
|
12
13
|
}
|
|
13
14
|
|
|
@@ -38,7 +39,7 @@ class DoorLock extends VerisureAccessory {
|
|
|
38
39
|
}
|
|
39
40
|
|
|
40
41
|
getCurrentLockState(callback) {
|
|
41
|
-
this.log('Getting current lock state.');
|
|
42
|
+
this.log('Getting current lock state.', 'debug');
|
|
42
43
|
|
|
43
44
|
// TODO: Use this.cachedValue, if available?
|
|
44
45
|
|
|
@@ -124,6 +125,36 @@ class DoorLock extends VerisureAccessory {
|
|
|
124
125
|
});
|
|
125
126
|
}
|
|
126
127
|
|
|
128
|
+
getAudioState(callback) {
|
|
129
|
+
this.installation.client({ url: this.configUrl })
|
|
130
|
+
.then((config) => {
|
|
131
|
+
this.audioState = config.volume !== this.platformConfig.audioOffValue;
|
|
132
|
+
callback(null, this.audioState);
|
|
133
|
+
})
|
|
134
|
+
.catch(callback);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
setAudioState(value, callback) {
|
|
138
|
+
this.audioState = value;
|
|
139
|
+
|
|
140
|
+
const volume = value
|
|
141
|
+
? this.platformConfig.audioOnValue
|
|
142
|
+
: this.platformConfig.audioOffValue;
|
|
143
|
+
|
|
144
|
+
const request = {
|
|
145
|
+
method: 'PUT',
|
|
146
|
+
url: this.configUrl,
|
|
147
|
+
data: { volume },
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
this.installation.client(request)
|
|
151
|
+
.then(() => callback(null))
|
|
152
|
+
.catch((error) => {
|
|
153
|
+
// TODO: Revert config state in this.value?
|
|
154
|
+
callback({ message: error.errorMessage });
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
|
|
127
158
|
getServices() {
|
|
128
159
|
const { Service, Characteristic } = this.homebridge.hap;
|
|
129
160
|
|
|
@@ -141,13 +172,25 @@ class DoorLock extends VerisureAccessory {
|
|
|
141
172
|
|
|
142
173
|
services.push(this.lockService);
|
|
143
174
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
.
|
|
147
|
-
|
|
148
|
-
|
|
175
|
+
if (this.platformConfig.showAutoLockSwitch) {
|
|
176
|
+
this.autoLockService = new Service.Switch(this.switchName, this.switchName);
|
|
177
|
+
this.autoLockService
|
|
178
|
+
.getCharacteristic(Characteristic.On)
|
|
179
|
+
.on('get', this.getAutoLockState.bind(this))
|
|
180
|
+
.on('set', this.setAutoLockState.bind(this));
|
|
181
|
+
|
|
182
|
+
services.push(this.autoLockService);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
if (this.platformConfig.showAudioSwitch) {
|
|
186
|
+
this.audioService = new Service.Switch(this.audioName, this.audioName);
|
|
187
|
+
this.audioService
|
|
188
|
+
.getCharacteristic(Characteristic.On)
|
|
189
|
+
.on('get', this.getAudioState.bind(this))
|
|
190
|
+
.on('set', this.setAudioState.bind(this));
|
|
149
191
|
|
|
150
|
-
|
|
192
|
+
services.push(this.audioService);
|
|
193
|
+
}
|
|
151
194
|
|
|
152
195
|
this.pollCharacteristics.push(currentStateCharacteristic);
|
|
153
196
|
|
|
@@ -53,8 +53,8 @@ class VerisureAccessory {
|
|
|
53
53
|
});
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
-
log(message) {
|
|
57
|
-
return this.logger(
|
|
56
|
+
log(message, level = 'info') {
|
|
57
|
+
return this.logger[level](`${this.installation.config.alias} ${this.name}: ${message}`);
|
|
58
58
|
}
|
|
59
59
|
}
|
|
60
60
|
|
package/lib/platform.js
CHANGED
|
@@ -24,7 +24,12 @@ class VerisurePlatform {
|
|
|
24
24
|
email,
|
|
25
25
|
token,
|
|
26
26
|
password,
|
|
27
|
+
installations = [],
|
|
27
28
|
pollInterval = 60,
|
|
29
|
+
showAutoLockSwitch = true,
|
|
30
|
+
showAudioSwitch = true,
|
|
31
|
+
audioOffValue = 'LOW',
|
|
32
|
+
audioOnValue = 'HIGH',
|
|
28
33
|
} = config;
|
|
29
34
|
|
|
30
35
|
this.config = {
|
|
@@ -33,7 +38,12 @@ class VerisurePlatform {
|
|
|
33
38
|
email: VERISURE_EMAIL || email,
|
|
34
39
|
password: VERISURE_PASSWORD || password,
|
|
35
40
|
token: VERISURE_TOKEN || token,
|
|
41
|
+
installations,
|
|
36
42
|
pollInterval,
|
|
43
|
+
showAutoLockSwitch,
|
|
44
|
+
showAudioSwitch,
|
|
45
|
+
audioOffValue,
|
|
46
|
+
audioOnValue,
|
|
37
47
|
};
|
|
38
48
|
|
|
39
49
|
this.homebridge = homebridge;
|
|
@@ -92,31 +102,44 @@ class VerisurePlatform {
|
|
|
92
102
|
}
|
|
93
103
|
|
|
94
104
|
async accessories(callback) {
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
this.
|
|
100
|
-
|
|
105
|
+
try {
|
|
106
|
+
if (!this.verisure.cookies.length) {
|
|
107
|
+
await this.verisure.getToken();
|
|
108
|
+
|
|
109
|
+
if (!this.verisure.getCookie('vid')) {
|
|
110
|
+
this.logger.error('MFA is enabled for user. Please see README.');
|
|
111
|
+
return callback([]);
|
|
112
|
+
}
|
|
101
113
|
}
|
|
114
|
+
|
|
115
|
+
this.installations = (await this.verisure.getInstallations())
|
|
116
|
+
// Filter out installations based on configuration.
|
|
117
|
+
.filter((installation) => this.config.installations.length === 0
|
|
118
|
+
|| this.config.installations.includes(installation.config.alias));
|
|
119
|
+
} catch (error) {
|
|
120
|
+
this.logger.error(`Unable to get installations. Please check configured credentials: ${error.message}`);
|
|
121
|
+
return callback([]);
|
|
102
122
|
}
|
|
103
123
|
|
|
104
|
-
|
|
124
|
+
if (this.installations.length === 0) {
|
|
125
|
+
this.logger.error(`No installations found matching config: ${JSON.stringify(this.config.installations)}`);
|
|
126
|
+
return callback([]);
|
|
127
|
+
}
|
|
105
128
|
|
|
106
|
-
|
|
107
|
-
installations.map((installation) => Promise.all([
|
|
129
|
+
const overviews = await Promise.all(
|
|
130
|
+
this.installations.map((installation) => Promise.all([
|
|
108
131
|
installation,
|
|
109
132
|
installation.getOverview(),
|
|
110
133
|
])),
|
|
111
|
-
)
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
134
|
+
);
|
|
135
|
+
|
|
136
|
+
try {
|
|
137
|
+
const accessoryLists = overviews.map(this.overviewToAccessories.bind(this));
|
|
138
|
+
return callback(accessoryLists.reduce((a, b) => [...a, ...b]));
|
|
139
|
+
} catch (error) {
|
|
140
|
+
this.logger.error((error.response && error.response.data) || error.message);
|
|
141
|
+
return callback([]);
|
|
142
|
+
}
|
|
120
143
|
}
|
|
121
144
|
}
|
|
122
145
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "homebridge-verisure",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.16.0",
|
|
4
4
|
"description": "Verisure plugin for homebridge: https://github.com/nfarina/homebridge",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"keywords": [
|
|
@@ -10,18 +10,20 @@
|
|
|
10
10
|
"type": "git",
|
|
11
11
|
"url": "git://github.com/ptz0n/homebridge-verisure.git"
|
|
12
12
|
},
|
|
13
|
-
"
|
|
14
|
-
"
|
|
13
|
+
"funding": {
|
|
14
|
+
"type": "paypal",
|
|
15
|
+
"url": "https://www.paypal.com/paypalme/ptz0n"
|
|
15
16
|
},
|
|
16
|
-
"
|
|
17
|
-
"
|
|
17
|
+
"scripts": {
|
|
18
|
+
"test": "eslint lib && jest --coverage"
|
|
18
19
|
},
|
|
20
|
+
"bin": "bin/verisure",
|
|
19
21
|
"bugs": {
|
|
20
22
|
"url": "http://github.com/ptz0n/homebridge-verisure/issues"
|
|
21
23
|
},
|
|
22
24
|
"engines": {
|
|
23
|
-
"node": ">=
|
|
24
|
-
"homebridge": ">=0.
|
|
25
|
+
"node": ">=12",
|
|
26
|
+
"homebridge": ">=1.0.0"
|
|
25
27
|
},
|
|
26
28
|
"dependencies": {
|
|
27
29
|
"enquirer": "^2.3.6",
|
|
@@ -33,6 +35,10 @@
|
|
|
33
35
|
"eslint-plugin-import": "^2.8.0",
|
|
34
36
|
"eslint-plugin-jest": "^23.1.0",
|
|
35
37
|
"hap-nodejs": "^0.7.2",
|
|
38
|
+
"homebridge": "^1.3.9",
|
|
36
39
|
"jest": "^25.0.0"
|
|
40
|
+
},
|
|
41
|
+
"jest": {
|
|
42
|
+
"testEnvironment": "node"
|
|
37
43
|
}
|
|
38
44
|
}
|