homebridge-deconz 0.1.7 → 0.1.9

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/cli/ui.js CHANGED
@@ -19,12 +19,14 @@ const { UsageError } = CommandLineParser
19
19
 
20
20
  const usage = {
21
21
  ui: `${b('ui')} [${b('-hVD')}] [${b('-U')} ${u('username')}] [${b('-G')} ${u('gateway')}] [${b('-t')} ${u('timeout')}] ${u('command')} [${u('argument')} ...]`,
22
- get: `${b('get')} [${b('-hsnjuatlkv')}] [${b('/devices')}[${b('/')}${u('id')}] | ${b('/accessories')}[${b('/')}${u('id')}]]`,
23
- put: `${b('put')} [${b('-hsnjuatlkv')}] [${b('/devices/')}${u('id')}] | ${b('/accessories/')}${u('id')}]] ${u('body')}`
22
+ discover: `${b('discover')} [${b('-hsnjuatlkv')}]`,
23
+ get: `${b('get')} [${b('-hsnjuatlkv')}] ${u('resource')}`,
24
+ put: `${b('put')} [${b('-h')}] ${u('resource')} ${u('body')}`
24
25
  }
25
26
 
26
27
  const description = {
27
28
  ui: 'Command line interface to Homebridge deCONZ UI Server for dynamic settings.',
29
+ discover: 'Discover UI servers and gateways.',
28
30
  get: 'Get dynamic settings.',
29
31
  put: 'Update dynamic settings.'
30
32
  }
@@ -54,6 +56,9 @@ Parameters:
54
56
  Set timeout to ${u('timeout')} seconds instead of default ${b(5)}.
55
57
 
56
58
  Commands:
59
+ ${usage.discover}
60
+ ${description.discover}
61
+
57
62
  ${usage.get}
58
63
  ${description.get}
59
64
 
@@ -61,6 +66,44 @@ Commands:
61
66
  ${description.put}
62
67
 
63
68
  For more help, issue: ${b('ui')} ${u('command')} ${b('-h')}`,
69
+ discover: `${description.discover}
70
+
71
+ Usage: ${b('ui')} ${usage.discover}
72
+
73
+ Parameters:
74
+ ${b('-h')}, ${b('--help')}
75
+ Print this help and exit.
76
+
77
+ ${b('-s')}, ${b('--sortKeys')}
78
+ Sort object key/value pairs alphabetically on key.
79
+
80
+ ${b('-n')}, ${b('-noWhiteSpace')}
81
+ Do not include spaces nor newlines in the output.
82
+
83
+ ${b('-j')}, ${b('--jsonArray')}
84
+ Output a JSON array of objects for each key/value pair.
85
+ Each object contains two key/value pairs: key "keys" with an array
86
+ of keys as value and key "value" with the value as value.
87
+
88
+ ${b('-u')}, ${b('--joinKeys')}
89
+ Output JSON array of objects for each key/value pair.
90
+ Each object contains one key/value pair: the path (concatenated
91
+ keys separated by '/') as key and the value as value.
92
+
93
+ ${b('-a')}, ${b('--ascii')}
94
+ Output path:value in plain text instead of JSON.
95
+
96
+ ${b('-t')}, ${b('--topOnly')}
97
+ Limit output to top-level key/values.
98
+
99
+ ${b('-l')}, ${b('--leavesOnly')}
100
+ Limit output to leaf (non-array, non-object) key/values.
101
+
102
+ ${b('-k')}, ${b('--keysOnly')}
103
+ Limit output to keys. With ${b('-u')}, output a JSON array of paths.
104
+
105
+ ${b('-v')}, ${b('--valuesOnly')}
106
+ Limit output to values. With ${b('-u')}, output a JSON array of values.`,
64
107
  get: `${description.get}
65
108
 
66
109
  Usage: ${b('ui')} ${usage.get}
@@ -98,13 +141,40 @@ Parameters:
98
141
  Limit output to keys. With ${b('-u')}, output a JSON array of paths.
99
142
 
100
143
  ${b('-v')}, ${b('--valuesOnly')}
101
- Limit output to values. With ${b('-u')}, output a JSON array of values.`,
144
+ Limit output to values. With ${b('-u')}, output a JSON array of values.
145
+
146
+ ${u('resource')}
147
+ The resource to get:
148
+ ${b('/')} Get gateway.
149
+ ${b('/accessories')} List accessories.
150
+ ${b('/accessories/')}${u('id')} Get accessory.
151
+ ${b('/devices')} List devices.
152
+ ${b('/devices/')}${u('id')} Get device.
153
+ ${b('/gateways')} List gateways.
154
+ ${b('/gateways/')}${u('gid')} Get gateway.
155
+ ${b('/gateways/')}${u('gid')}${b('/accessories')} List accessories.
156
+ ${b('/gateways/')}${u('gid')}${b('/accessories/')}${u('id')} Get accessory.
157
+ ${b('/gateways/')}${u('gid')}${b('/devices')} List devices.
158
+ ${b('/gateways/')}${u('gid')}${b('/devices/')}${u('id')} Get device.`,
102
159
  put: `${description.put}
103
160
 
104
161
  Usage: ${b('ui')} ${usage.put}
105
162
 
106
163
  Parameters:
107
- xxx`
164
+ ${b('-h')}, ${b('--help')}
165
+ Print this help and exit.
166
+
167
+ ${u('resource')}
168
+ The resource to update:
169
+ ${b('/')} Update gateway settings.
170
+ ${b('/accessories/')}${u('id')} Update accessory settings.
171
+ ${b('/devices/')}${u('id')} Update device settings.
172
+ ${b('/gateways/')}${u('gid')} Update gateway settings.
173
+ ${b('/gateways/')}${u('gid')}${b('/accessories/')}${u('id')} Update accessory settings.
174
+ ${b('/gateways/')}${u('gid')}${b('/devices/')}${u('id')} Update device settings.
175
+
176
+ ${u('body')}
177
+ The new settings as JSON string.`
108
178
  }
109
179
 
110
180
  class Main extends CommandLineTool {
@@ -217,8 +287,11 @@ class Main extends CommandLineTool {
217
287
  continue
218
288
  }
219
289
  try {
220
- const username = platform._bridge == null ? null : platform._bridge.username
221
- const cachedAccessories = await this.readCachedAccessories(dir, username, platformName)
290
+ const childBridge = platform._bridge != null
291
+ const username = childBridge ? platform._bridge.username : config.bridge.username
292
+ const cachedAccessories = await this.readCachedAccessories(
293
+ dir, childBridge ? username : null, platformName
294
+ )
222
295
  const cachedGateways = cachedAccessories.filter((accessory) => {
223
296
  return accessory.context.className === 'Gateway'
224
297
  })
@@ -226,6 +299,7 @@ class Main extends CommandLineTool {
226
299
  gateways.push({
227
300
  platformName: platform.name == null ? platform.platform : platform.name,
228
301
  username,
302
+ childBridge,
229
303
  uiPort: gateway.context.uiPort,
230
304
  gid: gateway.context.id,
231
305
  name: gateway.context.name
@@ -350,12 +424,38 @@ class Main extends CommandLineTool {
350
424
  throw new Error(`no UI server found for gateway ${this.clargs.gateway}`)
351
425
  }
352
426
  }
427
+ if (this.clargs.command === 'discover') {
428
+ return this.discover(platforms, this.clargs.args)
429
+ }
353
430
  const { gid, uiPort } = platforms[0]
354
431
  this.client = await this.createUiClient(uiPort)
355
432
  this.gid = gid
356
433
  return this[this.clargs.command](this.clargs.args)
357
434
  }
358
435
 
436
+ async discover (platforms, ...args) {
437
+ const parser = new CommandLineParser(packageJson)
438
+ const clargs = {
439
+ options: {}
440
+ }
441
+ parser
442
+ .help('h', 'help', help.get)
443
+ .flag('s', 'sortKeys', () => { clargs.options.sortKeys = true })
444
+ .flag('n', 'noWhiteSpace', () => {
445
+ clargs.options.noWhiteSpace = true
446
+ })
447
+ .flag('j', 'jsonArray', () => { clargs.options.noWhiteSpace = true })
448
+ .flag('u', 'joinKeys', () => { clargs.options.joinKeys = true })
449
+ .flag('a', 'ascii', () => { clargs.options.ascii = true })
450
+ .flag('t', 'topOnly', () => { clargs.options.topOnly = true })
451
+ .flag('l', 'leavesOnly', () => { clargs.options.leavesOnly = true })
452
+ .flag('k', 'keysOnly', () => { clargs.options.keysOnly = true })
453
+ .flag('v', 'valuesOnly', () => { clargs.options.valuesOnly = true })
454
+ .parse(...args)
455
+ const jsonFormatter = new JsonFormatter(clargs.options)
456
+ this.print(jsonFormatter.stringify(platforms))
457
+ }
458
+
359
459
  async get (...args) {
360
460
  const parser = new CommandLineParser(packageJson)
361
461
  const clargs = {
@@ -379,10 +479,15 @@ class Main extends CommandLineTool {
379
479
  })
380
480
  .parse(...args)
381
481
  if (clargs.resource === '/') {
382
- clargs.resource = ''
482
+ clargs.resource = '/gateways/' + this.gid
483
+ } else if (
484
+ clargs.resource.startsWith('/devices') ||
485
+ clargs.resource.startsWith('/accessories')
486
+ ) {
487
+ clargs.resource = '/gateways/' + this.gid + clargs.resource
383
488
  }
489
+ const { body } = await this.client.get(clargs.resource)
384
490
  const jsonFormatter = new JsonFormatter(clargs.options)
385
- const { body } = await this.client.get('/gateways/' + this.gid + clargs.resource)
386
491
  this.print(jsonFormatter.stringify(body))
387
492
  }
388
493
 
@@ -392,7 +497,7 @@ class Main extends CommandLineTool {
392
497
  options: {}
393
498
  }
394
499
  parser
395
- .help('h', 'help', help.get)
500
+ .help('h', 'help', help.put)
396
501
  .parameter('resource', (value) => {
397
502
  clargs.resource = OptionParser.toPath('resource', value)
398
503
  })
@@ -406,12 +511,16 @@ class Main extends CommandLineTool {
406
511
  })
407
512
  .parse(...args)
408
513
  if (clargs.resource === '/') {
409
- clargs.resource = ''
514
+ clargs.resource = '/gateways/' + this.gid
515
+ } else if (
516
+ clargs.resource.startsWith('/devices') ||
517
+ clargs.resource.startsWith('/accessories')
518
+ ) {
519
+ clargs.resource = '/gateways/' + this.gid + clargs.resource
410
520
  }
521
+ clargs.resource += '/settings'
411
522
  const jsonFormatter = new JsonFormatter(clargs.options)
412
- const { body } = await this.client.put(
413
- '/gateways/' + this.gid + clargs.resource + '/settings', clargs.body
414
- )
523
+ const { body } = await this.client.put(clargs.resource, clargs.body)
415
524
  this.print(jsonFormatter.stringify(body))
416
525
  }
417
526
  }
@@ -1034,6 +1034,18 @@ class Resource {
1034
1034
  break
1035
1035
  }
1036
1036
  break
1037
+ case '_TZ3000_mh9px7cq':
1038
+ switch (this.model) {
1039
+ case 'TS0044':
1040
+ buttons.push([1, 'Button 1', SINGLE | DOUBLE | LONG])
1041
+ buttons.push([2, 'Button 2', SINGLE | DOUBLE | LONG])
1042
+ buttons.push([3, 'Button 3', SINGLE | DOUBLE | LONG])
1043
+ buttons.push([4, 'Button 4', SINGLE | DOUBLE | LONG])
1044
+ break
1045
+ default:
1046
+ break
1047
+ }
1048
+ break
1037
1049
  case '_TZ3000_pzui3skt':
1038
1050
  switch (this.model) {
1039
1051
  case 'TS0041': // Tuya 1-button switch
@@ -116,7 +116,6 @@ class Gateway extends AccessoryDelegate {
116
116
  ':' + this.values.wsPort
117
117
  }
118
118
  })
119
- this.values.host = params.host
120
119
 
121
120
  this.addPropertyDelegate({
122
121
  key: 'periodicEvents',
@@ -707,16 +706,21 @@ class Gateway extends AccessoryDelegate {
707
706
  manufacturer: this.values.manufacturer,
708
707
  model: this.values.model,
709
708
  name: this.name,
710
- settings: {
711
- brightnessAdjustment: this.values.brightnessAdjustment * 100,
712
- expose: this.values.expose,
713
- heartrate: this.values.heartrate,
714
- logLevel: this.values.logLevel,
715
- periodicEvents: this.values.periodicEvents,
716
- restart: this.values.restart,
717
- search: this.values.search,
718
- unlock: this.values.unlock
719
- }
709
+ settings: this.values.apiKey == null
710
+ ? {
711
+ expose: this.values.expose,
712
+ logLevel: this.values.logLevel
713
+ }
714
+ : {
715
+ brightnessAdjustment: this.values.brightnessAdjustment * 100,
716
+ expose: this.values.expose,
717
+ heartrate: this.values.heartrate,
718
+ logLevel: this.values.logLevel,
719
+ periodicEvents: this.values.periodicEvents,
720
+ restart: this.values.restart,
721
+ search: this.values.search,
722
+ unlock: this.values.unlock
723
+ }
720
724
  }
721
725
  return { status: 200, body }
722
726
  }
@@ -763,15 +767,18 @@ class Gateway extends AccessoryDelegate {
763
767
  .on('userInputError', (error) => {
764
768
  this.warn(error)
765
769
  })
766
- .intKey('brightnessAdjustment', 10, 100)
767
770
  .boolKey('expose')
768
- .intKey('heartrate', 1, 60)
769
771
  .intKey('logLevel', 0, 3)
770
- .boolKey('periodicEvents')
771
- .boolKey('restart')
772
- .boolKey('search')
773
- .boolKey('unlock')
774
- await optionParser.parse(body)
772
+ if (this.values.apiKey != null) {
773
+ optionParser
774
+ .intKey('brightnessAdjustment', 10, 100)
775
+ .intKey('heartrate', 1, 60)
776
+ .boolKey('periodicEvents')
777
+ .boolKey('restart')
778
+ .boolKey('search')
779
+ .boolKey('unlock')
780
+ }
781
+ optionParser.parse(body)
775
782
 
776
783
  const responseBody = {}
777
784
  for (const key in settings) {
@@ -241,7 +241,7 @@ class DeconzAccessory extends AccessoryDelegate {
241
241
  serviceName: this.values.serviceName,
242
242
  splitLight: undefined,
243
243
  venetianBlind: this.service.values.venetianBlind,
244
- wallSwitch: undefined
244
+ wallSwitch: this.service.values.wallSwitch
245
245
  }
246
246
  : undefined,
247
247
  type: resource.rtype,
@@ -312,6 +312,14 @@ class DeconzAccessory extends AccessoryDelegate {
312
312
  continue
313
313
  }
314
314
  break
315
+ case 'wallSwitch':
316
+ if (this.service.values[key] != null) {
317
+ value = OptionParser.toBool(key, body[key])
318
+ this.service.values[key] = value
319
+ responseBody[key] = value
320
+ continue
321
+ }
322
+ break
315
323
  default:
316
324
  break
317
325
  }
@@ -141,7 +141,7 @@ class DeconzPlatform extends Platform {
141
141
  jobs.push(events.once(this, 'found'))
142
142
  for (const id in this.gatewayMap) {
143
143
  const gateway = this.gatewayMap[id]
144
- const host = gateway.context.host
144
+ const host = gateway.values.host
145
145
  this.debug('job %d: find gateway %s', jobs.length, id)
146
146
  jobs.push(events.once(gateway, 'initialised'))
147
147
  try {
@@ -270,10 +270,11 @@ class Light extends DeconzService.LightsResource {
270
270
  }
271
271
  }
272
272
 
273
- this.settings = {
274
- resetTimeout: this.platform.config.resetTimeout,
275
- waitTimeUpdate: this.platform.config.waitTimeUpdate,
276
- wallSwitch: false
273
+ if (this.resource.rtype === 'lights') {
274
+ this.addCharacteristicDelegate({
275
+ key: 'wallSwitch',
276
+ value: false
277
+ })
277
278
  }
278
279
  }
279
280
 
@@ -413,6 +414,13 @@ class Light extends DeconzService.LightsResource {
413
414
  }
414
415
  break
415
416
  case 'on':
417
+ if (this.values.wallSwitch && !state.reachable) {
418
+ if (this.values.on) {
419
+ this.log('not reachable: force On to false')
420
+ }
421
+ this.values.on = false
422
+ break
423
+ }
416
424
  this.values.on = value
417
425
  break
418
426
  case 'sat':
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",
7
+ "version": "0.1.9",
8
8
  "keywords": [
9
9
  "homebridge-plugin",
10
10
  "homekit",
@@ -23,10 +23,10 @@
23
23
  "engines": {
24
24
  "deCONZ": "2.19.3",
25
25
  "homebridge": "^1.6.0",
26
- "node": "^18.14.1"
26
+ "node": "^18.14.2"
27
27
  },
28
28
  "dependencies": {
29
- "homebridge-lib": "~6.3.10",
29
+ "homebridge-lib": "~6.3.11",
30
30
  "ws": "^8.12.1",
31
31
  "xml2js": "~0.4.23"
32
32
  },