homebridge-deconz 0.0.15 → 0.0.18
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/README.md +1 -4
- package/cli/deconz.js +2 -2
- package/homebridge-ui/public/index.html +249 -460
- package/homebridge-ui/public/index.old.html +506 -0
- package/lib/Deconz/ApiClient.js +3 -4
- package/lib/Deconz/Discovery.js +7 -4
- package/lib/Deconz/Resource.js +20 -3
- package/lib/DeconzAccessory/AirPurifier.js +38 -0
- package/lib/DeconzAccessory/Gateway.js +44 -20
- package/lib/DeconzAccessory/Motion.js +3 -0
- package/lib/DeconzAccessory/index.js +3 -3
- package/lib/DeconzPlatform.js +13 -12
- package/lib/DeconzService/AirPurifier.js +216 -0
- package/lib/DeconzService/AirQuality.js +23 -7
- package/lib/DeconzService/Button.js +4 -0
- package/lib/DeconzService/Consumption.js +1 -1
- package/lib/DeconzService/Contact.js +2 -0
- package/lib/DeconzService/Light.js +9 -9
- package/lib/DeconzService/LightLevel.js +2 -0
- package/lib/DeconzService/Motion.js +1 -1
- package/lib/DeconzService/Outlet.js +1 -1
- package/lib/DeconzService/Power.js +1 -1
- package/lib/DeconzService/Switch.js +35 -23
- package/lib/DeconzService/Temperature.js +1 -0
- package/lib/DeconzService/Thermostat.js +1 -0
- package/lib/DeconzService/WindowCovering.js +1 -1
- package/lib/DeconzService/index.js +1 -0
- package/package.json +6 -6
@@ -44,6 +44,7 @@ class Gateway extends homebridgeLib.AccessoryDelegate {
|
|
44
44
|
|
45
45
|
this.gateway = this
|
46
46
|
this.id = params.config.bridgeid
|
47
|
+
this.recommendedSoftware = this.platform.packageJson.engines.deCONZ
|
47
48
|
|
48
49
|
/** Persisted properties.
|
49
50
|
* @type {Object}
|
@@ -53,15 +54,26 @@ class Gateway extends homebridgeLib.AccessoryDelegate {
|
|
53
54
|
* devices.
|
54
55
|
* @property {Object} fullState - The gateway's full state, from the
|
55
56
|
* last time the gateway was polled.
|
57
|
+
* @property {Object} settings - The persisted settings, maintained through
|
58
|
+
* the Homebridge UI.
|
56
59
|
*/
|
57
60
|
this.context // eslint-disable-line no-unused-expressions
|
58
61
|
this.context.host = params.host
|
59
62
|
this.context.config = params.config
|
60
|
-
if (this.context.
|
61
|
-
this.context.
|
63
|
+
if (this.context.settingsById == null) {
|
64
|
+
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
|
62
71
|
}
|
63
72
|
if (this.context.fullState != null) {
|
64
|
-
this.analyseFullState(this.context.fullState, {
|
73
|
+
this.analyseFullState(this.context.fullState, {
|
74
|
+
analyseOnly: true,
|
75
|
+
logUnsupported: true
|
76
|
+
})
|
65
77
|
}
|
66
78
|
|
67
79
|
this.addPropertyDelegate({
|
@@ -109,6 +121,9 @@ class Gateway extends homebridgeLib.AccessoryDelegate {
|
|
109
121
|
'%s %s gateway v%s', this.values.manufacturer, this.values.model,
|
110
122
|
this.values.software
|
111
123
|
)
|
124
|
+
if (this.values.software !== this.recommendedSoftware) {
|
125
|
+
this.warn('recommended version: deCONZ v%s', this.recommendedSoftware)
|
126
|
+
}
|
112
127
|
|
113
128
|
/** Map of Accessory delegates by id for the gateway.
|
114
129
|
* @type {Object<string, DeconzAccessory.Device>}
|
@@ -182,6 +197,9 @@ class Gateway extends homebridgeLib.AccessoryDelegate {
|
|
182
197
|
this.values.manufacturer, this.values.model, this.values.software,
|
183
198
|
this.nAccessories, this.nDevices, this.nResourcesMonitored
|
184
199
|
)
|
200
|
+
if (this.values.software !== this.recommendedSoftware) {
|
201
|
+
this.warn('recommended version: deCONZ v%s', this.recommendedSoftware)
|
202
|
+
}
|
185
203
|
if (this.context.migration != null) {
|
186
204
|
this.log(
|
187
205
|
'migration: %s: %d resources',
|
@@ -210,9 +228,9 @@ class Gateway extends homebridgeLib.AccessoryDelegate {
|
|
210
228
|
'%d accessories with expose errors: %j', exposeErrors.length,
|
211
229
|
exposeErrors
|
212
230
|
)
|
213
|
-
const
|
231
|
+
const settings = Object.keys(this.context.settingsById).sort()
|
214
232
|
this.vdebug(
|
215
|
-
'
|
233
|
+
'settings: %d devices: %j', settings.length, settings)
|
216
234
|
}
|
217
235
|
}
|
218
236
|
|
@@ -458,7 +476,14 @@ class Gateway extends homebridgeLib.AccessoryDelegate {
|
|
458
476
|
this.deleteService(id)
|
459
477
|
}
|
460
478
|
this.exposeErrors = {}
|
461
|
-
this.context.
|
479
|
+
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
|
+
}
|
462
487
|
this.context.fullState = null
|
463
488
|
this.context.migration = null
|
464
489
|
this.service.values.lights = false
|
@@ -487,11 +512,7 @@ class Gateway extends homebridgeLib.AccessoryDelegate {
|
|
487
512
|
if (this.deviceById[id] == null) {
|
488
513
|
throw new RangeError(`${id}: unknown device ID`)
|
489
514
|
}
|
490
|
-
|
491
|
-
delete this.context.blacklist[id]
|
492
|
-
} else {
|
493
|
-
this.context.blacklist[id] = true
|
494
|
-
}
|
515
|
+
this.context.settingsById[id].expose = expose
|
495
516
|
this.pollNext = true
|
496
517
|
}
|
497
518
|
|
@@ -607,7 +628,7 @@ class Gateway extends homebridgeLib.AccessoryDelegate {
|
|
607
628
|
name: body.name + ' Settings',
|
608
629
|
subtype: id,
|
609
630
|
resource: rpaths.join(', '),
|
610
|
-
expose: this.context.
|
631
|
+
expose: this.context.settingsById[id].expose
|
611
632
|
})
|
612
633
|
this.serviceById[id] = service
|
613
634
|
}
|
@@ -716,11 +737,11 @@ class Gateway extends homebridgeLib.AccessoryDelegate {
|
|
716
737
|
this.vdebug('polling done')
|
717
738
|
this.pollNext = false
|
718
739
|
this.polling = false
|
719
|
-
|
720
|
-
|
721
|
-
|
722
|
-
|
723
|
-
|
740
|
+
}
|
741
|
+
if (!this.initialised) {
|
742
|
+
this.initialised = true
|
743
|
+
this.debug('initialised')
|
744
|
+
this.emit('initialised')
|
724
745
|
}
|
725
746
|
}
|
726
747
|
|
@@ -756,7 +777,7 @@ class Gateway extends homebridgeLib.AccessoryDelegate {
|
|
756
777
|
* @param {Object} fullState - The gateway full state, as returned by
|
757
778
|
* {@link DeconzAccessory.Gateway#poll poll()}.
|
758
779
|
* @param {Object} params - Parameters
|
759
|
-
* @param {boolean} [params.
|
780
|
+
* @param {boolean} [params.logUnsupported=false] - Issue debug
|
760
781
|
* messsages for unsupported resources.
|
761
782
|
* @param {boolean} [params.analyseOnly=false]
|
762
783
|
*/
|
@@ -847,7 +868,7 @@ class Gateway extends homebridgeLib.AccessoryDelegate {
|
|
847
868
|
if (
|
848
869
|
this.deviceById[id] == null
|
849
870
|
) {
|
850
|
-
delete this.context.
|
871
|
+
delete this.context.settingsById[id]
|
851
872
|
this.deleteAccessory(id)
|
852
873
|
this.deleteService(id)
|
853
874
|
changed = true
|
@@ -881,7 +902,10 @@ class Gateway extends homebridgeLib.AccessoryDelegate {
|
|
881
902
|
for (const rid of rids) {
|
882
903
|
try {
|
883
904
|
const { id } = this.deviceByRidByRtype[rtype][rid]
|
884
|
-
if (this.context.
|
905
|
+
if (this.context.settingsById[id] == null) {
|
906
|
+
this.context.settingsById[id] = { expose: true }
|
907
|
+
}
|
908
|
+
if (this.context.settingsById[id].expose) {
|
885
909
|
if (this.accessoryById[id] == null) {
|
886
910
|
this.addAccessory(id)
|
887
911
|
changed = true
|
@@ -34,6 +34,9 @@ class Motion extends DeconzAccessory {
|
|
34
34
|
this, {},
|
35
35
|
this.service.characteristicDelegate('motion'),
|
36
36
|
this.service.characteristicDelegate('lastActivation'),
|
37
|
+
this.serviceByServiceName.LightLevel == null
|
38
|
+
? null
|
39
|
+
: this.serviceByServiceName.LightLevel.characteristicDelegate('lightlevel'),
|
37
40
|
this.serviceByServiceName.Temperature == null
|
38
41
|
? null
|
39
42
|
: this.serviceByServiceName.Temperature.characteristicDelegate('temperature')
|
@@ -39,7 +39,7 @@ class DeconzAccessory extends homebridgeLib.AccessoryDelegate {
|
|
39
39
|
manufacturer: device.resource.manufacturer,
|
40
40
|
model: device.resource.model,
|
41
41
|
firmware: device.resource.firmware,
|
42
|
-
category
|
42
|
+
category
|
43
43
|
})
|
44
44
|
|
45
45
|
this.context.gid = gateway.id
|
@@ -187,8 +187,8 @@ class DeconzAccessory extends homebridgeLib.AccessoryDelegate {
|
|
187
187
|
}
|
188
188
|
this.serviceBySubtype[resource.subtype] = service
|
189
189
|
this.serviceByRpath[resource.rpath] = service
|
190
|
-
if (this.serviceByServiceName[
|
191
|
-
this.serviceByServiceName[
|
190
|
+
if (this.serviceByServiceName[params.serviceName] == null) {
|
191
|
+
this.serviceByServiceName[params.serviceName] = service
|
192
192
|
}
|
193
193
|
if (
|
194
194
|
resource.body.config != null &&
|
package/lib/DeconzPlatform.js
CHANGED
@@ -70,13 +70,17 @@ class DeconzPlatform extends homebridgeLib.Platform {
|
|
70
70
|
})
|
71
71
|
this.discovery
|
72
72
|
.on('error', (error) => {
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
73
|
+
if (error instanceof homebridgeLib.HttpClient.HttpError) {
|
74
|
+
this.log(
|
75
|
+
'%s: request %d: %s %s', error.request.name,
|
76
|
+
error.request.id, error.request.method, error.request.resource
|
77
|
+
)
|
78
|
+
this.warn(
|
79
|
+
'%s: request %d: %s', error.request.name, error.request.id, error
|
80
|
+
)
|
81
|
+
return
|
82
|
+
}
|
83
|
+
this.warn(error)
|
80
84
|
})
|
81
85
|
.on('request', (request) => {
|
82
86
|
this.debug(
|
@@ -105,10 +109,7 @@ class DeconzPlatform extends homebridgeLib.Platform {
|
|
105
109
|
async foundGateway (host, config) {
|
106
110
|
const id = config.bridgeid
|
107
111
|
if (this.gatewayMap[id] == null) {
|
108
|
-
this.gatewayMap[id] = new DeconzAccessory.Gateway(this, {
|
109
|
-
config: config,
|
110
|
-
host: host
|
111
|
-
})
|
112
|
+
this.gatewayMap[id] = new DeconzAccessory.Gateway(this, { config, host })
|
112
113
|
}
|
113
114
|
await this.gatewayMap[id].found(host, config)
|
114
115
|
await events.once(this.gatewayMap[id], 'initialised')
|
@@ -190,7 +191,7 @@ class DeconzPlatform extends homebridgeLib.Platform {
|
|
190
191
|
gatewayByHost[gateway.context.host] = {
|
191
192
|
config: gateway.context.config,
|
192
193
|
host: gateway.context.host,
|
193
|
-
id
|
194
|
+
id
|
194
195
|
}
|
195
196
|
}
|
196
197
|
return {
|
@@ -0,0 +1,216 @@
|
|
1
|
+
// homebridge-deconz/lib/DeconzService/AirPurifier.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 FilterMaintenance extends DeconzService.SensorsResource {
|
11
|
+
constructor (accessory, resource, params = {}) {
|
12
|
+
params.Service = accessory.Services.hap.FilterMaintenance
|
13
|
+
super(accessory, resource, params)
|
14
|
+
|
15
|
+
this.addCharacteristicDelegate({
|
16
|
+
key: 'filterChange',
|
17
|
+
Characteristic: this.Characteristics.hap.FilterChangeIndication
|
18
|
+
})
|
19
|
+
|
20
|
+
if (
|
21
|
+
resource.body.config.filterlifetime !== undefined &&
|
22
|
+
resource.body.state.filterruntime !== undefined
|
23
|
+
) {
|
24
|
+
this.addCharacteristicDelegate({
|
25
|
+
key: 'filterLifeLevel',
|
26
|
+
Characteristic: this.Characteristics.hap.FilterLifeLevel,
|
27
|
+
unit: '%'
|
28
|
+
})
|
29
|
+
this.addCharacteristicDelegate({
|
30
|
+
key: 'resetFilter',
|
31
|
+
Characteristic: this.Characteristics.hap.ResetFilterIndication,
|
32
|
+
props: { adminOnlyAccess: [this.Characteristic.Access.WRITE] },
|
33
|
+
value: 0
|
34
|
+
}).on('didSet', async (value, fromHomeKit) => {
|
35
|
+
await this.put('/config', { filterlifetime: 6 * 30 * 24 * 60 })
|
36
|
+
})
|
37
|
+
this.values.filterLifeTime = resource.body.config.filterlifetime
|
38
|
+
}
|
39
|
+
|
40
|
+
this.update(resource.body)
|
41
|
+
}
|
42
|
+
|
43
|
+
updateState (state) {
|
44
|
+
if (this.values.filterLifeTime != null && state.filterruntime != null) {
|
45
|
+
this.values.filterLifeLevel = 100 - Math.round(
|
46
|
+
100 * state.filterruntime / this.values.filterLifeTime
|
47
|
+
)
|
48
|
+
}
|
49
|
+
if (state.replacefilter != null) {
|
50
|
+
this.values.filterChange = state.filterChange
|
51
|
+
? this.Characteristics.hap.FilterChangeIndication.CHANGE_FILTER
|
52
|
+
: this.Characteristics.hap.FilterChangeIndication.FILTER_OK
|
53
|
+
}
|
54
|
+
}
|
55
|
+
|
56
|
+
updateConfig (config) {
|
57
|
+
if (config.filterlifetime != null) {
|
58
|
+
this.values.filterLifeTime = config.filterlifetime
|
59
|
+
}
|
60
|
+
}
|
61
|
+
}
|
62
|
+
|
63
|
+
/**
|
64
|
+
* @memberof DeconzService
|
65
|
+
*/
|
66
|
+
class AirPurifier extends DeconzService.SensorsResource {
|
67
|
+
constructor (accessory, resource, params = {}) {
|
68
|
+
params.Service = accessory.Services.hap.AirPurifier
|
69
|
+
super(accessory, resource, params)
|
70
|
+
|
71
|
+
this.addCharacteristicDelegate({
|
72
|
+
key: 'active',
|
73
|
+
Characteristic: this.Characteristics.hap.Active
|
74
|
+
}).on('didSet', async (value, fromHomeKit) => {
|
75
|
+
if (fromHomeKit) {
|
76
|
+
await this.put('/config', { mode: this.modeValue(value) })
|
77
|
+
}
|
78
|
+
})
|
79
|
+
|
80
|
+
this.addCharacteristicDelegate({
|
81
|
+
key: 'currentState',
|
82
|
+
Characteristic: this.Characteristics.hap.CurrentAirPurifierState
|
83
|
+
})
|
84
|
+
|
85
|
+
this.addCharacteristicDelegate({
|
86
|
+
key: 'targetState',
|
87
|
+
Characteristic: this.Characteristics.hap.TargetAirPurifierState
|
88
|
+
}).on('didSet', async (value, fromHomeKit) => {
|
89
|
+
if (fromHomeKit) {
|
90
|
+
await this.put('/config', { mode: this.modeValue(null, value) })
|
91
|
+
}
|
92
|
+
})
|
93
|
+
|
94
|
+
this.addCharacteristicDelegate({
|
95
|
+
key: 'rotationSpeed',
|
96
|
+
Characteristic: this.Characteristics.hap.RotationSpeed,
|
97
|
+
unit: '%'
|
98
|
+
}).on('didSet', async (value, fromHomeKit) => {
|
99
|
+
if (fromHomeKit) {
|
100
|
+
await this.put('/config', { mode: this.modeValue(null, null, value) })
|
101
|
+
}
|
102
|
+
})
|
103
|
+
|
104
|
+
if (resource.body.state.airquality !== undefined) {
|
105
|
+
this.airQualityService = new DeconzService.AirQuality(accessory, resource, {
|
106
|
+
linkedServiceDelegate: this
|
107
|
+
})
|
108
|
+
}
|
109
|
+
|
110
|
+
if (resource.body.state.replacefilter !== undefined) {
|
111
|
+
this.filterService = new FilterMaintenance(accessory, resource, {
|
112
|
+
linkedServiceDelegate: this
|
113
|
+
})
|
114
|
+
}
|
115
|
+
|
116
|
+
if (resource.body.state.deviceruntime !== undefined) {
|
117
|
+
// TODO
|
118
|
+
}
|
119
|
+
|
120
|
+
if (resource.body.config.ledindication !== undefined) {
|
121
|
+
// TODO
|
122
|
+
}
|
123
|
+
|
124
|
+
if (resource.body.config.locked !== undefined) {
|
125
|
+
this.addCharacteristicDelegate({
|
126
|
+
key: 'lockPhysicalControls',
|
127
|
+
Characteristic: this.Characteristics.hap.LockPhysicalControls
|
128
|
+
}).on('didSet', async (value, fromHomeKit) => {
|
129
|
+
if (fromHomeKit) {
|
130
|
+
await this.put('/config', {
|
131
|
+
locked: value === this.Characteristics.hap.LockPhysicalControls
|
132
|
+
.CONTROL_LOCK_ENABLED
|
133
|
+
})
|
134
|
+
}
|
135
|
+
})
|
136
|
+
}
|
137
|
+
|
138
|
+
super.addCharacteristicDelegates()
|
139
|
+
|
140
|
+
this.update(resource.body)
|
141
|
+
}
|
142
|
+
|
143
|
+
modeValue (
|
144
|
+
active = this.values.active,
|
145
|
+
targetState = this.values.targetState,
|
146
|
+
rotationSpeed = this.values.rotationSpeed
|
147
|
+
) {
|
148
|
+
if (active === this.Characteristics.hap.Active.INACTIVE) {
|
149
|
+
return 'off'
|
150
|
+
}
|
151
|
+
if (
|
152
|
+
targetState === this.Characteristics.hap.TargetAirPurifierState.AUTO ||
|
153
|
+
rotationSpeed === 0
|
154
|
+
) {
|
155
|
+
return 'auto'
|
156
|
+
}
|
157
|
+
return 'speed_' + Math.round(rotationSpeed / 20)
|
158
|
+
}
|
159
|
+
|
160
|
+
updateState (state) {
|
161
|
+
if (this.values.filterLifeTime != null && state.filterruntime != null) {
|
162
|
+
this.values.filterLifeLevel = 100 - Math.round(
|
163
|
+
100 * state.filterruntime / this.values.filterLifeTime
|
164
|
+
)
|
165
|
+
}
|
166
|
+
if (state.replacefilter != null) {
|
167
|
+
this.values.filterChange = state.replacefilter
|
168
|
+
? this.Characteristics.hap.FilterChangeIndication.CHANGE_FILTER
|
169
|
+
: this.Characteristics.hap.FilterChangeIndication.FILTER_OK
|
170
|
+
}
|
171
|
+
if (state.speed != null) {
|
172
|
+
this.values.active = state.speed > 0
|
173
|
+
? this.Characteristics.hap.Active.ACTIVE
|
174
|
+
: this.Characteristics.hap.Active.INACTIVE
|
175
|
+
this.values.currentState = state.speed === 0
|
176
|
+
? this.Characteristics.hap.CurrentAirPurifierState.INACTIVE
|
177
|
+
: this.Characteristics.hap.CurrentAirPurifierState.PURIFYING_AIR
|
178
|
+
this.values.rotationSpeed = state.speed
|
179
|
+
}
|
180
|
+
super.updateState(state)
|
181
|
+
if (this.airQualityService != null) {
|
182
|
+
this.airQualityService.updateState(state)
|
183
|
+
}
|
184
|
+
if (this.filterService != null) {
|
185
|
+
this.filterService.updateState(state)
|
186
|
+
}
|
187
|
+
}
|
188
|
+
|
189
|
+
updateConfig (config) {
|
190
|
+
if (config.filterlifetime != null) {
|
191
|
+
this.values.filterLifeTime = config.filterlifetime
|
192
|
+
}
|
193
|
+
if (config.ledindication != null) {
|
194
|
+
// TODO
|
195
|
+
}
|
196
|
+
if (config.locked != null) {
|
197
|
+
this.values.lockPhysicalControls = config.locked
|
198
|
+
? this.Characteristics.hap.LockPhysicalControls.CONTROL_LOCK_ENABLED
|
199
|
+
: this.Characteristics.hap.LockPhysicalControls.CONTROL_LOCK_DISABLED
|
200
|
+
}
|
201
|
+
if (config.mode != null) {
|
202
|
+
this.values.targetState = config.mode === 'auto'
|
203
|
+
? this.Characteristics.hap.TargetAirPurifierState.AUTO
|
204
|
+
: this.Characteristics.hap.TargetAirPurifierState.MANUAL
|
205
|
+
}
|
206
|
+
super.updateConfig(config)
|
207
|
+
if (this.airQualityService != null) {
|
208
|
+
this.airQualityService.updateConfig(config)
|
209
|
+
}
|
210
|
+
if (this.filterService != null) {
|
211
|
+
this.filterService.updateConfig(config)
|
212
|
+
}
|
213
|
+
}
|
214
|
+
}
|
215
|
+
|
216
|
+
module.exports = AirPurifier
|
@@ -20,14 +20,27 @@ class AirQuality extends DeconzService.SensorsResource {
|
|
20
20
|
Characteristic: this.Characteristics.hap.AirQuality
|
21
21
|
})
|
22
22
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
23
|
+
if (resource.body.state.airqualityppb !== undefined) {
|
24
|
+
this.addCharacteristicDelegate({
|
25
|
+
key: 'vocDensity',
|
26
|
+
Characteristic: this.Characteristics.hap.VOCDensity,
|
27
|
+
unit: ' µg/m³',
|
28
|
+
props: { minValue: 0, maxValue: 65535, minStep: 1 }
|
29
|
+
})
|
30
|
+
}
|
29
31
|
|
30
|
-
|
32
|
+
if (resource.body.state.pm2_5 !== undefined) {
|
33
|
+
this.addCharacteristicDelegate({
|
34
|
+
key: 'pm2_5Density',
|
35
|
+
Characteristic: this.Characteristics.hap.PM2_5Density,
|
36
|
+
unit: ' µg/m³',
|
37
|
+
props: { minValue: 0, maxValue: 65535, minStep: 1 }
|
38
|
+
})
|
39
|
+
}
|
40
|
+
|
41
|
+
if (params.linkedServiceDelegate == null) {
|
42
|
+
super.addCharacteristicDelegates()
|
43
|
+
}
|
31
44
|
|
32
45
|
this.update(resource.body)
|
33
46
|
}
|
@@ -56,6 +69,9 @@ class AirQuality extends DeconzService.SensorsResource {
|
|
56
69
|
if (state.airqualityppb != null) {
|
57
70
|
this.values.vocDensity = Math.round(state.airqualityppb * 4.57)
|
58
71
|
}
|
72
|
+
if (state.pm2_5 != null) {
|
73
|
+
this.values.pm2_5Density = state.pm2_5
|
74
|
+
}
|
59
75
|
super.updateState(state)
|
60
76
|
}
|
61
77
|
}
|
@@ -51,7 +51,7 @@ class Light extends DeconzService.LightsResource {
|
|
51
51
|
}).on('didSet', (value, fromHomeKit) => {
|
52
52
|
if (fromHomeKit) {
|
53
53
|
const bri = Math.round(value * 2.54)
|
54
|
-
this.put({ bri
|
54
|
+
this.put({ bri })
|
55
55
|
this.updateAdaptiveLighting()
|
56
56
|
}
|
57
57
|
})
|
@@ -97,7 +97,7 @@ class Light extends DeconzService.LightsResource {
|
|
97
97
|
this.capabilities.ctMin, Math.min(value, this.capabilities.ctMax)
|
98
98
|
)
|
99
99
|
if (fromHomeKit) {
|
100
|
-
this.put({ ct
|
100
|
+
this.put({ ct })
|
101
101
|
this.values.colormode = 'ct'
|
102
102
|
}
|
103
103
|
if (this.capabilities.xy && this.values.colormode === 'ct') {
|
@@ -118,7 +118,7 @@ class Light extends DeconzService.LightsResource {
|
|
118
118
|
const xy = hsvToXy(
|
119
119
|
value, this.values.saturation, this.capabilities.gamut
|
120
120
|
)
|
121
|
-
this.put({ xy
|
121
|
+
this.put({ xy })
|
122
122
|
this.values.colormode = 'xy'
|
123
123
|
}
|
124
124
|
})
|
@@ -129,7 +129,7 @@ class Light extends DeconzService.LightsResource {
|
|
129
129
|
}).on('didSet', (value, fromHomeKit) => {
|
130
130
|
if (fromHomeKit) {
|
131
131
|
const xy = hsvToXy(this.values.hue, value, this.capabilities.gamut)
|
132
|
-
this.put({ xy
|
132
|
+
this.put({ xy })
|
133
133
|
this.values.colormode = 'xy'
|
134
134
|
}
|
135
135
|
})
|
@@ -141,7 +141,7 @@ class Light extends DeconzService.LightsResource {
|
|
141
141
|
}).on('didSet', (value, fromHomeKit) => {
|
142
142
|
if (fromHomeKit) {
|
143
143
|
const hue = Math.round(this.values.hue * 65535.0 / 360.0)
|
144
|
-
this.put({ hue
|
144
|
+
this.put({ hue })
|
145
145
|
this.values.colormode = 'hs'
|
146
146
|
}
|
147
147
|
})
|
@@ -152,7 +152,7 @@ class Light extends DeconzService.LightsResource {
|
|
152
152
|
}).on('didSet', (value, fromHomeKit) => {
|
153
153
|
if (fromHomeKit) {
|
154
154
|
const sat = Math.round(this.values.saturation * 254.0 / 100.0)
|
155
|
-
this.put({ sat
|
155
|
+
this.put({ sat })
|
156
156
|
this.values.colormode = 'hs'
|
157
157
|
}
|
158
158
|
})
|
@@ -165,7 +165,7 @@ class Light extends DeconzService.LightsResource {
|
|
165
165
|
}).on('didSet', (value, fromHomeKit) => {
|
166
166
|
if (fromHomeKit) {
|
167
167
|
const effect = value ? 'colorloop' : 'none'
|
168
|
-
const state = { effect
|
168
|
+
const state = { effect }
|
169
169
|
if (value) {
|
170
170
|
state.colorloopspeed = this.values.colorLoopSpeed
|
171
171
|
}
|
@@ -181,7 +181,7 @@ class Light extends DeconzService.LightsResource {
|
|
181
181
|
}).on('didSet', (value, fromHomeKit) => {
|
182
182
|
if (fromHomeKit) {
|
183
183
|
const effect = 'colorloop'
|
184
|
-
this.put({ effect
|
184
|
+
this.put({ effect, colorloopspeed: value })
|
185
185
|
this.values.colormode = 'hs'
|
186
186
|
}
|
187
187
|
})
|
@@ -467,7 +467,7 @@ class Light extends DeconzService.LightsResource {
|
|
467
467
|
if (this.values.colormode === 'ct' && ct === this.values.colorTemperature) {
|
468
468
|
return
|
469
469
|
}
|
470
|
-
this.put({ ct
|
470
|
+
this.put({ ct })
|
471
471
|
this.fromAdaptiveLighting = true
|
472
472
|
this.values.colormode = 'ct'
|
473
473
|
if (ct !== this.values.colorTemperature) {
|
@@ -35,7 +35,7 @@ class Motion extends DeconzService.SensorsResource {
|
|
35
35
|
: value === this.Characteristics.eve.Sensitivity.LOW
|
36
36
|
? 0
|
37
37
|
: Math.round(this.sensitivitymax / 2)
|
38
|
-
await this.put('/config', { sensitivity
|
38
|
+
await this.put('/config', { sensitivity })
|
39
39
|
}
|
40
40
|
})
|
41
41
|
|
@@ -39,7 +39,7 @@ class Outlet extends DeconzService.LightsResource {
|
|
39
39
|
this.addCharacteristicDelegate({
|
40
40
|
key: 'outletInUse',
|
41
41
|
Characteristic: this.Characteristics.hap.OutletInUse,
|
42
|
-
value: 1
|
42
|
+
value: 1 // Eve interpretes OutletInUse as: device is physically plugged in.
|
43
43
|
})
|
44
44
|
|
45
45
|
this.addCharacteristicDelegates()
|