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.
@@ -129,10 +129,10 @@ class Resource {
129
129
  * @type {boolean}
130
130
  */
131
131
  this.zigbee = true
132
- } else if (this.isDeconzClip()) {
132
+ } else if (this.isMultiClip()) {
133
133
  const a = body.uniqueid.split('-')
134
- this.id = gateway.id + '-M' + a?.[0]
135
- this.subtype = a?.[1]
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.isDeconzClip()) {
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.debug('%s: add accessory', body.name)
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('%s: delete accessory', this.accessoryById[id].name)
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 this.serviceBySubtype) {
76
- try {
77
- const service = this.serviceBySubtype[subtype]
78
- const resource = device.resourceBySubtype[subtype]
79
- this.debug('%s: polled: %j', resource.rpath, resource.body)
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
- } catch (error) { this.error(error) }
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.state.bri !== undefined,
21
- ct: this.resource.body.state.ct !== undefined,
22
- hs: this.resource.body.state.xy === undefined &&
23
- this.resource.body.state.hue !== undefined,
24
- xy: this.resource.body.state.xy !== undefined
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?.capabilities?.color?.effects != null) {
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.state.bri / 2.54)
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.state.colormode,
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.state.ct
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.state[key]
384
- this.resource.body.state[key] = value
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.rpathState = this.rpath + (resource.rtype === 'groups' ? '/action' : '/state')
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.state[key] = state[key]
66
+ this.resource.body[this.stateKey][key] = state[key]
66
67
  this.targetState[key] = state[key]
67
68
  }
68
69
  return this._put()
@@ -51,7 +51,7 @@ class Outlet extends DeconzService.LightsResource {
51
51
  }
52
52
  }
53
53
 
54
- updateState (state, rpath) {
54
+ updateState (state) {
55
55
  for (const key in state) {
56
56
  const value = state[key]
57
57
  this.resource.body.state[key] = value
@@ -45,7 +45,7 @@ class Switch extends DeconzService.LightsResource {
45
45
  }
46
46
  }
47
47
 
48
- updateState (state, rpath) {
48
+ updateState (state) {
49
49
  for (const key in state) {
50
50
  const value = state[key]
51
51
  this.resource.body.state[key] = value
@@ -57,7 +57,7 @@ class WarningDevice extends DeconzService.LightsResource {
57
57
  this.update(resource.body, resource.rpath)
58
58
  }
59
59
 
60
- updateState (state, rpath) {
60
+ updateState (state) {
61
61
  if (state.on != null) {
62
62
  this.values.on = state.on
63
63
  }
@@ -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 (body.scenes != null && this.rtype === 'groups') {
108
- this.updateScenes(body.scenes)
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.12",
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.0",
26
- "node": "^18.15.0"
25
+ "homebridge": "^1.6.1",
26
+ "node": "^18.16.0"
27
27
  },
28
28
  "dependencies": {
29
- "homebridge-lib": "~6.3.13",
29
+ "homebridge-lib": "~6.3.15",
30
30
  "ws": "^8.13.0",
31
- "xml2js": "~0.4.23"
31
+ "xml2js": "~0.5.0"
32
32
  },
33
33
  "scripts": {
34
34
  "prepare": "standard && rm -rf out && jsdoc -c jsdoc.json",