homebridge-deconz 0.0.27 → 0.1.1
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/config.schema.json +0 -7
- package/lib/Deconz/Resource.js +27 -4
- package/lib/DeconzAccessory/AirPurifier.js +0 -2
- package/lib/DeconzAccessory/Gateway.js +298 -149
- package/lib/DeconzAccessory/Light.js +27 -37
- package/lib/DeconzAccessory/Sensor.js +91 -1
- package/lib/DeconzAccessory/Thermostat.js +1 -3
- package/lib/DeconzAccessory/WarningDevice.js +0 -8
- package/lib/DeconzAccessory/WindowCovering.js +0 -2
- package/lib/DeconzAccessory/index.js +123 -13
- package/lib/DeconzPlatform.js +12 -20
- package/lib/DeconzService/AirPressure.js +1 -1
- package/lib/DeconzService/AirPurifier.js +2 -2
- package/lib/DeconzService/AirQuality.js +1 -1
- package/lib/DeconzService/Alarm.js +1 -1
- package/lib/DeconzService/Battery.js +19 -9
- package/lib/DeconzService/Button.js +1 -0
- package/lib/DeconzService/CarbonMonoxide.js +1 -1
- package/lib/DeconzService/Consumption.js +3 -1
- package/lib/DeconzService/Contact.js +1 -25
- package/lib/DeconzService/Daylight.js +22 -19
- package/lib/DeconzService/Flag.js +1 -1
- package/lib/DeconzService/Gateway.js +48 -0
- package/lib/DeconzService/Humidity.js +1 -1
- package/lib/DeconzService/Leak.js +1 -1
- package/lib/DeconzService/Light.js +111 -86
- package/lib/DeconzService/LightLevel.js +3 -3
- package/lib/DeconzService/Motion.js +3 -9
- package/lib/DeconzService/Power.js +2 -1
- package/lib/DeconzService/Status.js +1 -1
- package/lib/DeconzService/Switch.js +1 -1
- package/lib/DeconzService/WindowCovering.js +14 -4
- package/lib/DeconzService/index.js +11 -12
- package/package.json +6 -6
- package/lib/DeconzAccessory/Contact.js +0 -53
- package/lib/DeconzAccessory/Motion.js +0 -53
- package/lib/DeconzAccessory/Temperature.js +0 -61
- package/lib/DeconzService/DeviceSettings.js +0 -65
- package/lib/DeconzService/GatewaySettings.js +0 -176
@@ -50,24 +50,15 @@ class Gateway extends homebridgeLib.AccessoryDelegate {
|
|
50
50
|
* @type {Object}
|
51
51
|
* @property {Object} config - Response body of unauthenticated
|
52
52
|
* GET `/config` (from {@link DeconzDiscovery#config config()}.
|
53
|
-
* @property {Object.<string, boolean>} blacklist - Map of blacklisted
|
54
|
-
* devices.
|
55
53
|
* @property {Object} fullState - The gateway's full state, from the
|
56
54
|
* last time the gateway was polled.
|
57
|
-
* @property {Object}
|
55
|
+
* @property {Object.<String, Object>} settingsById - The persisted settings, maintained through
|
58
56
|
* the Homebridge UI.
|
59
57
|
*/
|
60
58
|
this.context // eslint-disable-line no-unused-expressions
|
61
|
-
this.context.host = params.host
|
62
59
|
this.context.config = params.config
|
63
60
|
if (this.context.settingsById == null) {
|
64
61
|
this.context.settingsById = {}
|
65
|
-
// migration
|
66
|
-
for (const id in this.context.blacklist) {
|
67
|
-
this.context.settingsById[id] = { expose: false }
|
68
|
-
}
|
69
|
-
delete this.context.blacklist
|
70
|
-
// end migration
|
71
62
|
}
|
72
63
|
if (this.context.fullState != null) {
|
73
64
|
this.analyseFullState(this.context.fullState, {
|
@@ -83,6 +74,41 @@ class Gateway extends homebridgeLib.AccessoryDelegate {
|
|
83
74
|
this.client.apiKey = value
|
84
75
|
})
|
85
76
|
|
77
|
+
this.addPropertyDelegate({
|
78
|
+
key: 'autoExpose',
|
79
|
+
value: { groups: false, lights: true, schedules: false, sensors: true },
|
80
|
+
silent: true
|
81
|
+
}).on('didSet', async () => {
|
82
|
+
this.pollNext = true
|
83
|
+
})
|
84
|
+
|
85
|
+
this.addPropertyDelegate({
|
86
|
+
key: 'brightnessAdjustment',
|
87
|
+
value: 1,
|
88
|
+
silent: true
|
89
|
+
})
|
90
|
+
|
91
|
+
this.addPropertyDelegate({
|
92
|
+
key: 'expose',
|
93
|
+
value: true,
|
94
|
+
silent: true
|
95
|
+
}).on('didSet', async (value) => {
|
96
|
+
try {
|
97
|
+
this.service.values.statusActive = value
|
98
|
+
if (value) {
|
99
|
+
await this.connect()
|
100
|
+
} else {
|
101
|
+
await this.reset()
|
102
|
+
}
|
103
|
+
} catch (error) { this.error(error) }
|
104
|
+
})
|
105
|
+
|
106
|
+
this.addPropertyDelegate({
|
107
|
+
key: 'heartrate',
|
108
|
+
value: 30,
|
109
|
+
silent: true
|
110
|
+
})
|
111
|
+
|
86
112
|
this.addPropertyDelegate({
|
87
113
|
key: 'host',
|
88
114
|
value: params.host,
|
@@ -99,11 +125,54 @@ class Gateway extends homebridgeLib.AccessoryDelegate {
|
|
99
125
|
this.values.host = params.host
|
100
126
|
|
101
127
|
this.addPropertyDelegate({
|
102
|
-
key: '
|
103
|
-
value:
|
128
|
+
key: 'periodicEvents',
|
129
|
+
value: true,
|
104
130
|
silent: true
|
105
|
-
})
|
106
|
-
|
131
|
+
})
|
132
|
+
|
133
|
+
this.addPropertyDelegate({
|
134
|
+
key: 'restart',
|
135
|
+
value: false,
|
136
|
+
silent: true
|
137
|
+
}).on('didSet', async (value) => {
|
138
|
+
if (value) {
|
139
|
+
try {
|
140
|
+
await this.client.restart()
|
141
|
+
this.values.search = false
|
142
|
+
this.values.unlock = false
|
143
|
+
return
|
144
|
+
} catch (error) { this.warn(error) }
|
145
|
+
}
|
146
|
+
})
|
147
|
+
|
148
|
+
this.addPropertyDelegate({
|
149
|
+
key: 'search',
|
150
|
+
value: false,
|
151
|
+
silent: true
|
152
|
+
}).on('didSet', async (value) => {
|
153
|
+
if (value) {
|
154
|
+
try {
|
155
|
+
await this.client.search()
|
156
|
+
await homebridgeLib.timeout(120000)
|
157
|
+
this.values.search = false
|
158
|
+
return
|
159
|
+
} catch (error) { this.warn(error) }
|
160
|
+
}
|
161
|
+
})
|
162
|
+
|
163
|
+
this.addPropertyDelegate({
|
164
|
+
key: 'unlock',
|
165
|
+
value: false,
|
166
|
+
silent: true
|
167
|
+
}).on('didSet', async (value) => {
|
168
|
+
if (value) {
|
169
|
+
try {
|
170
|
+
await this.client.unlock()
|
171
|
+
await homebridgeLib.timeout(60000)
|
172
|
+
this.values.unlock = false
|
173
|
+
return
|
174
|
+
} catch (error) { this.warn(error) }
|
175
|
+
}
|
107
176
|
})
|
108
177
|
|
109
178
|
this.addPropertyDelegate({
|
@@ -142,20 +211,14 @@ class Gateway extends homebridgeLib.AccessoryDelegate {
|
|
142
211
|
*/
|
143
212
|
this.exposeErrorById = {}
|
144
213
|
|
145
|
-
/** Map of services to un-blacklist a gateway device.
|
146
|
-
* @type {Object<string, DeconzService.DeviceSettings>}
|
147
|
-
*/
|
148
|
-
this.serviceById = {}
|
149
|
-
|
150
214
|
/** The service delegate for the Gateway Settings settings.
|
151
215
|
* @type {DeconzService.GatewaySettings}
|
152
216
|
*/
|
153
|
-
this.service = new DeconzService.
|
154
|
-
name: this.name + ' Gateway
|
217
|
+
this.service = new DeconzService.Gateway(this, {
|
218
|
+
name: this.name + ' Gateway',
|
155
219
|
primaryService: true,
|
156
220
|
host: params.host
|
157
221
|
})
|
158
|
-
this.manageLogLevel(this.service.characteristicDelegate('logLevel'))
|
159
222
|
|
160
223
|
/** The service delegate for the Stateless Programmable Switch service.
|
161
224
|
* @type {DeconzService.Button}
|
@@ -164,8 +227,7 @@ class Gateway extends homebridgeLib.AccessoryDelegate {
|
|
164
227
|
name: this.name + ' Button',
|
165
228
|
button: 1,
|
166
229
|
events: DeconzService.Button.SINGLE | DeconzService.Button.DOUBLE |
|
167
|
-
DeconzService.Button.LONG
|
168
|
-
exposeConfiguredName: true
|
230
|
+
DeconzService.Button.LONG
|
169
231
|
})
|
170
232
|
|
171
233
|
this.createClient()
|
@@ -242,7 +304,6 @@ class Gateway extends homebridgeLib.AccessoryDelegate {
|
|
242
304
|
*/
|
243
305
|
async found (host, config) {
|
244
306
|
try {
|
245
|
-
this.context.host = host
|
246
307
|
this.values.host = host
|
247
308
|
this.context.config = config
|
248
309
|
this.values.software = config.swversion
|
@@ -256,6 +317,7 @@ class Gateway extends homebridgeLib.AccessoryDelegate {
|
|
256
317
|
}
|
257
318
|
|
258
319
|
async shutdown () {
|
320
|
+
this.service.values.statusActive = false
|
259
321
|
return this.wsClient.close()
|
260
322
|
}
|
261
323
|
|
@@ -265,14 +327,14 @@ class Gateway extends homebridgeLib.AccessoryDelegate {
|
|
265
327
|
async heartbeat (beat) {
|
266
328
|
beat -= this.initialBeat
|
267
329
|
try {
|
268
|
-
if (beat > 0) {
|
330
|
+
if (this.values.periodicEvents && beat > 0) {
|
269
331
|
for (const { rate, event } of periodicEvents) {
|
270
332
|
if (beat % rate === 0) {
|
271
333
|
this.buttonService.update(event)
|
272
334
|
}
|
273
335
|
}
|
274
336
|
}
|
275
|
-
if (beat - this.pollBeat >= this.
|
337
|
+
if (beat - this.pollBeat >= this.values.heartrate || this.pollNext) {
|
276
338
|
this.pollBeat = beat
|
277
339
|
await this.poll()
|
278
340
|
}
|
@@ -391,13 +453,13 @@ class Gateway extends homebridgeLib.AccessoryDelegate {
|
|
391
453
|
})
|
392
454
|
.on('added', (rtype, rid, body) => {
|
393
455
|
this.vdebug('/%s/%d: added: %j', rtype, rid, body)
|
394
|
-
if (this.
|
456
|
+
if (this.values.autoExpose[rtype]) {
|
395
457
|
this.pollNext = true
|
396
458
|
}
|
397
459
|
})
|
398
460
|
.on('deleted', (rtype, rid) => {
|
399
461
|
this.vdebug('/%s/%d: deleted', rtype, rid)
|
400
|
-
if (this.
|
462
|
+
if (this.values.autoExpose[rtype]) {
|
401
463
|
this.pollNext = true
|
402
464
|
}
|
403
465
|
})
|
@@ -419,7 +481,7 @@ class Gateway extends homebridgeLib.AccessoryDelegate {
|
|
419
481
|
* gateway, and analyse the full state.
|
420
482
|
*/
|
421
483
|
async connect (retry = 0) {
|
422
|
-
if (!this.
|
484
|
+
if (!this.values.expose) {
|
423
485
|
this.warn('unlock gateway and set Expose to obtain an API key')
|
424
486
|
return
|
425
487
|
}
|
@@ -429,6 +491,8 @@ class Gateway extends homebridgeLib.AccessoryDelegate {
|
|
429
491
|
await this.client.getApiKey('homebridge-deconz')
|
430
492
|
}
|
431
493
|
this.wsClient.listen()
|
494
|
+
this.service.values.restart = false
|
495
|
+
this.service.values.statusActive = true
|
432
496
|
this.checkApiKeys = true
|
433
497
|
for (const id in this.exposeErrorById) {
|
434
498
|
this.resetExposeError(id)
|
@@ -444,7 +508,7 @@ class Gateway extends homebridgeLib.AccessoryDelegate {
|
|
444
508
|
return this.connect(retry + 1)
|
445
509
|
}
|
446
510
|
this.error(error)
|
447
|
-
this.
|
511
|
+
this.values.expose = false
|
448
512
|
}
|
449
513
|
}
|
450
514
|
|
@@ -473,26 +537,14 @@ class Gateway extends homebridgeLib.AccessoryDelegate {
|
|
473
537
|
this.deleteAccessory(id)
|
474
538
|
}
|
475
539
|
}
|
476
|
-
for (const id in this.serviceById) {
|
477
|
-
this.deleteService(id)
|
478
|
-
}
|
479
540
|
this.exposeErrors = {}
|
480
541
|
this.context.settingsById = {}
|
481
|
-
this.context.settingsById[this.id] = {
|
482
|
-
autoExposeGroups: false,
|
483
|
-
autoExposeLights: false,
|
484
|
-
autoExposeSensors: false,
|
485
|
-
autoExposeSchedules: false,
|
486
|
-
logLevel: 2
|
487
|
-
}
|
488
542
|
this.context.fullState = null
|
489
543
|
this.context.migration = null
|
490
|
-
this.
|
491
|
-
this.
|
492
|
-
|
493
|
-
|
494
|
-
this.service.values.logLevel = 2
|
495
|
-
this.values.rtypes = []
|
544
|
+
this.values.logLevel = 2
|
545
|
+
this.values.autoExpose = {
|
546
|
+
groups: false, lights: true, schedules: false, sensors: true
|
547
|
+
}
|
496
548
|
} catch (error) { this.error(error) }
|
497
549
|
}
|
498
550
|
|
@@ -517,6 +569,25 @@ class Gateway extends homebridgeLib.AccessoryDelegate {
|
|
517
569
|
this.pollNext = true
|
518
570
|
}
|
519
571
|
|
572
|
+
/** Re-expose an accessory.
|
573
|
+
*
|
574
|
+
* Delete the accessory delegate, but keep the HAP accessory, including
|
575
|
+
* the persisted context.
|
576
|
+
* The delegate will be re-created when the gateway is next polled.
|
577
|
+
* @params {string} id - The device ID.
|
578
|
+
* @params {boolean} expose - Set to `false` to blacklist the device.
|
579
|
+
*/
|
580
|
+
reExposeAccessory (id) {
|
581
|
+
if (id === this.id) {
|
582
|
+
throw new RangeError(`${id}: gateway ID`)
|
583
|
+
}
|
584
|
+
if (this.accessoryById[id] == null) {
|
585
|
+
throw new RangeError(`${id}: unknown accessory ID`)
|
586
|
+
}
|
587
|
+
this.deleteAccessory(id, true)
|
588
|
+
this.pollNext = true
|
589
|
+
}
|
590
|
+
|
520
591
|
/** Add the accessory for the device.
|
521
592
|
* @params {string} id - The device ID.
|
522
593
|
* @return {?DeconzAccessory} - The accessory delegate.
|
@@ -532,7 +603,7 @@ class Gateway extends homebridgeLib.AccessoryDelegate {
|
|
532
603
|
const device = this.deviceById[id]
|
533
604
|
delete this.exposeErrorById[id]
|
534
605
|
const { body } = device.resource
|
535
|
-
this.
|
606
|
+
this.debug('%s: add accessory', body.name)
|
536
607
|
let { serviceName } = device.resource
|
537
608
|
if (DeconzAccessory[serviceName] == null) {
|
538
609
|
// this.warn('%s: %s: not yet supported %s type', body.name, body.type, rtype)
|
@@ -549,19 +620,23 @@ class Gateway extends homebridgeLib.AccessoryDelegate {
|
|
549
620
|
return this.accessoryById[id]
|
550
621
|
}
|
551
622
|
|
552
|
-
/** Delete the accessory
|
623
|
+
/** Delete the accessory delegate and associated HomeKit accessory.
|
553
624
|
* @params {string} id - The device ID.
|
625
|
+
* @params {boolean} [delegateOnly=false] - Delete the delegate, but keep the
|
626
|
+
* associated HomeKit accessory (including context).
|
554
627
|
*/
|
555
|
-
deleteAccessory (id) {
|
628
|
+
deleteAccessory (id, delegateOnly = false) {
|
556
629
|
if (id === this.id) {
|
557
630
|
throw new RangeError(`${id}: gateway ID`)
|
558
631
|
}
|
559
632
|
if (this.accessoryById[id] != null) {
|
560
|
-
this.log('%s: delete accessory', this.accessoryById[id].name)
|
561
633
|
this.monitorResources(this.accessoryById[id], false)
|
562
|
-
this.accessoryById[id].
|
634
|
+
this.log('%s: delete accessory', this.accessoryById[id].name)
|
635
|
+
this.accessoryById[id].destroy(delegateOnly)
|
563
636
|
delete this.accessoryById[id]
|
564
|
-
if (this.exposeErrorById[id]
|
637
|
+
if (this.exposeErrorById[id] != null) {
|
638
|
+
delete this.exposeErrorById[id]
|
639
|
+
} else if (!delegateOnly) {
|
565
640
|
const id = Object.keys(this.exposeErrorById)[0]
|
566
641
|
if (id != null) {
|
567
642
|
this.log(
|
@@ -570,8 +645,6 @@ class Gateway extends homebridgeLib.AccessoryDelegate {
|
|
570
645
|
this.deleteAccessory(id)
|
571
646
|
this.deleteService(id)
|
572
647
|
}
|
573
|
-
} else {
|
574
|
-
delete this.exposeErrorById[id]
|
575
648
|
}
|
576
649
|
}
|
577
650
|
}
|
@@ -608,86 +681,182 @@ class Gateway extends homebridgeLib.AccessoryDelegate {
|
|
608
681
|
this.deleteService(id)
|
609
682
|
}
|
610
683
|
|
611
|
-
|
612
|
-
|
613
|
-
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
throw new RangeError(`${id}: gateway ID`)
|
618
|
-
}
|
619
|
-
if (this.deviceById[id] == null) {
|
620
|
-
throw new RangeError(`${id}: unknown device ID`)
|
684
|
+
// ===========================================================================
|
685
|
+
|
686
|
+
_deviceToMap (id, details = false) {
|
687
|
+
const device = this.deviceById[id]
|
688
|
+
if (device == null) {
|
689
|
+
return { status: 404 } // Not Found
|
621
690
|
}
|
622
|
-
|
623
|
-
|
624
|
-
|
625
|
-
|
626
|
-
|
627
|
-
|
628
|
-
|
629
|
-
|
630
|
-
|
631
|
-
|
632
|
-
|
633
|
-
|
634
|
-
|
691
|
+
const body = {
|
692
|
+
expose: details ? undefined : this.accessoryById[device.id] != null,
|
693
|
+
id: details ? device.id : undefined,
|
694
|
+
manufacturer: device.resource.manufacturer,
|
695
|
+
model: device.resource.model,
|
696
|
+
name: device.resource.body.name,
|
697
|
+
resources: device.rpaths,
|
698
|
+
settings: details
|
699
|
+
? {
|
700
|
+
expose: this.accessoryById[device.id] != null,
|
701
|
+
outlet: undefined, // expose as _Outlet_
|
702
|
+
switch: undefined, // expose as _Switch
|
703
|
+
valve: undefined // expose as _Valve_
|
704
|
+
}
|
705
|
+
: undefined,
|
706
|
+
type: device.resource.rtype,
|
707
|
+
zigbee: device.zigbee
|
635
708
|
}
|
636
|
-
return
|
709
|
+
return { status: 200, body }
|
637
710
|
}
|
638
711
|
|
639
|
-
|
640
|
-
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
|
712
|
+
async onUiGet (path) {
|
713
|
+
this.debug('ui request: GET %s', path.join('/'))
|
714
|
+
if (path.length === 0) {
|
715
|
+
const body = {
|
716
|
+
host: this.values.host,
|
717
|
+
id: this.id,
|
718
|
+
manufacturer: this.values.manufacturer,
|
719
|
+
model: this.values.model,
|
720
|
+
name: this.name,
|
721
|
+
settings: {
|
722
|
+
autoExpose: this.values.autoExpose,
|
723
|
+
brightnessAdjustment: this.values.brightnessAdjustment * 100,
|
724
|
+
expose: this.values.expose,
|
725
|
+
heartrate: this.values.heartrate,
|
726
|
+
logLevel: this.values.logLevel,
|
727
|
+
periodicEvents: this.values.periodicEvents,
|
728
|
+
restart: this.values.restart,
|
729
|
+
search: this.values.search,
|
730
|
+
unlock: this.values.unlock
|
731
|
+
}
|
732
|
+
}
|
733
|
+
return { status: 200, body }
|
645
734
|
}
|
646
|
-
if (
|
647
|
-
|
648
|
-
|
735
|
+
if (path[0] === 'accessories') {
|
736
|
+
if (path.length === 1) {
|
737
|
+
const body = {}
|
738
|
+
for (const id of Object.keys(this.accessoryById).sort()) {
|
739
|
+
body[id] = this.accessoryById[id].onUiGet().body
|
740
|
+
}
|
741
|
+
return { status: 200, body }
|
742
|
+
}
|
743
|
+
if (path.length === 2) {
|
744
|
+
const id = path[1]
|
745
|
+
if (this.accessoryById[id] == null) {
|
746
|
+
return { status: 404 } // Not Found
|
747
|
+
}
|
748
|
+
return this.accessoryById[id].onUiGet(true)
|
749
|
+
}
|
649
750
|
}
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
|
654
|
-
|
655
|
-
this.debug('ui request: GET %s', a.join('/'))
|
656
|
-
if (a.length === 0) {
|
657
|
-
return {
|
658
|
-
status: 200,
|
659
|
-
body: {
|
660
|
-
expose: this.service.values.expose,
|
661
|
-
groups: this.service.values.groups,
|
662
|
-
heartrate: this.service.values.heartrate,
|
663
|
-
lights: this.service.values.lights,
|
664
|
-
logLevel: this.service.values.logLevel,
|
665
|
-
schedules: this.service.values.schedules,
|
666
|
-
sensors: this.service.values.sensors
|
667
|
-
// deviceByRidByRtype: this.deviceByRidByRtype
|
751
|
+
if (path[0] === 'devices') {
|
752
|
+
if (path.length === 1) {
|
753
|
+
const body = {}
|
754
|
+
for (const id of Object.keys(this.deviceById).sort()) {
|
755
|
+
body[id] = this._deviceToMap(id).body
|
668
756
|
}
|
757
|
+
return { status: 200, body }
|
758
|
+
}
|
759
|
+
if (path.length === 2) {
|
760
|
+
return this._deviceToMap(path[1], true)
|
669
761
|
}
|
670
762
|
}
|
671
|
-
|
672
|
-
|
763
|
+
return { status: 403 } // Forbidden
|
764
|
+
}
|
765
|
+
|
766
|
+
async onUiPut (path, body) {
|
767
|
+
this.debug('ui request: PUT %s %j', path.join('/'), body)
|
768
|
+
if (path.length === 0) {
|
769
|
+
return { status: 405 } // Method Not Allowed
|
673
770
|
}
|
674
|
-
if (
|
675
|
-
|
771
|
+
if (path[0] === 'settings') {
|
772
|
+
const settings = {}
|
773
|
+
const optionParser = new homebridgeLib.OptionParser(settings, true)
|
774
|
+
optionParser
|
775
|
+
.on('userInputError', (error) => {
|
776
|
+
this.warn(error)
|
777
|
+
})
|
778
|
+
.objectKey('autoExpose')
|
779
|
+
.intKey('brightnessAdjustment', 10, 100)
|
780
|
+
.boolKey('expose')
|
781
|
+
.intKey('heartrate', 1, 60)
|
782
|
+
.intKey('logLevel', 0, 3)
|
783
|
+
.boolKey('periodicEvents')
|
784
|
+
.boolKey('restart')
|
785
|
+
.boolKey('search')
|
786
|
+
.boolKey('unlock')
|
787
|
+
await optionParser.parse(body)
|
788
|
+
|
789
|
+
const responseBody = {}
|
790
|
+
for (const key in settings) {
|
791
|
+
switch (key) {
|
792
|
+
case 'autoExpose':
|
793
|
+
for (const rtype in settings[key]) {
|
794
|
+
if (this.values[key][rtype] == null) {
|
795
|
+
this.warn('ui error: %s.%s: invalid key', key, rtype)
|
796
|
+
continue
|
797
|
+
}
|
798
|
+
try {
|
799
|
+
settings[key][rtype] = homebridgeLib.OptionParser.toBool(
|
800
|
+
key + '.' + rtype, settings[key][rtype], true
|
801
|
+
)
|
802
|
+
} catch (error) {
|
803
|
+
this.warn(error)
|
804
|
+
continue
|
805
|
+
}
|
806
|
+
this.values[key][rtype] = settings[key][rtype]
|
807
|
+
if (responseBody[key] == null) {
|
808
|
+
responseBody[key] = {}
|
809
|
+
}
|
810
|
+
responseBody[key][rtype] = this.values[key][rtype]
|
811
|
+
}
|
812
|
+
break
|
813
|
+
case 'brightnessAdjustment':
|
814
|
+
this.values[key] = settings[key] / 100
|
815
|
+
responseBody[key] = this.values[key]
|
816
|
+
break
|
817
|
+
case 'expose':
|
818
|
+
case 'heartrate':
|
819
|
+
case 'logLevel':
|
820
|
+
case 'periodicEvents':
|
821
|
+
case 'restart':
|
822
|
+
case 'search':
|
823
|
+
case 'unlock':
|
824
|
+
this.values[key] = settings[key]
|
825
|
+
responseBody[key] = this.values[key]
|
826
|
+
break
|
827
|
+
default:
|
828
|
+
break
|
829
|
+
}
|
830
|
+
}
|
831
|
+
return { status: 200, body: responseBody }
|
676
832
|
}
|
677
|
-
if (
|
678
|
-
|
833
|
+
if (path[0] === 'accessories') {
|
834
|
+
if (path.length === 3 && path[2] === 'settings') {
|
835
|
+
const id = path[1]
|
836
|
+
if (this.accessoryById[id] == null) {
|
837
|
+
return { status: 404 } // Not Found
|
838
|
+
}
|
839
|
+
return this.accessoryById[id].onUiPut(body)
|
840
|
+
}
|
841
|
+
return { status: 405 } // Method Not Allowed
|
679
842
|
}
|
680
|
-
if (
|
681
|
-
|
843
|
+
if (path[0] === 'devices') {
|
844
|
+
if (path.length === 3 && path[2] === 'settings') {
|
845
|
+
const id = path[1]
|
846
|
+
if (this.deviceById[id] == null) {
|
847
|
+
return { status: 404 } // Not Found
|
848
|
+
}
|
849
|
+
if (body.expose != null) {
|
850
|
+
this.exposeDevice(id, body.expose)
|
851
|
+
return { status: 200, body: { expose: body.expose } }
|
852
|
+
}
|
853
|
+
return { status: 200 }
|
854
|
+
}
|
855
|
+
return { status: 405 } // Method Not Allowed
|
682
856
|
}
|
683
857
|
return { status: 403 } // Forbidden
|
684
858
|
}
|
685
859
|
|
686
|
-
async onUiPut (a, body) {
|
687
|
-
this.debug('ui request: PUT %s %j', a.join('/'), body)
|
688
|
-
return { status: 501 } // Not Implented
|
689
|
-
}
|
690
|
-
|
691
860
|
// ===========================================================================
|
692
861
|
|
693
862
|
/** Poll the gateway.
|
@@ -710,24 +879,24 @@ class Gateway extends homebridgeLib.AccessoryDelegate {
|
|
710
879
|
} else {
|
711
880
|
const config = await this.client.get('/config')
|
712
881
|
if (config.bridgeid === this.id && config.UTC == null) {
|
713
|
-
this.
|
882
|
+
this.values.expose = false
|
714
883
|
this.values.apiKey = null
|
715
884
|
await this.wsClient.close()
|
716
885
|
return
|
717
886
|
}
|
718
887
|
this.context.fullState.config = config
|
719
888
|
if (
|
720
|
-
this.
|
721
|
-
this.
|
889
|
+
this.values.autoExpose.lights || this.nDevicesByRtype.lights > 0 ||
|
890
|
+
this.values.autoExpose.sensors || this.nDevicesByRtype.sensors > 0
|
722
891
|
) {
|
723
892
|
this.context.fullState.lights = await this.client.get('/lights')
|
724
893
|
this.context.fullState.sensors = await this.client.get('/sensors')
|
725
894
|
}
|
726
|
-
if (this.
|
895
|
+
if (this.values.autoExpose.groups || this.nDevicesByRtype.groups > 0) {
|
727
896
|
this.context.fullState.groups = await this.client.get('/groups')
|
728
897
|
this.context.fullState.groups[0] = await this.client.get('/groups/0')
|
729
898
|
}
|
730
|
-
if (this.
|
899
|
+
if (this.values.autoExpose.schedules) {
|
731
900
|
this.context.fullState.schedules = await this.client.get('/schedules')
|
732
901
|
}
|
733
902
|
}
|
@@ -871,7 +1040,7 @@ class Gateway extends homebridgeLib.AccessoryDelegate {
|
|
871
1040
|
) {
|
872
1041
|
delete this.context.settingsById[id]
|
873
1042
|
this.deleteAccessory(id)
|
874
|
-
this.deleteService(id)
|
1043
|
+
// this.deleteService(id)
|
875
1044
|
changed = true
|
876
1045
|
} else {
|
877
1046
|
/** Emitted when the gateway has been polled.
|
@@ -883,43 +1052,23 @@ class Gateway extends homebridgeLib.AccessoryDelegate {
|
|
883
1052
|
} catch (error) { this.error(error) }
|
884
1053
|
}
|
885
1054
|
|
886
|
-
|
887
|
-
for (const id in this.serviceById) {
|
888
|
-
try {
|
889
|
-
if (
|
890
|
-
this.deviceById[id] == null ||
|
891
|
-
!this.values.rtypes.includes(this.deviceById[id].resource.rtype)
|
892
|
-
) {
|
893
|
-
delete this.exposeErrorById[id]
|
894
|
-
this.deleteService(id)
|
895
|
-
changed = true
|
896
|
-
}
|
897
|
-
} catch (error) { this.error(error) }
|
898
|
-
}
|
899
|
-
|
900
|
-
for (const rtype of this.values.rtypes) {
|
1055
|
+
for (const rtype of rtypes) {
|
901
1056
|
this.vdebug('analysing %s devices...', rtype)
|
902
1057
|
const rids = Object.keys(this.deviceByRidByRtype[rtype]).sort()
|
903
1058
|
for (const rid of rids) {
|
904
1059
|
try {
|
905
1060
|
const { id } = this.deviceByRidByRtype[rtype][rid]
|
906
1061
|
if (this.context.settingsById[id] == null) {
|
907
|
-
this.context.settingsById[id] = {
|
1062
|
+
this.context.settingsById[id] = {
|
1063
|
+
expose: this.values.autoExpose[rtype]
|
1064
|
+
}
|
908
1065
|
}
|
909
1066
|
if (this.context.settingsById[id].expose) {
|
910
1067
|
if (this.accessoryById[id] == null) {
|
911
1068
|
this.addAccessory(id)
|
912
1069
|
changed = true
|
913
1070
|
}
|
914
|
-
if (this.serviceById[id] != null) {
|
915
|
-
this.deleteService(id)
|
916
|
-
changed = true
|
917
|
-
}
|
918
1071
|
} else {
|
919
|
-
if (this.serviceById[id] == null) {
|
920
|
-
this.addService(id)
|
921
|
-
changed = true
|
922
|
-
}
|
923
1072
|
if (this.accessoryById[id] != null) {
|
924
1073
|
this.deleteAccessory(id)
|
925
1074
|
changed = true
|