homebridge-deconz 0.1.9 → 0.1.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cli/deconz.js +1 -4
- package/homebridge-ui/public/index.old.html +3 -5
- package/lib/Deconz/Resource.js +97 -298
- package/lib/DeconzAccessory/Gateway.js +66 -21
- package/lib/DeconzAccessory/Light.js +11 -11
- package/lib/DeconzAccessory/Sensor.js +23 -18
- package/lib/DeconzAccessory/index.js +31 -38
- package/lib/DeconzService/AirQuality.js +60 -29
- package/lib/DeconzService/Consumption.js +5 -5
- package/lib/DeconzService/Humidity.js +3 -0
- package/lib/DeconzService/Label.js +103 -0
- package/lib/DeconzService/Light.js +76 -71
- package/lib/DeconzService/Outlet.js +1 -1
- package/lib/DeconzService/Power.js +6 -5
- package/lib/DeconzService/Status.js +25 -1
- package/lib/DeconzService/Switch.js +43 -78
- package/lib/DeconzService/index.js +1 -0
- package/package.json +5 -5
@@ -13,6 +13,12 @@ const Deconz = require('../Deconz')
|
|
13
13
|
const DeconzAccessory = require('../DeconzAccessory')
|
14
14
|
const DeconzService = require('../DeconzService')
|
15
15
|
|
16
|
+
const migration = {
|
17
|
+
name: 'homebridge-deconz',
|
18
|
+
description: 'migration',
|
19
|
+
classid: 1
|
20
|
+
}
|
21
|
+
|
16
22
|
const rtypes = ['lights', 'sensors', 'groups']
|
17
23
|
|
18
24
|
const periodicEvents = [
|
@@ -516,9 +522,7 @@ class Gateway extends AccessoryDelegate {
|
|
516
522
|
}
|
517
523
|
try {
|
518
524
|
try {
|
519
|
-
|
520
|
-
await this.client.delete(this.context.migration)
|
521
|
-
}
|
525
|
+
await this.deleteMigration()
|
522
526
|
await this.client.deleteApiKey()
|
523
527
|
} catch (error) {}
|
524
528
|
this.values.apiKey = null
|
@@ -531,7 +535,6 @@ class Gateway extends AccessoryDelegate {
|
|
531
535
|
this.exposeErrors = {}
|
532
536
|
this.context.settingsById = {}
|
533
537
|
this.context.fullState = null
|
534
|
-
this.context.migration = null
|
535
538
|
this.values.logLevel = 2
|
536
539
|
} catch (error) { this.error(error) }
|
537
540
|
}
|
@@ -669,6 +672,60 @@ class Gateway extends AccessoryDelegate {
|
|
669
672
|
this.deleteService(id)
|
670
673
|
}
|
671
674
|
|
675
|
+
/** Assert that migration resourcelink exists and is valid.
|
676
|
+
*/
|
677
|
+
async checkMigration () {
|
678
|
+
if (this.context.migration != null) {
|
679
|
+
try {
|
680
|
+
const response = await this.client.get(this.context.migration)
|
681
|
+
if (
|
682
|
+
response.name !== migration.name ||
|
683
|
+
response.description !== migration.description ||
|
684
|
+
response.classid !== migration.classid ||
|
685
|
+
response.owner !== this.client.apiKey
|
686
|
+
) {
|
687
|
+
// not my migration resourcelink
|
688
|
+
this.warn('%s: migration resourcelink no longer valid', this.context.migration)
|
689
|
+
this.context.migration = null
|
690
|
+
}
|
691
|
+
} catch (error) {
|
692
|
+
if (error.statusCode === 404) {
|
693
|
+
this.warn('%s: migration resourcelink no longer exists', this.context.migration)
|
694
|
+
this.context.migration = null
|
695
|
+
}
|
696
|
+
}
|
697
|
+
}
|
698
|
+
}
|
699
|
+
|
700
|
+
/** Create or update migration resourcelink.
|
701
|
+
*/
|
702
|
+
async updateMigration () {
|
703
|
+
await this.checkMigration()
|
704
|
+
if (this.context.migration == null) {
|
705
|
+
const response = await this.client.post('/resourcelinks', {
|
706
|
+
name: migration.name,
|
707
|
+
description: migration.description,
|
708
|
+
classid: migration.classid,
|
709
|
+
links: Object.keys(this.accessoryByRpath).sort()
|
710
|
+
})
|
711
|
+
this.context.migration = '/resourcelinks/' + response.success.id
|
712
|
+
} else {
|
713
|
+
await this.client.put(this.context.migration, {
|
714
|
+
links: Object.keys(this.accessoryByRpath).sort()
|
715
|
+
})
|
716
|
+
}
|
717
|
+
}
|
718
|
+
|
719
|
+
/** Delete migration resourcelink.
|
720
|
+
*/
|
721
|
+
async deleteMigration () {
|
722
|
+
await this.checkMigration()
|
723
|
+
if (this.context.migration != null) {
|
724
|
+
await this.client.delete(this.context.migration)
|
725
|
+
this.context.migration = null
|
726
|
+
}
|
727
|
+
}
|
728
|
+
|
672
729
|
// ===========================================================================
|
673
730
|
|
674
731
|
_deviceToMap (id, details = false) {
|
@@ -733,7 +790,7 @@ class Gateway extends AccessoryDelegate {
|
|
733
790
|
return { status: 200, body }
|
734
791
|
}
|
735
792
|
if (path.length === 2) {
|
736
|
-
const id = path[1]
|
793
|
+
const id = path[1].replace(/:/g, '').toUpperCase()
|
737
794
|
if (this.accessoryById[id] == null) {
|
738
795
|
return { status: 404 } // Not Found
|
739
796
|
}
|
@@ -749,7 +806,7 @@ class Gateway extends AccessoryDelegate {
|
|
749
806
|
return { status: 200, body }
|
750
807
|
}
|
751
808
|
if (path.length === 2) {
|
752
|
-
return this._deviceToMap(path[1], true)
|
809
|
+
return this._deviceToMap(path[1].replace(/:/g, '').toUpperCase(), true)
|
753
810
|
}
|
754
811
|
}
|
755
812
|
return { status: 403 } // Forbidden
|
@@ -808,7 +865,7 @@ class Gateway extends AccessoryDelegate {
|
|
808
865
|
return { status: 405 } // Method Not Allowed
|
809
866
|
}
|
810
867
|
if (path.length === 3 && path[2] === 'settings') {
|
811
|
-
const id = path[1]
|
868
|
+
const id = path[1].replace(/:/g, '').toUpperCase()
|
812
869
|
if (this.accessoryById[id] == null) {
|
813
870
|
return { status: 404 } // Not Found
|
814
871
|
}
|
@@ -820,7 +877,7 @@ class Gateway extends AccessoryDelegate {
|
|
820
877
|
return { status: 405 } // Method Not Allowed
|
821
878
|
}
|
822
879
|
if (path.length === 3 && path[2] === 'settings') {
|
823
|
-
const id = path[1]
|
880
|
+
const id = path[1].replace(/:/g, '').toUpperCase()
|
824
881
|
if (this.deviceById[id] == null) {
|
825
882
|
return { status: 404 } // Not Found
|
826
883
|
}
|
@@ -1060,19 +1117,7 @@ class Gateway extends AccessoryDelegate {
|
|
1060
1117
|
}
|
1061
1118
|
|
1062
1119
|
if (changed) {
|
1063
|
-
|
1064
|
-
const response = await this.client.post('/resourcelinks', {
|
1065
|
-
name: 'homebridge-deconz',
|
1066
|
-
description: 'migration',
|
1067
|
-
classid: 1,
|
1068
|
-
links: Object.keys(this.accessoryByRpath).sort()
|
1069
|
-
})
|
1070
|
-
this.context.migration = '/resourcelinks/' + response.success.id
|
1071
|
-
} else {
|
1072
|
-
await this.client.put(this.context.migration, {
|
1073
|
-
links: Object.keys(this.accessoryByRpath).sort()
|
1074
|
-
})
|
1075
|
-
}
|
1120
|
+
await this.updateMigration()
|
1076
1121
|
this.identify()
|
1077
1122
|
}
|
1078
1123
|
}
|
@@ -25,7 +25,7 @@ class Light extends DeconzAccessory {
|
|
25
25
|
|
26
26
|
this.addPropertyDelegate({
|
27
27
|
key: 'serviceName',
|
28
|
-
value: device.resource.
|
28
|
+
value: device.resource.serviceName
|
29
29
|
})
|
30
30
|
|
31
31
|
this.service = this.createService(device.resource, {
|
@@ -65,20 +65,20 @@ class Light extends DeconzAccessory {
|
|
65
65
|
silent: true
|
66
66
|
})
|
67
67
|
}
|
68
|
-
if (this.
|
69
|
-
params.
|
70
|
-
if (this.service.values.
|
71
|
-
//
|
72
|
-
params.
|
73
|
-
key: '
|
74
|
-
Characteristic: this.Characteristics.eve.
|
68
|
+
if (this.servicesByServiceName.Consumption?.[0] != null) {
|
69
|
+
params.totalConsumptionDelegate = this.service.characteristicDelegate('totalConsumption')
|
70
|
+
if (this.service.values.consumption === undefined) {
|
71
|
+
// Power to be computed by history if not exposed by device
|
72
|
+
params.computedConsumptionDelegate = this.service.addCharacteristicDelegate({
|
73
|
+
key: 'consumption',
|
74
|
+
Characteristic: this.Characteristics.eve.Consumption,
|
75
75
|
unit: ' W'
|
76
76
|
})
|
77
77
|
}
|
78
|
-
} else if (this.
|
79
|
-
params.
|
78
|
+
} else if (this.servicesByServiceName.Power?.[0] != null) {
|
79
|
+
params.consumptionDelegate = this.service.characteristicDelegate('consumption')
|
80
80
|
// Total Consumption to be computed by history
|
81
|
-
params.
|
81
|
+
params.computedTotalConsumptionDelegate = this.service.addCharacteristicDelegate({
|
82
82
|
key: 'totalConsumption',
|
83
83
|
Characteristic: this.Characteristics.eve.TotalConsumption,
|
84
84
|
unit: ' kWh'
|
@@ -3,6 +3,11 @@
|
|
3
3
|
//
|
4
4
|
// Homebridge plugin for deCONZ.
|
5
5
|
|
6
|
+
// Keep separate for Eve History
|
7
|
+
// Switch/Outlet/Lightbulb
|
8
|
+
// Stateless Programmable Switch (Eve button)
|
9
|
+
// Sensors
|
10
|
+
|
6
11
|
'use strict'
|
7
12
|
|
8
13
|
const { ServiceDelegate } = require('homebridge-lib')
|
@@ -51,8 +56,8 @@ class Sensor extends DeconzAccessory {
|
|
51
56
|
}
|
52
57
|
|
53
58
|
const params = {}
|
54
|
-
if (this.
|
55
|
-
const service = this.
|
59
|
+
if (this.servicesByServiceName.Contact?.length === 1) {
|
60
|
+
const service = this.servicesByServiceName.Contact[0]
|
56
61
|
params.contactDelegate = service.characteristicDelegate('contact')
|
57
62
|
params.lastContactDelegate = service.addCharacteristicDelegate({
|
58
63
|
key: 'lastActivation',
|
@@ -66,8 +71,8 @@ class Sensor extends DeconzAccessory {
|
|
66
71
|
silent: true
|
67
72
|
})
|
68
73
|
}
|
69
|
-
if (this.
|
70
|
-
const service = this.
|
74
|
+
if (this.servicesByServiceName.Motion?.length === 1) {
|
75
|
+
const service = this.servicesByServiceName.Motion[0]
|
71
76
|
params.motionDelegate = service.characteristicDelegate('motion')
|
72
77
|
params.lastMotionDelegate = service.addCharacteristicDelegate({
|
73
78
|
key: 'lastActivation',
|
@@ -75,34 +80,34 @@ class Sensor extends DeconzAccessory {
|
|
75
80
|
silent: true
|
76
81
|
})
|
77
82
|
}
|
78
|
-
if (this.
|
79
|
-
const service = this.
|
83
|
+
if (this.servicesByServiceName.LightLevel?.length === 1) {
|
84
|
+
const service = this.servicesByServiceName.LightLevel[0]
|
80
85
|
params.lightLevelDelegate = service.characteristicDelegate('lightLevel')
|
81
86
|
}
|
82
|
-
if (this.
|
83
|
-
const service = this.
|
87
|
+
if (this.servicesByServiceName.Daylight?.length === 1) {
|
88
|
+
const service = this.servicesByServiceName.Daylight[0]
|
84
89
|
params.lightLevelDelegate = service.characteristicDelegate('lightLevel')
|
85
90
|
}
|
86
|
-
if (this.
|
87
|
-
const service = this.
|
91
|
+
if (this.servicesByServiceName.Temperature?.length === 1) {
|
92
|
+
const service = this.servicesByServiceName.Temperature[0]
|
88
93
|
params.temperatureDelegate = service.characteristicDelegate('temperature')
|
89
94
|
}
|
90
|
-
if (this.
|
91
|
-
const service = this.
|
95
|
+
if (this.servicesByServiceName.Humidity?.length === 1) {
|
96
|
+
const service = this.servicesByServiceName.Humidity[0]
|
92
97
|
params.humidityDelegate = service.characteristicDelegate('humidity')
|
93
98
|
}
|
94
|
-
if (this.
|
95
|
-
const service = this.
|
99
|
+
if (this.servicesByServiceName.AirPressure?.length === 1) {
|
100
|
+
const service = this.servicesByServiceName.AirPressure[0]
|
96
101
|
params.airPressureDelegate = service.characteristicDelegate('airPressure')
|
97
102
|
}
|
98
|
-
if (this.
|
99
|
-
const service = this.
|
103
|
+
if (this.servicesByServiceName.AirQuality?.length === 1) {
|
104
|
+
const service = this.servicesByServiceName.AirQuality[0]
|
100
105
|
if (service.characteristicDelegate('vocDensity') != null) {
|
101
106
|
params.vocDensityDelegate = service.characteristicDelegate('vocDensity')
|
102
107
|
}
|
103
108
|
}
|
104
|
-
if (this.
|
105
|
-
const service = this.
|
109
|
+
if (this.servicesByServiceName.Flag != null) {
|
110
|
+
const service = this.servicesByServiceName.Flag[0]
|
106
111
|
params.switchOnDelegate = service.characteristicDelegate('on')
|
107
112
|
params.lastSwitchOnDelegate = service.addCharacteristicDelegate({
|
108
113
|
key: 'lastActivation',
|
@@ -19,7 +19,9 @@ const { SINGLE, DOUBLE, LONG } = DeconzService.Button
|
|
19
19
|
class DeconzAccessory extends AccessoryDelegate {
|
20
20
|
static get Light () { return require('./Light') }
|
21
21
|
static get Gateway () { return require('./Gateway') }
|
22
|
+
static get Outlet () { return DeconzAccessory.Light }
|
22
23
|
static get Sensor () { return require('./Sensor') }
|
24
|
+
static get Switch () { return DeconzAccessory.Light }
|
23
25
|
static get WarningDevice () { return require('./WarningDevice') }
|
24
26
|
static get WindowCovering () { return require('./WindowCovering') }
|
25
27
|
|
@@ -29,7 +31,6 @@ class DeconzAccessory extends AccessoryDelegate {
|
|
29
31
|
* @param {Accessory.Category} category - The HomeKit accessory category.
|
30
32
|
*/
|
31
33
|
constructor (gateway, device, category) {
|
32
|
-
// TODO device settings
|
33
34
|
super(gateway.platform, {
|
34
35
|
id: device.id,
|
35
36
|
name: device.resource.body.name,
|
@@ -44,7 +45,7 @@ class DeconzAccessory extends AccessoryDelegate {
|
|
44
45
|
|
45
46
|
this.serviceByRpath = {}
|
46
47
|
this.serviceBySubtype = {}
|
47
|
-
this.
|
48
|
+
this.servicesByServiceName = {}
|
48
49
|
|
49
50
|
/** The gateway.
|
50
51
|
* @type {DeconzAccessory.Gateway}
|
@@ -139,23 +140,28 @@ class DeconzAccessory extends AccessoryDelegate {
|
|
139
140
|
this.debug('%s: params: %j', resource.rpath, params)
|
140
141
|
|
141
142
|
let service
|
142
|
-
if (params.serviceName === '
|
143
|
-
service = this.
|
143
|
+
if (params.serviceName === 'AirQuality') {
|
144
|
+
service = this.servicesByServiceName.AirQuality?.[0]
|
145
|
+
if (service != null) {
|
146
|
+
service.addResource(resource)
|
147
|
+
}
|
148
|
+
} else if (params.serviceName === 'Battery') {
|
149
|
+
service = this.servicesByServiceName.Battery?.[0]
|
144
150
|
} else if (params.serviceName === 'Consumption') {
|
145
|
-
service = this.
|
146
|
-
this.
|
147
|
-
this.
|
151
|
+
service = this.servicesByServiceName.Outlet?.[0] ||
|
152
|
+
this.servicesByServiceName.Light?.[0] ||
|
153
|
+
this.servicesByServiceName.Power?.[0]
|
148
154
|
if (service != null) {
|
149
155
|
service.addResource(resource)
|
150
156
|
}
|
151
157
|
} else if (params.serviceName === 'Power') {
|
152
|
-
service = this.
|
153
|
-
this.
|
154
|
-
this.
|
158
|
+
service = this.servicesByServiceName.Outlet?.[0] ||
|
159
|
+
this.servicesByServiceName.Light?.[0] ||
|
160
|
+
this.servicesByServiceName.Consumption?.[0]
|
155
161
|
if (service != null) {
|
156
162
|
service.addResource(resource)
|
157
163
|
}
|
158
|
-
} else if (params.serviceName === '
|
164
|
+
} else if (params.serviceName === 'Label') {
|
159
165
|
// Default button
|
160
166
|
if (resource.capabilities.buttons == null) {
|
161
167
|
this.warn(
|
@@ -171,9 +177,9 @@ class DeconzAccessory extends AccessoryDelegate {
|
|
171
177
|
resource.capabilities.namespace =
|
172
178
|
this.Characteristics.hap.ServiceLabelNamespace.ARABIC_NUMERALS
|
173
179
|
}
|
174
|
-
service = this.
|
180
|
+
service = this.servicesByServiceName.Label?.[0]
|
175
181
|
if (service == null) {
|
176
|
-
service = new DeconzService.
|
182
|
+
service = new DeconzService.Label(this, resource, {
|
177
183
|
primaryService: params.primaryService
|
178
184
|
})
|
179
185
|
}
|
@@ -186,17 +192,16 @@ class DeconzAccessory extends AccessoryDelegate {
|
|
186
192
|
}
|
187
193
|
this.serviceBySubtype[resource.subtype] = service
|
188
194
|
this.serviceByRpath[resource.rpath] = service
|
189
|
-
if (this.
|
190
|
-
this.
|
195
|
+
if (this.servicesByServiceName[params.serviceName] == null) {
|
196
|
+
this.servicesByServiceName[params.serviceName] = [service]
|
197
|
+
} else {
|
198
|
+
this.servicesByServiceName[params.serviceName].push(service)
|
191
199
|
}
|
192
|
-
if (
|
193
|
-
|
194
|
-
|
195
|
-
) {
|
196
|
-
if (this.serviceByServiceName.Battery == null) {
|
197
|
-
this.serviceByServiceName.Battery = new DeconzService.Battery(this, resource)
|
200
|
+
if (resource.body.config?.battery !== undefined) {
|
201
|
+
if (this.servicesByServiceName.Battery?.[0] == null) {
|
202
|
+
this.servicesByServiceName.Battery = [new DeconzService.Battery(this, resource)]
|
198
203
|
}
|
199
|
-
service.batteryService = this.
|
204
|
+
service.batteryService = this.servicesByServiceName.Battery[0]
|
200
205
|
}
|
201
206
|
return service
|
202
207
|
}
|
@@ -232,12 +237,8 @@ class DeconzAccessory extends AccessoryDelegate {
|
|
232
237
|
multiClip: undefined,
|
233
238
|
multiLight: undefined,
|
234
239
|
logLevel: this.values.logLevel,
|
235
|
-
lowBatteryThreshold: this.
|
236
|
-
|
237
|
-
: this.serviceByServiceName.Battery.values.lowBatteryThreshold,
|
238
|
-
// offset: this.serviceByServiceName.Temperature == null
|
239
|
-
// ? undefined
|
240
|
-
// : this.serviceByServiceName.Temperature.values.offset,
|
240
|
+
lowBatteryThreshold: this.servicesByServiceName?.Battery?.[0].values.lowBatteryThreshold,
|
241
|
+
// offset: this.servicesByServiceName?.Temperature?.[0].values.offset,
|
241
242
|
serviceName: this.values.serviceName,
|
242
243
|
splitLight: undefined,
|
243
244
|
venetianBlind: this.service.values.venetianBlind,
|
@@ -285,21 +286,13 @@ class DeconzAccessory extends AccessoryDelegate {
|
|
285
286
|
responseBody[key] = value
|
286
287
|
continue
|
287
288
|
case 'lowBatteryThreshold':
|
288
|
-
if (this.
|
289
|
+
if (this.servicesByServiceName.Battery?.[0] != null) {
|
289
290
|
value = OptionParser.toInt(key, body[key], 10, 100)
|
290
|
-
this.
|
291
|
+
this.servicesByServiceName.Battery[0].values[key] = value
|
291
292
|
responseBody[key] = value
|
292
293
|
continue
|
293
294
|
}
|
294
295
|
break
|
295
|
-
// case 'offset': // TODO: doesn't work because of fromHomeKit
|
296
|
-
// if (this.serviceByServiceName.Temperature != null) {
|
297
|
-
// const value = OptionParser.toNumber(key, body[key], -5, 5)
|
298
|
-
// this.serviceByServiceName.Temperature.values[key] = value
|
299
|
-
// responseBody[key] = value
|
300
|
-
// continue
|
301
|
-
// }
|
302
|
-
// break
|
303
296
|
case 'serviceName':
|
304
297
|
if (this.values.serviceName != null) {
|
305
298
|
value = OptionParser.toString(key, body[key])
|
@@ -5,73 +5,104 @@
|
|
5
5
|
|
6
6
|
'use strict'
|
7
7
|
|
8
|
+
const Deconz = require('../Deconz')
|
8
9
|
const DeconzService = require('../DeconzService')
|
9
10
|
|
11
|
+
const { dateToString } = Deconz.ApiClient
|
12
|
+
|
10
13
|
/**
|
11
14
|
* @memberof DeconzService
|
12
15
|
*/
|
13
16
|
class AirQuality extends DeconzService.SensorsResource {
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
})
|
17
|
+
static addResource (service, resource) {
|
18
|
+
if (service.values.airQuality === undefined) {
|
19
|
+
service.addCharacteristicDelegate({
|
20
|
+
key: 'airQuality',
|
21
|
+
Characteristic: service.Characteristics.hap.AirQuality
|
22
|
+
})
|
23
|
+
}
|
22
24
|
|
23
25
|
if (resource.body.state.airqualityppb !== undefined) {
|
24
|
-
|
26
|
+
service.addCharacteristicDelegate({
|
25
27
|
key: 'vocDensity',
|
26
|
-
Characteristic:
|
28
|
+
Characteristic: service.Characteristics.hap.VOCDensity,
|
27
29
|
unit: ' µg/m³',
|
28
30
|
props: { minValue: 0, maxValue: 65535, minStep: 1 }
|
29
31
|
})
|
30
32
|
}
|
31
33
|
|
32
34
|
if (resource.body.state.pm2_5 !== undefined) {
|
33
|
-
|
34
|
-
key: '
|
35
|
-
Characteristic:
|
35
|
+
service.addCharacteristicDelegate({
|
36
|
+
key: 'pm25Density',
|
37
|
+
Characteristic: service.Characteristics.hap.PM2_5Density,
|
36
38
|
unit: ' µg/m³',
|
37
39
|
props: { minValue: 0, maxValue: 65535, minStep: 1 }
|
38
40
|
})
|
39
41
|
}
|
40
42
|
|
41
|
-
if (
|
42
|
-
|
43
|
+
if (service.values.lastUpdated === undefined) {
|
44
|
+
service.addCharacteristicDelegate({
|
45
|
+
key: 'lastUpdated',
|
46
|
+
Characteristic: service.Characteristics.my.LastUpdated,
|
47
|
+
silent: true
|
48
|
+
})
|
43
49
|
}
|
44
50
|
|
45
|
-
|
51
|
+
AirQuality.updateResourceState(service, resource.body.state)
|
46
52
|
}
|
47
53
|
|
48
|
-
airQualityValue (value) {
|
54
|
+
static airQualityValue (service, value) {
|
49
55
|
switch (value) {
|
50
56
|
case 'excellent':
|
51
|
-
return
|
57
|
+
return service.Characteristics.hap.AirQuality.EXCELLENT
|
52
58
|
case 'good':
|
53
|
-
return
|
59
|
+
return service.Characteristics.hap.AirQuality.GOOD
|
54
60
|
case 'moderate':
|
55
|
-
return
|
61
|
+
return service.Characteristics.hap.AirQuality.FAIR
|
56
62
|
case 'poor':
|
57
|
-
return
|
63
|
+
return service.Characteristics.hap.AirQuality.INFERIOR
|
58
64
|
case 'unhealthy':
|
59
|
-
return
|
65
|
+
return service.Characteristics.hap.AirQuality.POOR
|
60
66
|
default:
|
61
|
-
return
|
67
|
+
return service.Characteristics.hap.AirQuality.UNKNOWN
|
62
68
|
}
|
63
69
|
}
|
64
70
|
|
65
|
-
|
66
|
-
if (state.airquality != null) {
|
67
|
-
this.values.airQuality = this.airQualityValue(state.airquality)
|
68
|
-
}
|
71
|
+
static updateResourceState (service, state) {
|
69
72
|
if (state.airqualityppb != null) {
|
70
|
-
|
73
|
+
service.values.vocDensity = Math.round(state.airqualityppb * 4.57)
|
74
|
+
if (state.airquality != null) {
|
75
|
+
service.values.airQuality = AirQuality.airQualityValue(
|
76
|
+
service, state.airquality
|
77
|
+
)
|
78
|
+
}
|
71
79
|
}
|
72
80
|
if (state.pm2_5 != null) {
|
73
|
-
|
81
|
+
service.values.pm25Density = state.pm2_5
|
82
|
+
if (state.airquality != null && service.values.vocDensity === undefined) {
|
83
|
+
service.values.airQuality = AirQuality.airQualityValue(
|
84
|
+
service, state.airquality
|
85
|
+
)
|
86
|
+
}
|
87
|
+
}
|
88
|
+
if (state.lastupdated != null) {
|
89
|
+
service.values.lastUpdated = dateToString(state.lastupdated)
|
74
90
|
}
|
91
|
+
}
|
92
|
+
|
93
|
+
constructor (accessory, resource, params = {}) {
|
94
|
+
params.Service = accessory.Services.hap.AirQualitySensor
|
95
|
+
super(accessory, resource, params)
|
96
|
+
|
97
|
+
AirQuality.addResource(this, resource)
|
98
|
+
|
99
|
+
super.addCharacteristicDelegates({ noLastUpdated: true })
|
100
|
+
|
101
|
+
this.update(resource.body, resource.rpath)
|
102
|
+
}
|
103
|
+
|
104
|
+
updateState (state) {
|
105
|
+
AirQuality.updateResourceState(this, state)
|
75
106
|
super.updateState(state)
|
76
107
|
}
|
77
108
|
}
|
@@ -23,11 +23,11 @@ class Consumption extends DeconzService.SensorsResource {
|
|
23
23
|
|
24
24
|
if (
|
25
25
|
resource.body.state.power !== undefined &&
|
26
|
-
service.values.
|
26
|
+
service.values.consumption === undefined
|
27
27
|
) {
|
28
28
|
service.addCharacteristicDelegate({
|
29
|
-
key: '
|
30
|
-
Characteristic: service.Characteristics.eve.
|
29
|
+
key: 'consumption',
|
30
|
+
Characteristic: service.Characteristics.eve.Consumption,
|
31
31
|
unit: ' W'
|
32
32
|
})
|
33
33
|
}
|
@@ -40,7 +40,7 @@ class Consumption extends DeconzService.SensorsResource {
|
|
40
40
|
})
|
41
41
|
}
|
42
42
|
|
43
|
-
|
43
|
+
Consumption.updateResourceState(service, resource.body.state)
|
44
44
|
}
|
45
45
|
|
46
46
|
static updateResourceState (service, state) {
|
@@ -48,7 +48,7 @@ class Consumption extends DeconzService.SensorsResource {
|
|
48
48
|
service.values.totalConsumption = state.consumption / 1000
|
49
49
|
}
|
50
50
|
if (state.power != null) {
|
51
|
-
service.values.
|
51
|
+
service.values.consumption = state.power
|
52
52
|
}
|
53
53
|
if (state.lastupdated != null) {
|
54
54
|
service.values.lastUpdated = dateToString(state.lastupdated)
|
@@ -30,6 +30,9 @@ class Humidity extends DeconzService.SensorsResource {
|
|
30
30
|
if (state.humidity != null) {
|
31
31
|
this.values.humidity = Math.round(state.humidity / 10) / 10
|
32
32
|
}
|
33
|
+
if (state.moisture != null) {
|
34
|
+
this.values.humidity = Math.round(state.moisture / 10) / 10
|
35
|
+
}
|
33
36
|
super.updateState(state)
|
34
37
|
}
|
35
38
|
}
|