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 +122 -13
- package/lib/Deconz/Resource.js +12 -0
- package/lib/DeconzAccessory/Gateway.js +25 -18
- package/lib/DeconzAccessory/index.js +9 -1
- package/lib/DeconzPlatform.js +1 -1
- package/lib/DeconzService/Light.js +12 -4
- package/package.json +3 -3
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
|
-
|
23
|
-
|
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
|
-
|
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
|
221
|
-
const
|
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.
|
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
|
}
|
package/lib/Deconz/Resource.js
CHANGED
@@ -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
|
-
|
712
|
-
|
713
|
-
|
714
|
-
|
715
|
-
|
716
|
-
|
717
|
-
|
718
|
-
|
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
|
-
|
771
|
-
|
772
|
-
|
773
|
-
|
774
|
-
|
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:
|
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
|
}
|
package/lib/DeconzPlatform.js
CHANGED
@@ -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.
|
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.
|
274
|
-
|
275
|
-
|
276
|
-
|
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
|
+
"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.
|
26
|
+
"node": "^18.14.2"
|
27
27
|
},
|
28
28
|
"dependencies": {
|
29
|
-
"homebridge-lib": "~6.3.
|
29
|
+
"homebridge-lib": "~6.3.11",
|
30
30
|
"ws": "^8.12.1",
|
31
31
|
"xml2js": "~0.4.23"
|
32
32
|
},
|