@homebridge-plugins/homebridge-wemo 7.0.0
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 +809 -0
- package/LICENSE +21 -0
- package/README.md +66 -0
- package/config.schema.json +814 -0
- package/eslint.config.js +50 -0
- package/lib/connection/http.js +174 -0
- package/lib/connection/upnp.js +155 -0
- package/lib/device/coffee.js +167 -0
- package/lib/device/crockpot.js +380 -0
- package/lib/device/dimmer.js +280 -0
- package/lib/device/heater.js +416 -0
- package/lib/device/humidifier.js +379 -0
- package/lib/device/index.js +39 -0
- package/lib/device/insight.js +353 -0
- package/lib/device/lightswitch.js +154 -0
- package/lib/device/link-bulb.js +467 -0
- package/lib/device/link-hub.js +63 -0
- package/lib/device/maker-garage.js +426 -0
- package/lib/device/maker-switch.js +202 -0
- package/lib/device/motion.js +148 -0
- package/lib/device/outlet.js +148 -0
- package/lib/device/purifier.js +468 -0
- package/lib/device/simulation/purifier-insight.js +357 -0
- package/lib/device/simulation/purifier.js +159 -0
- package/lib/device/simulation/switch-insight.js +315 -0
- package/lib/device/simulation/switch.js +154 -0
- package/lib/fakegato/LICENSE +21 -0
- package/lib/fakegato/fakegato-history.js +814 -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 +315 -0
- package/lib/homebridge-ui/server.js +10 -0
- package/lib/index.js +8 -0
- package/lib/platform.js +1423 -0
- package/lib/utils/colour.js +135 -0
- package/lib/utils/constants.js +129 -0
- package/lib/utils/eve-chars.js +130 -0
- package/lib/utils/functions.js +52 -0
- package/lib/utils/lang-en.js +125 -0
- package/package.json +70 -0
|
@@ -0,0 +1,468 @@
|
|
|
1
|
+
import { Builder, parseStringPromise } from 'xml2js'
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
decodeXML,
|
|
5
|
+
generateRandomString,
|
|
6
|
+
parseError,
|
|
7
|
+
sleep,
|
|
8
|
+
} from '../utils/functions.js'
|
|
9
|
+
import platformLang from '../utils/lang-en.js'
|
|
10
|
+
|
|
11
|
+
export default class {
|
|
12
|
+
constructor(platform, accessory) {
|
|
13
|
+
// Set up variables from the platform
|
|
14
|
+
this.hapChar = platform.api.hap.Characteristic
|
|
15
|
+
this.hapErr = platform.api.hap.HapStatusError
|
|
16
|
+
this.hapServ = platform.api.hap.Service
|
|
17
|
+
this.platform = platform
|
|
18
|
+
|
|
19
|
+
// Set up variables from the accessory
|
|
20
|
+
this.accessory = accessory
|
|
21
|
+
|
|
22
|
+
// Add the purifier service if it doesn't already exist
|
|
23
|
+
this.service = this.accessory.getService(this.hapServ.AirPurifier)
|
|
24
|
+
|| this.accessory.addService(this.hapServ.AirPurifier)
|
|
25
|
+
|
|
26
|
+
// Add the air quality service if it doesn't already exist
|
|
27
|
+
this.airService = this.accessory.getService(this.hapServ.AirQualitySensor)
|
|
28
|
+
|| this.accessory.addService(this.hapServ.AirQualitySensor, 'Air Quality', 'airquality')
|
|
29
|
+
|
|
30
|
+
// Add the (ionizer) switch service if it doesn't already exist
|
|
31
|
+
this.ioService = this.accessory.getService(this.hapServ.Switch)
|
|
32
|
+
|| this.accessory.addService(this.hapServ.Switch, 'Ionizer', 'ionizer')
|
|
33
|
+
|
|
34
|
+
// Add the set handler to the purifier active characteristic
|
|
35
|
+
this.service
|
|
36
|
+
.getCharacteristic(this.hapChar.Active)
|
|
37
|
+
.removeOnSet()
|
|
38
|
+
.onSet(async value => this.internalStateUpdate(value))
|
|
39
|
+
|
|
40
|
+
// Add options to the purifier target state characteristic
|
|
41
|
+
this.service
|
|
42
|
+
.getCharacteristic(this.hapChar.TargetAirPurifierState)
|
|
43
|
+
.updateValue(1)
|
|
44
|
+
.setProps({
|
|
45
|
+
minValue: 1,
|
|
46
|
+
maxValue: 1,
|
|
47
|
+
validValues: [1],
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
// Add the set handler to the purifier rotation speed (for mode) characteristic
|
|
51
|
+
this.service
|
|
52
|
+
.getCharacteristic(this.hapChar.RotationSpeed)
|
|
53
|
+
.setProps({ minStep: 25 })
|
|
54
|
+
.onSet(async (value) => {
|
|
55
|
+
await this.internalModeUpdate(value)
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
// Add the FilterChangeIndication characteristic to the air purifier if it isn't already
|
|
59
|
+
if (!this.service.testCharacteristic(this.hapChar.FilterChangeIndication)) {
|
|
60
|
+
this.service.addCharacteristic(this.hapChar.FilterChangeIndication)
|
|
61
|
+
}
|
|
62
|
+
this.cacheFilterX = this.service.getCharacteristic(this.hapChar.FilterChangeIndication).value
|
|
63
|
+
|
|
64
|
+
// Add the FilterLifeLevel characteristic to the air purifier if it isn't already
|
|
65
|
+
if (!this.service.testCharacteristic(this.hapChar.FilterLifeLevel)) {
|
|
66
|
+
this.service.addCharacteristic(this.hapChar.FilterLifeLevel)
|
|
67
|
+
}
|
|
68
|
+
this.cacheFilter = this.service.getCharacteristic(this.hapChar.FilterLifeLevel).value
|
|
69
|
+
|
|
70
|
+
// Add the set handler to the switch (for ionizer) characteristic
|
|
71
|
+
this.ioService.getCharacteristic(this.hapChar.On).onSet(async (value) => {
|
|
72
|
+
await this.internalIonizerUpdate(value)
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
// Add a last mode cache value if not already set
|
|
76
|
+
if (![1, 2, 3, 4].includes(this.accessory.context.cacheLastOnMode)) {
|
|
77
|
+
this.accessory.context.cacheLastOnMode = 1
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Add an ionizer on/off cache value if not already set
|
|
81
|
+
if (![0, 1].includes(this.accessory.context.cacheIonizerOn)) {
|
|
82
|
+
this.accessory.context.cacheIonizerOn = 0
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Some conversion objects
|
|
86
|
+
this.aqW2HK = {
|
|
87
|
+
0: 5, // poor -> poor
|
|
88
|
+
1: 3, // moderate -> fair
|
|
89
|
+
2: 1, // good -> excellent
|
|
90
|
+
}
|
|
91
|
+
this.aqLabels = {
|
|
92
|
+
5: platformLang.labelPoor,
|
|
93
|
+
3: platformLang.labelFair,
|
|
94
|
+
1: platformLang.labelExc,
|
|
95
|
+
}
|
|
96
|
+
this.modeLabels = {
|
|
97
|
+
0: platformLang.labelOff,
|
|
98
|
+
1: platformLang.labelLow,
|
|
99
|
+
2: platformLang.labelMed,
|
|
100
|
+
3: platformLang.labelHigh,
|
|
101
|
+
4: platformLang.labelAuto,
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Output the customised options to the log
|
|
105
|
+
const opts = JSON.stringify({
|
|
106
|
+
})
|
|
107
|
+
platform.log('[%s] %s %s.', accessory.displayName, platformLang.devInitOpts, opts)
|
|
108
|
+
|
|
109
|
+
// Request a device update immediately
|
|
110
|
+
this.requestDeviceUpdate()
|
|
111
|
+
|
|
112
|
+
// Start a polling interval if the user has disabled upnp
|
|
113
|
+
if (this.accessory.context.connection === 'http') {
|
|
114
|
+
this.pollingInterval = setInterval(
|
|
115
|
+
() => this.requestDeviceUpdate(),
|
|
116
|
+
platform.config.pollingInterval * 1000,
|
|
117
|
+
)
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
receiveDeviceUpdate(attribute) {
|
|
122
|
+
// Log the receiving update if debug is enabled
|
|
123
|
+
this.accessory.logDebug(`${platformLang.recUpd} [${attribute.name}: ${JSON.stringify(attribute.value)}]`)
|
|
124
|
+
|
|
125
|
+
// Check which attribute we are getting
|
|
126
|
+
switch (attribute.name) {
|
|
127
|
+
case 'AirQuality':
|
|
128
|
+
this.externalAirQualityUpdate(attribute.value)
|
|
129
|
+
break
|
|
130
|
+
case 'ExpiredFilterTime':
|
|
131
|
+
this.externalFilterChangeUpdate(attribute.value !== 0 ? 1 : 0)
|
|
132
|
+
break
|
|
133
|
+
case 'FilterLife':
|
|
134
|
+
this.externalFilterLifeUpdate(Math.round((attribute.value / 60480) * 100))
|
|
135
|
+
break
|
|
136
|
+
case 'Ionizer':
|
|
137
|
+
this.externalIonizerUpdate(attribute.value)
|
|
138
|
+
break
|
|
139
|
+
case 'Mode':
|
|
140
|
+
this.externalModeUpdate(attribute.value)
|
|
141
|
+
break
|
|
142
|
+
default:
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
async requestDeviceUpdate() {
|
|
147
|
+
try {
|
|
148
|
+
// Request the update
|
|
149
|
+
const data = await this.platform.httpClient.sendDeviceUpdate(
|
|
150
|
+
this.accessory,
|
|
151
|
+
'urn:Belkin:service:deviceevent:1',
|
|
152
|
+
'GetAttributes',
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
// Parse the response
|
|
156
|
+
const decoded = decodeXML(data.attributeList)
|
|
157
|
+
const xml = `<attributeList>${decoded}</attributeList>`
|
|
158
|
+
const result = await parseStringPromise(xml, { explicitArray: false })
|
|
159
|
+
Object.keys(result.attributeList.attribute).forEach((key) => {
|
|
160
|
+
// Only send the required attributes to the receiveDeviceUpdate function
|
|
161
|
+
switch (result.attributeList.attribute[key].name) {
|
|
162
|
+
case 'AirQuality':
|
|
163
|
+
case 'ExpiredFilterTime':
|
|
164
|
+
case 'FilterLife':
|
|
165
|
+
case 'Ionizer':
|
|
166
|
+
case 'Mode':
|
|
167
|
+
this.receiveDeviceUpdate({
|
|
168
|
+
name: result.attributeList.attribute[key].name,
|
|
169
|
+
value: Number.parseInt(result.attributeList.attribute[key].value, 10),
|
|
170
|
+
})
|
|
171
|
+
break
|
|
172
|
+
default:
|
|
173
|
+
}
|
|
174
|
+
})
|
|
175
|
+
} catch (err) {
|
|
176
|
+
const eText = parseError(err, [
|
|
177
|
+
platformLang.timeout,
|
|
178
|
+
platformLang.timeoutUnreach,
|
|
179
|
+
platformLang.noService,
|
|
180
|
+
])
|
|
181
|
+
this.accessory.logDebugWarn(`${platformLang.rduErr} ${eText}`)
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
async sendDeviceUpdate(attributes) {
|
|
186
|
+
// Log the sending update if debug is enabled
|
|
187
|
+
this.accessory.log(`${platformLang.senUpd} ${JSON.stringify(attributes)}`)
|
|
188
|
+
|
|
189
|
+
// Generate the XML to send
|
|
190
|
+
const builder = new Builder({
|
|
191
|
+
rootName: 'attribute',
|
|
192
|
+
headless: true,
|
|
193
|
+
renderOpts: { pretty: false },
|
|
194
|
+
})
|
|
195
|
+
const xmlAttributes = Object.keys(attributes)
|
|
196
|
+
.map(attributeKey => builder.buildObject({
|
|
197
|
+
name: attributeKey,
|
|
198
|
+
value: attributes[attributeKey],
|
|
199
|
+
}))
|
|
200
|
+
.join('')
|
|
201
|
+
|
|
202
|
+
// Send the update
|
|
203
|
+
await this.platform.httpClient.sendDeviceUpdate(
|
|
204
|
+
this.accessory,
|
|
205
|
+
'urn:Belkin:service:deviceevent:1',
|
|
206
|
+
'SetAttributes',
|
|
207
|
+
{
|
|
208
|
+
attributeList: { '#text': xmlAttributes },
|
|
209
|
+
},
|
|
210
|
+
)
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
async internalStateUpdate(value) {
|
|
214
|
+
const prevState = this.service.getCharacteristic(this.hapChar.Active).value
|
|
215
|
+
try {
|
|
216
|
+
// Don't continue if the state is the same as before
|
|
217
|
+
if (value === prevState) {
|
|
218
|
+
return
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// We also want to update the mode (by rotation speed)
|
|
222
|
+
let newSpeed = 0
|
|
223
|
+
if (value !== 0) {
|
|
224
|
+
// If turning on then we want to show the last used mode (by rotation speed)
|
|
225
|
+
switch (this.accessory.context.cacheLastOnMode) {
|
|
226
|
+
case 2:
|
|
227
|
+
newSpeed = 50
|
|
228
|
+
break
|
|
229
|
+
case 3:
|
|
230
|
+
newSpeed = 75
|
|
231
|
+
break
|
|
232
|
+
case 4:
|
|
233
|
+
newSpeed = 100
|
|
234
|
+
break
|
|
235
|
+
default:
|
|
236
|
+
newSpeed = 25
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// Update the rotation speed, use setCharacteristic so the set handler is run to send updates
|
|
241
|
+
this.service.setCharacteristic(this.hapChar.RotationSpeed, newSpeed)
|
|
242
|
+
|
|
243
|
+
// Update the characteristic if we are now ON ie purifying air
|
|
244
|
+
this.service.updateCharacteristic(
|
|
245
|
+
this.hapChar.CurrentAirPurifierState,
|
|
246
|
+
newSpeed === 0 ? 0 : 2,
|
|
247
|
+
)
|
|
248
|
+
|
|
249
|
+
// Update the ionizer characteristic if the purifier is on and the ionizer was on before
|
|
250
|
+
this.ioService.updateCharacteristic(
|
|
251
|
+
this.hapChar.On,
|
|
252
|
+
value === 1 && this.accessory.context.cacheIonizerOn === 1,
|
|
253
|
+
)
|
|
254
|
+
} catch (err) {
|
|
255
|
+
const eText = parseError(err, [platformLang.timeout, platformLang.timeoutUnreach])
|
|
256
|
+
this.accessory.logWarn(`${platformLang.cantCtl} ${eText}`)
|
|
257
|
+
|
|
258
|
+
// Throw a 'no response' error and set a timeout to revert this after 2 seconds
|
|
259
|
+
setTimeout(() => {
|
|
260
|
+
this.service.updateCharacteristic(this.hapChar.Active, prevState)
|
|
261
|
+
}, 2000)
|
|
262
|
+
throw new this.hapErr(-70402)
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
async internalModeUpdate(value) {
|
|
267
|
+
const prevSpeed = this.service.getCharacteristic(this.hapChar.RotationSpeed).value
|
|
268
|
+
try {
|
|
269
|
+
// Avoid multiple updates in quick succession
|
|
270
|
+
const updateKey = generateRandomString(5)
|
|
271
|
+
this.updateKey = updateKey
|
|
272
|
+
await sleep(500)
|
|
273
|
+
if (updateKey !== this.updateKey) {
|
|
274
|
+
return
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// Don't continue if the speed is the same as before
|
|
278
|
+
if (value === prevSpeed) {
|
|
279
|
+
return
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// Generate newValue for the needed mode depending on the new rotation speed value
|
|
283
|
+
let newValue = 0
|
|
284
|
+
if (value > 10 && value <= 35) {
|
|
285
|
+
newValue = 1
|
|
286
|
+
} else if (value > 35 && value <= 60) {
|
|
287
|
+
newValue = 2
|
|
288
|
+
} else if (value > 60 && value <= 85) {
|
|
289
|
+
newValue = 3
|
|
290
|
+
} else if (value > 85) {
|
|
291
|
+
newValue = 4
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// Send the update
|
|
295
|
+
await this.sendDeviceUpdate({
|
|
296
|
+
Mode: newValue.toString(),
|
|
297
|
+
})
|
|
298
|
+
|
|
299
|
+
// Update the cache last used mode if not turning off
|
|
300
|
+
if (newValue !== 0) {
|
|
301
|
+
this.accessory.context.cacheLastOnMode = newValue
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
// Log the new mode if appropriate
|
|
305
|
+
this.accessory.log(`${platformLang.curMode} [${this.modeLabels[newValue]}]`)
|
|
306
|
+
} catch (err) {
|
|
307
|
+
const eText = parseError(err, [platformLang.timeout, platformLang.timeoutUnreach])
|
|
308
|
+
this.accessory.logWarn(`${platformLang.cantCtl} ${eText}`)
|
|
309
|
+
|
|
310
|
+
// Throw a 'no response' error and set a timeout to revert this after 2 seconds
|
|
311
|
+
setTimeout(() => {
|
|
312
|
+
this.service.updateCharacteristic(this.hapChar.RotationSpeed, prevSpeed)
|
|
313
|
+
}, 2000)
|
|
314
|
+
throw new this.hapErr(-70402)
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
async internalIonizerUpdate(value) {
|
|
319
|
+
const prevState = this.ioService.getCharacteristic(this.hapChar.On).value
|
|
320
|
+
try {
|
|
321
|
+
// If turning on, but the purifier device is off, then turn the ionizer back off
|
|
322
|
+
if (value && this.service.getCharacteristic(this.hapChar.Active).value === 0) {
|
|
323
|
+
await sleep(1000)
|
|
324
|
+
this.ioService.updateCharacteristic(this.hapChar.On, false)
|
|
325
|
+
return
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
// Send the update
|
|
329
|
+
await this.sendDeviceUpdate({
|
|
330
|
+
Ionizer: value ? 1 : 0,
|
|
331
|
+
})
|
|
332
|
+
|
|
333
|
+
// Update the cache state of the ionizer
|
|
334
|
+
this.accessory.context.cacheIonizerOn = value ? 1 : 0
|
|
335
|
+
|
|
336
|
+
// Log the update if appropriate
|
|
337
|
+
this.accessory.log(`${platformLang.curIon} [${value ? 'on' : 'off'}}]`)
|
|
338
|
+
} catch (err) {
|
|
339
|
+
const eText = parseError(err, [platformLang.timeout, platformLang.timeoutUnreach])
|
|
340
|
+
this.accessory.logWarn(`${platformLang.cantCtl} ${eText}`)
|
|
341
|
+
|
|
342
|
+
// Throw a 'no response' error and set a timeout to revert this after 2 seconds
|
|
343
|
+
setTimeout(() => {
|
|
344
|
+
this.ioService.updateCharacteristic(this.hapChar.On, prevState)
|
|
345
|
+
}, 2000)
|
|
346
|
+
throw new this.hapErr(-70402)
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
externalModeUpdate(value) {
|
|
351
|
+
try {
|
|
352
|
+
// We want to find a rotation speed based on the given mode
|
|
353
|
+
let rotSpeed = 0
|
|
354
|
+
switch (value) {
|
|
355
|
+
case 1: {
|
|
356
|
+
rotSpeed = 25
|
|
357
|
+
break
|
|
358
|
+
}
|
|
359
|
+
case 2: {
|
|
360
|
+
rotSpeed = 50
|
|
361
|
+
break
|
|
362
|
+
}
|
|
363
|
+
case 3: {
|
|
364
|
+
rotSpeed = 75
|
|
365
|
+
break
|
|
366
|
+
}
|
|
367
|
+
case 4: {
|
|
368
|
+
rotSpeed = 100
|
|
369
|
+
break
|
|
370
|
+
}
|
|
371
|
+
default:
|
|
372
|
+
return
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
// Update the HomeKit characteristics
|
|
376
|
+
this.service.updateCharacteristic(this.hapChar.Active, value !== 0 ? 1 : 0)
|
|
377
|
+
this.service.updateCharacteristic(this.hapChar.RotationSpeed, rotSpeed)
|
|
378
|
+
|
|
379
|
+
// Turn the ionizer on or off based on whether the purifier is on or off
|
|
380
|
+
if (value === 0) {
|
|
381
|
+
this.ioService.updateCharacteristic(this.hapChar.On, false)
|
|
382
|
+
} else {
|
|
383
|
+
this.ioService.updateCharacteristic(
|
|
384
|
+
this.hapChar.On,
|
|
385
|
+
this.accessory.context.cacheIonizerOn === 1,
|
|
386
|
+
)
|
|
387
|
+
this.accessory.context.cacheLastOnMode = value
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
// Log the change if appropriate
|
|
391
|
+
this.accessory.log(`${platformLang.curMode} [${this.modeLabels[value]}]`)
|
|
392
|
+
} catch (err) {
|
|
393
|
+
this.accessory.logWarn(`${platformLang.cantUpd} ${parseError(err)}`)
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
externalAirQualityUpdate(value) {
|
|
398
|
+
try {
|
|
399
|
+
const newValue = this.aqW2HK[value]
|
|
400
|
+
// Don't continue if the value is the same as before
|
|
401
|
+
if (this.airService.getCharacteristic(this.hapChar.AirQuality).value === newValue) {
|
|
402
|
+
return
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
// Update the HomeKit characteristics
|
|
406
|
+
this.airService.updateCharacteristic(this.hapChar.AirQuality, newValue)
|
|
407
|
+
|
|
408
|
+
// Log the change if appropriate
|
|
409
|
+
this.accessory.log(`${platformLang.curAir} [${this.aqLabels[newValue]}]`)
|
|
410
|
+
} catch (err) {
|
|
411
|
+
this.accessory.logWarn(`${platformLang.cantUpd} ${parseError(err)}`)
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
externalIonizerUpdate(value) {
|
|
416
|
+
try {
|
|
417
|
+
// Don't continue if the value is the same as before
|
|
418
|
+
const state = this.ioService.getCharacteristic(this.hapChar.On).value ? 1 : 0
|
|
419
|
+
if (state === value) {
|
|
420
|
+
return
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
// Update the HomeKit characteristics
|
|
424
|
+
this.ioService.updateCharacteristic(this.hapChar.On, value === 1)
|
|
425
|
+
|
|
426
|
+
// Update the cache value and log the change if appropriate
|
|
427
|
+
this.accessory.context.cacheIonizerOn = value
|
|
428
|
+
this.accessory.log(`${platformLang.curIon} [${value === 1 ? 'on' : 'off'}]`)
|
|
429
|
+
} catch (err) {
|
|
430
|
+
this.accessory.logWarn(`${platformLang.cantUpd} ${parseError(err)}`)
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
externalFilterChangeUpdate(value) {
|
|
435
|
+
try {
|
|
436
|
+
// Don't continue if the value is the same as before
|
|
437
|
+
if (value === this.cacheFilterX) {
|
|
438
|
+
return
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
// Update the HomeKit characteristics
|
|
442
|
+
this.service.updateCharacteristic(this.hapChar.FilterChangeIndication, value)
|
|
443
|
+
|
|
444
|
+
// Update the cache value and log the change if appropriate
|
|
445
|
+
this.cacheFilterX = value
|
|
446
|
+
} catch (err) {
|
|
447
|
+
this.accessory.logWarn(`${platformLang.cantUpd} ${parseError(err)}`)
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
externalFilterLifeUpdate(value) {
|
|
452
|
+
try {
|
|
453
|
+
// Don't continue if the value is the same as before
|
|
454
|
+
if (value === this.cacheFilter) {
|
|
455
|
+
return
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
// Update the HomeKit characteristics
|
|
459
|
+
this.service.updateCharacteristic(this.hapChar.FilterLifeLevel, value)
|
|
460
|
+
|
|
461
|
+
// Update the cache value and log the change if appropriate
|
|
462
|
+
this.cacheFilter = value
|
|
463
|
+
this.accessory.log(`${platformLang.curFilter} [${value}%]`)
|
|
464
|
+
} catch (err) {
|
|
465
|
+
this.accessory.logWarn(`${platformLang.cantUpd} ${parseError(err)}`)
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
}
|