@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.
Files changed (113) hide show
  1. package/CHANGELOG.md +1363 -0
  2. package/LICENSE +21 -0
  3. package/README.md +68 -0
  4. package/config.schema.json +1757 -0
  5. package/eslint.config.js +15 -0
  6. package/lib/connection/api.js +508 -0
  7. package/lib/connection/http.js +304 -0
  8. package/lib/connection/lan.js +318 -0
  9. package/lib/connection/ws.js +414 -0
  10. package/lib/device/curtain.js +324 -0
  11. package/lib/device/diffuser.js +473 -0
  12. package/lib/device/fan.js +349 -0
  13. package/lib/device/group.js +106 -0
  14. package/lib/device/humidifier.js +199 -0
  15. package/lib/device/index.js +61 -0
  16. package/lib/device/light-cct.js +333 -0
  17. package/lib/device/light-dimmer.js +257 -0
  18. package/lib/device/light-rgb-cct.js +809 -0
  19. package/lib/device/light-rgb.js +272 -0
  20. package/lib/device/motor.js +363 -0
  21. package/lib/device/outlet-multi.js +417 -0
  22. package/lib/device/outlet-single-inched.js +409 -0
  23. package/lib/device/outlet-single.js +384 -0
  24. package/lib/device/panel.js +382 -0
  25. package/lib/device/rf-bridge.js +321 -0
  26. package/lib/device/rf-button.js +125 -0
  27. package/lib/device/rf-sensor.js +173 -0
  28. package/lib/device/sensor-ambient.js +311 -0
  29. package/lib/device/sensor-contact.js +140 -0
  30. package/lib/device/sensor-temp-humi.js +182 -0
  31. package/lib/device/simulation/blind.js +253 -0
  32. package/lib/device/simulation/cooler.js +312 -0
  33. package/lib/device/simulation/door.js +253 -0
  34. package/lib/device/simulation/doorbell.js +190 -0
  35. package/lib/device/simulation/garage-eachen.js +235 -0
  36. package/lib/device/simulation/garage-four.js +176 -0
  37. package/lib/device/simulation/garage-od-switch.js +36 -0
  38. package/lib/device/simulation/garage-one.js +395 -0
  39. package/lib/device/simulation/garage-two.js +394 -0
  40. package/lib/device/simulation/gate-one.js +327 -0
  41. package/lib/device/simulation/heater.js +389 -0
  42. package/lib/device/simulation/index.js +75 -0
  43. package/lib/device/simulation/light-fan.js +258 -0
  44. package/lib/device/simulation/lock-eachen.js +163 -0
  45. package/lib/device/simulation/lock-one.js +366 -0
  46. package/lib/device/simulation/p-button.js +223 -0
  47. package/lib/device/simulation/purifier.js +289 -0
  48. package/lib/device/simulation/rf-blind.js +192 -0
  49. package/lib/device/simulation/rf-door.js +180 -0
  50. package/lib/device/simulation/rf-window.js +180 -0
  51. package/lib/device/simulation/sensor-hidden.js +105 -0
  52. package/lib/device/simulation/sensor-leak.js +123 -0
  53. package/lib/device/simulation/sensor-visible.js +231 -0
  54. package/lib/device/simulation/sensor.js +300 -0
  55. package/lib/device/simulation/switch-valve.js +351 -0
  56. package/lib/device/simulation/tap-one.js +283 -0
  57. package/lib/device/simulation/tap-two.js +266 -0
  58. package/lib/device/simulation/th-cooler.js +443 -0
  59. package/lib/device/simulation/th-dehumidifier.js +424 -0
  60. package/lib/device/simulation/th-heater.js +449 -0
  61. package/lib/device/simulation/th-humidifier.js +424 -0
  62. package/lib/device/simulation/th-thermostat.js +611 -0
  63. package/lib/device/simulation/tv.js +252 -0
  64. package/lib/device/simulation/valve-four.js +232 -0
  65. package/lib/device/simulation/valve-one.js +345 -0
  66. package/lib/device/simulation/valve-two.js +340 -0
  67. package/lib/device/simulation/window.js +253 -0
  68. package/lib/device/switch-man.js +106 -0
  69. package/lib/device/switch-mate.js +82 -0
  70. package/lib/device/switch-multi.js +411 -0
  71. package/lib/device/switch-single-inched.js +332 -0
  72. package/lib/device/switch-single.js +307 -0
  73. package/lib/device/template.js +43 -0
  74. package/lib/device/thermostat.js +286 -0
  75. package/lib/device/zigbee/index.js +27 -0
  76. package/lib/device/zigbee/light-cct.js +263 -0
  77. package/lib/device/zigbee/light-dimmer.js +148 -0
  78. package/lib/device/zigbee/light-rgb-cct.js +400 -0
  79. package/lib/device/zigbee/motor.js +301 -0
  80. package/lib/device/zigbee/sensor-ambient.js +177 -0
  81. package/lib/device/zigbee/sensor-contact.js +137 -0
  82. package/lib/device/zigbee/sensor-leak.js +119 -0
  83. package/lib/device/zigbee/sensor-motion.js +119 -0
  84. package/lib/device/zigbee/sensor-occupancy.js +119 -0
  85. package/lib/device/zigbee/sensor-smoke.js +96 -0
  86. package/lib/device/zigbee/switch-stateless.js +104 -0
  87. package/lib/device/zigbee/thermostat.js +323 -0
  88. package/lib/fakegato/LICENSE +21 -0
  89. package/lib/fakegato/fakegato-history.js +813 -0
  90. package/lib/fakegato/fakegato-storage.js +108 -0
  91. package/lib/fakegato/fakegato-timer.js +125 -0
  92. package/lib/fakegato/uuid.js +27 -0
  93. package/lib/homebridge-ui/public/index.html +365 -0
  94. package/lib/homebridge-ui/server.js +46 -0
  95. package/lib/index.js +7 -0
  96. package/lib/node-dns-sd/LICENSE +21 -0
  97. package/lib/node-dns-sd/README.md +613 -0
  98. package/lib/node-dns-sd/lib/dns-sd-classes.json +6 -0
  99. package/lib/node-dns-sd/lib/dns-sd-composer.js +83 -0
  100. package/lib/node-dns-sd/lib/dns-sd-parser.js +344 -0
  101. package/lib/node-dns-sd/lib/dns-sd-types.json +52 -0
  102. package/lib/node-dns-sd/lib/dns-sd.js +580 -0
  103. package/lib/platform.js +2156 -0
  104. package/lib/utils/colour.js +552 -0
  105. package/lib/utils/constants.js +589 -0
  106. package/lib/utils/custom-chars.js +33 -0
  107. package/lib/utils/eve-chars.js +130 -0
  108. package/lib/utils/functions.js +42 -0
  109. package/lib/utils/lang-en.js +160 -0
  110. package/lib/utils/lang-fr.js +163 -0
  111. package/lib/utils/lang-th.js +160 -0
  112. package/lib/utils/lang.js +5 -0
  113. package/package.json +75 -0
@@ -0,0 +1,424 @@
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.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
+ // 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
+ this.humiOffset = deviceConf.humidityOffset
26
+ ? Number.parseInt(deviceConf.humidityOffset, 10)
27
+ : platformConsts.defaultValues.humidityOffset
28
+ this.humiOffsetFactor = deviceConf.humidityOffsetFactor
29
+
30
+ // Set the correct logging variables for this accessory
31
+ switch (deviceConf.overrideLogging) {
32
+ case 'standard':
33
+ this.enableLogging = true
34
+ this.enableDebugLogging = false
35
+ break
36
+ case 'debug':
37
+ this.enableLogging = true
38
+ this.enableDebugLogging = true
39
+ break
40
+ case 'disable':
41
+ this.enableLogging = false
42
+ this.enableDebugLogging = false
43
+ break
44
+ default:
45
+ this.enableLogging = !platform.config.disableDeviceLogging
46
+ this.enableDebugLogging = platform.config.debug
47
+ break
48
+ }
49
+
50
+ // If the accessory has a switch service then remove it
51
+ if (this.accessory.getService(this.hapServ.Switch)) {
52
+ this.accessory.removeService(this.accessory.getService(this.hapServ.Switch))
53
+ }
54
+
55
+ // If the accessory has a temperature sensor service then remove it
56
+ if (this.accessory.getService(this.hapServ.TemperatureSensor)) {
57
+ this.accessory.removeService(this.accessory.getService(this.hapServ.TemperatureSensor))
58
+ }
59
+
60
+ // Set up the accessory with default target relative humidity when added the first time
61
+ if (!hasProperty(this.accessory.context, 'cacheTarget')) {
62
+ this.accessory.context.cacheTarget = 50
63
+ }
64
+
65
+ // Check to make sure user has not switched from humidifier to dehumidifier
66
+ if (this.accessory.context.cacheType !== 'dehumidifier') {
67
+ // Remove and re-setup as a HeaterCooler
68
+ if (this.accessory.getService(this.hapServ.HumidifierDehumidifier)) {
69
+ this.accessory.removeService(this.accessory.getService(this.hapServ.HumidifierDehumidifier))
70
+ }
71
+ this.accessory.context.cacheType = 'dehumidifier'
72
+ this.accessory.context.cacheTarget = 50
73
+ }
74
+
75
+ // If the accessory has a thermostat service then remove it
76
+ if (this.accessory.getService(this.hapServ.Thermostat)) {
77
+ this.accessory.removeService(this.accessory.getService(this.hapServ.Thermostat))
78
+ }
79
+
80
+ // If the accessory has a heater service then remove it
81
+ if (this.accessory.getService(this.hapServ.HeaterCooler)) {
82
+ this.accessory.removeService(this.accessory.getService(this.hapServ.HeaterCooler))
83
+ }
84
+
85
+ // If the accessory has a humidity sensor service then remove it
86
+ if (this.accessory.getService(this.hapServ.HumiditySensor)) {
87
+ this.accessory.removeService(this.accessory.getService(this.hapServ.HumiditySensor))
88
+ }
89
+
90
+ // Add the dehumidifier service if it doesn't already exist
91
+ this.service = this.accessory.getService(this.hapServ.HumidifierDehumidifier)
92
+ || this.accessory.addService(this.hapServ.HumidifierDehumidifier)
93
+
94
+ // Add the temperature sensor service if it doesn't already exist
95
+ this.tempService = this.accessory.getService(this.hapServ.TemperatureSensor)
96
+ || this.accessory.addService(this.hapServ.TemperatureSensor)
97
+ this.cacheTemp = this.tempService.getCharacteristic(this.hapChar.CurrentTemperature).value
98
+ this.updateCache()
99
+
100
+ // Set the dehumidifier as the primary service
101
+ this.service.setPrimaryService()
102
+
103
+ // Add the set handler to the humidifier active characteristic
104
+ this.service
105
+ .getCharacteristic(this.hapChar.Active)
106
+ .onSet(async value => this.internalStateUpdate(value))
107
+
108
+ // Add options to the target state characteristic
109
+ this.service
110
+ .getCharacteristic(this.hapChar.TargetHumidifierDehumidifierState)
111
+ .updateValue(2)
112
+ .setProps({
113
+ minValue: 2,
114
+ maxValue: 2,
115
+ validValues: [2],
116
+ })
117
+
118
+ // Add the set handler to the target relative humidity characteristic
119
+ this.service
120
+ .getCharacteristic(this.hapChar.RelativeHumidityDehumidifierThreshold)
121
+ .updateValue(this.accessory.context.cacheTarget)
122
+ .onSet(async value => this.internalTargetHumidityUpdate(value))
123
+
124
+ // Add the get handlers only if the user hasn't disabled the disableNoResponse setting
125
+ if (!platform.config.disableNoResponse) {
126
+ this.tempService.getCharacteristic(this.hapChar.CurrentTemperature).onGet(() => {
127
+ if (!this.isOnline) {
128
+ throw new this.hapErr(-70402)
129
+ }
130
+ return this.tempService.getCharacteristic(this.hapChar.CurrentTemperature).value
131
+ })
132
+ this.service.getCharacteristic(this.hapChar.Active).onGet(() => {
133
+ if (!this.isOnline) {
134
+ throw new this.hapErr(-70402)
135
+ }
136
+ return this.service.getCharacteristic(this.hapChar.Active).value
137
+ })
138
+ this.service.getCharacteristic(this.hapChar.CurrentHumidifierDehumidifierState).onGet(() => {
139
+ if (!this.isOnline) {
140
+ throw new this.hapErr(-70402)
141
+ }
142
+ return this.service.getCharacteristic(this.hapChar.CurrentHumidifierDehumidifierState).value
143
+ })
144
+ this.service.getCharacteristic(this.hapChar.TargetHumidifierDehumidifierState).onGet(() => {
145
+ if (!this.isOnline) {
146
+ throw new this.hapErr(-70402)
147
+ }
148
+ return this.service.getCharacteristic(this.hapChar.TargetHumidifierDehumidifierState).value
149
+ })
150
+ this.service.getCharacteristic(this.hapChar.CurrentRelativeHumidity).onGet(() => {
151
+ if (!this.isOnline) {
152
+ throw new this.hapErr(-70402)
153
+ }
154
+ return this.service.getCharacteristic(this.hapChar.CurrentRelativeHumidity).value
155
+ })
156
+ this.service
157
+ .getCharacteristic(this.hapChar.RelativeHumidityDehumidifierThreshold)
158
+ .updateValue(this.accessory.context.cacheTarget)
159
+ .onGet(() => {
160
+ if (!this.isOnline) {
161
+ throw new this.hapErr(-70402)
162
+ }
163
+ return this.service.getCharacteristic(this.hapChar.RelativeHumidityDehumidifierThreshold)
164
+ .value
165
+ })
166
+ }
167
+
168
+ // Initialise these caches now since they aren't determined by the initial externalUpdate()
169
+ this.cacheState = this.service.getCharacteristic(this.hapChar.Active).value === 1 ? 'on' : 'off'
170
+ this.cacheHumid = this.cacheState === 'on'
171
+ && this.service.getCharacteristic(this.hapChar.CurrentHumidifierDehumidifierState).value === 3
172
+ ? 'on'
173
+ : 'off'
174
+
175
+ // Pass the accessory to Fakegato to set up with Eve
176
+ this.accessory.eveService = new platform.eveService('custom', this.accessory, {
177
+ log: () => {},
178
+ })
179
+
180
+ // Set up an interval to get eWeLink to send regular temperature/humidity updates
181
+ if (platform.config.mode !== 'lan') {
182
+ setTimeout(() => {
183
+ this.internalUIUpdate()
184
+ this.intervalPoll = setInterval(() => this.internalUIUpdate(), 120000)
185
+ }, 5000)
186
+
187
+ // Stop the intervals on Homebridge shutdown
188
+ platform.api.on('shutdown', () => clearInterval(this.intervalPoll))
189
+ }
190
+
191
+ // Output the customised options to the log
192
+ const normalLogging = this.enableLogging ? 'standard' : 'disable'
193
+ const opts = JSON.stringify({
194
+ humidityOffset: this.humiOffset,
195
+ humidityOffsetFactor: this.humiOffsetFactor,
196
+ logging: this.enableDebugLogging ? 'debug' : normalLogging,
197
+ offset: this.tempOffset,
198
+ offsetFactor: this.tempOffsetFactor,
199
+ showAs: 'dehumidifier',
200
+ })
201
+ this.log('[%s] %s %s.', this.name, this.lang.devInitOpts, opts)
202
+ }
203
+
204
+ async internalStateUpdate(value) {
205
+ try {
206
+ const params = { deviceType: 'normal' }
207
+ let newState
208
+ let newHumid
209
+ if (value === 0) {
210
+ params.mainSwitch = 'off'
211
+ params.switch = 'off'
212
+ newState = 'off'
213
+ newHumid = 'off'
214
+ } else if (this.cacheHumi > this.accessory.context.cacheTarget) {
215
+ params.mainSwitch = 'on'
216
+ params.switch = 'on'
217
+ newState = 'on'
218
+ newHumid = 'on'
219
+ } else {
220
+ params.mainSwitch = 'off'
221
+ params.switch = 'off'
222
+ newState = 'on'
223
+ newHumid = 'off'
224
+ }
225
+
226
+ // Only send the update if either:
227
+ // * The new value (state) is OFF and the cacheHumid was ON
228
+ // * The new value (state) is ON and newHumid is 'on'
229
+ if ((value === 0 && this.cacheHumid === 'on') || (value === 1 && newHumid === 'on')) {
230
+ await this.platform.sendDeviceUpdate(this.accessory, params)
231
+ }
232
+ if (newState !== this.cacheState) {
233
+ this.cacheState = newState
234
+ if (this.enableLogging) {
235
+ this.log('[%s] %s [%s].', this.name, this.lang.curState, this.cacheState)
236
+ }
237
+ }
238
+ if (newHumid !== this.cacheHumid) {
239
+ this.cacheHumid = newHumid
240
+ if (this.enableLogging) {
241
+ this.log('[%s] %s [%s].', this.name, this.lang.curDehumid, this.cacheHumid)
242
+ }
243
+ }
244
+ const hapState = this.cacheHumid === 'on' ? 3 : 1
245
+ this.service.updateCharacteristic(
246
+ this.hapChar.CurrentHumidifierDehumidifierState,
247
+ value === 1 ? hapState : 0,
248
+ )
249
+ } catch (err) {
250
+ this.platform.deviceUpdateError(this.accessory, err, true)
251
+ setTimeout(() => {
252
+ this.service.updateCharacteristic(this.hapChar.Active, this.cacheState === 'on' ? 1 : 0)
253
+ }, 2000)
254
+ throw new this.hapErr(-70402)
255
+ }
256
+ }
257
+
258
+ async internalTargetHumidityUpdate(value) {
259
+ try {
260
+ if (value === this.accessory.context.cacheTarget) {
261
+ return
262
+ }
263
+ this.accessory.context.cacheTarget = value
264
+ if (this.enableLogging) {
265
+ this.log('[%s] %s [%s%].', this.name, this.lang.curTarg, value)
266
+ }
267
+ if (this.cacheState === 'off') {
268
+ return
269
+ }
270
+ const params = { deviceType: 'normal' }
271
+ let newHumid
272
+ if (this.cacheHumi > value) {
273
+ params.mainSwitch = 'on'
274
+ params.switch = 'on'
275
+ newHumid = 'on'
276
+ } else {
277
+ params.mainSwitch = 'off'
278
+ params.switch = 'off'
279
+ newHumid = 'off'
280
+ }
281
+ if (newHumid === this.cacheHumid) {
282
+ return
283
+ }
284
+ await this.platform.sendDeviceUpdate(this.accessory, params)
285
+ this.cacheHumid = newHumid
286
+ if (this.enableLogging) {
287
+ this.log('[%s] %s [%s].', this.name, this.lang.curDehumid, this.cacheHumid)
288
+ }
289
+ this.service.updateCharacteristic(
290
+ this.hapChar.CurrentHumidifierDehumidifierState,
291
+ this.cacheHumid === 'on' ? 3 : 1,
292
+ )
293
+ } catch (err) {
294
+ this.platform.deviceUpdateError(this.accessory, err, true)
295
+ setTimeout(() => {
296
+ this.service.updateCharacteristic(
297
+ this.hapChar.RelativeHumidityDehumidifierThreshold,
298
+ this.accessory.context.cacheTarget,
299
+ )
300
+ }, 2000)
301
+ throw new this.hapErr(-70402)
302
+ }
303
+ }
304
+
305
+ async internalCurrentHumidityUpdate() {
306
+ try {
307
+ if (this.cacheState === 'off') {
308
+ return
309
+ }
310
+ const params = { deviceType: 'normal' }
311
+ let newHumid
312
+ if (this.cacheHumi > this.accessory.context.cacheTarget) {
313
+ params.mainSwitch = 'on'
314
+ params.switch = 'on'
315
+ newHumid = 'on'
316
+ } else {
317
+ params.mainSwitch = 'off'
318
+ params.switch = 'off'
319
+ newHumid = 'off'
320
+ }
321
+ if (newHumid === this.cacheHumid) {
322
+ return
323
+ }
324
+ await this.platform.sendDeviceUpdate(this.accessory, params)
325
+ this.cacheHumid = newHumid
326
+ if (this.enableLogging) {
327
+ this.log('[%s] %s [%s].', this.name, this.lang.curDehumid, this.cacheHumid)
328
+ }
329
+ this.service.updateCharacteristic(
330
+ this.hapChar.CurrentHumidifierDehumidifierState,
331
+ this.cacheHumid === 'on' ? 3 : 1,
332
+ )
333
+ } catch (err) {
334
+ // Suppress errors here
335
+ }
336
+ }
337
+
338
+ async internalUIUpdate() {
339
+ try {
340
+ // Skip polling if device isn't online
341
+ if (!this.isOnline) {
342
+ return
343
+ }
344
+
345
+ // Send the params to request the updates
346
+ await this.platform.sendDeviceUpdate(this.accessory, { uiActive: 120 })
347
+ } catch (err) {
348
+ // Suppress errors here
349
+ }
350
+ }
351
+
352
+ async externalUpdate(params) {
353
+ try {
354
+ if (
355
+ hasProperty(params, 'currentTemperature')
356
+ && params.currentTemperature !== 'unavailable'
357
+ ) {
358
+ let newTemp = Number(params.currentTemperature)
359
+ if (this.tempOffsetFactor) {
360
+ newTemp *= this.tempOffset
361
+ } else {
362
+ newTemp += this.tempOffset
363
+ }
364
+ if (newTemp !== this.cacheTemp) {
365
+ this.cacheTemp = newTemp
366
+ this.tempService.updateCharacteristic(this.hapChar.CurrentTemperature, this.cacheTemp)
367
+ this.accessory.eveService.addEntry({ temp: this.cacheTemp })
368
+ if (params.updateSource && this.enableLogging) {
369
+ this.log('[%s] %s [%s°C].', this.name, this.lang.curTemp, this.cacheTemp)
370
+ }
371
+
372
+ // Update the cache file with the new temperature
373
+ this.updateCache()
374
+ }
375
+ }
376
+ if (
377
+ hasProperty(params, 'currentHumidity')
378
+ && params.currentHumidity !== 'unavailable'
379
+ ) {
380
+ let newHumi = Number.parseInt(params.currentHumidity, 10)
381
+ if (this.humiOffsetFactor) {
382
+ newHumi *= this.humiOffset
383
+ } else {
384
+ newHumi += this.humiOffset
385
+ }
386
+ newHumi = Math.max(Math.min(Number.parseInt(newHumi, 10), 100), 0)
387
+ if (newHumi !== this.cacheHumi) {
388
+ this.cacheHumi = newHumi
389
+ this.service.updateCharacteristic(this.hapChar.CurrentRelativeHumidity, this.cacheHumi)
390
+ this.accessory.eveService.addEntry({ humidity: this.cacheHumi })
391
+ if (params.updateSource && this.enableLogging) {
392
+ this.log('[%s] %s [%s%].', this.name, this.lang.curHumi, this.cacheHumi)
393
+ }
394
+ this.internalCurrentHumidityUpdate()
395
+ }
396
+ }
397
+ } catch (err) {
398
+ this.platform.deviceUpdateError(this.accessory, err, false)
399
+ }
400
+ }
401
+
402
+ async updateCache() {
403
+ // Don't continue if the storage client hasn't initialised properly
404
+ if (!this.platform.storageClientData) {
405
+ return
406
+ }
407
+
408
+ // Attempt to save the new temperature to the cache
409
+ try {
410
+ await this.platform.storageData.setItem(
411
+ `${this.accessory.context.eweDeviceId}_temp`,
412
+ this.cacheTemp,
413
+ )
414
+ } catch (err) {
415
+ if (this.enableLogging) {
416
+ this.log.warn('[%s] %s %s.', this.name, this.lang.storageWriteErr, parseError(err))
417
+ }
418
+ }
419
+ }
420
+
421
+ markStatus(isOnline) {
422
+ this.isOnline = isOnline
423
+ }
424
+ }