homebridge-deconz 0.0.26 → 0.1.0

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.
Files changed (41) hide show
  1. package/config.schema.json +0 -7
  2. package/lib/Deconz/ApiError.js +12 -5
  3. package/lib/Deconz/ApiResponse.js +10 -7
  4. package/lib/Deconz/Resource.js +27 -4
  5. package/lib/DeconzAccessory/AirPurifier.js +0 -2
  6. package/lib/DeconzAccessory/Gateway.js +297 -147
  7. package/lib/DeconzAccessory/Light.js +32 -61
  8. package/lib/DeconzAccessory/Sensor.js +89 -1
  9. package/lib/DeconzAccessory/Thermostat.js +5 -8
  10. package/lib/DeconzAccessory/WarningDevice.js +2 -13
  11. package/lib/DeconzAccessory/WindowCovering.js +0 -2
  12. package/lib/DeconzAccessory/index.js +123 -13
  13. package/lib/DeconzPlatform.js +12 -20
  14. package/lib/DeconzService/AirPressure.js +8 -1
  15. package/lib/DeconzService/AirPurifier.js +2 -2
  16. package/lib/DeconzService/AirQuality.js +1 -1
  17. package/lib/DeconzService/Alarm.js +1 -1
  18. package/lib/DeconzService/Battery.js +21 -10
  19. package/lib/DeconzService/Button.js +1 -0
  20. package/lib/DeconzService/CarbonMonoxide.js +1 -1
  21. package/lib/DeconzService/Consumption.js +3 -1
  22. package/lib/DeconzService/Contact.js +1 -25
  23. package/lib/DeconzService/Daylight.js +22 -19
  24. package/lib/DeconzService/Flag.js +1 -1
  25. package/lib/DeconzService/Gateway.js +48 -0
  26. package/lib/DeconzService/Humidity.js +1 -1
  27. package/lib/DeconzService/Leak.js +1 -1
  28. package/lib/DeconzService/Light.js +121 -74
  29. package/lib/DeconzService/LightLevel.js +3 -3
  30. package/lib/DeconzService/LightsResource.js +24 -18
  31. package/lib/DeconzService/Motion.js +3 -9
  32. package/lib/DeconzService/Power.js +2 -1
  33. package/lib/DeconzService/Status.js +1 -1
  34. package/lib/DeconzService/WindowCovering.js +14 -4
  35. package/lib/DeconzService/index.js +14 -3
  36. package/package.json +6 -6
  37. package/lib/DeconzAccessory/Contact.js +0 -54
  38. package/lib/DeconzAccessory/Motion.js +0 -54
  39. package/lib/DeconzAccessory/Temperature.js +0 -63
  40. package/lib/DeconzService/DeviceSettings.js +0 -56
  41. package/lib/DeconzService/GatewaySettings.js +0 -175
@@ -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} settings - The persisted settings, maintained through
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: 'rtypes',
103
- value: [],
128
+ key: 'periodicEvents',
129
+ value: true,
104
130
  silent: true
105
- }).on('didSet', async () => {
106
- this.pollNext = true
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.GatewaySettings(this, {
154
- name: this.name + ' Gateway Settings',
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}
@@ -241,7 +304,6 @@ class Gateway extends homebridgeLib.AccessoryDelegate {
241
304
  */
242
305
  async found (host, config) {
243
306
  try {
244
- this.context.host = host
245
307
  this.values.host = host
246
308
  this.context.config = config
247
309
  this.values.software = config.swversion
@@ -255,6 +317,7 @@ class Gateway extends homebridgeLib.AccessoryDelegate {
255
317
  }
256
318
 
257
319
  async shutdown () {
320
+ this.service.values.statusActive = false
258
321
  return this.wsClient.close()
259
322
  }
260
323
 
@@ -264,14 +327,14 @@ class Gateway extends homebridgeLib.AccessoryDelegate {
264
327
  async heartbeat (beat) {
265
328
  beat -= this.initialBeat
266
329
  try {
267
- if (beat > 0) {
330
+ if (this.values.periodicEvents && beat > 0) {
268
331
  for (const { rate, event } of periodicEvents) {
269
332
  if (beat % rate === 0) {
270
333
  this.buttonService.update(event)
271
334
  }
272
335
  }
273
336
  }
274
- if (beat - this.pollBeat >= this.service.values.heartrate || this.pollNext) {
337
+ if (beat - this.pollBeat >= this.values.heartrate || this.pollNext) {
275
338
  this.pollBeat = beat
276
339
  await this.poll()
277
340
  }
@@ -390,13 +453,13 @@ class Gateway extends homebridgeLib.AccessoryDelegate {
390
453
  })
391
454
  .on('added', (rtype, rid, body) => {
392
455
  this.vdebug('/%s/%d: added: %j', rtype, rid, body)
393
- if (this.service.values[rtype]) {
456
+ if (this.values.autoExpose[rtype]) {
394
457
  this.pollNext = true
395
458
  }
396
459
  })
397
460
  .on('deleted', (rtype, rid) => {
398
461
  this.vdebug('/%s/%d: deleted', rtype, rid)
399
- if (this.service.values[rtype]) {
462
+ if (this.values.autoExpose[rtype]) {
400
463
  this.pollNext = true
401
464
  }
402
465
  })
@@ -418,7 +481,7 @@ class Gateway extends homebridgeLib.AccessoryDelegate {
418
481
  * gateway, and analyse the full state.
419
482
  */
420
483
  async connect (retry = 0) {
421
- if (!this.service.values.expose) {
484
+ if (!this.values.expose) {
422
485
  this.warn('unlock gateway and set Expose to obtain an API key')
423
486
  return
424
487
  }
@@ -428,6 +491,8 @@ class Gateway extends homebridgeLib.AccessoryDelegate {
428
491
  await this.client.getApiKey('homebridge-deconz')
429
492
  }
430
493
  this.wsClient.listen()
494
+ this.service.values.restart = false
495
+ this.service.values.statusActive = true
431
496
  this.checkApiKeys = true
432
497
  for (const id in this.exposeErrorById) {
433
498
  this.resetExposeError(id)
@@ -443,7 +508,7 @@ class Gateway extends homebridgeLib.AccessoryDelegate {
443
508
  return this.connect(retry + 1)
444
509
  }
445
510
  this.error(error)
446
- this.service.values.expose = false
511
+ this.values.expose = false
447
512
  }
448
513
  }
449
514
 
@@ -472,26 +537,14 @@ class Gateway extends homebridgeLib.AccessoryDelegate {
472
537
  this.deleteAccessory(id)
473
538
  }
474
539
  }
475
- for (const id in this.serviceById) {
476
- this.deleteService(id)
477
- }
478
540
  this.exposeErrors = {}
479
541
  this.context.settingsById = {}
480
- this.context.settingsById[this.id] = {
481
- autoExposeGroups: false,
482
- autoExposeLights: false,
483
- autoExposeSensors: false,
484
- autoExposeSchedules: false,
485
- logLevel: 2
486
- }
487
542
  this.context.fullState = null
488
543
  this.context.migration = null
489
- this.service.values.lights = false
490
- this.service.values.sensors = false
491
- this.service.values.groups = false
492
- this.service.values.schedules = false
493
- this.service.values.logLevel = 2
494
- this.values.rtypes = []
544
+ this.values.logLevel = 2
545
+ this.values.autoExpose = {
546
+ groups: false, lights: true, schedules: false, sensors: true
547
+ }
495
548
  } catch (error) { this.error(error) }
496
549
  }
497
550
 
@@ -516,6 +569,25 @@ class Gateway extends homebridgeLib.AccessoryDelegate {
516
569
  this.pollNext = true
517
570
  }
518
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
+
519
591
  /** Add the accessory for the device.
520
592
  * @params {string} id - The device ID.
521
593
  * @return {?DeconzAccessory} - The accessory delegate.
@@ -531,7 +603,7 @@ class Gateway extends homebridgeLib.AccessoryDelegate {
531
603
  const device = this.deviceById[id]
532
604
  delete this.exposeErrorById[id]
533
605
  const { body } = device.resource
534
- this.log('%s: add accessory', body.name)
606
+ this.debug('%s: add accessory', body.name)
535
607
  let { serviceName } = device.resource
536
608
  if (DeconzAccessory[serviceName] == null) {
537
609
  // this.warn('%s: %s: not yet supported %s type', body.name, body.type, rtype)
@@ -548,19 +620,23 @@ class Gateway extends homebridgeLib.AccessoryDelegate {
548
620
  return this.accessoryById[id]
549
621
  }
550
622
 
551
- /** Delete the accessory for the device.
623
+ /** Delete the accessory delegate and associated HomeKit accessory.
552
624
  * @params {string} id - The device ID.
625
+ * @params {boolean} [delegateOnly=false] - Delete the delegate, but keep the
626
+ * associated HomeKit accessory (including context).
553
627
  */
554
- deleteAccessory (id) {
628
+ deleteAccessory (id, delegateOnly = false) {
555
629
  if (id === this.id) {
556
630
  throw new RangeError(`${id}: gateway ID`)
557
631
  }
558
632
  if (this.accessoryById[id] != null) {
559
- this.log('%s: delete accessory', this.accessoryById[id].name)
560
633
  this.monitorResources(this.accessoryById[id], false)
561
- this.accessoryById[id].destroy()
634
+ this.log('%s: delete accessory', this.accessoryById[id].name)
635
+ this.accessoryById[id].destroy(delegateOnly)
562
636
  delete this.accessoryById[id]
563
- if (this.exposeErrorById[id] == null) {
637
+ if (this.exposeErrorById[id] != null) {
638
+ delete this.exposeErrorById[id]
639
+ } else if (!delegateOnly) {
564
640
  const id = Object.keys(this.exposeErrorById)[0]
565
641
  if (id != null) {
566
642
  this.log(
@@ -569,8 +645,6 @@ class Gateway extends homebridgeLib.AccessoryDelegate {
569
645
  this.deleteAccessory(id)
570
646
  this.deleteService(id)
571
647
  }
572
- } else {
573
- delete this.exposeErrorById[id]
574
648
  }
575
649
  }
576
650
  }
@@ -607,86 +681,182 @@ class Gateway extends homebridgeLib.AccessoryDelegate {
607
681
  this.deleteService(id)
608
682
  }
609
683
 
610
- /** Add a service to the gateway accessory to un-blacklist a device.
611
- * @params {string} id - The device ID.
612
- * @return {DeconzService.DeviceSettings} - The service delegate.
613
- */
614
- addService (id) {
615
- if (id === this.id) {
616
- throw new RangeError(`${id}: gateway ID`)
617
- }
618
- if (this.deviceById[id] == null) {
619
- 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
620
690
  }
621
- if (this.serviceById[id] == null) {
622
- if (Object.keys(this.serviceById).length >= 97) {
623
- return null
624
- }
625
- const { resource, rpaths } = this.deviceById[id]
626
- const { body } = resource
627
- const service = new DeconzService.DeviceSettings(this, {
628
- name: body.name + ' Settings',
629
- subtype: id,
630
- resource: rpaths.join(', '),
631
- expose: this.context.settingsById[id].expose
632
- })
633
- this.serviceById[id] = service
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
634
708
  }
635
- return this.serviceById[id]
709
+ return { status: 200, body }
636
710
  }
637
711
 
638
- /** Delete the service on the gateway accessory to un-blacklist a device.
639
- * @params {string} id - The device ID.
640
- */
641
- deleteService (id) {
642
- if (id === this.id) {
643
- throw new RangeError(`${id}: gateway ID`)
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 }
644
734
  }
645
- if (this.serviceById[id] != null) {
646
- this.serviceById[id].destroy()
647
- delete this.serviceById[id]
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
+ }
648
750
  }
649
- }
650
-
651
- // ===========================================================================
652
-
653
- async onUiGet (a) {
654
- this.debug('ui request: GET %s', a.join('/'))
655
- if (a.length === 0) {
656
- return {
657
- status: 200,
658
- body: {
659
- expose: this.service.values.expose,
660
- groups: this.service.values.groups,
661
- heartrate: this.service.values.heartrate,
662
- lights: this.service.values.lights,
663
- logLevel: this.service.values.logLevel,
664
- schedules: this.service.values.schedules,
665
- sensors: this.service.values.sensors
666
- // 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
667
756
  }
757
+ return { status: 200, body }
758
+ }
759
+ if (path.length === 2) {
760
+ return this._deviceToMap(path[1], true)
668
761
  }
669
762
  }
670
- if (a[0] !== 'accessories') {
671
- return { status: 403 } // Forbidden
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
672
770
  }
673
- if (a.length === 1) {
674
- return { status: 200, body: this.deviceByRidByRtype }
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 }
675
832
  }
676
- if (this.deviceById[a[1]] == null) {
677
- return { status: 404 } // Not Found
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
678
842
  }
679
- if (a.length === 2) {
680
- return { status: 200, body: this.deviceById[a[1]] }
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
681
856
  }
682
857
  return { status: 403 } // Forbidden
683
858
  }
684
859
 
685
- async onUiPut (a, body) {
686
- this.debug('ui request: PUT %s %j', a.join('/'), body)
687
- return { status: 501 } // Not Implented
688
- }
689
-
690
860
  // ===========================================================================
691
861
 
692
862
  /** Poll the gateway.
@@ -709,24 +879,24 @@ class Gateway extends homebridgeLib.AccessoryDelegate {
709
879
  } else {
710
880
  const config = await this.client.get('/config')
711
881
  if (config.bridgeid === this.id && config.UTC == null) {
712
- this.service.values.expose = false
882
+ this.values.expose = false
713
883
  this.values.apiKey = null
714
884
  await this.wsClient.close()
715
885
  return
716
886
  }
717
887
  this.context.fullState.config = config
718
888
  if (
719
- this.service.values.lights || this.nDevicesByRtype.lights > 0 ||
720
- this.service.values.sensors || this.nDevicesByRtype.sensors > 0
889
+ this.values.autoExpose.lights || this.nDevicesByRtype.lights > 0 ||
890
+ this.values.autoExpose.sensors || this.nDevicesByRtype.sensors > 0
721
891
  ) {
722
892
  this.context.fullState.lights = await this.client.get('/lights')
723
893
  this.context.fullState.sensors = await this.client.get('/sensors')
724
894
  }
725
- if (this.service.values.groups || this.nDevicesByRtype.groups > 0) {
895
+ if (this.values.autoExpose.groups || this.nDevicesByRtype.groups > 0) {
726
896
  this.context.fullState.groups = await this.client.get('/groups')
727
897
  this.context.fullState.groups[0] = await this.client.get('/groups/0')
728
898
  }
729
- if (this.service.values.schedules) {
899
+ if (this.values.autoExpose.schedules) {
730
900
  this.context.fullState.schedules = await this.client.get('/schedules')
731
901
  }
732
902
  }
@@ -870,7 +1040,7 @@ class Gateway extends homebridgeLib.AccessoryDelegate {
870
1040
  ) {
871
1041
  delete this.context.settingsById[id]
872
1042
  this.deleteAccessory(id)
873
- this.deleteService(id)
1043
+ // this.deleteService(id)
874
1044
  changed = true
875
1045
  } else {
876
1046
  /** Emitted when the gateway has been polled.
@@ -882,43 +1052,23 @@ class Gateway extends homebridgeLib.AccessoryDelegate {
882
1052
  } catch (error) { this.error(error) }
883
1053
  }
884
1054
 
885
- this.vdebug('analysing services...')
886
- for (const id in this.serviceById) {
887
- try {
888
- if (
889
- this.deviceById[id] == null ||
890
- !this.values.rtypes.includes(this.deviceById[id].resource.rtype)
891
- ) {
892
- delete this.exposeErrorById[id]
893
- this.deleteService(id)
894
- changed = true
895
- }
896
- } catch (error) { this.error(error) }
897
- }
898
-
899
- for (const rtype of this.values.rtypes) {
1055
+ for (const rtype of rtypes) {
900
1056
  this.vdebug('analysing %s devices...', rtype)
901
1057
  const rids = Object.keys(this.deviceByRidByRtype[rtype]).sort()
902
1058
  for (const rid of rids) {
903
1059
  try {
904
1060
  const { id } = this.deviceByRidByRtype[rtype][rid]
905
1061
  if (this.context.settingsById[id] == null) {
906
- this.context.settingsById[id] = { expose: true }
1062
+ this.context.settingsById[id] = {
1063
+ expose: this.values.autoExpose[rtype]
1064
+ }
907
1065
  }
908
1066
  if (this.context.settingsById[id].expose) {
909
1067
  if (this.accessoryById[id] == null) {
910
1068
  this.addAccessory(id)
911
1069
  changed = true
912
1070
  }
913
- if (this.serviceById[id] != null) {
914
- this.deleteService(id)
915
- changed = true
916
- }
917
1071
  } else {
918
- if (this.serviceById[id] == null) {
919
- this.addService(id)
920
- changed = true
921
- }
922
1072
  if (this.accessoryById[id] != null) {
923
1073
  this.deleteAccessory(id)
924
1074
  changed = true