homebridge-deconz 1.1.2 → 1.2.2

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.
@@ -49,6 +49,25 @@ const hueTapMap = {
49
49
  99: 0 // release 3 and 4
50
50
  }
51
51
 
52
+ const hkEvent = {
53
+ SINGLE: 0x01,
54
+ DOUBLE: 0x02,
55
+ LONG: 0x04
56
+ }
57
+
58
+ const buttonEventMap = {
59
+ 0: 0, // PRESS
60
+ 1: hkEvent.LONG, // HOLD
61
+ 2: hkEvent.SINGLE, // SHORT_RELEASE
62
+ 3: hkEvent.LONG, // LONG_RELEASE
63
+ 4: hkEvent.DOUBLE, // DOUBLE_PRESS
64
+ 5: hkEvent.LONG, // TRIPLE_PRESS
65
+ 6: hkEvent.LONG, // QUADRUPLE_PRESS
66
+ 7: hkEvent.LONG, // SHAKE
67
+ 8: hkEvent.DOUBLE, // DROP
68
+ 9: 0 // TILT
69
+ }
70
+
52
71
  const ancillaryControlMap = {
53
72
  disarmed: 1002,
54
73
  already_disarmed: 1002,
@@ -437,6 +456,30 @@ class Resource {
437
456
  * @param {DeconzAccessory.Gateway} gateway - The gateway.
438
457
  */
439
458
  patchLabel (gateway) {
459
+ // FIX_ME: use introspect until buttons and events are reported as capability
460
+ if (this.body.introspect?.buttons != null) {
461
+ this.capabilities._introspect = true
462
+ this.capabilities._buttons = {}
463
+ let dots = 0
464
+ for (const button in this.body.introspect.buttons) {
465
+ const label = this.body.introspect.buttons[button].name
466
+ this.capabilities._buttons[button] = { label, events: 0 }
467
+ if (label.includes(' Dot')) {
468
+ dots++
469
+ }
470
+ }
471
+ this.capabilities._namespace = dots === this.body.introspect.buttons.length
472
+ ? gateway.Characteristics.hap.ServiceLabelNamespace.DOTS
473
+ : gateway.Characteristics.hap.ServiceLabelNamespace.ARABIC_NUMERALS
474
+ for (const value in this.body.introspect.values) {
475
+ const button = Math.round(value / 1000)
476
+ const event = value % 1000
477
+ if (this.capabilities._buttons[button] != null) {
478
+ this.capabilities._buttons[button].events |= buttonEventMap[event]
479
+ }
480
+ }
481
+ }
482
+ // End FIX_ME
440
483
  const buttons = []
441
484
  let dots = false
442
485
  switch (this.manufacturer) {
@@ -551,15 +594,11 @@ class Resource {
551
594
  buttons.push([3, 'Previous', SINGLE | LONG])
552
595
  buttons.push([4, 'Next', SINGLE | LONG])
553
596
  break
554
- case 'RODRET Dimmer':
555
- buttons.push([1, 'Dim Up', SINGLE | LONG])
556
- buttons.push([2, 'Dim Down', SINGLE | LONG])
557
- break
558
- case 'SOMRIG shortcut button':
559
- dots = true
560
- buttons.push([1, '1', SINGLE | DOUBLE | LONG])
561
- buttons.push([2, '2', SINGLE | DOUBLE | LONG])
562
- break
597
+ // case 'SOMRIG shortcut button':
598
+ // dots = true
599
+ // buttons.push([1, '1', SINGLE | DOUBLE | LONG])
600
+ // buttons.push([2, '2', SINGLE | DOUBLE | LONG])
601
+ // break
563
602
  case 'SYMFONISK Sound Controller':
564
603
  if (this.cluster === '1000') {
565
604
  buttons.push([1, 'Button', SINGLE | DOUBLE | LONG])
@@ -584,17 +623,6 @@ class Resource {
584
623
  buttons.push([6, 'One Dot', SINGLE | DOUBLE | LONG])
585
624
  buttons.push([7, 'Two Dots', SINGLE | DOUBLE | LONG])
586
625
  break
587
- case 'TRADFRI SHORTCUT Button':
588
- buttons.push([1, 'Button', SINGLE | DOUBLE | LONG])
589
- break
590
- case 'TRADFRI on/off switch':
591
- buttons.push([1, 'On', SINGLE | LONG])
592
- buttons.push([2, 'Off', SINGLE | LONG])
593
- break
594
- case 'TRADFRI open/close remote':
595
- buttons.push([1, 'Open', SINGLE | LONG])
596
- buttons.push([2, 'Close', SINGLE | LONG])
597
- break
598
626
  case 'TRADFRI remote control':
599
627
  buttons.push([1, 'Power', SINGLE])
600
628
  buttons.push([2, 'Dim Up', SINGLE | LONG])
@@ -676,7 +704,6 @@ class Resource {
676
704
  case 'lumi.remote.b186acn02':
677
705
  buttons.push([1, 'Button', SINGLE | DOUBLE | LONG])
678
706
  break
679
- case 'lumi.remote.b28ac1':
680
707
  case 'lumi.remote.b286acn01':
681
708
  case 'lumi.remote.b286acn02':
682
709
  buttons.push([1, 'Left', SINGLE | DOUBLE | LONG])
@@ -751,7 +778,7 @@ class Resource {
751
778
  }
752
779
  break
753
780
  case 'lumi.sensor_switch': // Xiaomi Mi wireless switch
754
- case 'lumi.sensor_switch.aq2': // Xiaomi Aqara smart wireless switch
781
+ // fallthrough
755
782
  case 'lumi.sensor_switch.aq3': // Xiaomi Aqara smart wireless switch with gyro
756
783
  buttons.push([1, 'Button', SINGLE | DOUBLE | LONG])
757
784
  break
@@ -822,11 +849,6 @@ class Resource {
822
849
  break
823
850
  case 'OSRAM':
824
851
  switch (this.model) {
825
- case 'Lightify Switch Mini':
826
- buttons.push([1, 'Up', SINGLE | LONG])
827
- buttons.push([2, 'Down', SINGLE | LONG])
828
- buttons.push([3, 'Middle', SINGLE | LONG])
829
- break
830
852
  case 'Switch 4x EU-LIGHTIFY':
831
853
  case 'Switch 4x-LIGHTIFY':
832
854
  buttons.push([1, 'Top Left', SINGLE | LONG])
@@ -1037,18 +1059,6 @@ class Resource {
1037
1059
  break
1038
1060
  }
1039
1061
  break
1040
- case '_TZ3000_mh9px7cq':
1041
- switch (this.model) {
1042
- case 'TS0044':
1043
- buttons.push([1, 'Button 1', SINGLE | DOUBLE | LONG])
1044
- buttons.push([2, 'Button 2', SINGLE | DOUBLE | LONG])
1045
- buttons.push([3, 'Button 3', SINGLE | DOUBLE | LONG])
1046
- buttons.push([4, 'Button 4', SINGLE | DOUBLE | LONG])
1047
- break
1048
- default:
1049
- break
1050
- }
1051
- break
1052
1062
  case '_TZ3000_pzui3skt':
1053
1063
  switch (this.model) {
1054
1064
  case 'TS0041': // Tuya 1-button switch
@@ -1234,30 +1244,6 @@ class Resource {
1234
1244
  break
1235
1245
  }
1236
1246
  break
1237
- case 'ubisys':
1238
- switch (this.model) {
1239
- case 'C4 (5504)':
1240
- case 'C4-R (5604)':
1241
- buttons.push([1, '1', SINGLE | LONG])
1242
- buttons.push([2, '2', SINGLE | LONG])
1243
- buttons.push([3, '3', SINGLE | LONG])
1244
- buttons.push([4, '4', SINGLE | LONG])
1245
- break
1246
- case 'D1 (5503)':
1247
- case 'D1-R (5603)':
1248
- case 'S1-R (5601)':
1249
- case 'S2 (5502)':
1250
- case 'S2-R (5602)':
1251
- buttons.push([1, '1', SINGLE | LONG])
1252
- buttons.push([2, '2', SINGLE | LONG])
1253
- break
1254
- case 'S1 (5501)':
1255
- buttons.push([1, '1', SINGLE | LONG])
1256
- break
1257
- default:
1258
- break
1259
- }
1260
- break
1261
1247
  default:
1262
1248
  if (this.body.type === 'ZHAAncillaryControl') {
1263
1249
  buttons.push([1, 'Disarm', SINGLE])
@@ -1279,13 +1265,20 @@ class Resource {
1279
1265
  for (const button of buttons) {
1280
1266
  this.capabilities.buttons[button[0]] = {
1281
1267
  label: button[1],
1282
- events: button[2],
1283
- hasRepeat: button[3]
1268
+ events: button[2]
1269
+ }
1270
+ if (button[3]) {
1271
+ this.capabilities.buttons[button[0]].hasRepeat = button[3]
1284
1272
  }
1285
1273
  }
1286
1274
  this.capabilities.namespace = dots
1287
1275
  ? gateway.Characteristics.hap.ServiceLabelNamespace.DOTS
1288
1276
  : gateway.Characteristics.hap.ServiceLabelNamespace.ARABIC_NUMERALS
1277
+ } else if (this.capabilities._buttons != null) {
1278
+ this.capabilities.buttons = this.capabilities._buttons
1279
+ this.capabilities.namespace = this.capabilities._namespace
1280
+ delete this.capabilities._buttons
1281
+ delete this.capabilities._namespace
1289
1282
  }
1290
1283
  }
1291
1284
 
@@ -1304,7 +1297,8 @@ class Resource {
1304
1297
  patchThermostat () {
1305
1298
  if (
1306
1299
  (this.manufacturer === 'Danfoss' && ['eTRV0100', 'eTRV0103'].includes(this.model)) ||
1307
- (this.manufacturer === 'ELKO' && this.model === 'Super TR')
1300
+ (this.manufacturer === 'ELKO' && this.model === 'Super TR') ||
1301
+ (this.manufacturer === 'LUMI' && this.model === 'lumi.airrtc.agl001')
1308
1302
  ) {
1309
1303
  this.capabilities.heatValue = 'heat'
1310
1304
  } else {
@@ -78,12 +78,12 @@ class Gateway extends AccessoryDelegate {
78
78
  if (this.context.settingsById == null) {
79
79
  this.context.settingsById = {}
80
80
  }
81
- if (this.context.fullState != null) {
82
- this.analyseFullState(this.context.fullState, {
83
- analyseOnly: true,
84
- logUnsupported: true
85
- })
86
- }
81
+ // if (this.context.fullState != null) {
82
+ // this.analyseFullState(this.context.fullState, {
83
+ // analyseOnly: true,
84
+ // logUnsupported: true
85
+ // })
86
+ // }
87
87
 
88
88
  this.addPropertyDelegate({
89
89
  key: 'apiKey',
@@ -997,8 +997,22 @@ class Gateway extends AccessoryDelegate {
997
997
  } catch (error) {
998
998
  fullState.alarmsystems = {}
999
999
  }
1000
+ // FIX_ME: use introspect until buttons and events are reported as capability
1001
+ fullState.introspectByRid = {}
1002
+ for (const rid in fullState.sensors) {
1003
+ const sensor = fullState.sensors[rid]
1004
+ if (sensor.type === 'ZHASwitch') {
1005
+ try {
1006
+ fullState.introspectByRid[rid] = await this.client.get(
1007
+ '/devices/' + sensor.uniqueid + '/state/buttonevent/introspect'
1008
+ )
1009
+ } catch (error) { }
1010
+ }
1011
+ }
1012
+ // End FIX_ME
1000
1013
  this.context.fullState = fullState
1001
1014
  this.pollFullState = false
1015
+ await this.analyseFullState(this.context.fullState, { logUnsupported: true })
1002
1016
  } else {
1003
1017
  const config = await this.client.get('/config')
1004
1018
  if (config.bridgeid === this.id && config.UTC == null) {
@@ -1027,8 +1041,8 @@ class Gateway extends AccessoryDelegate {
1027
1041
  if (this.values.exposeSchedules) {
1028
1042
  this.context.fullState.schedules = await this.client.get('/schedules')
1029
1043
  }
1044
+ await this.analyseFullState(this.context.fullState)
1030
1045
  }
1031
- await this.analyseFullState(this.context.fullState)
1032
1046
  } catch (error) {
1033
1047
  this.error('poll error: %s', error)
1034
1048
  } finally {
@@ -1316,8 +1330,39 @@ class Gateway extends AccessoryDelegate {
1316
1330
  const warn = (logUnsupported ? this.warn : this.vdebug).bind(this)
1317
1331
  const debug = (logUnsupported ? this.debug : this.vdebug).bind(this)
1318
1332
 
1333
+ // FIX_ME: use introspect until buttons and events are reported as capability
1334
+ if (this.context.fullState.introspectByRid?.[rid] != null) {
1335
+ body.introspect = this.context.fullState.introspectByRid[rid]
1336
+ }
1337
+ // End FIX_ME
1319
1338
  const resource = new Deconz.Resource(this, rtype, rid, body)
1320
1339
  const { id, serviceName } = resource
1340
+ // FIX_ME: check introspect against whitelist
1341
+ if (logUnsupported && resource.body.type === 'ZHASwitch') {
1342
+ if (!resource.capabilities._introspect) {
1343
+ this.warn(
1344
+ '%s: /sensors/%d: %s by %s: no introspect',
1345
+ id, rid, resource.model, resource.manufacturer
1346
+ )
1347
+ }
1348
+ } else if (resource.capabilities._buttons != null) {
1349
+ if (
1350
+ JSON.stringify(resource.capabilities._buttons) !==
1351
+ JSON.stringify(resource.capabilities.buttons) ||
1352
+ resource.capabilities._namespace !== resource.capabilities.namespace
1353
+ ) {
1354
+ this.debug(
1355
+ '%s: /sensors/%d: %s by %s: whitelist vs introspect mismatch: %j',
1356
+ id, rid, resource.model, resource.manufacturer, resource.capabilities
1357
+ )
1358
+ } else {
1359
+ this.warn(
1360
+ '%s: /sensors/%d: %s by %s: whitelist matches introspect',
1361
+ id, rid, resource.model, resource.manufacturer
1362
+ )
1363
+ }
1364
+ }
1365
+ // End FIX_ME
1321
1366
  if (this.blacklist[rtype]?.[rid]) {
1322
1367
  debug('%s: /%s/%d: ignoring blacklisted resource', id, rtype, rid)
1323
1368
  return
@@ -253,11 +253,6 @@ class DeconzPlatform extends Platform {
253
253
  ) {
254
254
  this.gatewayMap[id] = new DeconzAccessory.Gateway(this, context)
255
255
  }
256
- } else {
257
- const gateway = this.gatewayMap[context.gid]
258
- if (gateway != null) {
259
- gateway.addAccessory(id)
260
- }
261
256
  }
262
257
  } catch (error) { this.error(error) }
263
258
  }
package/package.json CHANGED
@@ -7,7 +7,7 @@
7
7
  "ebaauw"
8
8
  ],
9
9
  "license": "Apache-2.0",
10
- "version": "1.1.2",
10
+ "version": "1.2.2",
11
11
  "keywords": [
12
12
  "homebridge-plugin",
13
13
  "homekit",
@@ -26,13 +26,13 @@
26
26
  "ui": "cli/ui.js"
27
27
  },
28
28
  "engines": {
29
- "deCONZ": "2.29.5",
30
- "homebridge": "^1.9.0||^2.0.0-beta",
31
- "node": "^22||^20||^18"
29
+ "deCONZ": "2.30.2",
30
+ "homebridge": "^1.11.0||^2.0.0-beta",
31
+ "node": "^22||^20"
32
32
  },
33
33
  "dependencies": {
34
- "hb-deconz-tools": "~2.0.10",
35
- "homebridge-lib": "~7.1.5"
34
+ "hb-deconz-tools": "~2.0.14",
35
+ "homebridge-lib": "~7.1.7"
36
36
  },
37
37
  "scripts": {
38
38
  "prepare": "standard && rm -rf out && jsdoc -c jsdoc.json",