@homebridge-plugins/homebridge-ewelink 12.3.3
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/CHANGELOG.md +1363 -0
- package/LICENSE +21 -0
- package/README.md +68 -0
- package/config.schema.json +1757 -0
- package/eslint.config.js +15 -0
- package/lib/connection/api.js +508 -0
- package/lib/connection/http.js +304 -0
- package/lib/connection/lan.js +318 -0
- package/lib/connection/ws.js +414 -0
- package/lib/device/curtain.js +324 -0
- package/lib/device/diffuser.js +473 -0
- package/lib/device/fan.js +349 -0
- package/lib/device/group.js +106 -0
- package/lib/device/humidifier.js +199 -0
- package/lib/device/index.js +61 -0
- package/lib/device/light-cct.js +333 -0
- package/lib/device/light-dimmer.js +257 -0
- package/lib/device/light-rgb-cct.js +809 -0
- package/lib/device/light-rgb.js +272 -0
- package/lib/device/motor.js +363 -0
- package/lib/device/outlet-multi.js +417 -0
- package/lib/device/outlet-single-inched.js +409 -0
- package/lib/device/outlet-single.js +384 -0
- package/lib/device/panel.js +382 -0
- package/lib/device/rf-bridge.js +321 -0
- package/lib/device/rf-button.js +125 -0
- package/lib/device/rf-sensor.js +173 -0
- package/lib/device/sensor-ambient.js +311 -0
- package/lib/device/sensor-contact.js +140 -0
- package/lib/device/sensor-temp-humi.js +182 -0
- package/lib/device/simulation/blind.js +253 -0
- package/lib/device/simulation/cooler.js +312 -0
- package/lib/device/simulation/door.js +253 -0
- package/lib/device/simulation/doorbell.js +190 -0
- package/lib/device/simulation/garage-eachen.js +235 -0
- package/lib/device/simulation/garage-four.js +176 -0
- package/lib/device/simulation/garage-od-switch.js +36 -0
- package/lib/device/simulation/garage-one.js +395 -0
- package/lib/device/simulation/garage-two.js +394 -0
- package/lib/device/simulation/gate-one.js +327 -0
- package/lib/device/simulation/heater.js +389 -0
- package/lib/device/simulation/index.js +75 -0
- package/lib/device/simulation/light-fan.js +258 -0
- package/lib/device/simulation/lock-eachen.js +163 -0
- package/lib/device/simulation/lock-one.js +366 -0
- package/lib/device/simulation/p-button.js +223 -0
- package/lib/device/simulation/purifier.js +289 -0
- package/lib/device/simulation/rf-blind.js +192 -0
- package/lib/device/simulation/rf-door.js +180 -0
- package/lib/device/simulation/rf-window.js +180 -0
- package/lib/device/simulation/sensor-hidden.js +105 -0
- package/lib/device/simulation/sensor-leak.js +123 -0
- package/lib/device/simulation/sensor-visible.js +231 -0
- package/lib/device/simulation/sensor.js +300 -0
- package/lib/device/simulation/switch-valve.js +351 -0
- package/lib/device/simulation/tap-one.js +283 -0
- package/lib/device/simulation/tap-two.js +266 -0
- package/lib/device/simulation/th-cooler.js +443 -0
- package/lib/device/simulation/th-dehumidifier.js +424 -0
- package/lib/device/simulation/th-heater.js +449 -0
- package/lib/device/simulation/th-humidifier.js +424 -0
- package/lib/device/simulation/th-thermostat.js +611 -0
- package/lib/device/simulation/tv.js +252 -0
- package/lib/device/simulation/valve-four.js +232 -0
- package/lib/device/simulation/valve-one.js +345 -0
- package/lib/device/simulation/valve-two.js +340 -0
- package/lib/device/simulation/window.js +253 -0
- package/lib/device/switch-man.js +106 -0
- package/lib/device/switch-mate.js +82 -0
- package/lib/device/switch-multi.js +411 -0
- package/lib/device/switch-single-inched.js +332 -0
- package/lib/device/switch-single.js +307 -0
- package/lib/device/template.js +43 -0
- package/lib/device/thermostat.js +286 -0
- package/lib/device/zigbee/index.js +27 -0
- package/lib/device/zigbee/light-cct.js +263 -0
- package/lib/device/zigbee/light-dimmer.js +148 -0
- package/lib/device/zigbee/light-rgb-cct.js +400 -0
- package/lib/device/zigbee/motor.js +301 -0
- package/lib/device/zigbee/sensor-ambient.js +177 -0
- package/lib/device/zigbee/sensor-contact.js +137 -0
- package/lib/device/zigbee/sensor-leak.js +119 -0
- package/lib/device/zigbee/sensor-motion.js +119 -0
- package/lib/device/zigbee/sensor-occupancy.js +119 -0
- package/lib/device/zigbee/sensor-smoke.js +96 -0
- package/lib/device/zigbee/switch-stateless.js +104 -0
- package/lib/device/zigbee/thermostat.js +323 -0
- package/lib/fakegato/LICENSE +21 -0
- package/lib/fakegato/fakegato-history.js +813 -0
- package/lib/fakegato/fakegato-storage.js +108 -0
- package/lib/fakegato/fakegato-timer.js +125 -0
- package/lib/fakegato/uuid.js +27 -0
- package/lib/homebridge-ui/public/index.html +365 -0
- package/lib/homebridge-ui/server.js +46 -0
- package/lib/index.js +7 -0
- package/lib/node-dns-sd/LICENSE +21 -0
- package/lib/node-dns-sd/README.md +613 -0
- package/lib/node-dns-sd/lib/dns-sd-classes.json +6 -0
- package/lib/node-dns-sd/lib/dns-sd-composer.js +83 -0
- package/lib/node-dns-sd/lib/dns-sd-parser.js +344 -0
- package/lib/node-dns-sd/lib/dns-sd-types.json +52 -0
- package/lib/node-dns-sd/lib/dns-sd.js +580 -0
- package/lib/platform.js +2156 -0
- package/lib/utils/colour.js +552 -0
- package/lib/utils/constants.js +589 -0
- package/lib/utils/custom-chars.js +33 -0
- package/lib/utils/eve-chars.js +130 -0
- package/lib/utils/functions.js +42 -0
- package/lib/utils/lang-en.js +160 -0
- package/lib/utils/lang-fr.js +163 -0
- package/lib/utils/lang-th.js +160 -0
- package/lib/utils/lang.js +5 -0
- package/package.json +75 -0
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
import platformConsts from '../utils/constants.js'
|
|
2
|
+
import { hasProperty, parseError } from '../utils/functions.js'
|
|
3
|
+
|
|
4
|
+
export default class {
|
|
5
|
+
constructor(platform, accessory) {
|
|
6
|
+
// Set up variables from the platform
|
|
7
|
+
this.hapChar = platform.api.hap.Characteristic
|
|
8
|
+
this.hapServ = platform.api.hap.Service
|
|
9
|
+
this.hapErr = platform.api.hap.HapStatusError
|
|
10
|
+
this.lang = platform.lang
|
|
11
|
+
this.log = platform.log
|
|
12
|
+
this.platform = platform
|
|
13
|
+
|
|
14
|
+
// Set up variables from the accessory
|
|
15
|
+
this.name = accessory.displayName
|
|
16
|
+
this.accessory = accessory
|
|
17
|
+
|
|
18
|
+
// Initially set the online flag as true (to be then updated as false if necessary)
|
|
19
|
+
this.isOnline = true
|
|
20
|
+
|
|
21
|
+
// Set up custom variables for this device type
|
|
22
|
+
const deviceConf = platform.deviceConf[accessory.context.eweDeviceId] || {}
|
|
23
|
+
this.tempOffset = deviceConf.offset || platformConsts.defaultValues.offset
|
|
24
|
+
this.tempOffsetFactor = deviceConf.offsetFactor
|
|
25
|
+
|
|
26
|
+
// Set the correct logging variables for this accessory
|
|
27
|
+
switch (deviceConf.overrideLogging) {
|
|
28
|
+
case 'standard':
|
|
29
|
+
this.enableLogging = true
|
|
30
|
+
this.enableDebugLogging = false
|
|
31
|
+
break
|
|
32
|
+
case 'debug':
|
|
33
|
+
this.enableLogging = true
|
|
34
|
+
this.enableDebugLogging = true
|
|
35
|
+
break
|
|
36
|
+
case 'disable':
|
|
37
|
+
this.enableLogging = false
|
|
38
|
+
this.enableDebugLogging = false
|
|
39
|
+
break
|
|
40
|
+
default:
|
|
41
|
+
this.enableLogging = !platform.config.disableDeviceLogging
|
|
42
|
+
this.enableDebugLogging = platform.config.debug
|
|
43
|
+
break
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/*
|
|
47
|
+
**************
|
|
48
|
+
*** PARAMS ***
|
|
49
|
+
**************
|
|
50
|
+
"volatility": 1, no plan to implement
|
|
51
|
+
"targetTemp": 20, implemented; will set mode in ewelink to C
|
|
52
|
+
"workMode": 1, implemented 1; 1=manual, 2=programmed 3=economical
|
|
53
|
+
"switch": "on", implemented
|
|
54
|
+
"temperature": 29, implemented; F will be converted to C
|
|
55
|
+
"fault": 0, no plan to implemented
|
|
56
|
+
"workState": 2, implemented 1&2; 1=heating, 2=auto
|
|
57
|
+
"tempScale": "c", implemented c; no plan to implement f
|
|
58
|
+
"childLock": "off", no plan to implement
|
|
59
|
+
"mon": "016800c801e0009602b20096032a009603fc00dc05280096", no
|
|
60
|
+
"tues": "016800c801e0009602b20096032a009603fc00dc05280096", plans
|
|
61
|
+
"wed": "016800c801e0009602b20096032a009603fc00dc05280096", to
|
|
62
|
+
"thur": "016800c801e0009602b20096032a009603fc00dc05280096", implement
|
|
63
|
+
"fri": "016800c801e0009602b20096032a009603fc00dc05280096", the
|
|
64
|
+
"sat": "016800c801e000c802b200c8032a00c803fc00c805280096", schedule
|
|
65
|
+
"sun": "016800c801e000c802b200c8032a00c803fc00c805280096", program
|
|
66
|
+
*/
|
|
67
|
+
|
|
68
|
+
// Add the thermostat service if it doesn't already exist
|
|
69
|
+
this.service = this.accessory.getService(this.hapServ.Thermostat)
|
|
70
|
+
|| this.accessory.addService(this.hapServ.Thermostat)
|
|
71
|
+
|
|
72
|
+
// Set custom properties of the current temperature characteristic
|
|
73
|
+
this.service.getCharacteristic(this.hapChar.CurrentTemperature).setProps({
|
|
74
|
+
minStep: 0.1,
|
|
75
|
+
})
|
|
76
|
+
this.cacheTemp = this.service.getCharacteristic(this.hapChar.CurrentTemperature).value
|
|
77
|
+
this.updateCache()
|
|
78
|
+
|
|
79
|
+
// Add the set handler to the target state characteristic
|
|
80
|
+
this.service
|
|
81
|
+
.getCharacteristic(this.hapChar.TargetHeatingCoolingState)
|
|
82
|
+
.setProps({
|
|
83
|
+
minValue: 0,
|
|
84
|
+
maxValue: 1,
|
|
85
|
+
validValues: [0, 1],
|
|
86
|
+
})
|
|
87
|
+
.onSet(async value => this.internalStateUpdate(value))
|
|
88
|
+
|
|
89
|
+
// Add the set handler to the target temperature characteristic
|
|
90
|
+
this.service
|
|
91
|
+
.getCharacteristic(this.hapChar.TargetTemperature)
|
|
92
|
+
.setProps({
|
|
93
|
+
minValue: 5,
|
|
94
|
+
maxValue: 45,
|
|
95
|
+
minStep: 0.5,
|
|
96
|
+
})
|
|
97
|
+
.onSet(async value => this.internalTargetUpdate(value))
|
|
98
|
+
|
|
99
|
+
// Add the get handlers only if the user hasn't disabled the disableNoResponse setting
|
|
100
|
+
if (!platform.config.disableNoResponse) {
|
|
101
|
+
this.service.getCharacteristic(this.hapChar.CurrentTemperature).onGet(() => {
|
|
102
|
+
if (!this.isOnline) {
|
|
103
|
+
throw new this.hapErr(-70402)
|
|
104
|
+
}
|
|
105
|
+
return this.service.getCharacteristic(this.hapChar.CurrentTemperature).value
|
|
106
|
+
})
|
|
107
|
+
this.service.getCharacteristic(this.hapChar.CurrentHeatingCoolingState).onGet(() => {
|
|
108
|
+
if (!this.isOnline) {
|
|
109
|
+
throw new this.hapErr(-70402)
|
|
110
|
+
}
|
|
111
|
+
return this.service.getCharacteristic(this.hapChar.CurrentHeatingCoolingState).value
|
|
112
|
+
})
|
|
113
|
+
this.service.getCharacteristic(this.hapChar.TargetHeatingCoolingState).onGet(() => {
|
|
114
|
+
if (!this.isOnline) {
|
|
115
|
+
throw new this.hapErr(-70402)
|
|
116
|
+
}
|
|
117
|
+
return this.service.getCharacteristic(this.hapChar.TargetHeatingCoolingState).value
|
|
118
|
+
})
|
|
119
|
+
this.service.getCharacteristic(this.hapChar.TargetTemperature).onGet(() => {
|
|
120
|
+
if (!this.isOnline) {
|
|
121
|
+
throw new this.hapErr(-70402)
|
|
122
|
+
}
|
|
123
|
+
return this.service.getCharacteristic(this.hapChar.TargetTemperature).value
|
|
124
|
+
})
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Pass the accessory to Fakegato to set up with Eve
|
|
128
|
+
this.accessory.eveService = new platform.eveService('custom', this.accessory, {
|
|
129
|
+
log: () => {},
|
|
130
|
+
})
|
|
131
|
+
|
|
132
|
+
// Output the customised options to the log
|
|
133
|
+
const normalLogging = this.enableLogging ? 'standard' : 'disable'
|
|
134
|
+
const opts = JSON.stringify({
|
|
135
|
+
logging: this.enableDebugLogging ? 'debug' : normalLogging,
|
|
136
|
+
offset: this.tempOffset,
|
|
137
|
+
offsetFactor: this.tempOffsetFactor,
|
|
138
|
+
})
|
|
139
|
+
this.log('[%s] %s %s.', this.name, this.lang.devInitOpts, opts)
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
async internalStateUpdate(value) {
|
|
143
|
+
try {
|
|
144
|
+
const newValue = value !== 0 ? 'on' : 'off'
|
|
145
|
+
const params = {
|
|
146
|
+
switch: newValue,
|
|
147
|
+
}
|
|
148
|
+
await this.platform.sendDeviceUpdate(this.accessory, params)
|
|
149
|
+
if (value === 0) {
|
|
150
|
+
this.service.updateCharacteristic(this.hapChar.CurrentHeatingCoolingState, 0)
|
|
151
|
+
}
|
|
152
|
+
this.cacheState = newValue
|
|
153
|
+
if (this.enableLogging) {
|
|
154
|
+
this.log('[%s] %s [%s].', this.name, this.lang.curState, this.cacheState)
|
|
155
|
+
}
|
|
156
|
+
} catch (err) {
|
|
157
|
+
this.platform.deviceUpdateError(this.accessory, err, true)
|
|
158
|
+
setTimeout(() => {
|
|
159
|
+
this.service.updateCharacteristic(
|
|
160
|
+
this.hapChar.TargetHeatingCoolingState,
|
|
161
|
+
this.cacheState === 'on' ? 1 : 0,
|
|
162
|
+
)
|
|
163
|
+
}, 2000)
|
|
164
|
+
throw new this.hapErr(-70402)
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
async internalTargetUpdate(value) {
|
|
169
|
+
try {
|
|
170
|
+
const params = {
|
|
171
|
+
workMode: 1,
|
|
172
|
+
targetTemp: value,
|
|
173
|
+
tempScale: 'c',
|
|
174
|
+
}
|
|
175
|
+
await this.platform.sendDeviceUpdate(this.accessory, params)
|
|
176
|
+
this.cacheTarg = value
|
|
177
|
+
if (this.enableLogging) {
|
|
178
|
+
this.log('[%s] %s [%s°C].', this.name, this.lang.curTarg, this.cacheTarg)
|
|
179
|
+
}
|
|
180
|
+
} catch (err) {
|
|
181
|
+
this.platform.deviceUpdateError(this.accessory, err, true)
|
|
182
|
+
setTimeout(() => {
|
|
183
|
+
this.service.updateCharacteristic(this.hapChar.TargetTemperature, this.cacheTarg)
|
|
184
|
+
}, 2000)
|
|
185
|
+
throw new this.hapErr(-70402)
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
async externalUpdate(params) {
|
|
190
|
+
try {
|
|
191
|
+
if (params.switch && params.switch !== this.cacheState) {
|
|
192
|
+
this.cacheState = params.switch
|
|
193
|
+
if (this.cacheState === 'off') {
|
|
194
|
+
this.service.updateCharacteristic(this.hapChar.CurrentHeatingCoolingState, 0)
|
|
195
|
+
}
|
|
196
|
+
this.service.updateCharacteristic(
|
|
197
|
+
this.hapChar.TargetHeatingCoolingState,
|
|
198
|
+
this.cacheState === 'on' ? 1 : 0,
|
|
199
|
+
)
|
|
200
|
+
if (params.updateSource && this.enableLogging) {
|
|
201
|
+
this.log('[%s] %s [%s].', this.name, this.lang.curState, this.cacheState)
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
if (params.workState) {
|
|
206
|
+
const workState = params.workState === 1 ? 'on' : 'off'
|
|
207
|
+
if (this.cacheHeat !== workState) {
|
|
208
|
+
this.cacheHeat = workState
|
|
209
|
+
this.service.updateCharacteristic(
|
|
210
|
+
this.hapChar.CurrentHeatingCoolingState,
|
|
211
|
+
this.cacheHeat === 'on' ? 1 : 0,
|
|
212
|
+
)
|
|
213
|
+
if (params.updateSource && this.enableLogging) {
|
|
214
|
+
this.log('[%s] %s [%s].', this.name, this.lang.curHeat, this.cacheHeat)
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
if (hasProperty(params, 'targetTemp')) {
|
|
220
|
+
const targetTemp = Number(params.targetTemp)
|
|
221
|
+
if (this.cacheTarg !== targetTemp) {
|
|
222
|
+
this.cacheTarg = targetTemp
|
|
223
|
+
this.service.updateCharacteristic(this.hapChar.TargetTemperature, this.cacheTarg)
|
|
224
|
+
if (params.updateSource && this.enableLogging) {
|
|
225
|
+
this.log('[%s] %s [%s°C].', this.name, this.lang.curTarg, this.cacheTarg)
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
if (hasProperty(params, 'temperature')) {
|
|
231
|
+
let currentTemp
|
|
232
|
+
if (params.tempScale && params.tempScale === 'f') {
|
|
233
|
+
// Convert to celcius
|
|
234
|
+
currentTemp = ((Number(params.temperature) - 32) * 5) / 9
|
|
235
|
+
|
|
236
|
+
// Round to nearest 0.5
|
|
237
|
+
currentTemp = Math.round(currentTemp * 2) / 2
|
|
238
|
+
} else {
|
|
239
|
+
currentTemp = Number(params.temperature)
|
|
240
|
+
}
|
|
241
|
+
if (this.tempOffsetFactor) {
|
|
242
|
+
currentTemp *= this.tempOffset
|
|
243
|
+
} else {
|
|
244
|
+
currentTemp += this.tempOffset
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
if (this.cacheTemp !== currentTemp) {
|
|
248
|
+
this.cacheTemp = currentTemp
|
|
249
|
+
this.service.updateCharacteristic(this.hapChar.CurrentTemperature, this.cacheTemp)
|
|
250
|
+
this.accessory.eveService.addEntry({ temp: this.cacheTemp })
|
|
251
|
+
if (params.updateSource && this.enableLogging) {
|
|
252
|
+
this.log('[%s] %s [%s°C].', this.name, this.lang.curTemp, this.cacheTemp)
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// Update the cache file with the new temperature
|
|
256
|
+
this.updateCache()
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
} catch (err) {
|
|
260
|
+
this.platform.deviceUpdateError(this.accessory, err, false)
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
async updateCache() {
|
|
265
|
+
// Don't continue if the storage client hasn't initialised properly
|
|
266
|
+
if (!this.platform.storageClientData) {
|
|
267
|
+
return
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// Attempt to save the new temperature to the cache
|
|
271
|
+
try {
|
|
272
|
+
await this.platform.storageData.setItem(
|
|
273
|
+
`${this.accessory.context.eweDeviceId}_temp`,
|
|
274
|
+
this.cacheTemp,
|
|
275
|
+
)
|
|
276
|
+
} catch (err) {
|
|
277
|
+
if (this.enableLogging) {
|
|
278
|
+
this.log.warn('[%s] %s %s.', this.name, this.lang.storageWriteErr, parseError(err))
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
markStatus(isOnline) {
|
|
284
|
+
this.isOnline = isOnline
|
|
285
|
+
}
|
|
286
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import deviceLightCCT from './light-cct.js'
|
|
2
|
+
import deviceLightDimmer from './light-dimmer.js'
|
|
3
|
+
import deviceLightRGBCCT from './light-rgb-cct.js'
|
|
4
|
+
import deviceMotor from './motor.js'
|
|
5
|
+
import deviceSensorAmbient from './sensor-ambient.js'
|
|
6
|
+
import deviceSensorContact from './sensor-contact.js'
|
|
7
|
+
import deviceSensorLeak from './sensor-leak.js'
|
|
8
|
+
import deviceSensorMotion from './sensor-motion.js'
|
|
9
|
+
import deviceSensorOccupancy from './sensor-occupancy.js'
|
|
10
|
+
import deviceSensorSmoke from './sensor-smoke.js'
|
|
11
|
+
import deviceSwitchStateless from './switch-stateless.js'
|
|
12
|
+
import deviceThermostat from './thermostat.js'
|
|
13
|
+
|
|
14
|
+
export default {
|
|
15
|
+
deviceLightCCT,
|
|
16
|
+
deviceLightRGBCCT,
|
|
17
|
+
deviceLightDimmer,
|
|
18
|
+
deviceMotor,
|
|
19
|
+
deviceSensorAmbient,
|
|
20
|
+
deviceSensorContact,
|
|
21
|
+
deviceSensorLeak,
|
|
22
|
+
deviceSensorMotion,
|
|
23
|
+
deviceSensorOccupancy,
|
|
24
|
+
deviceSensorSmoke,
|
|
25
|
+
deviceSwitchStateless,
|
|
26
|
+
deviceThermostat,
|
|
27
|
+
}
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
import platformConsts from '../../utils/constants.js'
|
|
2
|
+
import { generateRandomString, hasProperty, sleep } from '../../utils/functions.js'
|
|
3
|
+
|
|
4
|
+
export default class {
|
|
5
|
+
constructor(platform, accessory) {
|
|
6
|
+
// Set up variables from the platform
|
|
7
|
+
this.hapChar = platform.api.hap.Characteristic
|
|
8
|
+
this.hapErr = platform.api.hap.HapStatusError
|
|
9
|
+
this.hapServ = platform.api.hap.Service
|
|
10
|
+
this.lang = platform.lang
|
|
11
|
+
this.log = platform.log
|
|
12
|
+
this.platform = platform
|
|
13
|
+
|
|
14
|
+
// Set up variables from the accessory
|
|
15
|
+
this.name = accessory.displayName
|
|
16
|
+
this.accessory = accessory
|
|
17
|
+
|
|
18
|
+
// Set up custom variables for this device type
|
|
19
|
+
const deviceConf = platform.deviceConf[accessory.context.eweDeviceId] || {}
|
|
20
|
+
this.brightStep = deviceConf.brightnessStep
|
|
21
|
+
? Math.min(deviceConf.brightnessStep, 100)
|
|
22
|
+
: platformConsts.defaultValues.brightnessStep
|
|
23
|
+
this.alShift = deviceConf.adaptiveLightingShift || platformConsts.defaultValues.adaptiveLightingShift
|
|
24
|
+
|
|
25
|
+
// Set the correct logging variables for this accessory
|
|
26
|
+
switch (deviceConf.overrideLogging) {
|
|
27
|
+
case 'standard':
|
|
28
|
+
this.enableLogging = true
|
|
29
|
+
this.enableDebugLogging = false
|
|
30
|
+
break
|
|
31
|
+
case 'debug':
|
|
32
|
+
this.enableLogging = true
|
|
33
|
+
this.enableDebugLogging = true
|
|
34
|
+
break
|
|
35
|
+
case 'disable':
|
|
36
|
+
this.enableLogging = false
|
|
37
|
+
this.enableDebugLogging = false
|
|
38
|
+
break
|
|
39
|
+
default:
|
|
40
|
+
this.enableLogging = !platform.config.disableDeviceLogging
|
|
41
|
+
this.enableDebugLogging = platform.config.debug
|
|
42
|
+
break
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Different bulbs have different colour temperature ranges
|
|
46
|
+
this.minK = 2200
|
|
47
|
+
this.maxK = 4000
|
|
48
|
+
|
|
49
|
+
// Add the lightbulb service if it doesn't already exist
|
|
50
|
+
this.service = this.accessory.getService(this.hapServ.Lightbulb)
|
|
51
|
+
|| this.accessory.addService(this.hapServ.Lightbulb)
|
|
52
|
+
|
|
53
|
+
// If adaptive lighting has just been disabled then remove and re-add service to hide AL icon
|
|
54
|
+
if (this.alShift === -1 && this.accessory.context.adaptiveLighting) {
|
|
55
|
+
this.accessory.removeService(this.service)
|
|
56
|
+
this.service = this.accessory.addService(this.hapServ.Lightbulb)
|
|
57
|
+
this.accessory.context.adaptiveLighting = false
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Add the get/set handler to the lightbulb on/off characteristic
|
|
61
|
+
this.service
|
|
62
|
+
.getCharacteristic(this.hapChar.On)
|
|
63
|
+
.onSet(async value => this.internalStateUpdate(value))
|
|
64
|
+
|
|
65
|
+
// Add the set handler to the lightbulb brightness characteristic
|
|
66
|
+
this.service
|
|
67
|
+
.getCharacteristic(this.hapChar.Brightness)
|
|
68
|
+
.setProps({ minStep: this.brightStep })
|
|
69
|
+
.onSet(async value => this.internalBrightnessUpdate(value))
|
|
70
|
+
|
|
71
|
+
// This is needed as sometimes we need to send the brightness with a cct update
|
|
72
|
+
this.cacheBright = this.service.getCharacteristic(this.hapChar.Brightness).value
|
|
73
|
+
|
|
74
|
+
// Add the set handler to the lightbulb colour temperature characteristic
|
|
75
|
+
this.service.getCharacteristic(this.hapChar.ColorTemperature).onSet(async value => this.internalCTUpdate(value))
|
|
76
|
+
|
|
77
|
+
// Set up the adaptive lighting controller if not disabled by user
|
|
78
|
+
if (this.alShift !== -1) {
|
|
79
|
+
this.accessory.alController = new platform.api.hap.AdaptiveLightingController(this.service, {
|
|
80
|
+
customTemperatureAdjustment: this.alShift,
|
|
81
|
+
})
|
|
82
|
+
this.accessory.configureController(this.accessory.alController)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Add the get handlers only if the user hasn't disabled the disableNoResponse setting
|
|
86
|
+
if (!platform.config.disableNoResponse) {
|
|
87
|
+
this.service.getCharacteristic(this.hapChar.On).onGet(() => {
|
|
88
|
+
if (!this.isOnline) {
|
|
89
|
+
throw new this.hapErr(-70402)
|
|
90
|
+
}
|
|
91
|
+
return this.service.getCharacteristic(this.hapChar.On).value
|
|
92
|
+
})
|
|
93
|
+
this.service
|
|
94
|
+
.getCharacteristic(this.hapChar.Brightness)
|
|
95
|
+
.onGet(() => {
|
|
96
|
+
if (!this.isOnline) {
|
|
97
|
+
throw new this.hapErr(-70402)
|
|
98
|
+
}
|
|
99
|
+
return this.service.getCharacteristic(this.hapChar.Brightness).value
|
|
100
|
+
})
|
|
101
|
+
this.service.getCharacteristic(this.hapChar.ColorTemperature).onGet(() => {
|
|
102
|
+
if (!this.isOnline) {
|
|
103
|
+
throw new this.hapErr(-70402)
|
|
104
|
+
}
|
|
105
|
+
return this.service.getCharacteristic(this.hapChar.ColorTemperature).value
|
|
106
|
+
})
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Output the customised options to the log
|
|
110
|
+
const normalLogging = this.enableLogging ? 'standard' : 'disable'
|
|
111
|
+
const opts = JSON.stringify({
|
|
112
|
+
adaptiveLightingShift: this.alShift,
|
|
113
|
+
brightnessStep: this.brightStep,
|
|
114
|
+
logging: this.enableDebugLogging ? 'debug' : normalLogging,
|
|
115
|
+
})
|
|
116
|
+
this.log('[%s] %s %s.', this.name, this.lang.devInitOpts, opts)
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
async internalStateUpdate(value) {
|
|
120
|
+
try {
|
|
121
|
+
const newValue = value ? 'on' : 'off'
|
|
122
|
+
await this.platform.sendDeviceUpdate(this.accessory, {
|
|
123
|
+
switch: newValue,
|
|
124
|
+
})
|
|
125
|
+
this.cacheState = newValue
|
|
126
|
+
if (this.enableLogging) {
|
|
127
|
+
this.log('[%s] %s [%s].', this.name, this.lang.curState, this.cacheState)
|
|
128
|
+
}
|
|
129
|
+
} catch (err) {
|
|
130
|
+
this.platform.deviceUpdateError(this.accessory, err, true)
|
|
131
|
+
setTimeout(() => {
|
|
132
|
+
this.service.updateCharacteristic(this.hapChar.On, this.cacheState === 'on')
|
|
133
|
+
}, 2000)
|
|
134
|
+
throw new this.hapErr(-70402)
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
async internalBrightnessUpdate(value) {
|
|
139
|
+
try {
|
|
140
|
+
if (this.cacheBright === value || value === 0) {
|
|
141
|
+
return
|
|
142
|
+
}
|
|
143
|
+
const updateKey = generateRandomString(5)
|
|
144
|
+
this.updateKeyBright = updateKey
|
|
145
|
+
await sleep(500)
|
|
146
|
+
if (updateKey !== this.updateKeyBright) {
|
|
147
|
+
return
|
|
148
|
+
}
|
|
149
|
+
const params = {
|
|
150
|
+
switch: 'on',
|
|
151
|
+
brightness: value,
|
|
152
|
+
}
|
|
153
|
+
await this.platform.sendDeviceUpdate(this.accessory, params)
|
|
154
|
+
this.cacheBright = value
|
|
155
|
+
if (this.enableLogging) {
|
|
156
|
+
this.log('[%s] %s [%s%].', this.name, this.lang.curBright, this.cacheBright)
|
|
157
|
+
}
|
|
158
|
+
} catch (err) {
|
|
159
|
+
this.platform.deviceUpdateError(this.accessory, err, true)
|
|
160
|
+
setTimeout(() => {
|
|
161
|
+
this.service.updateCharacteristic(this.hapChar.Brightness, this.cacheBright)
|
|
162
|
+
}, 2000)
|
|
163
|
+
throw new this.hapErr(-70402)
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
async internalCTUpdate(value) {
|
|
168
|
+
try {
|
|
169
|
+
if (this.cacheMired === value) {
|
|
170
|
+
return
|
|
171
|
+
}
|
|
172
|
+
if (
|
|
173
|
+
this.accessory.alController
|
|
174
|
+
&& this.accessory.alController.isAdaptiveLightingActive()
|
|
175
|
+
&& (this.cacheState !== 'on' || !this.isOnline)
|
|
176
|
+
) {
|
|
177
|
+
return
|
|
178
|
+
}
|
|
179
|
+
const updateKey = generateRandomString(5)
|
|
180
|
+
this.updateKeyCT = updateKey
|
|
181
|
+
await sleep(400)
|
|
182
|
+
if (updateKey !== this.updateKeyCT) {
|
|
183
|
+
return
|
|
184
|
+
}
|
|
185
|
+
const kelvin = Math.round(1000000 / value)
|
|
186
|
+
const scaledK = Math.max(Math.min(kelvin, this.maxK), this.minK)
|
|
187
|
+
const scaledCT = Math.round(((scaledK - this.minK) / (this.maxK - this.minK)) * 100)
|
|
188
|
+
const params = {
|
|
189
|
+
switch: 'on',
|
|
190
|
+
colorTemp: scaledCT,
|
|
191
|
+
}
|
|
192
|
+
await this.platform.sendDeviceUpdate(this.accessory, params)
|
|
193
|
+
this.cacheMired = value
|
|
194
|
+
this.cacheCT = scaledCT
|
|
195
|
+
if (this.enableLogging) {
|
|
196
|
+
if (this.accessory.alController && this.accessory.alController.isAdaptiveLightingActive()) {
|
|
197
|
+
this.log('[%s] %s [%sK] %s.', this.name, this.lang.curColour, scaledK, this.lang.viaAL)
|
|
198
|
+
} else {
|
|
199
|
+
this.log('[%s] %s [%sK].', this.name, this.lang.curColour, scaledK)
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
} catch (err) {
|
|
203
|
+
this.platform.deviceUpdateError(this.accessory, err, true)
|
|
204
|
+
setTimeout(() => {
|
|
205
|
+
this.service.updateCharacteristic(this.hapChar.ColorTemperature, this.cacheMired)
|
|
206
|
+
}, 2000)
|
|
207
|
+
throw new this.hapErr(-70402)
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
async externalUpdate(params) {
|
|
212
|
+
try {
|
|
213
|
+
if (params.switch && params.switch !== this.cacheState) {
|
|
214
|
+
this.cacheState = params.switch
|
|
215
|
+
this.service.updateCharacteristic(this.hapChar.On, this.cacheState === 'on')
|
|
216
|
+
if (params.updateSource && this.enableLogging) {
|
|
217
|
+
this.log('[%s] %s [%s].', this.name, this.lang.curState, this.cacheState)
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
if (hasProperty(params, 'brightness')) {
|
|
221
|
+
if (params.brightness !== this.cacheBright) {
|
|
222
|
+
this.cacheBright = params.brightness
|
|
223
|
+
this.service.updateCharacteristic(this.hapChar.Brightness, this.cacheBright)
|
|
224
|
+
if (params.updateSource && this.enableLogging) {
|
|
225
|
+
this.log('[%s] %s [%s%].', this.name, this.lang.curBright, this.cacheBright)
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
if (hasProperty(params, 'colorTemp')) {
|
|
230
|
+
if (params.colorTemp !== this.cacheCT) {
|
|
231
|
+
const ctDiff = Math.abs(params.colorTemp - this.cacheCT)
|
|
232
|
+
this.cacheCT = params.colorTemp
|
|
233
|
+
const kelvin = (this.cacheCT / 100) * (this.maxK - this.minK) + this.minK
|
|
234
|
+
const scaledK = Math.round(kelvin)
|
|
235
|
+
this.cacheMired = Math.min(Math.max(Math.round(1000000 / scaledK), 140), 500)
|
|
236
|
+
this.service.updateCharacteristic(this.hapChar.ColorTemperature, this.cacheMired)
|
|
237
|
+
if (params.updateSource) {
|
|
238
|
+
if (this.enableLogging) {
|
|
239
|
+
this.log('[%s] %s [%sK].', this.name, this.lang.curColour, scaledK)
|
|
240
|
+
}
|
|
241
|
+
if (
|
|
242
|
+
this.accessory.alController
|
|
243
|
+
&& this.accessory.alController.isAdaptiveLightingActive()
|
|
244
|
+
&& ctDiff > 20
|
|
245
|
+
) {
|
|
246
|
+
// Look for a variation greater than twenty
|
|
247
|
+
this.accessory.alController.disableAdaptiveLighting()
|
|
248
|
+
if (this.enableLogging) {
|
|
249
|
+
this.log('[%s] %s.', this.name, this.lang.disabledAL)
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
} catch (err) {
|
|
256
|
+
this.platform.deviceUpdateError(this.accessory, err, false)
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
markStatus(isOnline) {
|
|
261
|
+
this.isOnline = isOnline
|
|
262
|
+
}
|
|
263
|
+
}
|