homebridge-deconz 0.0.10 → 0.0.13

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 (53) hide show
  1. package/README.md +3 -6
  2. package/cli/deconz.js +12 -0
  3. package/config.schema.json +1 -0
  4. package/homebridge-ui/public/index.html +26 -0
  5. package/homebridge-ui/public/style.css +0 -0
  6. package/homebridge-ui/server.js +43 -0
  7. package/lib/Deconz/ApiClient.js +34 -1
  8. package/lib/Deconz/ApiResponse.js +1 -1
  9. package/lib/Deconz/Device.js +0 -7
  10. package/lib/Deconz/Resource.js +751 -25
  11. package/lib/DeconzAccessory/Contact.js +54 -0
  12. package/lib/DeconzAccessory/Gateway.js +102 -66
  13. package/lib/DeconzAccessory/Light.js +42 -37
  14. package/lib/DeconzAccessory/Motion.js +51 -0
  15. package/lib/DeconzAccessory/Sensor.js +35 -0
  16. package/lib/DeconzAccessory/Temperature.js +63 -0
  17. package/lib/DeconzAccessory/Thermostat.js +50 -0
  18. package/lib/DeconzAccessory/WarningDevice.js +56 -0
  19. package/lib/DeconzAccessory/WindowCovering.js +47 -0
  20. package/lib/DeconzAccessory/index.js +144 -2
  21. package/lib/DeconzPlatform.js +5 -2
  22. package/lib/DeconzService/AirPressure.js +43 -0
  23. package/lib/DeconzService/AirQuality.js +20 -11
  24. package/lib/DeconzService/Alarm.js +13 -9
  25. package/lib/DeconzService/Battery.js +53 -0
  26. package/lib/DeconzService/Button.js +9 -2
  27. package/lib/DeconzService/CarbonMonoxide.js +38 -0
  28. package/lib/DeconzService/Consumption.js +65 -0
  29. package/lib/DeconzService/Contact.js +60 -0
  30. package/lib/DeconzService/Daylight.js +132 -0
  31. package/lib/DeconzService/DeviceSettings.js +11 -0
  32. package/lib/DeconzService/Flag.js +52 -0
  33. package/lib/DeconzService/Humidity.js +37 -0
  34. package/lib/DeconzService/Leak.js +38 -0
  35. package/lib/DeconzService/Light.js +122 -172
  36. package/lib/DeconzService/LightLevel.js +54 -0
  37. package/lib/DeconzService/LightsResource.js +112 -0
  38. package/lib/DeconzService/Motion.js +101 -0
  39. package/lib/DeconzService/Outlet.js +76 -0
  40. package/lib/DeconzService/Power.js +83 -0
  41. package/lib/DeconzService/SensorsResource.js +96 -0
  42. package/lib/DeconzService/Smoke.js +38 -0
  43. package/lib/DeconzService/Status.js +53 -0
  44. package/lib/DeconzService/Switch.js +93 -0
  45. package/lib/DeconzService/Temperature.js +63 -0
  46. package/lib/DeconzService/Thermostat.js +175 -0
  47. package/lib/DeconzService/WarningDevice.js +68 -0
  48. package/lib/DeconzService/WindowCovering.js +162 -0
  49. package/lib/DeconzService/index.js +79 -25
  50. package/package.json +6 -5
  51. package/lib/Client/ApiError.js +0 -42
  52. package/lib/DeconzAccessory/Device.js +0 -69
  53. package/lib/DeconzService/Sensor.js +0 -61
@@ -0,0 +1,54 @@
1
+ // homebridge-deconz/lib/DeconzService/LightLevel.js
2
+ // Copyright © 2022 Erik Baauw. All rights reserved.
3
+ //
4
+ // Homebridge plugin for deCONZ.
5
+
6
+ 'use strict'
7
+
8
+ const DeconzService = require('../DeconzService')
9
+ const Deconz = require('../Deconz')
10
+
11
+ const { lightLevelToLux } = Deconz.ApiClient
12
+
13
+ /**
14
+ * @memberof DeconzService
15
+ */
16
+ class LightLevel extends DeconzService.SensorsResource {
17
+ constructor (accessory, resource, params = {}) {
18
+ params.Service = accessory.Services.hap.LightSensor
19
+ super(accessory, resource, params)
20
+
21
+ this.addCharacteristicDelegate({
22
+ key: 'lightlevel',
23
+ Characteristic: this.Characteristics.hap.CurrentAmbientLightLevel,
24
+ unit: ' lux'
25
+ })
26
+
27
+ this.addCharacteristicDelegate({
28
+ key: 'dark',
29
+ Characteristic: this.Characteristics.my.Dark
30
+ })
31
+
32
+ this.addCharacteristicDelegate({
33
+ key: 'daylight',
34
+ Characteristic: this.Characteristics.my.Daylight
35
+ })
36
+
37
+ this.addCharacteristicDelegates()
38
+ }
39
+
40
+ updateState (state) {
41
+ if (state.lightlevel != null) {
42
+ this.values.lightlevel = lightLevelToLux(state.lightlevel)
43
+ }
44
+ if (state.dark != null) {
45
+ this.values.dark = state.dark
46
+ }
47
+ if (state.daylight != null) {
48
+ this.values.daylight = state.daylight
49
+ }
50
+ super.updateState(state)
51
+ }
52
+ }
53
+
54
+ module.exports = LightLevel
@@ -0,0 +1,112 @@
1
+ // homebridge-deconz/lib/DeconzService/LightsResource.js
2
+ // Copyright © 2022 Erik Baauw. All rights reserved.
3
+ //
4
+ // Homebridge plugin for deCONZ.
5
+
6
+ 'use strict'
7
+
8
+ const homebridgeLib = require('homebridge-lib')
9
+ const Deconz = require('../Deconz')
10
+ const DeconzService = require('../DeconzService')
11
+
12
+ const { HttpError } = Deconz.ApiClient
13
+ const { timeout } = homebridgeLib
14
+
15
+ class LightsResource extends DeconzService {
16
+ constructor (accessory, resource, params) {
17
+ super(accessory, resource, params)
18
+ this.rpath += resource.rtype === 'groups' ? '/action' : '/state'
19
+
20
+ this.targetState = {}
21
+ this.deferrals = []
22
+ }
23
+
24
+ addCharacteristicDelegates (params = {}) {
25
+ this.addCharacteristicDelegate({
26
+ key: 'lastSeen',
27
+ Characteristic: this.Characteristics.my.LastSeen,
28
+ silent: true
29
+ })
30
+
31
+ this.addCharacteristicDelegate({
32
+ key: 'statusFault',
33
+ Characteristic: this.Characteristics.hap.StatusFault
34
+ })
35
+ }
36
+
37
+ updateState (state) {
38
+ if (state.reachable != null) {
39
+ this.values.statusFault = state.reachable
40
+ ? this.Characteristics.hap.StatusFault.NO_FAULT
41
+ : this.Characteristics.hap.StatusFault.GENERAL_FAULT
42
+ }
43
+ }
44
+
45
+ async identify () {
46
+ if (this.capabilities.alert) {
47
+ if (this.capabilities.breathe) {
48
+ await this.client.put(this.rpath, { alert: 'breathe' })
49
+ await timeout(1500)
50
+ await this.client.put(this.rpath, { alert: 'stop' })
51
+ }
52
+ await this.put(this.rpath, { alert: 'select' })
53
+ }
54
+ }
55
+
56
+ // Collect changes into a combined request.
57
+ put (state) {
58
+ for (const key in state) {
59
+ this.resource.body.state[key] = state[key]
60
+ this.targetState[key] = state[key]
61
+ }
62
+ this._put()
63
+ }
64
+
65
+ // Send the request (for the combined changes) to the gateway.
66
+ async _put () {
67
+ try {
68
+ if (this.updating) {
69
+ return
70
+ }
71
+ this.updating = true
72
+ if (this.platform.config.waitTimeUpdate > 0) {
73
+ await timeout(this.platform.config.waitTimeUpdate)
74
+ }
75
+ const targetState = this.targetState
76
+ this.targetState = {}
77
+ this.updating = false
78
+ if (
79
+ this.gateway.transitionTime !== this.gateway.defaultTransitionTime &&
80
+ targetState.transitiontime === undefined
81
+ ) {
82
+ targetState.transitiontime = this.gateway.transitionTime * 10
83
+ this.gateway.resetTransitionTime()
84
+ }
85
+ if (this.capabilities.noTransition) {
86
+ if (
87
+ (
88
+ targetState.on != null || targetState.bri != null ||
89
+ targetState.bri_inc != null
90
+ ) && (
91
+ targetState.xy != null || targetState.ct != null ||
92
+ targetState.hue != null || targetState.sat != null ||
93
+ targetState.effect != null
94
+ )
95
+ ) {
96
+ targetState.transitiontime = 0
97
+ }
98
+ }
99
+ this.debug('PUT %s %j', this.rpath, targetState)
100
+ await this.client.put(this.rpath, targetState)
101
+ this.recentlyUpdated = true
102
+ await timeout(500)
103
+ this.recentlyUpdated = false
104
+ } catch (error) {
105
+ if (!(error instanceof HttpError)) {
106
+ this.warn(error)
107
+ }
108
+ }
109
+ }
110
+ }
111
+
112
+ module.exports = LightsResource
@@ -0,0 +1,101 @@
1
+ // homebridge-deconz/lib/DeconzService/Motion.js
2
+ // Copyright © 2022 Erik Baauw. All rights reserved.
3
+ //
4
+ // Homebridge plugin for deCONZ.
5
+
6
+ 'use strict'
7
+
8
+ const DeconzService = require('../DeconzService')
9
+
10
+ /**
11
+ * @memberof DeconzService
12
+ */
13
+ class Motion extends DeconzService.SensorsResource {
14
+ constructor (accessory, resource, params = {}) {
15
+ params.Service = accessory.Services.hap.MotionSensor
16
+ super(accessory, resource, params)
17
+
18
+ this.durationKey = resource.body.config.delay !== null ? 'delay' : 'duration'
19
+ this.sensitivitymax = resource.body.config.sensitivitymax
20
+
21
+ this.addCharacteristicDelegate({
22
+ key: 'motion',
23
+ Characteristic: this.Characteristics.hap.MotionDetected,
24
+ value: 0
25
+ })
26
+
27
+ this.addCharacteristicDelegate({
28
+ key: 'sensitivity',
29
+ Characteristic: this.Characteristics.eve.Sensitivity,
30
+ value: this.Characteristics.hap.TemperatureDisplayUnits.CELSIUS
31
+ }).on('didSet', async (value, fromHomeKit) => {
32
+ if (fromHomeKit) {
33
+ const sensitivity = value === this.Characteristics.eve.Sensitivity.HIGH
34
+ ? this.sensitivitymax
35
+ : value === this.Characteristics.eve.Sensitivity.LOW
36
+ ? 0
37
+ : Math.round(this.sensitivitymax / 2)
38
+ await this.put('/config', { sensitivity: sensitivity })
39
+ }
40
+ })
41
+
42
+ this.addCharacteristicDelegate({
43
+ key: 'duration',
44
+ Characteristic: this.Characteristics.eve.Duration,
45
+ unit: 's'
46
+ }).on('didSet', async (value, fromHomeKit) => {
47
+ if (fromHomeKit) {
48
+ const config = {}
49
+ config[this.durationKey] =
50
+ value === this.Characteristics.eve.Duration.VALID_VALUES[0] ? 0 : value
51
+ await this.put('/config', config)
52
+ }
53
+ })
54
+
55
+ this.addCharacteristicDelegate({
56
+ key: 'lastActivation',
57
+ Characteristic: this.Characteristics.eve.LastActivation,
58
+ silent: true
59
+ })
60
+
61
+ this.addCharacteristicDelegates()
62
+
63
+ this.update(resource.body)
64
+ }
65
+
66
+ updateState (state) {
67
+ if (state.presence != null) {
68
+ this.values.motion = state.presence
69
+ }
70
+ if (state.vibration != null) {
71
+ this.values.motion = state.vibration
72
+ }
73
+ if (state.tampered != null) {
74
+ this.values.tampered = state.tampered
75
+ }
76
+ super.updateState(state)
77
+ }
78
+
79
+ updateConfig (config) {
80
+ if (config[this.durationKey] != null) {
81
+ let duration
82
+ for (const value of this.Characteristics.eve.Duration.VALID_VALUES) {
83
+ duration = value
84
+ if (config[this.durationKey] <= value) {
85
+ break
86
+ }
87
+ }
88
+ this.values.duration = duration
89
+ }
90
+ if (config.sensitivity != null) {
91
+ this.values.sensitivity = config.sensitivity === this.sensitivitymax
92
+ ? this.Characteristics.eve.Sensitivity.HIGH
93
+ : config.sensitivity === 0
94
+ ? this.Characteristics.eve.Sensitivity.LOW
95
+ : this.Characteristics.eve.Sensitivity.MEDIUM
96
+ }
97
+ super.updateConfig(config)
98
+ }
99
+ }
100
+
101
+ module.exports = Motion
@@ -0,0 +1,76 @@
1
+ // homebridge-deconz/lib/DeconzService/Outlet.js
2
+ // Copyright © 2022 Erik Baauw. All rights reserved.
3
+ //
4
+ // Homebridge plugin for deCONZ.
5
+
6
+ 'use strict'
7
+
8
+ const DeconzService = require('../DeconzService')
9
+
10
+ class Outlet extends DeconzService.LightsResource {
11
+ constructor (accessory, resource, params = {}) {
12
+ params.Service = accessory.Services.hap.Outlet
13
+ super(accessory, resource, params)
14
+
15
+ this.addCharacteristicDelegate({
16
+ key: 'on',
17
+ Characteristic: this.Characteristics.hap.On,
18
+ value: this.capabilities.on
19
+ ? this.resource.body.state.on
20
+ : this.resource.body.state.all_on
21
+ }).on('didSet', (value, fromHomeKit) => {
22
+ if (fromHomeKit) {
23
+ this.put({ on: value })
24
+ }
25
+ })
26
+
27
+ if (!this.capabilities.on) {
28
+ this.addCharacteristicDelegate({
29
+ key: 'anyOn',
30
+ Characteristic: this.Characteristics.my.AnyOn,
31
+ value: this.resource.body.state.any_on
32
+ }).on('didSet', (value, fromHomeKit) => {
33
+ if (fromHomeKit) {
34
+ this.put({ on: value })
35
+ }
36
+ })
37
+ }
38
+
39
+ this.addCharacteristicDelegate({
40
+ key: 'outletInUse',
41
+ Characteristic: this.Characteristics.hap.OutletInUse,
42
+ value: 1
43
+ })
44
+
45
+ this.addCharacteristicDelegates()
46
+
47
+ this.settings = {
48
+ resetTimeout: this.platform.config.resetTimeout,
49
+ waitTimeUpdate: this.platform.config.waitTimeUpdate,
50
+ wallSwitch: false
51
+ }
52
+ }
53
+
54
+ updateState (state, rpath) {
55
+ for (const key in state) {
56
+ const value = state[key]
57
+ this.resource.body.state[key] = value
58
+ switch (key) {
59
+ case 'all_on':
60
+ this.values.on = value
61
+ break
62
+ case 'any_on':
63
+ this.values.anyOn = value
64
+ break
65
+ case 'on':
66
+ this.values.on = value
67
+ break
68
+ default:
69
+ break
70
+ }
71
+ }
72
+ super.updateState(state)
73
+ }
74
+ }
75
+
76
+ module.exports = Outlet
@@ -0,0 +1,83 @@
1
+ // homebridge-deconz/lib/DeconzService/Power.js
2
+ // Copyright © 2022 Erik Baauw. All rights reserved.
3
+ //
4
+ // Homebridge plugin for deCONZ.
5
+
6
+ 'use strict'
7
+
8
+ const Deconz = require('../Deconz')
9
+ const DeconzService = require('../DeconzService')
10
+
11
+ const { dateToString } = Deconz.ApiClient
12
+
13
+ /**
14
+ * @memberof DeconzService
15
+ */
16
+ class Power extends DeconzService.SensorsResource {
17
+ static addResource (service, resource) {
18
+ if (service.values.currentConsumption === undefined) {
19
+ service.addCharacteristicDelegate({
20
+ key: 'currentConsumption',
21
+ Characteristic: service.Characteristics.eve.CurrentConsumption,
22
+ unit: ' W'
23
+ })
24
+ }
25
+
26
+ if (resource.body.state.current !== undefined) {
27
+ service.addCharacteristicDelegate({
28
+ key: 'electricCurrent',
29
+ Characteristic: service.Characteristics.eve.ElectricCurrent,
30
+ unit: ' A'
31
+ })
32
+ }
33
+
34
+ if (resource.body.state.voltage !== undefined) {
35
+ service.addCharacteristicDelegate({
36
+ key: 'voltage',
37
+ Characteristic: service.Characteristics.eve.Voltage,
38
+ unit: ' V'
39
+ })
40
+ }
41
+
42
+ if (service.values.lastUpdated === undefined) {
43
+ service.addCharacteristicDelegate({
44
+ key: 'lastUpdated',
45
+ Characteristic: service.Characteristics.my.LastUpdated,
46
+ silent: true
47
+ })
48
+ }
49
+ }
50
+
51
+ static updateResourceState (service, state) {
52
+ if (state.power != null) {
53
+ service.values.currentConsumption = state.power
54
+ }
55
+ if (state.current != null) {
56
+ service.values.electricCurrent = state.current / 1000
57
+ }
58
+ if (state.voltage != null) {
59
+ service.values.voltage = state.voltage
60
+ }
61
+ if (state.lastupdated != null) {
62
+ service.values.lastUpdated = dateToString(state.lastupdated)
63
+ }
64
+ }
65
+
66
+ constructor (accessory, resource, params = {}) {
67
+ params.Service = accessory.Services.my.Resource
68
+ super(accessory, resource, params)
69
+
70
+ Power.addResource(this, resource)
71
+
72
+ super.addCharacteristicDelegates()
73
+
74
+ this.update(resource.body)
75
+ }
76
+
77
+ updateState (state) {
78
+ Power.updateResourceState(this.service, state)
79
+ super.updateState(state)
80
+ }
81
+ }
82
+
83
+ module.exports = Power
@@ -0,0 +1,96 @@
1
+ // homebridge-deconz/lib/DeconzService/SensorsResource.js
2
+ // Copyright © 2022 Erik Baauw. All rights reserved.
3
+ //
4
+ // Homebridge plugin for deCONZ.
5
+
6
+ 'use strict'
7
+
8
+ const Deconz = require('../Deconz')
9
+ const DeconzService = require('../DeconzService')
10
+
11
+ const { dateToString, HttpError } = Deconz.ApiClient
12
+
13
+ /**
14
+ * @memberof DeconzService
15
+ */
16
+ class SensorsResource extends DeconzService {
17
+ // constructor (accessory, resource, params) {
18
+ // super(accessory, resource, params)
19
+ // }
20
+
21
+ addCharacteristicDelegates (params = {}) {
22
+ if (!params.noLastUpdated) {
23
+ this.addCharacteristicDelegate({
24
+ key: 'lastUpdated',
25
+ Characteristic: this.Characteristics.my.LastUpdated,
26
+ silent: true
27
+ })
28
+ }
29
+
30
+ this.addCharacteristicDelegate({
31
+ key: 'enabled',
32
+ Characteristic: this.Characteristics.my.Enabled
33
+ }).on('didSet', (value) => {
34
+ this.values.statusActive = value
35
+ })
36
+
37
+ this.addCharacteristicDelegate({
38
+ key: 'statusActive',
39
+ Characteristic: this.Characteristics.hap.StatusActive
40
+ })
41
+
42
+ if (this.resource.body.config.reachable !== undefined) {
43
+ this.addCharacteristicDelegate({
44
+ key: 'statusFault',
45
+ Characteristic: this.Characteristics.hap.StatusFault
46
+ })
47
+ }
48
+
49
+ if (this.resource.body.state.tampered !== undefined && !params.noTampered) {
50
+ this.addCharacteristicDelegate({
51
+ key: 'tampered',
52
+ Characteristic: this.Characteristics.hap.StatusTampered
53
+ })
54
+ }
55
+ }
56
+
57
+ async identify () {
58
+ if (this.resource.body.config.alert) {
59
+ return this.put('/config', { alert: 'select' })
60
+ }
61
+ }
62
+
63
+ updateState (state) {
64
+ if (state.lastupdated != null) {
65
+ this.values.lastUpdated = dateToString(state.lastupdated)
66
+ }
67
+ if (state.tampered != null) {
68
+ this.values.tampered = state.tampered
69
+ ? this.Characteristics.hap.StatusTampered.TAMPERED
70
+ : this.Characteristics.hap.StatusTampered.NOT_TAMPERED
71
+ }
72
+ }
73
+
74
+ updateConfig (config) {
75
+ if (config.on != null) {
76
+ this.values.enabled = !!config.on
77
+ }
78
+ if (config.reachable != null) {
79
+ this.values.statusFault = config.reachable
80
+ ? this.Characteristics.hap.StatusFault.NO_FAULT
81
+ : this.Characteristics.hap.StatusFault.GENERAL_FAULT
82
+ }
83
+ }
84
+
85
+ async put (resource, body) {
86
+ try {
87
+ await this.client.put(this.rpath + resource, body)
88
+ } catch (error) {
89
+ if (!(error instanceof HttpError)) {
90
+ this.warn(error)
91
+ }
92
+ }
93
+ }
94
+ }
95
+
96
+ module.exports = SensorsResource
@@ -0,0 +1,38 @@
1
+ // homebridge-deconz/lib/DeconzService/Smoke.js
2
+ // Copyright © 2022 Erik Baauw. All rights reserved.
3
+ //
4
+ // Homebridge plugin for deCONZ.
5
+
6
+ 'use strict'
7
+
8
+ const DeconzService = require('../DeconzService')
9
+
10
+ /**
11
+ * @memberof DeconzService
12
+ */
13
+ class Smoke extends DeconzService.SensorsResource {
14
+ constructor (accessory, resource, params = {}) {
15
+ params.Service = accessory.Services.hap.SmokeSensor
16
+ super(accessory, resource, params)
17
+
18
+ this.addCharacteristicDelegate({
19
+ key: 'fire',
20
+ Characteristic: this.Characteristics.hap.SmokeDetected
21
+ })
22
+
23
+ super.addCharacteristicDelegates(params)
24
+
25
+ this.update(resource.body, resource.rpath)
26
+ }
27
+
28
+ updateState (state) {
29
+ if (state.fire != null || state.test != null) {
30
+ this.values.fire = state.fire || state.test
31
+ ? this.Characteristics.hap.SmokeDetected.SMOKE_DETECTED
32
+ : this.Characteristics.hap.SmokeDetected.SMOKE_NOT_DETECTED
33
+ }
34
+ super.updateState(state)
35
+ }
36
+ }
37
+
38
+ module.exports = Smoke
@@ -0,0 +1,53 @@
1
+ // homebridge-deconz/lib/DeconzService/Status.js
2
+ // Copyright © 2022 Erik Baauw. All rights reserved.
3
+ //
4
+ // Homebridge plugin for deCONZ.
5
+
6
+ 'use strict'
7
+
8
+ const DeconzService = require('../DeconzService')
9
+
10
+ /**
11
+ * @memberof DeconzService
12
+ */
13
+ class Status extends DeconzService.SensorsResource {
14
+ constructor (accessory, resource, params = {}) {
15
+ params.Service = accessory.Services.my.Status
16
+ super(accessory, resource, params)
17
+
18
+ if (resource.capabilities.readonly) {
19
+ this.addCharacteristicDelegate({
20
+ key: 'status',
21
+ Characteristic: this.Characteristics.my.Status,
22
+ props: {
23
+ perms: [
24
+ this.Characteristic.Perms.READ, this.Characteristic.Perms.NOTIFY
25
+ ]
26
+ }
27
+ })
28
+ } else {
29
+ this.addCharacteristicDelegate({
30
+ key: 'status',
31
+ Characteristic: this.Characteristics.my.Status,
32
+ props: resource.capabilities.props
33
+ }).on('didSet', async (value, fromHomeKit) => {
34
+ if (fromHomeKit) {
35
+ await this.put('/state', { status: value })
36
+ }
37
+ })
38
+ }
39
+
40
+ this.addCharacteristicDelegates()
41
+
42
+ this.update(resource.body)
43
+ }
44
+
45
+ updateState (state) {
46
+ if (state.status != null) {
47
+ this.values.status = state.status
48
+ }
49
+ super.updateState(state)
50
+ }
51
+ }
52
+
53
+ module.exports = Status
@@ -0,0 +1,93 @@
1
+ // homebridge-deconz/lib/DeconzService/Switch.js
2
+ // Copyright © 2022 Erik Baauw. All rights reserved.
3
+ //
4
+ // Homebridge plugin for deCONZ.
5
+
6
+ 'use strict'
7
+
8
+ const DeconzService = require('../DeconzService')
9
+
10
+ /**
11
+ * @memberof DeconzService
12
+ */
13
+ class Switch extends DeconzService.SensorsResource {
14
+ constructor (accessory, resource, params = {}) {
15
+ params.Service = accessory.Services.hap.ServiceLabel
16
+ super(accessory, resource, params)
17
+
18
+ this.addCharacteristicDelegate({
19
+ key: 'namespace',
20
+ Characteristic: this.Characteristics.hap.ServiceLabelNamespace,
21
+ value: resource.capabilities.namespace
22
+ })
23
+
24
+ this.addCharacteristicDelegates({ noLastUpdated: true })
25
+
26
+ this.buttonResources = {}
27
+ this.buttonServices = {}
28
+ this.hasRepeat = false
29
+ }
30
+
31
+ createButtonServices (resource) {
32
+ this.buttonResources[resource.rpath] = {
33
+ buttonEvent: resource.body.state.buttonevent,
34
+ lastUpdated: '',
35
+ toButtonEvent: resource.capabilities.toButtonEvent
36
+ }
37
+ for (const i in resource.capabilities.buttons) {
38
+ const { label, events, hasRepeat } = resource.capabilities.buttons[i]
39
+ if (hasRepeat) {
40
+ this.hasRepeat = hasRepeat
41
+ }
42
+ this.buttonServices[i] = new DeconzService.Button(this.accessoryDelegate, {
43
+ name: this.name + ' ' + label,
44
+ button: Number(i),
45
+ events: events,
46
+ hasRepeat: hasRepeat
47
+ })
48
+ }
49
+ }
50
+
51
+ updateState (state, rpath) {
52
+ const buttonResource = this.buttonResources[rpath]
53
+ if (buttonResource.lastUpdated === '') {
54
+ buttonResource.lastUpdated = state.lastupdated
55
+ } else if (
56
+ state.lastupdated != null &&
57
+ state.lastupdated !== buttonResource.lastUpdated
58
+ ) {
59
+ buttonResource.lastUpdated = state.lastupdated
60
+ const oldValue = buttonResource.buttonEvent
61
+ if (state.buttonevent != null) {
62
+ buttonResource.buttonEvent = buttonResource.toButtonEvent == null
63
+ ? state.buttonevent
64
+ : buttonResource.toButtonEvent(state.buttonevent)
65
+ }
66
+ // TODO handle repeat
67
+ this.updateButtonEvent(
68
+ buttonResource.buttonEvent, oldValue,
69
+ this.accessoryDelegate.settingsService.values.repeat
70
+ )
71
+ }
72
+ super.updateState(state)
73
+ }
74
+
75
+ updateConfig (config) {
76
+ // TODO handle change in devicemode
77
+ super.updateConfig(config)
78
+ }
79
+
80
+ updateButtonEvent (value, oldValue, repeat) {
81
+ const i = Math.floor(value / 1000)
82
+ if (this.buttonServices[i] != null) {
83
+ this.buttonServices[i].update(value, oldValue, repeat)
84
+ }
85
+ }
86
+
87
+ async identify () {
88
+ this.debug('hasRepeat: %j', this.hasRepeat)
89
+ return super.identify()
90
+ }
91
+ }
92
+
93
+ module.exports = Switch