homebridge-deconz 0.0.9 → 0.0.12
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 +3 -6
- package/cli/deconz.js +12 -0
- package/config.schema.json +2 -1
- package/homebridge-ui/public/index.html +26 -0
- package/homebridge-ui/public/style.css +0 -0
- package/homebridge-ui/server.js +43 -0
- package/lib/Deconz/ApiClient.js +34 -1
- package/lib/Deconz/ApiResponse.js +1 -1
- package/lib/Deconz/Device.js +0 -7
- package/lib/Deconz/Resource.js +752 -27
- package/lib/DeconzAccessory/Contact.js +54 -0
- package/lib/DeconzAccessory/Gateway.js +102 -66
- package/lib/DeconzAccessory/Light.js +42 -35
- package/lib/DeconzAccessory/Motion.js +51 -0
- package/lib/DeconzAccessory/Sensor.js +35 -0
- package/lib/DeconzAccessory/Temperature.js +63 -0
- package/lib/DeconzAccessory/Thermostat.js +50 -0
- package/lib/DeconzAccessory/WarningDevice.js +56 -0
- package/lib/DeconzAccessory/WindowCovering.js +47 -0
- package/lib/DeconzAccessory/index.js +145 -4
- package/lib/DeconzPlatform.js +6 -3
- package/lib/DeconzService/AirPressure.js +43 -0
- package/lib/DeconzService/AirQuality.js +20 -11
- package/lib/DeconzService/Alarm.js +13 -9
- package/lib/DeconzService/Battery.js +53 -0
- package/lib/DeconzService/Button.js +9 -2
- package/lib/DeconzService/CarbonMonoxide.js +38 -0
- package/lib/DeconzService/Consumption.js +65 -0
- package/lib/DeconzService/Contact.js +60 -0
- package/lib/DeconzService/Daylight.js +132 -0
- package/lib/DeconzService/DeviceSettings.js +12 -4
- package/lib/DeconzService/Flag.js +52 -0
- package/lib/DeconzService/GatewaySettings.js +1 -4
- package/lib/DeconzService/Humidity.js +37 -0
- package/lib/DeconzService/Leak.js +38 -0
- package/lib/DeconzService/Light.js +289 -280
- package/lib/DeconzService/LightLevel.js +54 -0
- package/lib/DeconzService/LightsResource.js +112 -0
- package/lib/DeconzService/Motion.js +101 -0
- package/lib/DeconzService/Outlet.js +76 -0
- package/lib/DeconzService/Power.js +83 -0
- package/lib/DeconzService/SensorsResource.js +96 -0
- package/lib/DeconzService/Smoke.js +38 -0
- package/lib/DeconzService/Status.js +53 -0
- package/lib/DeconzService/Switch.js +93 -0
- package/lib/DeconzService/Temperature.js +63 -0
- package/lib/DeconzService/Thermostat.js +175 -0
- package/lib/DeconzService/WarningDevice.js +68 -0
- package/lib/DeconzService/WindowCovering.js +139 -0
- package/lib/DeconzService/index.js +79 -25
- package/package.json +6 -5
- package/lib/Client/ApiError.js +0 -42
- package/lib/DeconzAccessory/Device.js +0 -69
- package/lib/DeconzService/Sensor.js +0 -61
@@ -1,4 +1,4 @@
|
|
1
|
-
// homebridge-deconz/lib/DeconzService/
|
1
|
+
// homebridge-deconz/lib/DeconzService/Light.js
|
2
2
|
// Copyright © 2022 Erik Baauw. All rights reserved.
|
3
3
|
//
|
4
4
|
// Homebridge plugin for deCONZ.
|
@@ -6,54 +6,39 @@
|
|
6
6
|
'use strict'
|
7
7
|
|
8
8
|
const homebridgeLib = require('homebridge-lib')
|
9
|
-
const
|
9
|
+
const DeconzService = require('../DeconzService')
|
10
10
|
|
11
|
-
const { dateToString } = Deconz.ApiClient
|
12
11
|
const { timeout } = homebridgeLib
|
13
12
|
const { xyToHsv, hsvToXy, ctToXy } = homebridgeLib.Colour
|
14
13
|
|
15
|
-
class Light extends
|
16
|
-
constructor (accessory, resource) {
|
17
|
-
|
18
|
-
|
19
|
-
name: resource.body.name,
|
20
|
-
subtype: resource.subtype,
|
21
|
-
Service: accessory.Services.hap.Lightbulb
|
22
|
-
})
|
23
|
-
this.id = resource.id
|
24
|
-
this.gateway = accessory.gateway
|
25
|
-
this.client = accessory.client
|
26
|
-
this.resource = resource
|
27
|
-
this.rtype = resource.rtype
|
28
|
-
this.rid = resource.rid
|
29
|
-
this.rpath = resource.rpath +
|
30
|
-
(resource.rtype === 'groups' ? '/action' : '/state')
|
31
|
-
this.capabilities = resource.capabilities
|
32
|
-
|
33
|
-
this.debug('%s: capabilities: %j', this.resource.rpath, this.capabilities)
|
34
|
-
|
35
|
-
this.targetState = {}
|
36
|
-
this.deferrals = []
|
14
|
+
class Light extends DeconzService.LightsResource {
|
15
|
+
constructor (accessory, resource, params = {}) {
|
16
|
+
params.Service = accessory.Services.hap.Lightbulb
|
17
|
+
super(accessory, resource, params)
|
37
18
|
|
38
19
|
this.addCharacteristicDelegate({
|
39
20
|
key: 'on',
|
40
21
|
Characteristic: this.Characteristics.hap.On,
|
41
22
|
value: this.capabilities.on
|
42
23
|
? this.resource.body.state.on
|
43
|
-
: this.resource.body.state.all_on
|
44
|
-
|
45
|
-
|
46
|
-
|
24
|
+
: this.resource.body.state.all_on
|
25
|
+
}).on('didSet', (value, fromHomeKit) => {
|
26
|
+
if (fromHomeKit) {
|
27
|
+
this.put({ on: value })
|
28
|
+
this.updateAdaptiveLighting()
|
29
|
+
}
|
47
30
|
})
|
48
31
|
|
49
32
|
if (!this.capabilities.on) {
|
50
33
|
this.addCharacteristicDelegate({
|
51
34
|
key: 'anyOn',
|
52
35
|
Characteristic: this.Characteristics.my.AnyOn,
|
53
|
-
value: this.resource.body.state.any_on
|
54
|
-
|
55
|
-
|
56
|
-
|
36
|
+
value: this.resource.body.state.any_on
|
37
|
+
}).on('didSet', (value, fromHomeKit) => {
|
38
|
+
if (fromHomeKit) {
|
39
|
+
this.put({ on: value })
|
40
|
+
this.updateAdaptiveLighting()
|
41
|
+
}
|
57
42
|
})
|
58
43
|
}
|
59
44
|
|
@@ -62,23 +47,21 @@ class Light extends homebridgeLib.ServiceDelegate {
|
|
62
47
|
key: 'brightness',
|
63
48
|
Characteristic: this.Characteristics.hap.Brightness,
|
64
49
|
unit: '%',
|
65
|
-
value: this.resource.body.state.bri
|
66
|
-
|
67
|
-
|
68
|
-
|
50
|
+
value: Math.round(this.resource.body.state.bri / 2.54)
|
51
|
+
}).on('didSet', (value, fromHomeKit) => {
|
52
|
+
if (fromHomeKit) {
|
53
|
+
const bri = Math.round(value * 2.54)
|
54
|
+
this.put({ bri: bri })
|
55
|
+
this.updateAdaptiveLighting()
|
69
56
|
}
|
70
|
-
}).on('didSet', (value, fromHomekit) => {
|
71
|
-
this.checkAdaptiveLighting()
|
72
57
|
})
|
73
58
|
|
74
59
|
this.addCharacteristicDelegate({
|
75
60
|
key: 'brightnessChange',
|
76
61
|
Characteristic: this.Characteristics.my.BrightnessChange,
|
77
|
-
value: 0
|
78
|
-
|
79
|
-
|
80
|
-
}
|
81
|
-
}).on('didSet', async () => {
|
62
|
+
value: 0
|
63
|
+
}).on('didSet', async (value) => {
|
64
|
+
this.put({ bri_inc: Math.round(value * 254.0 / 100.0) })
|
82
65
|
await timeout(this.platform.config.waitTimeReset)
|
83
66
|
this.values.brightnessChange = 0
|
84
67
|
})
|
@@ -88,7 +71,13 @@ class Light extends homebridgeLib.ServiceDelegate {
|
|
88
71
|
if (this.capabilities.ct || this.capabilities.xy || this.capabilities.hs) {
|
89
72
|
this.addCharacteristicDelegate({
|
90
73
|
key: 'colormode',
|
91
|
-
value: this.resource.body.state.colormode
|
74
|
+
value: this.resource.body.state.colormode,
|
75
|
+
silent: true
|
76
|
+
}).on('didSet', (value) => {
|
77
|
+
this.resource.body.colormode = value
|
78
|
+
if (value !== 'ct') {
|
79
|
+
this.checkAdaptiveLighting()
|
80
|
+
}
|
92
81
|
})
|
93
82
|
}
|
94
83
|
|
@@ -101,118 +90,70 @@ class Light extends homebridgeLib.ServiceDelegate {
|
|
101
90
|
minValue: this.capabilities.ctMin,
|
102
91
|
maxValue: this.capabilities.ctMax
|
103
92
|
},
|
104
|
-
value: this.resource.body.state.ct
|
105
|
-
setter: async (value) => {
|
106
|
-
const ct = Math.max(
|
107
|
-
this.capabilities.ctMin, Math.min(value, this.capabilities.ctMax)
|
108
|
-
)
|
109
|
-
return this.put({ ct: ct })
|
110
|
-
}
|
93
|
+
value: this.resource.body.state.ct
|
111
94
|
}).on('didSet', (value, fromHomeKit) => {
|
95
|
+
this.checkAdaptiveLighting()
|
96
|
+
const ct = Math.max(
|
97
|
+
this.capabilities.ctMin, Math.min(value, this.capabilities.ctMax)
|
98
|
+
)
|
112
99
|
if (fromHomeKit) {
|
113
|
-
this.
|
100
|
+
this.put({ ct: ct })
|
101
|
+
this.values.colormode = 'ct'
|
114
102
|
}
|
115
|
-
if (
|
116
|
-
|
117
|
-
this.values.colormode === 'ct'
|
118
|
-
) {
|
119
|
-
const { h, s } = xyToHsv(ctToXy(value), this.capabilities.gamut)
|
103
|
+
if (this.capabilities.xy && this.values.colormode === 'ct') {
|
104
|
+
const { h, s } = xyToHsv(ctToXy(ct), this.capabilities.gamut)
|
120
105
|
this.values.hue = h
|
121
106
|
this.values.saturation = s
|
122
107
|
}
|
123
108
|
})
|
124
|
-
|
125
|
-
if (this.capabilities.bri) {
|
126
|
-
this.addCharacteristicDelegate({
|
127
|
-
key: 'supportedTransitionConfiguration',
|
128
|
-
Characteristic: this.Characteristics.hap
|
129
|
-
.SupportedCharacteristicValueTransitionConfiguration,
|
130
|
-
silent: true
|
131
|
-
})
|
132
|
-
this.addCharacteristicDelegate({
|
133
|
-
key: 'transitionControl',
|
134
|
-
Characteristic: this.Characteristics.hap
|
135
|
-
.CharacteristicValueTransitionControl,
|
136
|
-
silent: true,
|
137
|
-
getter: async () => {
|
138
|
-
await this.initAdaptiveLighting()
|
139
|
-
return this.adaptiveLighting.generateControl()
|
140
|
-
},
|
141
|
-
setter: async (value) => {
|
142
|
-
await this.initAdaptiveLighting()
|
143
|
-
this.adaptiveLighting.parseControl(value)
|
144
|
-
const response = this.adaptiveLighting.generateControlResponse()
|
145
|
-
this.values.activeTransitionCount = 1
|
146
|
-
return response
|
147
|
-
}
|
148
|
-
})
|
149
|
-
this.addCharacteristicDelegate({
|
150
|
-
key: 'activeTransitionCount',
|
151
|
-
Characteristic: this.Characteristics.hap
|
152
|
-
.CharacteristicValueActiveTransitionCount,
|
153
|
-
value: 0
|
154
|
-
}).on('didSet', (value) => {
|
155
|
-
if (!value) {
|
156
|
-
this.adaptiveLighting.deactivate()
|
157
|
-
} else {
|
158
|
-
this.checkAdaptiveLighting()
|
159
|
-
}
|
160
|
-
})
|
161
|
-
}
|
162
109
|
}
|
163
110
|
|
164
111
|
if (this.capabilities.xy) {
|
165
112
|
this.addCharacteristicDelegate({
|
166
113
|
key: 'hue',
|
167
114
|
Characteristic: this.Characteristics.hap.Hue,
|
168
|
-
unit: '°'
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
this.values.
|
115
|
+
unit: '°'
|
116
|
+
}).on('didSet', (value, fromHomeKit) => {
|
117
|
+
if (fromHomeKit) {
|
118
|
+
const xy = hsvToXy(
|
119
|
+
value, this.values.saturation, this.capabilities.gamut
|
120
|
+
)
|
121
|
+
this.put({ xy: xy })
|
122
|
+
this.values.colormode = 'xy'
|
176
123
|
}
|
177
124
|
})
|
178
125
|
this.addCharacteristicDelegate({
|
179
126
|
key: 'saturation',
|
180
127
|
Characteristic: this.Characteristics.hap.Saturation,
|
181
|
-
unit: '%'
|
182
|
-
|
128
|
+
unit: '%'
|
129
|
+
}).on('didSet', (value, fromHomeKit) => {
|
130
|
+
if (fromHomeKit) {
|
183
131
|
const xy = hsvToXy(this.values.hue, value, this.capabilities.gamut)
|
184
|
-
|
185
|
-
|
186
|
-
}).on('didSet', (value, fromHomekit) => {
|
187
|
-
if (fromHomekit) {
|
188
|
-
this.values.activeTransitionCount = 0
|
132
|
+
this.put({ xy: xy })
|
133
|
+
this.values.colormode = 'xy'
|
189
134
|
}
|
190
135
|
})
|
191
136
|
} else if (this.capabilities.hs) {
|
192
137
|
this.addCharacteristicDelegate({
|
193
138
|
key: 'hue',
|
194
139
|
Characteristic: this.Characteristics.hap.Hue,
|
195
|
-
unit: '°'
|
196
|
-
|
140
|
+
unit: '°'
|
141
|
+
}).on('didSet', (value, fromHomeKit) => {
|
142
|
+
if (fromHomeKit) {
|
197
143
|
const hue = Math.round(this.hk.hue * 65535.0 / 360.0)
|
198
|
-
|
199
|
-
|
200
|
-
}).on('didSet', (value, fromHomekit) => {
|
201
|
-
if (fromHomekit) {
|
202
|
-
this.values.activeTransitionCount = 0
|
144
|
+
this.put({ hue: hue })
|
145
|
+
this.values.colormode = 'hs'
|
203
146
|
}
|
204
147
|
})
|
205
148
|
this.addCharacteristicDelegate({
|
206
149
|
key: 'saturation',
|
207
150
|
Characteristic: this.Characteristics.hap.Saturation,
|
208
|
-
unit: '%'
|
209
|
-
|
151
|
+
unit: '%'
|
152
|
+
}).on('didSet', (value, fromHomeKit) => {
|
153
|
+
if (fromHomeKit) {
|
210
154
|
const sat = Math.round(this.hk.sat * 254.0 / 100.0)
|
211
|
-
|
212
|
-
|
213
|
-
}).on('didSet', (value, fromHomekit) => {
|
214
|
-
if (fromHomekit) {
|
215
|
-
this.values.activeTransitionCount = 0
|
155
|
+
this.put({ sat: sat })
|
156
|
+
this.values.colormode = 'hs'
|
216
157
|
}
|
217
158
|
})
|
218
159
|
}
|
@@ -220,36 +161,180 @@ class Light extends homebridgeLib.ServiceDelegate {
|
|
220
161
|
if (this.capabilities.colorLoop) {
|
221
162
|
this.addCharacteristicDelegate({
|
222
163
|
key: 'colorLoop',
|
223
|
-
Characteristic: this.Characteristics.my.ColorLoop
|
224
|
-
|
164
|
+
Characteristic: this.Characteristics.my.ColorLoop
|
165
|
+
}).on('didSet', (value, fromHomeKit) => {
|
166
|
+
if (fromHomeKit) {
|
225
167
|
const effect = value ? 'colorloop' : 'none'
|
226
168
|
const state = { effect: effect }
|
227
169
|
if (value) {
|
228
170
|
state.colorloopspeed = this.values.colorLoopSpeed
|
229
171
|
}
|
230
|
-
|
172
|
+
this.put(state)
|
173
|
+
this.values.colormode = 'hs'
|
231
174
|
}
|
232
175
|
})
|
233
176
|
this.addCharacteristicDelegate({
|
234
177
|
key: 'colorLoopSpeed',
|
235
178
|
Characteristic: this.Characteristics.my.ColorLoopSpeed,
|
236
179
|
unit: 's',
|
237
|
-
value: 25
|
180
|
+
value: 25
|
181
|
+
}).on('didSet', (value, fromHomeKit) => {
|
182
|
+
if (fromHomeKit) {
|
183
|
+
const effect = 'colorloop'
|
184
|
+
this.put({ effect: effect, colorloopspeed: value })
|
185
|
+
this.values.colormode = 'hs'
|
186
|
+
}
|
187
|
+
})
|
188
|
+
}
|
189
|
+
|
190
|
+
this.addCharacteristicDelegates()
|
191
|
+
|
192
|
+
if (this.capabilities.bri && this.capabilities.ct && !this.capabilities.hs) {
|
193
|
+
this.addCharacteristicDelegate({
|
194
|
+
key: 'supportedTransitionConfiguration',
|
195
|
+
Characteristic: this.Characteristics.hap
|
196
|
+
.SupportedCharacteristicValueTransitionConfiguration,
|
197
|
+
silent: true,
|
198
|
+
getter: async () => {
|
199
|
+
this.initAdaptiveLighting()
|
200
|
+
return this.adaptiveLighting.generateConfiguration()
|
201
|
+
}
|
202
|
+
})
|
203
|
+
this.addCharacteristicDelegate({
|
204
|
+
key: 'transitionControl',
|
205
|
+
Characteristic: this.Characteristics.hap
|
206
|
+
.CharacteristicValueTransitionControl,
|
207
|
+
silent: true,
|
208
|
+
getter: async () => {
|
209
|
+
return this.adaptiveLighting.generateControl()
|
210
|
+
},
|
238
211
|
setter: async (value) => {
|
239
|
-
|
212
|
+
const control = this.adaptiveLighting.parseControl(value)
|
213
|
+
this.context.transitionControl = value
|
214
|
+
const response = this.adaptiveLighting.generateControlResponse()
|
215
|
+
const parsedResponse = this.adaptiveLighting.parseControl(response)
|
216
|
+
this.vdebug(
|
217
|
+
'Adaptive Lighting: control update: %j => %j',
|
218
|
+
control, parsedResponse
|
219
|
+
)
|
220
|
+
this.values.activeTransitionCount = parsedResponse === '' ? 0 : 1
|
221
|
+
return response
|
222
|
+
}
|
223
|
+
})
|
224
|
+
this.addCharacteristicDelegate({
|
225
|
+
key: 'activeTransitionCount',
|
226
|
+
Characteristic: this.Characteristics.hap
|
227
|
+
.CharacteristicValueActiveTransitionCount,
|
228
|
+
silent: true,
|
229
|
+
value: 0
|
230
|
+
}).on('didSet', (value) => {
|
231
|
+
this.log('Adaptive Lighting: %sabled', value > 0 ? 'en' : 'dis')
|
232
|
+
if (value) {
|
233
|
+
this.updateAdaptiveLighting()
|
240
234
|
}
|
241
235
|
})
|
242
236
|
}
|
243
237
|
|
244
|
-
this.
|
245
|
-
|
246
|
-
|
247
|
-
|
238
|
+
if (this.resource.rtype === 'groups') {
|
239
|
+
this.sceneServices = []
|
240
|
+
for (const scene of this.resource.body.scenes) {
|
241
|
+
const service = new homebridgeLib.ServiceDelegate(accessory, {
|
242
|
+
name: this.resource.body.name + ' ' + scene.name,
|
243
|
+
Service: this.Services.hap.Switch,
|
244
|
+
subtype: this.subtype + '-S' + scene.id
|
245
|
+
})
|
246
|
+
service.addCharacteristicDelegate({
|
247
|
+
key: 'on',
|
248
|
+
Characteristic: this.Characteristics.hap.On,
|
249
|
+
value: false
|
250
|
+
}).on('didSet', async (value, fromHomeKit) => {
|
251
|
+
this.checkAdaptiveLighting()
|
252
|
+
if (fromHomeKit && value) {
|
253
|
+
try {
|
254
|
+
const path = this.resource.rpath + '/scenes/' + scene.id + '/recall'
|
255
|
+
this.debug('PUT %s', path)
|
256
|
+
await this.client.put(path)
|
257
|
+
} catch (error) { this.error(error) }
|
258
|
+
await timeout(this.platform.config.waitTimeReset)
|
259
|
+
service.values.on = false
|
260
|
+
}
|
261
|
+
})
|
262
|
+
this.sceneServices.push(service)
|
263
|
+
}
|
264
|
+
}
|
248
265
|
|
249
|
-
this.
|
250
|
-
|
251
|
-
|
252
|
-
|
266
|
+
if (this.capabilities.effects != null) {
|
267
|
+
this.effectServices = []
|
268
|
+
this.addCharacteristicDelegate({
|
269
|
+
key: 'effect',
|
270
|
+
value: -1,
|
271
|
+
silent: true
|
272
|
+
}).on('didSet', (value) => {
|
273
|
+
for (const i in this.capabilities.effects) {
|
274
|
+
this.effectServices[i].values.on = value === i
|
275
|
+
}
|
276
|
+
})
|
277
|
+
for (const i in this.capabilities.effects) {
|
278
|
+
const effect = this.capabilities.effects[i]
|
279
|
+
const service = new homebridgeLib.ServiceDelegate(accessory, {
|
280
|
+
name: this.resource.body.name + ' ' + effect,
|
281
|
+
Service: this.Services.hap.Switch,
|
282
|
+
subtype: this.subtype + '-E' + i
|
283
|
+
})
|
284
|
+
service.addCharacteristicDelegate({
|
285
|
+
key: 'on',
|
286
|
+
Characteristic: this.Characteristics.hap.On
|
287
|
+
}).on('didSet', (value, fromHomeKit) => {
|
288
|
+
if (fromHomeKit) {
|
289
|
+
this.checkAdaptiveLighting()
|
290
|
+
this.values.effect = value ? i : -1
|
291
|
+
const newEffect = value
|
292
|
+
? effect.toLowerCase()
|
293
|
+
: 'none'
|
294
|
+
this.put({ effect: newEffect })
|
295
|
+
}
|
296
|
+
})
|
297
|
+
this.effectServices.push(service)
|
298
|
+
}
|
299
|
+
// if (this.capabilities.effectSpeed) {
|
300
|
+
// this.addCharacteristicDelegate({
|
301
|
+
// key: 'effectSpeed',
|
302
|
+
// Characteristic: this.Characteristics.my.EffectSpeed,
|
303
|
+
// value: 50
|
304
|
+
// }).on('didSet', (value) => {
|
305
|
+
// this.setEffectSpeed(value)
|
306
|
+
// })
|
307
|
+
// this.hk.effectColours = []
|
308
|
+
// for (let i = 0; i <= 5; i++) {
|
309
|
+
// const service = new this.Service.Lightbulb(
|
310
|
+
// this.name + ' Effect Color ' + (i + 1), this.subtype + '-C' + i
|
311
|
+
// )
|
312
|
+
// service.addCharacteristicDelegate({
|
313
|
+
// key: 'on',
|
314
|
+
// Characteristic: this.Characteristics.hap.On,
|
315
|
+
// value: true
|
316
|
+
// }).on('didSet', (value) => {
|
317
|
+
// this.setEffectOn(i, value)
|
318
|
+
// })
|
319
|
+
// service.addCharacteristicDelegate({
|
320
|
+
// key: 'hue',
|
321
|
+
// Characteristic: this.Characteristics.hap.Hue,
|
322
|
+
// value: i * 60
|
323
|
+
// }).on('didSet', (value) => {
|
324
|
+
// this.setEffectHue(i, value)
|
325
|
+
// })
|
326
|
+
// service.addCharacteristicDelegate({
|
327
|
+
// key: 'saturation',
|
328
|
+
// Characteristic: this.Characteristics.hap.Saturation,
|
329
|
+
// value: 100
|
330
|
+
// }).on('didSet', (value) => {
|
331
|
+
// this.setEffectSat(i, value)
|
332
|
+
// })
|
333
|
+
// this.effectServices.push(service)
|
334
|
+
// }
|
335
|
+
// }
|
336
|
+
// this.checkEffect(this.obj.state.effect)
|
337
|
+
}
|
253
338
|
|
254
339
|
this.settings = {
|
255
340
|
brightnessAdjustment: 1,
|
@@ -257,72 +342,42 @@ class Light extends homebridgeLib.ServiceDelegate {
|
|
257
342
|
waitTimeUpdate: this.platform.config.waitTimeUpdate,
|
258
343
|
wallSwitch: false
|
259
344
|
}
|
260
|
-
|
261
|
-
this.update(this.resource.body)
|
262
|
-
}
|
263
|
-
|
264
|
-
update (body) {
|
265
|
-
for (const key in body) {
|
266
|
-
const value = body[key]
|
267
|
-
switch (key) {
|
268
|
-
case 'action':
|
269
|
-
// Copied to `state` by `Resource` during polling.
|
270
|
-
break
|
271
|
-
case 'state':
|
272
|
-
this.updateState(value)
|
273
|
-
break
|
274
|
-
case 'lastannounced':
|
275
|
-
// this.values.lastBoot = dateToString(value)
|
276
|
-
break
|
277
|
-
case 'lastseen':
|
278
|
-
this.values.lastSeen = dateToString(value)
|
279
|
-
break
|
280
|
-
case 'colorcapabilities':
|
281
|
-
case 'ctmax':
|
282
|
-
case 'ctmin':
|
283
|
-
case 'devicemembership':
|
284
|
-
case 'etag':
|
285
|
-
case 'id':
|
286
|
-
case 'lights':
|
287
|
-
case 'hascolor':
|
288
|
-
case 'manufacturername':
|
289
|
-
case 'modelid':
|
290
|
-
case 'name':
|
291
|
-
case 'powerup':
|
292
|
-
case 'scenes':
|
293
|
-
case 'swversion':
|
294
|
-
case 'type':
|
295
|
-
case 'uniqueid':
|
296
|
-
break
|
297
|
-
default:
|
298
|
-
this.warn('%s: unknown %s attribute', key, this.rtype)
|
299
|
-
break
|
300
|
-
}
|
301
|
-
}
|
302
345
|
}
|
303
346
|
|
304
347
|
updateState (state) {
|
348
|
+
let updateAdaptiveLighting = false
|
305
349
|
for (const key in state) {
|
306
350
|
const value = state[key]
|
351
|
+
this.resource.body.state[key] = value
|
307
352
|
switch (key) {
|
308
353
|
case 'all_on':
|
309
354
|
this.values.on = value
|
355
|
+
updateAdaptiveLighting = true
|
310
356
|
break
|
311
357
|
case 'any_on':
|
312
358
|
this.values.anyOn = value
|
313
|
-
|
314
|
-
case 'alert':
|
359
|
+
updateAdaptiveLighting = true
|
315
360
|
break
|
316
361
|
case 'bri':
|
317
|
-
|
362
|
+
if (!this.recentlyUpdated) {
|
363
|
+
this.values.brightness = Math.round(value / 2.54)
|
364
|
+
updateAdaptiveLighting = true
|
365
|
+
}
|
318
366
|
break
|
319
367
|
case 'colormode':
|
320
368
|
this.values.colormode = value
|
321
369
|
break
|
322
370
|
case 'ct':
|
323
|
-
this.values.
|
371
|
+
if (!this.recentlyUpdated && this.values.colormode === 'ct') {
|
372
|
+
this.values.colorTemperature = value
|
373
|
+
}
|
324
374
|
break
|
325
375
|
case 'effect':
|
376
|
+
this.values.colorLoop = value === 'colorloop'
|
377
|
+
if (this.capabilities.effects != null) {
|
378
|
+
const effectName = value[0].toUpperCase() + value.slice(1)
|
379
|
+
this.values.effect = '' + this.capabilities.effects.indexOf(effectName)
|
380
|
+
}
|
326
381
|
break
|
327
382
|
case 'hue':
|
328
383
|
if (!this.capabilities.xy) {
|
@@ -332,137 +387,91 @@ class Light extends homebridgeLib.ServiceDelegate {
|
|
332
387
|
case 'on':
|
333
388
|
this.values.on = value
|
334
389
|
break
|
335
|
-
case 'reachable':
|
336
|
-
this.values.statusFault = value
|
337
|
-
? this.Characteristics.hap.StatusFault.NO_FAULT
|
338
|
-
: this.Characteristics.hap.StatusFault.GENERAL_FAULT
|
339
|
-
break
|
340
390
|
case 'sat':
|
341
391
|
if (!this.capabilities.xy) {
|
342
392
|
this.values.hue = value
|
343
393
|
}
|
344
394
|
break
|
345
|
-
case 'scene':
|
346
|
-
break
|
347
395
|
case 'xy':
|
348
|
-
if (
|
396
|
+
if (
|
397
|
+
!this.recentlyUpdated &&
|
398
|
+
(this.values.colormode !== 'ct' || this.capabilities.computesXy)
|
399
|
+
) {
|
349
400
|
const { h, s } = xyToHsv(value, this.capabilities.gamut)
|
350
401
|
this.values.hue = h
|
351
402
|
this.values.saturation = s
|
352
403
|
}
|
353
404
|
break
|
354
405
|
default:
|
355
|
-
this.warn('state.%s: unknown %s attribute', key, this.rtype)
|
356
406
|
break
|
357
407
|
}
|
358
408
|
}
|
409
|
+
if (updateAdaptiveLighting) {
|
410
|
+
this.updateAdaptiveLighting()
|
411
|
+
}
|
412
|
+
super.updateState(state)
|
359
413
|
}
|
360
414
|
|
361
|
-
|
362
|
-
try {
|
363
|
-
if (this.capabilities.alert) {
|
364
|
-
if (this.capabilities.breathe) {
|
365
|
-
await this.put({ alert: 'breathe' })
|
366
|
-
await timeout(1500)
|
367
|
-
return this.put({ alert: 'stop' })
|
368
|
-
}
|
369
|
-
return this.put({ alert: 'select' })
|
370
|
-
}
|
371
|
-
} catch (error) { this.warn(error) }
|
372
|
-
}
|
373
|
-
|
374
|
-
async initAdaptiveLighting () {
|
415
|
+
initAdaptiveLighting () {
|
375
416
|
if (this.adaptiveLighting == null) {
|
376
417
|
this.adaptiveLighting = new homebridgeLib.AdaptiveLighting(
|
377
418
|
this.brightnessDelegate, this.colorTemperatureDelegate
|
378
419
|
)
|
379
|
-
this.values.
|
380
|
-
this.adaptiveLighting.
|
381
|
-
|
382
|
-
|
383
|
-
this.
|
384
|
-
|
385
|
-
this.adaptiveLighting.parseControl(this.values.transitionControl)
|
420
|
+
if (this.values.activeTransitionCount > 0) {
|
421
|
+
const control = this.adaptiveLighting.parseControl(
|
422
|
+
this.context.transitionControl
|
423
|
+
)
|
424
|
+
this.vdebug('Adaptive Lighting: restore control: %j', control)
|
425
|
+
this.adaptiveLighting.parseControl(this.context.transitionControl)
|
386
426
|
}
|
427
|
+
this.log(
|
428
|
+
'Adaptive Lighting: %sabled',
|
429
|
+
this.values.activeTransitionCount > 0 ? 'en' : 'dis'
|
430
|
+
)
|
387
431
|
}
|
388
432
|
}
|
389
433
|
|
390
|
-
async
|
391
|
-
if (
|
434
|
+
async updateAdaptiveLighting () {
|
435
|
+
if (
|
436
|
+
this.adaptiveLighting == null || // not supported
|
437
|
+
this.values.activeTransitionCount === 0 || // disabled
|
438
|
+
!this.values.on // light is off
|
439
|
+
) {
|
392
440
|
return
|
393
441
|
}
|
394
442
|
const ct = this.adaptiveLighting.getCt(
|
395
443
|
this.values.brightness * this.settings.brightnessAdjustment
|
396
444
|
)
|
397
|
-
if (ct == null
|
445
|
+
if (ct == null) {
|
446
|
+
this.warn('assertion failed')
|
398
447
|
return
|
399
448
|
}
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
}
|
414
|
-
this.
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
}, this.settings.waitTimeUpdate)
|
419
|
-
} else {
|
420
|
-
this._put()
|
421
|
-
}
|
422
|
-
})
|
449
|
+
this.debug(
|
450
|
+
'/%s/%d: adaptive lighting: {"state":{"ct": %d}}',
|
451
|
+
this.rtype, this.rid, ct
|
452
|
+
)
|
453
|
+
if (this.values.colormode === 'ct' && ct === this.values.colorTemperature) {
|
454
|
+
return
|
455
|
+
}
|
456
|
+
this.put({ ct: ct })
|
457
|
+
this.fromAdaptiveLighting = true
|
458
|
+
this.values.colormode = 'ct'
|
459
|
+
if (ct !== this.values.colorTemperature) {
|
460
|
+
this.values.colorTemperature = ct
|
461
|
+
} else if (this.capabilities.xy) { // colormode changed
|
462
|
+
const { h, s } = xyToHsv(ctToXy(ct), this.capabilities.gamut)
|
463
|
+
this.values.hue = h
|
464
|
+
this.values.saturation = s
|
465
|
+
}
|
466
|
+
this.fromAdaptiveLighting = false
|
423
467
|
}
|
424
468
|
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
const deferrals = this.deferrals
|
429
|
-
this.targetState = {}
|
430
|
-
this.deferrals = []
|
431
|
-
this.updating = false
|
432
|
-
if (
|
433
|
-
this.gateway.transitionTime !== this.gateway.defaultTransitionTime &&
|
434
|
-
targetState.transitiontime === undefined
|
435
|
-
) {
|
436
|
-
targetState.transitiontime = this.gateway.transitionTime * 10
|
437
|
-
this.gateway.resetTransitionTime()
|
438
|
-
}
|
439
|
-
if (this.capabilities.noTransition) {
|
440
|
-
if (
|
441
|
-
(
|
442
|
-
targetState.on != null || targetState.bri != null ||
|
443
|
-
targetState.bri_inc != null
|
444
|
-
) && (
|
445
|
-
targetState.xy != null || targetState.ct != null ||
|
446
|
-
targetState.hue != null || targetState.sat != null ||
|
447
|
-
targetState.effect != null
|
448
|
-
)
|
449
|
-
) {
|
450
|
-
targetState.transitiontime = 0
|
451
|
-
}
|
469
|
+
checkAdaptiveLighting (key, value) {
|
470
|
+
if (this.adaptiveLighting == null || this.fromAdaptiveLighting) {
|
471
|
+
return
|
452
472
|
}
|
453
|
-
this.
|
454
|
-
|
455
|
-
for (const d of deferrals) {
|
456
|
-
d.resolve(true)
|
457
|
-
}
|
458
|
-
setTimeout(() => {
|
459
|
-
this.recentlyUpdated = false
|
460
|
-
}, 500)
|
461
|
-
}).catch((error) => {
|
462
|
-
for (const d of deferrals) {
|
463
|
-
d.reject(error)
|
464
|
-
}
|
465
|
-
})
|
473
|
+
this.adaptiveLighting.deactivate()
|
474
|
+
this.values.activeTransitionCount = 0
|
466
475
|
}
|
467
476
|
}
|
468
477
|
|