homebridge-deconz 0.1.12 → 0.1.14
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 +8 -4
- package/lib/DeconzAccessory/Gateway.js +5 -2
- package/lib/DeconzAccessory/index.js +21 -6
- package/lib/DeconzService/Label.js +5 -0
- package/lib/DeconzService/Light.js +20 -17
- package/lib/DeconzService/LightsResource.js +3 -2
- package/lib/DeconzService/Outlet.js +1 -1
- package/lib/DeconzService/Switch.js +1 -1
- package/lib/DeconzService/WarningDevice.js +1 -1
- package/lib/DeconzService/index.js +8 -2
- package/package.json +5 -5
package/lib/Deconz/Resource.js
CHANGED
@@ -129,10 +129,10 @@ class Resource {
|
|
129
129
|
* @type {boolean}
|
130
130
|
*/
|
131
131
|
this.zigbee = true
|
132
|
-
} else if (this.
|
132
|
+
} else if (this.isMultiClip()) {
|
133
133
|
const a = body.uniqueid.split('-')
|
134
|
-
this.id = gateway.id + '-M' + a
|
135
|
-
this.subtype = a
|
134
|
+
this.id = gateway.id + '-M' + a[0]
|
135
|
+
this.subtype = a[1]
|
136
136
|
this.zigbee = false
|
137
137
|
} else {
|
138
138
|
this.subtype = rtype[0].toUpperCase() + rid
|
@@ -195,7 +195,7 @@ class Resource {
|
|
195
195
|
if (this.rtype === 'groups') {
|
196
196
|
return -1
|
197
197
|
}
|
198
|
-
if (this.rtype === 'lights' || this.
|
198
|
+
if (this.rtype === 'lights' || this.isMultiClip()) {
|
199
199
|
return 0xFF - this.endpoint
|
200
200
|
}
|
201
201
|
return sensorsPrios.indexOf(this.serviceName)
|
@@ -341,6 +341,10 @@ class Resource {
|
|
341
341
|
)
|
342
342
|
}
|
343
343
|
|
344
|
+
isMultiClip () {
|
345
|
+
return this.isDeconzClip() && /^[0-9]+-[0-9]+$/.test(this.body.uniqueid)
|
346
|
+
}
|
347
|
+
|
344
348
|
/** Patch a resource corresponding to a `Flag` service.
|
345
349
|
*/
|
346
350
|
patchFlag () {
|
@@ -594,7 +594,7 @@ class Gateway extends AccessoryDelegate {
|
|
594
594
|
const device = this.deviceById[id]
|
595
595
|
delete this.exposeErrorById[id]
|
596
596
|
const { body } = device.resource
|
597
|
-
this.
|
597
|
+
this.log('%s: add accessory', body.name)
|
598
598
|
let { serviceName } = device.resource
|
599
599
|
if (DeconzAccessory[serviceName] == null) {
|
600
600
|
// this.warn('%s: %s: not yet supported %s type', body.name, body.type, rtype)
|
@@ -622,7 +622,10 @@ class Gateway extends AccessoryDelegate {
|
|
622
622
|
}
|
623
623
|
if (this.accessoryById[id] != null) {
|
624
624
|
this.monitorResources(this.accessoryById[id], false)
|
625
|
-
this.log(
|
625
|
+
this.log(
|
626
|
+
'%s: delete accessory%s', this.accessoryById[id].name,
|
627
|
+
delegateOnly ? ' delegate' : ''
|
628
|
+
)
|
626
629
|
this.accessoryById[id].destroy(delegateOnly)
|
627
630
|
delete this.accessoryById[id]
|
628
631
|
if (this.exposeErrorById[id] != null) {
|
@@ -71,14 +71,29 @@ class DeconzAccessory extends AccessoryDelegate {
|
|
71
71
|
|
72
72
|
this
|
73
73
|
.on('polled', (device) => {
|
74
|
+
let reExpose = false
|
74
75
|
this.values.firmware = device.resource.firmware
|
75
|
-
for (const subtype in
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
76
|
+
for (const subtype in device.resourceBySubtype) {
|
77
|
+
const resource = device.resourceBySubtype[subtype]
|
78
|
+
this.debug('%s: polled: %j', resource.rpath, resource.body)
|
79
|
+
const service = this.serviceBySubtype[subtype]
|
80
|
+
if (service == null) {
|
81
|
+
this.log('%s: new resource: %j', resource.rpath, resource.body)
|
82
|
+
reExpose = true
|
83
|
+
} else {
|
80
84
|
service.update(resource.body, resource.rpath)
|
81
|
-
}
|
85
|
+
}
|
86
|
+
}
|
87
|
+
for (const subtype in this.serviceBySubtype) {
|
88
|
+
const service = this.serviceBySubtype[subtype]
|
89
|
+
const resource = device.resourceBySubtype[subtype]
|
90
|
+
if (resource == null) {
|
91
|
+
this.log('%s: resource deleted', service.rpath)
|
92
|
+
reExpose = true
|
93
|
+
}
|
94
|
+
}
|
95
|
+
if (reExpose) {
|
96
|
+
this.gateway.reExposeAccessory(this.id)
|
82
97
|
}
|
83
98
|
})
|
84
99
|
.on('changed', (rpath, body) => {
|
@@ -59,6 +59,11 @@ class Label extends DeconzService.SensorsResource {
|
|
59
59
|
|
60
60
|
updateState (state, rpath) {
|
61
61
|
const buttonResource = this.buttonResources[rpath]
|
62
|
+
if (buttonResource == null) {
|
63
|
+
this.log('%s: resource deleted', rpath)
|
64
|
+
this.gateway.reExposeAccessory(this.accessory.id)
|
65
|
+
return
|
66
|
+
}
|
62
67
|
if (buttonResource.lastUpdated === '') {
|
63
68
|
buttonResource.lastUpdated = state.lastupdated
|
64
69
|
} else if (
|
@@ -17,13 +17,15 @@ class Light extends DeconzService.LightsResource {
|
|
17
17
|
|
18
18
|
this.capabilities = {
|
19
19
|
on: this.resource.body.state.on !== undefined,
|
20
|
-
bri: this.resource.body.
|
21
|
-
ct: this.resource.body.
|
22
|
-
hs: this.resource.body.
|
23
|
-
this.resource.body.
|
24
|
-
xy: this.resource.body.
|
20
|
+
bri: this.resource.body[this.stateKey].bri !== undefined,
|
21
|
+
ct: this.resource.body[this.stateKey].ct !== undefined,
|
22
|
+
hs: this.resource.body[this.stateKey].xy === undefined &&
|
23
|
+
this.resource.body[this.stateKey].hue !== undefined,
|
24
|
+
xy: this.resource.body[this.stateKey].xy !== undefined
|
25
25
|
}
|
26
|
-
if (this.resource.body?.
|
26
|
+
if (this.resource.body.action?.effect !== undefined) {
|
27
|
+
this.capabilities.colorLoop = true
|
28
|
+
} else if (this.resource.body?.capabilities?.color?.effects != null) {
|
27
29
|
const effects = this.resource.body.capabilities.color.effects
|
28
30
|
if (effects.length > 1 && effects[1] === 'colorloop') {
|
29
31
|
this.capabilities.colorLoop = true
|
@@ -64,7 +66,7 @@ class Light extends DeconzService.LightsResource {
|
|
64
66
|
key: 'brightness',
|
65
67
|
Characteristic: this.Characteristics.hap.Brightness,
|
66
68
|
unit: '%',
|
67
|
-
value: Math.round(this.resource.body.
|
69
|
+
value: Math.round(this.resource.body[this.stateKey].bri / 2.54)
|
68
70
|
}).on('didSet', (value, fromHomeKit) => {
|
69
71
|
if (fromHomeKit) {
|
70
72
|
const bri = Math.round(value * 2.54)
|
@@ -88,7 +90,7 @@ class Light extends DeconzService.LightsResource {
|
|
88
90
|
if (this.capabilities.ct || this.capabilities.xy || this.capabilities.hs) {
|
89
91
|
this.addCharacteristicDelegate({
|
90
92
|
key: 'colormode',
|
91
|
-
value: this.resource.body.
|
93
|
+
value: this.resource.body[this.stateKey].colormode,
|
92
94
|
silent: true
|
93
95
|
}).on('didSet', (value) => {
|
94
96
|
this.resource.body.colormode = value
|
@@ -124,7 +126,7 @@ class Light extends DeconzService.LightsResource {
|
|
124
126
|
minValue: ctMin,
|
125
127
|
maxValue: ctMax
|
126
128
|
},
|
127
|
-
value: this.resource.body.
|
129
|
+
value: this.resource.body[this.stateKey].ct
|
128
130
|
}).on('didSet', (value, fromHomeKit) => {
|
129
131
|
const ct = Math.max(ctMin, Math.min(value, ctMax))
|
130
132
|
if (fromHomeKit) {
|
@@ -375,13 +377,13 @@ class Light extends DeconzService.LightsResource {
|
|
375
377
|
// this.checkEffect(this.obj.state.effect)
|
376
378
|
}
|
377
379
|
|
378
|
-
updateState (state) {
|
380
|
+
updateState (state, rpath, stateKey = 'state') {
|
379
381
|
this.initAdaptiveLighting()
|
380
382
|
let updateAdaptiveLighting = false
|
381
383
|
for (const key in state) {
|
382
384
|
const value = state[key]
|
383
|
-
// const oldValue = this.resource.body
|
384
|
-
this.resource.body
|
385
|
+
// const oldValue = this.resource.body[stateKey][key]
|
386
|
+
this.resource.body[stateKey][key] = value
|
385
387
|
switch (key) {
|
386
388
|
case 'all_on':
|
387
389
|
this.values.on = value
|
@@ -393,7 +395,8 @@ class Light extends DeconzService.LightsResource {
|
|
393
395
|
break
|
394
396
|
case 'bri':
|
395
397
|
if (!this.recentlyUpdated) {
|
396
|
-
this.values.brightness = Math.round(value / 2.54)
|
398
|
+
this.values.brightness = Math.max(1, Math.round(value / 2.54)) // iOS 16.4 Home bug
|
399
|
+
// this.values.brightness = Math.round(value / 2.54)
|
397
400
|
updateAdaptiveLighting = true
|
398
401
|
}
|
399
402
|
break
|
@@ -417,6 +420,9 @@ class Light extends DeconzService.LightsResource {
|
|
417
420
|
}
|
418
421
|
break
|
419
422
|
case 'on':
|
423
|
+
if (stateKey === 'action') {
|
424
|
+
break
|
425
|
+
}
|
420
426
|
if (this.values.wallSwitch && !state.reachable) {
|
421
427
|
if (this.values.on) {
|
422
428
|
this.log('not reachable: force On to false')
|
@@ -476,8 +482,7 @@ class Light extends DeconzService.LightsResource {
|
|
476
482
|
const service = new ServiceDelegate(this.accessoryDelegate, {
|
477
483
|
name: this.resource.body.name + ' ' + scene.name,
|
478
484
|
Service: this.Services.hap.Lightbulb,
|
479
|
-
subtype: this.subtype + '-S' + scene.id
|
480
|
-
exposeConfiguredName: true
|
485
|
+
subtype: this.resource.subtype + '-S' + scene.id
|
481
486
|
})
|
482
487
|
service.addCharacteristicDelegate({
|
483
488
|
key: 'on',
|
@@ -502,8 +507,6 @@ class Light extends DeconzService.LightsResource {
|
|
502
507
|
})
|
503
508
|
this.sceneServices[scene.id] = service
|
504
509
|
}
|
505
|
-
this.sceneServices[scene.id].values.configuredName =
|
506
|
-
this.resource.body.name + ' ' + scene.name
|
507
510
|
}
|
508
511
|
for (const id in this.scenesServices) {
|
509
512
|
if (sceneById[id] == null) {
|
@@ -14,7 +14,8 @@ const { HttpError } = Deconz.ApiClient
|
|
14
14
|
class LightsResource extends DeconzService {
|
15
15
|
constructor (accessory, resource, params) {
|
16
16
|
super(accessory, resource, params)
|
17
|
-
this.
|
17
|
+
this.stateKey = resource.rtype === 'groups' ? 'action' : 'state'
|
18
|
+
this.rpathState = this.rpath + '/' + this.stateKey
|
18
19
|
|
19
20
|
this.updating = 0
|
20
21
|
this.targetState = {}
|
@@ -62,7 +63,7 @@ class LightsResource extends DeconzService {
|
|
62
63
|
// Collect changes into a combined request.
|
63
64
|
async put (state) {
|
64
65
|
for (const key in state) {
|
65
|
-
this.resource.body.
|
66
|
+
this.resource.body[this.stateKey][key] = state[key]
|
66
67
|
this.targetState[key] = state[key]
|
67
68
|
}
|
68
69
|
return this._put()
|
@@ -55,6 +55,7 @@ class DeconzService extends ServiceDelegate {
|
|
55
55
|
})
|
56
56
|
this.id = resource.id
|
57
57
|
this.gateway = accessory.gateway
|
58
|
+
this.accessory = accessory
|
58
59
|
this.client = accessory.client
|
59
60
|
this.resource = resource
|
60
61
|
this.rtype = resource.rtype
|
@@ -104,8 +105,13 @@ class DeconzService extends ServiceDelegate {
|
|
104
105
|
if (body.state != null) {
|
105
106
|
this.updateState(body.state, rpath)
|
106
107
|
}
|
107
|
-
if (
|
108
|
-
|
108
|
+
if (this.rtype === 'groups') {
|
109
|
+
if (body.action != null) {
|
110
|
+
this.updateState(body.action, rpath, 'action')
|
111
|
+
}
|
112
|
+
if (body.scenes != null) {
|
113
|
+
this.updateScenes(body.scenes)
|
114
|
+
}
|
109
115
|
}
|
110
116
|
}
|
111
117
|
}
|
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.14",
|
8
8
|
"keywords": [
|
9
9
|
"homebridge-plugin",
|
10
10
|
"homekit",
|
@@ -22,13 +22,13 @@
|
|
22
22
|
},
|
23
23
|
"engines": {
|
24
24
|
"deCONZ": "2.21.2",
|
25
|
-
"homebridge": "^1.6.
|
26
|
-
"node": "^18.
|
25
|
+
"homebridge": "^1.6.1",
|
26
|
+
"node": "^18.16.0"
|
27
27
|
},
|
28
28
|
"dependencies": {
|
29
|
-
"homebridge-lib": "~6.3.
|
29
|
+
"homebridge-lib": "~6.3.15",
|
30
30
|
"ws": "^8.13.0",
|
31
|
-
"xml2js": "~0.
|
31
|
+
"xml2js": "~0.5.0"
|
32
32
|
},
|
33
33
|
"scripts": {
|
34
34
|
"prepare": "standard && rm -rf out && jsdoc -c jsdoc.json",
|