homebridge-deconz 0.1.15 → 0.1.17
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/lib/Deconz/Resource.js +86 -40
- package/lib/DeconzAccessory/Gateway.js +45 -13
- package/lib/DeconzAccessory/WarningDevice.js +18 -0
- package/lib/DeconzService/Gateway.js +10 -0
- package/lib/DeconzService/Schedule.js +69 -0
- package/lib/DeconzService/Smoke.js +15 -2
- package/lib/DeconzService/WarningDevice.js +1 -1
- package/lib/DeconzService/index.js +1 -0
- package/package.json +2 -2
package/lib/Deconz/Resource.js
CHANGED
@@ -15,6 +15,12 @@ const { buttonEvent } = Deconz.ApiClient
|
|
15
15
|
const { SINGLE, DOUBLE, LONG } = DeconzService.Button
|
16
16
|
const rtypes = ['lights', 'sensors', 'groups']
|
17
17
|
|
18
|
+
const patterns = {
|
19
|
+
uniqueid: /^([0-9a-f]{1,2}(?:[:-]?(?:[0-9a-f]{1,2})){7})-([0-9a-z]{2})(?:-([0-9a-z]{4}))?$/i,
|
20
|
+
clipId: /^(S[0-9]{1,3})-([0-9a-z]{2})-([0-9a-z]{4})$/i,
|
21
|
+
swversion: /^([0-9]+)(?:\.([0-9]+)(?:\.([0-9]+)(?:_([0-9]{4}))?)?)?$/
|
22
|
+
}
|
23
|
+
|
18
24
|
// From low to high.
|
19
25
|
const sensorsPrios = [
|
20
26
|
'Power',
|
@@ -24,7 +30,8 @@ const sensorsPrios = [
|
|
24
30
|
'Motion',
|
25
31
|
'Contact',
|
26
32
|
'AirPurifier',
|
27
|
-
'Thermostat'
|
33
|
+
'Thermostat',
|
34
|
+
'Flag'
|
28
35
|
]
|
29
36
|
|
30
37
|
// =============================================================================
|
@@ -51,12 +58,41 @@ class Resource {
|
|
51
58
|
*/
|
52
59
|
static parseUniqueid (uniqueid) {
|
53
60
|
toString('uniqueid', uniqueid, true)
|
54
|
-
const a = uniqueid.replace(/:/g, '').toUpperCase()
|
61
|
+
const a = patterns.uniqueid.exec(uniqueid.replace(/:/g, '').toUpperCase())
|
62
|
+
return {
|
63
|
+
mac: a?.[1],
|
64
|
+
endpoint: a?.[2],
|
65
|
+
cluster: a?.[3]
|
66
|
+
}
|
67
|
+
}
|
68
|
+
|
69
|
+
/** Parse the `uniqueid` in the resource body of a resource for a CLIP sensor.
|
70
|
+
* @param {string} uniqueid - The `uniqueid`.
|
71
|
+
* @return {object} The MultiCLIP `id`, `endpoint`, and `cluster`.
|
72
|
+
*/
|
73
|
+
static parseClipId (uniqueid) {
|
74
|
+
toString('uniqueid', uniqueid, true)
|
75
|
+
const a = patterns.clipId.exec(uniqueid.replace(/:/g, '').toUpperCase())
|
55
76
|
return {
|
56
|
-
|
57
|
-
endpoint: a?.[
|
58
|
-
cluster: a?.[
|
77
|
+
id: a?.[1],
|
78
|
+
endpoint: a?.[2],
|
79
|
+
cluster: a?.[3]
|
80
|
+
}
|
81
|
+
}
|
82
|
+
|
83
|
+
/** Parse the `swversion` in the resource body of a resource for a Zigbee device.
|
84
|
+
* @param {string} swversion - The `swversion`.
|
85
|
+
* @return {string} The normalised version in semver format.
|
86
|
+
*/
|
87
|
+
static parseSwversion (swversion) {
|
88
|
+
if (swversion == null) {
|
89
|
+
return '0.0.0'
|
90
|
+
}
|
91
|
+
const a = patterns.swversion.exec(swversion)
|
92
|
+
if (a?.[1] === '0' && a?.[2] === '0' && a?.[3] === '0' && a?.[4] != null) {
|
93
|
+
return '0.0.' + Number(a[4]).toString()
|
59
94
|
}
|
95
|
+
return swversion
|
60
96
|
}
|
61
97
|
|
62
98
|
/** Create a new instance of a delegate of a resource.
|
@@ -90,6 +126,8 @@ class Resource {
|
|
90
126
|
toString('body.name', body.name, true)
|
91
127
|
toString('body.type', body.type, true)
|
92
128
|
|
129
|
+
let realDevice = false
|
130
|
+
|
93
131
|
if (
|
94
132
|
this.rtype === 'lights' ||
|
95
133
|
(this.rtype === 'sensors' && this.body.type.startsWith('Z'))
|
@@ -129,10 +167,31 @@ class Resource {
|
|
129
167
|
* @type {boolean}
|
130
168
|
*/
|
131
169
|
this.zigbee = true
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
170
|
+
|
171
|
+
realDevice = true
|
172
|
+
} else if (this.rtype === 'sensors') {
|
173
|
+
const { mac, endpoint, cluster } = Resource.parseUniqueid(body.uniqueid)
|
174
|
+
if (mac != null && endpoint != null && cluster != null) {
|
175
|
+
// uniqueid for proxy device has proper mac, endpoint, cluster
|
176
|
+
this.id = mac
|
177
|
+
this.subtype = endpoint + '-' + cluster
|
178
|
+
this.endpoint = endpoint
|
179
|
+
this.cluster = cluster
|
180
|
+
realDevice = true
|
181
|
+
} else {
|
182
|
+
const { id, endpoint, cluster } = Resource.parseClipId(body.uniqueid)
|
183
|
+
if (id != null && endpoint != null && cluster != null) {
|
184
|
+
// uniqueid for MultiCLIP has proper id, endpoint, cluster
|
185
|
+
this.id = gateway.id + '-' + id
|
186
|
+
this.subtype = endpoint + '-' + cluster
|
187
|
+
this.endpoint = endpoint
|
188
|
+
this.cluster = cluster
|
189
|
+
} else {
|
190
|
+
// ignore uniqueid for regular CLIP
|
191
|
+
this.subtype = rtype[0].toUpperCase() + rid
|
192
|
+
this.id = gateway.id + '-' + this.subtype
|
193
|
+
}
|
194
|
+
}
|
136
195
|
this.zigbee = false
|
137
196
|
} else {
|
138
197
|
this.subtype = rtype[0].toUpperCase() + rid
|
@@ -147,8 +206,8 @@ class Resource {
|
|
147
206
|
* For virtual devices, this is the _Manufacturer_ for the gateway.
|
148
207
|
* @type {string}
|
149
208
|
*/
|
150
|
-
this.manufacturer =
|
151
|
-
? body.manufacturername
|
209
|
+
this.manufacturer = realDevice
|
210
|
+
? body.manufacturername.replace(/\//g, '')
|
152
211
|
: gateway.values.manufacturer
|
153
212
|
|
154
213
|
/** The associated HomeKit _Model_.
|
@@ -158,7 +217,7 @@ class Resource {
|
|
158
217
|
* For virtual devices, this is the `type` in the resource body.
|
159
218
|
* @type {string}
|
160
219
|
*/
|
161
|
-
this.model =
|
220
|
+
this.model = realDevice ? body.modelid : body.type
|
162
221
|
|
163
222
|
/** The associated HomeKit _Firmware Version_.
|
164
223
|
*
|
@@ -166,8 +225,8 @@ class Resource {
|
|
166
225
|
* resource body.
|
167
226
|
* For virtual devices, this is the _Firmware Version_ for the gateway.
|
168
227
|
*/
|
169
|
-
this.firmware =
|
170
|
-
?
|
228
|
+
this.firmware = realDevice
|
229
|
+
? Resource.parseSwversion(body.swversion)
|
171
230
|
: gateway.values.software
|
172
231
|
|
173
232
|
/** The name of the {@link DeconzService} subclass of the delegate of the
|
@@ -195,7 +254,7 @@ class Resource {
|
|
195
254
|
if (this.rtype === 'groups') {
|
196
255
|
return -1
|
197
256
|
}
|
198
|
-
if (this.rtype === 'lights'
|
257
|
+
if (this.rtype === 'lights') {
|
199
258
|
return 0xFF - this.endpoint
|
200
259
|
}
|
201
260
|
return sensorsPrios.indexOf(this.serviceName)
|
@@ -230,6 +289,7 @@ class Resource {
|
|
230
289
|
case 'On/Off light': return 'Light'
|
231
290
|
case 'On/Off output': return 'Outlet'
|
232
291
|
case 'On/Off plug-in unit': return 'Outlet'
|
292
|
+
case 'On/Off switch': return 'Switch'
|
233
293
|
case 'Smart plug': return 'Outlet'
|
234
294
|
case 'Configuration tool': return ''
|
235
295
|
case 'Range extender': return ''
|
@@ -327,36 +387,20 @@ class Resource {
|
|
327
387
|
}
|
328
388
|
}
|
329
389
|
|
330
|
-
/** Check whether resource is a CLIP sensor for Homebridge deCONZ.
|
331
|
-
* For these, we use the following conventions:
|
332
|
-
* - Use `uniqueid` to indicate device ID and subtype;
|
333
|
-
* - Use `swversion` to indicate readonly and range for `Flag` and `Status`.
|
334
|
-
*/
|
335
|
-
isDeconzClip () {
|
336
|
-
return this.rtype === 'sensors' &&
|
337
|
-
this.body.type.startsWith('CLIP') &&
|
338
|
-
this.body.modelid === this.body.type && (
|
339
|
-
this.body.manufacturername === 'homebridge-deconz' ||
|
340
|
-
this.body.manufacturername === 'homebridge-hue'
|
341
|
-
)
|
342
|
-
}
|
343
|
-
|
344
|
-
isMultiClip () {
|
345
|
-
return this.isDeconzClip() && /^[0-9]+-[0-9]+$/.test(this.body.uniqueid)
|
346
|
-
}
|
347
|
-
|
348
390
|
/** Patch a resource corresponding to a `Flag` service.
|
349
391
|
*/
|
350
392
|
patchFlag () {
|
351
|
-
if (this.
|
352
|
-
this.
|
393
|
+
if (this.endpoint != null && this.cluster === '0006') {
|
394
|
+
if (this.body.swversion === '0') {
|
395
|
+
this.capabilities.readonly = true
|
396
|
+
}
|
353
397
|
}
|
354
398
|
}
|
355
399
|
|
356
400
|
/** Patch a resource corresponding to a `Status` service.
|
357
401
|
*/
|
358
402
|
patchStatus () {
|
359
|
-
if (this.
|
403
|
+
if (this.endpoint != null && this.cluster === '0012') {
|
360
404
|
const a = this.body.swversion.split(',')
|
361
405
|
const min = parseInt(a[0])
|
362
406
|
const max = parseInt(a[1])
|
@@ -1059,11 +1103,13 @@ class Resource {
|
|
1059
1103
|
}
|
1060
1104
|
}
|
1061
1105
|
|
1062
|
-
/** Patch a resource corresponding to a `
|
1106
|
+
/** Patch a resource corresponding to a `Motion` service.
|
1063
1107
|
*/
|
1064
|
-
|
1065
|
-
if (this.manufacturer === '
|
1066
|
-
this.
|
1108
|
+
patchMotion () {
|
1109
|
+
if (this.manufacturer === 'Aqara' && this.model === 'PS-S02D') {
|
1110
|
+
if (this.endpoint !== '01') {
|
1111
|
+
this.id += '-' + this.endpoint
|
1112
|
+
}
|
1067
1113
|
}
|
1068
1114
|
}
|
1069
1115
|
|
@@ -103,6 +103,14 @@ class Gateway extends AccessoryDelegate {
|
|
103
103
|
} catch (error) { this.error(error) }
|
104
104
|
})
|
105
105
|
|
106
|
+
this.addPropertyDelegate({
|
107
|
+
key: 'exposeSchedules',
|
108
|
+
value: false,
|
109
|
+
silent: true
|
110
|
+
}).on('didSet', async (value) => {
|
111
|
+
this.pollNext = true
|
112
|
+
})
|
113
|
+
|
106
114
|
this.addPropertyDelegate({
|
107
115
|
key: 'heartrate',
|
108
116
|
value: 30,
|
@@ -149,6 +157,7 @@ class Gateway extends AccessoryDelegate {
|
|
149
157
|
value: false,
|
150
158
|
silent: true
|
151
159
|
}).on('didSet', async (value) => {
|
160
|
+
this.service.values.search = value
|
152
161
|
if (value) {
|
153
162
|
try {
|
154
163
|
await this.client.search()
|
@@ -229,6 +238,11 @@ class Gateway extends AccessoryDelegate {
|
|
229
238
|
DeconzService.Button.LONG
|
230
239
|
})
|
231
240
|
|
241
|
+
/** The service delegates for the Schedule services.
|
242
|
+
* @type {Object<string, DeconzService.Schedule>}
|
243
|
+
*/
|
244
|
+
this.scheduleServicesByRid = {}
|
245
|
+
|
232
246
|
this.createClient()
|
233
247
|
this.createWsClient()
|
234
248
|
this.heartbeatEnabled = true
|
@@ -342,7 +356,9 @@ class Gateway extends AccessoryDelegate {
|
|
342
356
|
|
343
357
|
update (config) {
|
344
358
|
this.values.software = config.swversion
|
345
|
-
this.values.firmware = config.fwversion
|
359
|
+
this.values.firmware = parseInt(config.fwversion.slice(6, 8)) + '.' +
|
360
|
+
parseInt(config.fwversion.slice(2, 4), 16) + '.' +
|
361
|
+
parseInt(config.fwversion.slice(4, 6), 16)
|
346
362
|
this.values.wsPort = config.websocketport
|
347
363
|
this.service.update(config)
|
348
364
|
if (this.checkApiKeys) {
|
@@ -637,7 +653,6 @@ class Gateway extends AccessoryDelegate {
|
|
637
653
|
'%s: resetting after expose error: %s', id, this.exposeErrorById[id]
|
638
654
|
)
|
639
655
|
this.deleteAccessory(id)
|
640
|
-
this.deleteService(id)
|
641
656
|
}
|
642
657
|
}
|
643
658
|
}
|
@@ -672,7 +687,6 @@ class Gateway extends AccessoryDelegate {
|
|
672
687
|
'%s: resetting after expose error: %s', id, this.exposeErrorById[id]
|
673
688
|
)
|
674
689
|
this.deleteAccessory(id)
|
675
|
-
this.deleteService(id)
|
676
690
|
}
|
677
691
|
|
678
692
|
/** Assert that migration resourcelink exists and is valid.
|
@@ -774,6 +788,7 @@ class Gateway extends AccessoryDelegate {
|
|
774
788
|
: {
|
775
789
|
brightnessAdjustment: this.values.brightnessAdjustment * 100,
|
776
790
|
expose: this.values.expose,
|
791
|
+
exposeSchedules: this.values.exposeSchedules,
|
777
792
|
heartrate: this.values.heartrate,
|
778
793
|
logLevel: this.values.logLevel,
|
779
794
|
periodicEvents: this.values.periodicEvents,
|
@@ -832,6 +847,7 @@ class Gateway extends AccessoryDelegate {
|
|
832
847
|
if (this.values.apiKey != null) {
|
833
848
|
optionParser
|
834
849
|
.intKey('brightnessAdjustment', 10, 100)
|
850
|
+
.boolKey('exposeSchedules')
|
835
851
|
.intKey('heartrate', 1, 60)
|
836
852
|
.boolKey('periodicEvents')
|
837
853
|
.boolKey('restart')
|
@@ -848,6 +864,7 @@ class Gateway extends AccessoryDelegate {
|
|
848
864
|
responseBody[key] = this.values[key]
|
849
865
|
break
|
850
866
|
case 'expose':
|
867
|
+
case 'exposeSchedules':
|
851
868
|
case 'heartrate':
|
852
869
|
case 'logLevel':
|
853
870
|
case 'periodicEvents':
|
@@ -921,6 +938,10 @@ class Gateway extends AccessoryDelegate {
|
|
921
938
|
await this.wsClient.close()
|
922
939
|
return
|
923
940
|
}
|
941
|
+
if (config.bridgeid === '0000000000000000' || config.fwversion === '0x00000000') {
|
942
|
+
this.warn('deCONZ not ready')
|
943
|
+
return
|
944
|
+
}
|
924
945
|
this.context.fullState.config = config
|
925
946
|
this.context.fullState.lights = await this.client.get('/lights')
|
926
947
|
this.context.fullState.sensors = await this.client.get('/sensors')
|
@@ -928,7 +949,7 @@ class Gateway extends AccessoryDelegate {
|
|
928
949
|
this.context.fullState.groups = await this.client.get('/groups')
|
929
950
|
this.context.fullState.groups[0] = await this.client.get('/groups/0')
|
930
951
|
}
|
931
|
-
if (this.
|
952
|
+
if (this.values.exposeSchedules) {
|
932
953
|
this.context.fullState.schedules = await this.client.get('/schedules')
|
933
954
|
}
|
934
955
|
}
|
@@ -964,16 +985,10 @@ class Gateway extends AccessoryDelegate {
|
|
964
985
|
* {@link DeconzAccessory.Gateway#deleteAccessory deleteAccessory()} for
|
965
986
|
* stale accessories, corresponding to devices that have been deleted from
|
966
987
|
* the gateway, blacklisted, or excluded by device primary resource type.
|
967
|
-
* 3.
|
968
|
-
* {@link DeconzAccessory.Gateway#
|
969
|
-
* for stale services, corresponding to devices that have been deleted from
|
970
|
-
* the gateway, un-blacklisted, or excluded by device primary resource type.
|
971
|
-
* 4. Analysing supported devices with enabled device primary resource types,
|
972
|
-
* calling {@link DeconzAccessory.Gateway#addAccessory addAccessory()} and
|
973
|
-
* {@link DeconzAccessory.Gateway#deleteService deleteService()} for new
|
988
|
+
* 3. Analysing supported devices with enabled device primary resource types,
|
989
|
+
* calling {@link DeconzAccessory.Gateway#addAccessory addAccessory()} for new
|
974
990
|
* _Device_ accessories, corresponding to devices added to the gateway,
|
975
991
|
* un-blacklisted, or included by device primary resource type, and calling
|
976
|
-
* {@link DeconzAccessory.Gateway#addService addService()} and
|
977
992
|
* {@link DeconzAccessory.Gateway#deleteAccessory deleteAccessory()} for
|
978
993
|
* accessories, corresponding to devices have been blacklisted.
|
979
994
|
* @param {Object} fullState - The gateway full state, as returned by
|
@@ -1072,7 +1087,6 @@ class Gateway extends AccessoryDelegate {
|
|
1072
1087
|
) {
|
1073
1088
|
delete this.context.settingsById[id]
|
1074
1089
|
this.deleteAccessory(id)
|
1075
|
-
// this.deleteService(id)
|
1076
1090
|
changed = true
|
1077
1091
|
} else {
|
1078
1092
|
/** Emitted when the gateway has been polled.
|
@@ -1119,6 +1133,24 @@ class Gateway extends AccessoryDelegate {
|
|
1119
1133
|
)
|
1120
1134
|
}
|
1121
1135
|
|
1136
|
+
this.vdebug('analysing schedules...')
|
1137
|
+
if (this.values.exposeSchedules) {
|
1138
|
+
for (const rid in fullState.schedules) {
|
1139
|
+
if (this.scheduleServicesByRid[rid] == null) {
|
1140
|
+
this.scheduleServicesByRid[rid] = new DeconzService.Schedule(
|
1141
|
+
this, rid, fullState.schedules[rid]
|
1142
|
+
)
|
1143
|
+
}
|
1144
|
+
this.scheduleServicesByRid[rid].update(fullState.schedules[rid])
|
1145
|
+
}
|
1146
|
+
}
|
1147
|
+
for (const rid in this.scheduleServicesByRid) {
|
1148
|
+
if (!this.values.exposeSchedules || fullState.schedules[rid] == null) {
|
1149
|
+
this.scheduleServicesByRid[rid].destroy()
|
1150
|
+
delete this.scheduleServicesByRid[rid]
|
1151
|
+
}
|
1152
|
+
}
|
1153
|
+
|
1122
1154
|
if (changed) {
|
1123
1155
|
await this.updateMigration()
|
1124
1156
|
this.identify()
|
@@ -5,6 +5,7 @@
|
|
5
5
|
|
6
6
|
'use strict'
|
7
7
|
|
8
|
+
const { ServiceDelegate } = require('homebridge-lib')
|
8
9
|
const DeconzAccessory = require('../DeconzAccessory')
|
9
10
|
|
10
11
|
/** Delegate class for a HomeKit accessory, corresponding to a light device
|
@@ -32,6 +33,23 @@ class WarningDevice extends DeconzAccessory {
|
|
32
33
|
this.createService(resource)
|
33
34
|
}
|
34
35
|
|
36
|
+
const params = {}
|
37
|
+
if (this.servicesByServiceName.WarningDevice?.length === 1) {
|
38
|
+
params.switchOnDelegate = this.service.characteristicDelegate('on')
|
39
|
+
params.lastSwitchOnDelegate = this.service.addCharacteristicDelegate({
|
40
|
+
key: 'lastActivation',
|
41
|
+
Characteristic: this.Characteristics.eve.LastActivation,
|
42
|
+
silent: true
|
43
|
+
})
|
44
|
+
}
|
45
|
+
if (this.servicesByServiceName.Temperature?.length === 1) {
|
46
|
+
const service = this.servicesByServiceName.Temperature[0]
|
47
|
+
params.temperatureDelegate = service.characteristicDelegate('temperature')
|
48
|
+
}
|
49
|
+
if (Object.keys(params).length > 0) {
|
50
|
+
this.historyService = new ServiceDelegate.History(this, params)
|
51
|
+
}
|
52
|
+
|
35
53
|
setImmediate(() => {
|
36
54
|
this.debug('initialised')
|
37
55
|
this.emit('initialised')
|
@@ -31,6 +31,16 @@ class Gateway extends ServiceDelegate {
|
|
31
31
|
silent: true
|
32
32
|
})
|
33
33
|
|
34
|
+
this.addCharacteristicDelegate({
|
35
|
+
key: 'search',
|
36
|
+
Characteristic: this.Characteristics.my.Search,
|
37
|
+
value: false
|
38
|
+
}).on('didSet', (value, fromHomeKit) => {
|
39
|
+
if (fromHomeKit) {
|
40
|
+
this.gateway.values.search = value
|
41
|
+
}
|
42
|
+
})
|
43
|
+
|
34
44
|
this.addCharacteristicDelegate({
|
35
45
|
key: 'transitionTime',
|
36
46
|
Characteristic: this.Characteristics.my.TransitionTime,
|
@@ -0,0 +1,69 @@
|
|
1
|
+
// homebridge-deconz/lib/DeconzService/Schedule.js
|
2
|
+
// Copyright© 2022-2023 Erik Baauw. All rights reserved.
|
3
|
+
//
|
4
|
+
// Homebridge plugin for deCONZ.
|
5
|
+
|
6
|
+
'use strict'
|
7
|
+
|
8
|
+
const Deconz = require('../Deconz')
|
9
|
+
const { ServiceDelegate } = require('homebridge-lib')
|
10
|
+
|
11
|
+
const { HttpError } = Deconz.ApiClient
|
12
|
+
|
13
|
+
/**
|
14
|
+
* @memberof DeconzService
|
15
|
+
*/
|
16
|
+
class Schedule extends ServiceDelegate {
|
17
|
+
constructor (accessory, rid, body) {
|
18
|
+
super(accessory, {
|
19
|
+
id: accessory.gateway.id + '-T' + rid,
|
20
|
+
name: body.name,
|
21
|
+
Service: accessory.Services.my.Resource,
|
22
|
+
subtype: 'T' + rid,
|
23
|
+
exposeConfiguredName: true
|
24
|
+
})
|
25
|
+
this.id = accessory.gateway.id + '-T' + rid
|
26
|
+
this.gateway = accessory.gateway
|
27
|
+
this.accessory = accessory
|
28
|
+
this.client = accessory.client
|
29
|
+
this.rtype = 'schedules'
|
30
|
+
this.rid = rid
|
31
|
+
this.rpath = '/' + this.rtype + '/' + this.rid
|
32
|
+
|
33
|
+
this.addCharacteristicDelegate({
|
34
|
+
key: 'enabled',
|
35
|
+
Characteristic: this.Characteristics.my.Enabled
|
36
|
+
}).on('didSet', async (value, fromHomeKit) => {
|
37
|
+
await this.put({ status: value ? 'enabled' : 'disabled' })
|
38
|
+
this.values.statusActive = value
|
39
|
+
})
|
40
|
+
|
41
|
+
this.addCharacteristicDelegate({
|
42
|
+
key: 'statusActive',
|
43
|
+
Characteristic: this.Characteristics.hap.StatusActive
|
44
|
+
})
|
45
|
+
|
46
|
+
// this.addCharacteristicDelegate({
|
47
|
+
// key: 'index',
|
48
|
+
// Characteristic: this.Characteristics.hap.ServiceLabelIndex,
|
49
|
+
// value: rid
|
50
|
+
// })
|
51
|
+
}
|
52
|
+
|
53
|
+
update (body) {
|
54
|
+
this.values.enabled = body.status === 'enabled'
|
55
|
+
this.values.statusActive = this.values.enabled
|
56
|
+
}
|
57
|
+
|
58
|
+
async put (body) {
|
59
|
+
try {
|
60
|
+
await this.client.put(this.rpath, body)
|
61
|
+
} catch (error) {
|
62
|
+
if (!(error instanceof HttpError)) {
|
63
|
+
this.warn(error)
|
64
|
+
}
|
65
|
+
}
|
66
|
+
}
|
67
|
+
}
|
68
|
+
|
69
|
+
module.exports = Schedule
|
@@ -16,10 +16,15 @@ class Smoke extends DeconzService.SensorsResource {
|
|
16
16
|
super(accessory, resource, params)
|
17
17
|
|
18
18
|
this.addCharacteristicDelegate({
|
19
|
-
key: '
|
19
|
+
key: 'smoke',
|
20
20
|
Characteristic: this.Characteristics.hap.SmokeDetected
|
21
21
|
})
|
22
22
|
|
23
|
+
this.addCharacteristicDelegate({
|
24
|
+
key: 'deviceStatus',
|
25
|
+
Characteristic: this.Characteristics.eve.ElgatoDeviceStatus
|
26
|
+
})
|
27
|
+
|
23
28
|
super.addCharacteristicDelegates(params)
|
24
29
|
|
25
30
|
this.update(resource.body, resource.rpath)
|
@@ -27,9 +32,17 @@ class Smoke extends DeconzService.SensorsResource {
|
|
27
32
|
|
28
33
|
updateState (state) {
|
29
34
|
if (state.fire != null || state.test != null) {
|
30
|
-
this.values.
|
35
|
+
this.values.smoke = state.fire
|
31
36
|
? this.Characteristics.hap.SmokeDetected.SMOKE_DETECTED
|
32
37
|
: this.Characteristics.hap.SmokeDetected.SMOKE_NOT_DETECTED
|
38
|
+
let status = 0
|
39
|
+
if (state.fire) {
|
40
|
+
status |= this.Characteristics.eve.ElgatoDeviceStatus.SMOKE_DETECTED
|
41
|
+
}
|
42
|
+
if (state.test) {
|
43
|
+
status |= this.Characteristics.eve.ElgatoDeviceStatus.ALARM_TEST_ACTIVE
|
44
|
+
}
|
45
|
+
this.values.deviceStatus = status
|
33
46
|
}
|
34
47
|
super.updateState(state)
|
35
48
|
}
|
@@ -9,7 +9,7 @@ const DeconzService = require('../DeconzService')
|
|
9
9
|
|
10
10
|
class WarningDevice extends DeconzService.LightsResource {
|
11
11
|
constructor (accessory, resource, params = {}) {
|
12
|
-
params.Service = accessory.Services.hap.
|
12
|
+
params.Service = accessory.Services.hap.Switch
|
13
13
|
super(accessory, resource, params)
|
14
14
|
|
15
15
|
this.addCharacteristicDelegate({
|
@@ -35,6 +35,7 @@ class DeconzService extends ServiceDelegate {
|
|
35
35
|
static get Motion () { return require('./Motion') }
|
36
36
|
static get Outlet () { return require('./Outlet') }
|
37
37
|
static get Power () { return require('./Power') }
|
38
|
+
static get Schedule () { return require('./Schedule') }
|
38
39
|
static get SensorsResource () { return require('./SensorsResource') }
|
39
40
|
static get Status () { return require('./Status') }
|
40
41
|
static get Smoke () { return require('./Smoke') }
|
package/package.json
CHANGED
@@ -4,7 +4,7 @@
|
|
4
4
|
"displayName": "Homebridge deCONZ",
|
5
5
|
"author": "Erik Baauw",
|
6
6
|
"license": "Apache-2.0",
|
7
|
-
"version": "0.1.
|
7
|
+
"version": "0.1.17",
|
8
8
|
"keywords": [
|
9
9
|
"homebridge-plugin",
|
10
10
|
"homekit",
|
@@ -26,7 +26,7 @@
|
|
26
26
|
"node": "^18.16.0"
|
27
27
|
},
|
28
28
|
"dependencies": {
|
29
|
-
"homebridge-lib": "~6.3.
|
29
|
+
"homebridge-lib": "~6.3.17",
|
30
30
|
"ws": "^8.13.0",
|
31
31
|
"xml2js": "~0.5.0"
|
32
32
|
},
|