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,56 @@
1
+ // homebridge-deconz/lib/DeconzAccessory/WarningDevice.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 DeconzAccessory = require('../DeconzAccessory')
10
+
11
+ const { History } = homebridgeLib.ServiceDelegate
12
+
13
+ /** Delegate class for a HomeKit accessory, corresponding to a light device
14
+ * or groups resource.
15
+ * @extends DeconzAccessory
16
+ * @memberof DeconzAccessory
17
+ */
18
+ class WarningDevice extends DeconzAccessory {
19
+ /** Instantiate a delegate for an accessory corresponding to a device.
20
+ * @param {DeconzAccessory.Gateway} gateway - The gateway.
21
+ * @param {Deconz.Device} device - The device.
22
+ */
23
+ constructor (gateway, device, settings = {}) {
24
+ super(gateway, device, gateway.Accessory.Categories.SENSOR)
25
+
26
+ this.identify()
27
+
28
+ this.service = this.createService(device.resource, { primaryService: true })
29
+
30
+ for (const subtype in device.resourceBySubtype) {
31
+ const resource = device.resourceBySubtype[subtype]
32
+ if (subtype === device.primary) {
33
+ continue
34
+ }
35
+ this.createService(resource)
36
+ }
37
+
38
+ if (this.serviceByServiceName.Temperature != null) {
39
+ this.historyService = new History.Weather(
40
+ this, {},
41
+ this.serviceByServiceName.Temperature.characteristicDelegate('temperature'),
42
+ null,
43
+ null
44
+ )
45
+ }
46
+
47
+ this.createSettingsService()
48
+
49
+ setImmediate(() => {
50
+ this.debug('initialised')
51
+ this.emit('initialised')
52
+ })
53
+ }
54
+ }
55
+
56
+ module.exports = WarningDevice
@@ -0,0 +1,47 @@
1
+ // homebridge-deconz/lib/DeconzAccessory/WindowCovering.js
2
+ // Copyright © 2022 Erik Baauw. All rights reserved.
3
+ //
4
+ // Homebridge plugin for deCONZ.
5
+
6
+ 'use strict'
7
+
8
+ const DeconzAccessory = require('../DeconzAccessory')
9
+
10
+ /** Delegate class for a HomeKit accessory, corresponding to a light device
11
+ * or groups resource.
12
+ * @extends DeconzAccessory
13
+ * @memberof DeconzAccessory
14
+ */
15
+ class WindowCovering extends DeconzAccessory {
16
+ /** Instantiate a delegate for an accessory corresponding to a device.
17
+ * @param {DeconzAccessory.Gateway} gateway - The gateway.
18
+ * @param {Deconz.Device} device - The device.
19
+ */
20
+ constructor (gateway, device, settings = {}) {
21
+ super(gateway, device, gateway.Accessory.Categories.WINDOW_COVERING)
22
+
23
+ this.identify()
24
+
25
+ this.service = this.createService(device.resource, {
26
+ primaryService: true,
27
+ serviceName: this.values.serviceName
28
+ })
29
+
30
+ for (const subtype in device.resourceBySubtype) {
31
+ const resource = device.resourceBySubtype[subtype]
32
+ if (subtype === device.primary) {
33
+ continue
34
+ }
35
+ this.createService(resource)
36
+ }
37
+
38
+ this.createSettingsService()
39
+
40
+ setImmediate(() => {
41
+ this.debug('initialised')
42
+ this.emit('initialised')
43
+ })
44
+ }
45
+ }
46
+
47
+ module.exports = WindowCovering
@@ -6,14 +6,25 @@
6
6
  'use strict'
7
7
 
8
8
  const homebridgeLib = require('homebridge-lib')
9
+ const Deconz = require('../Deconz')
10
+ const DeconzService = require('../DeconzService')
11
+
12
+ const { HttpError } = Deconz.ApiClient
13
+ const { SINGLE, DOUBLE, LONG } = DeconzService.Button
9
14
 
10
15
  /** Abstract superclass for a delegate of a HomeKit accessory,
11
16
  * corresponding to a Zigbee or virtual device on a deCONZ gateway.
17
+ * @extends AccessoryDelegate
12
18
  */
13
19
  class DeconzAccessory extends homebridgeLib.AccessoryDelegate {
14
- static get Device () { return require('./Device') }
20
+ static get Contact () { return require('./Contact') }
15
21
  static get Light () { return require('./Light') }
16
22
  static get Gateway () { return require('./Gateway') }
23
+ static get Motion () { return require('./Motion') }
24
+ static get Sensor () { return require('./Sensor') }
25
+ static get Temperature () { return require('./Temperature') }
26
+ static get WarningDevice () { return require('./WarningDevice') }
27
+ static get WindowCovering () { return require('./WindowCovering') }
17
28
 
18
29
  /** Instantiate a delegate for an accessory corresponding to a device.
19
30
  * @param {DeconzAccessory.Gateway} gateway - The gateway.
@@ -31,6 +42,12 @@ class DeconzAccessory extends homebridgeLib.AccessoryDelegate {
31
42
  category: category
32
43
  })
33
44
 
45
+ this.context.gid = gateway.id
46
+
47
+ this.serviceByRpath = {}
48
+ this.serviceBySubtype = {}
49
+ this.serviceByServiceName = {}
50
+
34
51
  /** The gateway.
35
52
  * @type {DeconzAccessory.Gateway}
36
53
  */
@@ -52,6 +69,35 @@ class DeconzAccessory extends homebridgeLib.AccessoryDelegate {
52
69
  * @type {Deconz.ApiClient}
53
70
  */
54
71
  this.client = gateway.client
72
+
73
+ this
74
+ .on('polled', (device) => {
75
+ this.values.firmware = device.resource.firmware
76
+ for (const subtype in this.serviceBySubtype) {
77
+ try {
78
+ const service = this.serviceBySubtype[subtype]
79
+ const resource = device.resourceBySubtype[subtype]
80
+ this.debug('%s: polled: %j', resource.rpath, resource.body)
81
+ service.update(resource.body, resource.rpath)
82
+ } catch (error) { this.error(error) }
83
+ }
84
+ })
85
+ .on('changed', (rpath, body) => {
86
+ this.debug('%s: changed: %j', rpath, body)
87
+ const service = this.serviceByRpath[rpath]
88
+ if (service != null) {
89
+ service.update(body, rpath)
90
+ }
91
+ })
92
+ .on('identify', async () => {
93
+ try {
94
+ await this.identify()
95
+ } catch (error) {
96
+ if (!(error instanceof HttpError)) {
97
+ this.warn(error)
98
+ }
99
+ }
100
+ })
55
101
  }
56
102
 
57
103
  /** The primary resource of the device.
@@ -64,12 +110,108 @@ class DeconzAccessory extends homebridgeLib.AccessoryDelegate {
64
110
  */
65
111
  get rpaths () { return this.device.rpaths }
66
112
 
67
- identify () {
113
+ async identify () {
68
114
  this.log(
69
115
  '%s %s v%s (%d resources)', this.values.manufacturer, this.values.model,
70
116
  this.values.firmware, this.rpaths.length
71
117
  )
72
118
  this.debug('%d resources: %s', this.rpaths.length, this.rpaths.join(', '))
119
+ if (this.service != null) {
120
+ await this.service.identify()
121
+ }
122
+ }
123
+
124
+ createService (resource, params = {}) {
125
+ if (resource == null) {
126
+ return
127
+ }
128
+ if (params.serviceName == null) {
129
+ params.serviceName = resource.serviceName
130
+ }
131
+ if (DeconzService[params.serviceName] == null) {
132
+ this.warn(
133
+ '%s: %s: not yet supported %s type',
134
+ resource.rpath, resource.body.type, resource.rtype
135
+ )
136
+ return
137
+ }
138
+ this.debug(
139
+ '%s: capabilities: %j', resource.rpath, resource.capabilities
140
+ )
141
+ this.debug('%s: params: %j', resource.rpath, params)
142
+
143
+ let service
144
+ if (params.serviceName === 'Battery') {
145
+ service = this.serviceByServiceName.Battery
146
+ } else if (params.serviceName === 'Consumption') {
147
+ service = this.serviceByServiceName.Light ||
148
+ this.serviceByServiceName.Power
149
+ if (service != null) {
150
+ service.addResource(resource)
151
+ }
152
+ } else if (params.serviceName === 'Power') {
153
+ service = this.serviceByServiceName.Light ||
154
+ this.serviceByServiceName.Consumption
155
+ if (service != null) {
156
+ service.addResource(resource)
157
+ }
158
+ this.consumptionService = service
159
+ } else if (params.serviceName === 'Switch') {
160
+ // Default button
161
+ if (resource.capabilities.buttons == null) {
162
+ this.warn(
163
+ '%s: unknown %s: %j', resource.rpath, resource.body.type,
164
+ resource.body
165
+ )
166
+ resource.capabilities.buttons = {
167
+ 1: {
168
+ label: 'Unknown Button',
169
+ events: SINGLE | DOUBLE | LONG
170
+ }
171
+ }
172
+ resource.capabilities.namespace =
173
+ this.Characteristics.hap.ServiceLabelNamespace.ARABIC_NUMERALS
174
+ }
175
+ service = this.serviceByServiceName.Switch
176
+ if (service == null) {
177
+ service = new DeconzService.Switch(this, resource, {
178
+ primaryService: params.primaryService
179
+ })
180
+ }
181
+ service.createButtonServices(resource, params)
182
+ }
183
+ if (service == null) {
184
+ service = new DeconzService[params.serviceName](this, resource, {
185
+ primaryService: params.primaryService
186
+ })
187
+ }
188
+ this.serviceBySubtype[resource.subtype] = service
189
+ this.serviceByRpath[resource.rpath] = service
190
+ if (this.serviceByServiceName[resource.serviceName] == null) {
191
+ this.serviceByServiceName[resource.serviceName] = service
192
+ }
193
+ if (
194
+ resource.body.config != null &&
195
+ resource.body.config.battery !== undefined
196
+ ) {
197
+ if (this.serviceByServiceName.Battery == null) {
198
+ this.serviceByServiceName.Battery = new DeconzService.Battery(this, resource)
199
+ }
200
+ service.batteryService = this.serviceByServiceName.Battery
201
+ }
202
+ return service
203
+ }
204
+
205
+ createSettingsService (params = {}) {
206
+ this.settingsService = new DeconzService.DeviceSettings(this, {
207
+ name: this.name + ' Settings',
208
+ subtype: this.id,
209
+ resource: this.device.rpaths.join(', '),
210
+ expose: true,
211
+ logLevel: this.gateway.logLevel,
212
+ hasRepeat: this.service.hasRepeat
213
+ })
214
+ this.manageLogLevel(this.settingsService.characteristicDelegate('logLevel'))
73
215
  }
74
216
  }
75
217
 
@@ -21,8 +21,6 @@ class DeconzPlatform extends homebridgeLib.Platform {
21
21
  .on('accessoryRestored', this.accessoryRestored)
22
22
  .once('heartbeat', this.init)
23
23
  .on('heartbeat', this.heartbeat)
24
-
25
- this.warn('This plugin is work in progress')
26
24
  }
27
25
 
28
26
  parseConfigJson (configJson) {
@@ -190,6 +188,11 @@ class DeconzPlatform extends homebridgeLib.Platform {
190
188
  ) {
191
189
  this.gatewayMap[id] = new DeconzAccessory.Gateway(this, context)
192
190
  }
191
+ } else {
192
+ const gateway = this.gatewayMap[context.gid]
193
+ if (gateway != null) {
194
+ gateway.addAccessory(id)
195
+ }
193
196
  }
194
197
  } catch (error) { this.error(error) }
195
198
  }
@@ -0,0 +1,43 @@
1
+ // homebridge-deconz/lib/DeconzService/AirPressure.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 AirPressure extends DeconzService.SensorsResource {
14
+ constructor (accessory, resource, params = {}) {
15
+ params.Service = accessory.Services.eve.AirPressureSensor
16
+ super(accessory, resource, params)
17
+
18
+ this.addCharacteristicDelegate({
19
+ key: 'airPressure',
20
+ Characteristic: this.Characteristics.eve.AirPressure,
21
+ unit: ' hPa'
22
+ })
23
+
24
+ this.addCharacteristicDelegate({
25
+ key: 'elevation',
26
+ Characteristic: this.Characteristics.eve.Elevation,
27
+ value: 0
28
+ })
29
+
30
+ this.addCharacteristicDelegates()
31
+
32
+ this.update(resource.body)
33
+ }
34
+
35
+ updateState (state) {
36
+ if (state.pressure != null) {
37
+ this.values.airPressure = Math.round(state.pressure * 10) / 10
38
+ }
39
+ super.updateState(state)
40
+ }
41
+ }
42
+
43
+ module.exports = AirPressure
@@ -10,21 +10,26 @@ const DeconzService = require('../DeconzService')
10
10
  /**
11
11
  * @memberof DeconzService
12
12
  */
13
- class AirQuality extends DeconzService.Sensor {
14
- constructor (deconzAccessory, params = {}) {
15
- params.Service = deconzAccessory.Services.hap.AirQualitySensor
16
- super(deconzAccessory, params)
13
+ class AirQuality extends DeconzService.SensorsResource {
14
+ constructor (accessory, resource, params = {}) {
15
+ params.Service = accessory.Services.hap.AirQualitySensor
16
+ super(accessory, resource, params)
17
17
 
18
18
  this.addCharacteristicDelegate({
19
19
  key: 'airQuality',
20
20
  Characteristic: this.Characteristics.hap.AirQuality
21
21
  })
22
+
22
23
  this.addCharacteristicDelegate({
23
24
  key: 'vocDensity',
24
- Characteristic: this.Characteristics.hap.VOCDensity
25
+ Characteristic: this.Characteristics.hap.VOCDensity,
26
+ unit: ' µg/m³',
27
+ props: { minValue: 0, maxValue: 65535, minStep: 1 }
25
28
  })
26
- super.addCharacteristicDelegates(params)
27
- this.update(params.sensor)
29
+
30
+ super.addCharacteristicDelegates()
31
+
32
+ this.update(resource.body)
28
33
  }
29
34
 
30
35
  airQualityValue (value) {
@@ -44,10 +49,14 @@ class AirQuality extends DeconzService.Sensor {
44
49
  }
45
50
  }
46
51
 
47
- update (sensor) {
48
- this.values.airQuality = this.airQualityValue(sensor.state.airquality)
49
- this.values.vocDensity = Math.round(sensor.state.airqualityppb * 4.56)
50
- super.update(sensor)
52
+ updateState (state) {
53
+ if (state.airquality != null) {
54
+ this.values.airQuality = this.airQualityValue(state.airquality)
55
+ }
56
+ if (state.airqualityppb != null) {
57
+ this.values.vocDensity = Math.round(state.airqualityppb * 4.57)
58
+ }
59
+ super.updateState(state)
51
60
  }
52
61
  }
53
62
 
@@ -10,22 +10,26 @@ const DeconzService = require('../DeconzService')
10
10
  /**
11
11
  * @memberof DeconzService
12
12
  */
13
- class Alarm extends DeconzService.Sensor {
14
- constructor (deconzAccessory, params = {}) {
15
- params.Service = deconzAccessory.Services.hap.AirQualitySensor
16
- super(deconzAccessory, params)
13
+ class Alarm extends DeconzService.SensorsResource {
14
+ constructor (accessory, resource, params = {}) {
15
+ params.Service = accessory.Services.my.Resource
16
+ super(accessory, resource, params)
17
17
 
18
18
  this.addCharacteristicDelegate({
19
19
  key: 'alarm',
20
- Characteristic: this.Characteristics.hap.my.Alamrm
20
+ Characteristic: this.Characteristics.my.Alarm
21
21
  })
22
+
22
23
  super.addCharacteristicDelegates(params)
23
- this.update(params.sensor)
24
+
25
+ this.update(resource.body)
24
26
  }
25
27
 
26
- update (sensor) {
27
- this.value.alarm = sensor.state.alarm || sensor.state.test
28
- super.update(sensor)
28
+ updateState (state) {
29
+ if (state.alarm != null || state.test != null) {
30
+ this.values.alarm = state.alarm || state.test
31
+ }
32
+ super.updateState(state)
29
33
  }
30
34
  }
31
35
 
@@ -0,0 +1,53 @@
1
+ // homebridge-deconz/lib/DeconzService/Battery.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
+
11
+ // const { dateToString } = Deconz.ApiClient
12
+
13
+ /**
14
+ * @memberof DeconzService
15
+ */
16
+ class Battery extends homebridgeLib.ServiceDelegate.Battery {
17
+ constructor (accessory, resource, params = {}) {
18
+ super(accessory, {
19
+ name: accessory.name + ' Battery'
20
+ })
21
+ }
22
+
23
+ update (body) {
24
+ if (this.updating) {
25
+ return
26
+ }
27
+ if (body.config != null) {
28
+ this.updateConfig(body.config)
29
+ }
30
+ if (body.state != null) {
31
+ this.updateState(body.state)
32
+ }
33
+ }
34
+
35
+ updateState (state) {
36
+ if (state.battery != null) {
37
+ this.values.batteryLevel = state.battery
38
+ }
39
+ if (state.charging != null) {
40
+ this.values.chargingState = state.charging
41
+ ? this.Characteristics.hap.ChargingState.CHARGING
42
+ : this.Characteristics.hap.ChargingState.NOT_CHARGING
43
+ }
44
+ }
45
+
46
+ updateConfig (config) {
47
+ if (config.battery != null) {
48
+ this.values.batteryLevel = config.battery
49
+ }
50
+ }
51
+ }
52
+
53
+ module.exports = Battery
@@ -115,6 +115,12 @@ class Button extends homebridgeLib.ServiceDelegate {
115
115
  Characteristic: this.Characteristics.hap.ProgrammableSwitchEvent,
116
116
  props: this.props(params.events)
117
117
  })
118
+
119
+ this.addCharacteristicDelegate({
120
+ key: 'index',
121
+ Characteristic: this.Characteristics.hap.ServiceLabelIndex,
122
+ value: params.button
123
+ })
118
124
  }
119
125
 
120
126
  homeKitValue (value, oldValue = 0, repeat = false) {
@@ -132,11 +138,12 @@ class Button extends homebridgeLib.ServiceDelegate {
132
138
  case deconzEvent.SHORT_RELEASE:
133
139
  return homeKitEvent.SINGLE_PRESS
134
140
  case deconzEvent.HOLD:
135
- case deconzEvent.LONG_RELEASE:
136
141
  if (repeat) {
137
142
  return homeKitEvent.SINGLE_PRESS
138
143
  }
139
- if (button === oldButton && oldEvent === deconzEvent.HOLD) {
144
+ // falls through
145
+ case deconzEvent.LONG_RELEASE:
146
+ if (repeat || (button === oldButton && oldEvent === deconzEvent.HOLD)) {
140
147
  // Already issued action on previous Hold.
141
148
  return null
142
149
  }
@@ -0,0 +1,38 @@
1
+ // homebridge-deconz/lib/DeconzService/CarbonMonoxide.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 CarbonMonoxide extends DeconzService.SensorsResource {
14
+ constructor (accessory, resource, params = {}) {
15
+ params.Service = accessory.Services.hap.CarbonMonoxideSensor
16
+ super(accessory, resource, params)
17
+
18
+ this.addCharacteristicDelegate({
19
+ key: 'carbonmonoxide',
20
+ Characteristic: this.Characteristics.hap.CarbonMonoxideDetected
21
+ })
22
+
23
+ super.addCharacteristicDelegates(params)
24
+
25
+ this.update(resource.body)
26
+ }
27
+
28
+ updateState (state) {
29
+ if (state.carbonmonoxide != null || state.test != null) {
30
+ this.values.carbonmonoxide = state.carbonmonoxide || state.test
31
+ ? this.Characteristics.hap.CarbonMonoxideDetected.CO_LEVELS_ABNORMAL
32
+ : this.Characteristics.hap.CarbonMonoxideDetected.CO_LEVELS_NORMAL
33
+ }
34
+ super.updateState(state)
35
+ }
36
+ }
37
+
38
+ module.exports = CarbonMonoxide
@@ -0,0 +1,65 @@
1
+ // homebridge-deconz/lib/DeconzService/Consumption.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 Consumption extends DeconzService.SensorsResource {
17
+ static addResource (service, resource) {
18
+ service.addCharacteristicDelegate({
19
+ key: 'totalConsumption',
20
+ Characteristic: service.Characteristics.eve.TotalConsumption,
21
+ unit: ' kWh'
22
+ })
23
+
24
+ if (
25
+ resource.body.state.power !== undefined &&
26
+ service.values.currentConsumption === undefined
27
+ ) {
28
+ service.addCharacteristicDelegate({
29
+ key: 'currentConsumption',
30
+ Characteristic: service.Characteristics.eve.CurrentConsumption,
31
+ unit: ' W'
32
+ })
33
+ }
34
+ }
35
+
36
+ static updateResourceState (service, state) {
37
+ if (state.consumption != null) {
38
+ service.values.totalConsumption = state.consumption / 1000
39
+ }
40
+ if (state.power != null) {
41
+ service.values.currentConsumption = state.power
42
+ }
43
+ if (state.lastupdated != null) {
44
+ service.values.lastUpdated = dateToString(state.lastupdated)
45
+ }
46
+ }
47
+
48
+ constructor (accessory, resource, params = {}) {
49
+ params.Service = accessory.Services.my.Resource
50
+ super(accessory, resource, params)
51
+
52
+ Consumption.addResource(this, resource)
53
+
54
+ super.addCharacteristicDelegates()
55
+
56
+ this.update(resource.body)
57
+ }
58
+
59
+ updateState (state) {
60
+ Consumption.updateResourceState(this.service, state)
61
+ super.updateState(state)
62
+ }
63
+ }
64
+
65
+ module.exports = Consumption
@@ -0,0 +1,60 @@
1
+ // homebridge-deconz/lib/DeconzService/Contact.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 Contact extends DeconzService.SensorsResource {
14
+ constructor (accessory, resource, params = {}) {
15
+ params.Service = accessory.Services.hap.ContactSensor
16
+ super(accessory, resource, params)
17
+
18
+ this.addCharacteristicDelegate({
19
+ key: 'contact',
20
+ Characteristic: this.Characteristics.hap.ContactSensorState
21
+ })
22
+
23
+ this.addCharacteristicDelegate({
24
+ key: 'timesOpened',
25
+ Characteristic: this.Characteristics.eve.TimesOpened,
26
+ value: 0
27
+ })
28
+
29
+ this.addCharacteristicDelegate({
30
+ key: 'openDuration',
31
+ Characteristic: this.Characteristics.eve.OpenDuration,
32
+ value: 0
33
+ })
34
+
35
+ this.addCharacteristicDelegate({
36
+ key: 'closedDuration',
37
+ Characteristic: this.Characteristics.eve.ClosedDuration,
38
+ value: 0
39
+ })
40
+
41
+ this.addCharacteristicDelegate({
42
+ key: 'lastActivation',
43
+ Characteristic: this.Characteristics.eve.LastActivation,
44
+ silent: true
45
+ })
46
+
47
+ this.addCharacteristicDelegates({ noTampered: true })
48
+ }
49
+
50
+ updateState (state) {
51
+ if (state.open != null) {
52
+ this.values.contact = state.open
53
+ ? this.Characteristics.hap.ContactSensorState.CONTACT_NOT_DETECTED
54
+ : this.Characteristics.hap.ContactSensorState.CONTACT_DETECTED
55
+ }
56
+ super.updateState(state)
57
+ }
58
+ }
59
+
60
+ module.exports = Contact