@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,366 @@
1
+ import platformConsts from '../../utils/constants.js'
2
+ import { hasProperty, sleep } from '../../utils/functions.js'
3
+
4
+ export default class {
5
+ constructor(platform, accessory) {
6
+ // Set up variables from the platform
7
+ this.eveChar = platform.eveChar
8
+ this.hapChar = platform.api.hap.Characteristic
9
+ this.hapErr = platform.api.hap.HapStatusError
10
+ this.hapServ = platform.api.hap.Service
11
+ this.lang = platform.lang
12
+ this.log = platform.log
13
+ this.platform = platform
14
+
15
+ // Set up variables from the accessory
16
+ this.name = accessory.displayName
17
+ this.accessory = accessory
18
+
19
+ // Initially set the online flag as true (to be then updated as false if necessary)
20
+ this.isOnline = true
21
+
22
+ // Set up custom variables for this device type
23
+ const deviceConf = platform.deviceConf[accessory.context.eweDeviceId] || {}
24
+ this.operationTime = deviceConf.operationTime || platformConsts.defaultValues.operationTime
25
+ this.isManual = this.operationTime === 0
26
+
27
+ // Set the correct logging variables for this accessory
28
+ switch (deviceConf.overrideLogging) {
29
+ case 'standard':
30
+ this.enableLogging = true
31
+ this.enableDebugLogging = false
32
+ break
33
+ case 'debug':
34
+ this.enableLogging = true
35
+ this.enableDebugLogging = true
36
+ break
37
+ case 'disable':
38
+ this.enableLogging = false
39
+ this.enableDebugLogging = false
40
+ break
41
+ default:
42
+ this.enableLogging = !platform.config.disableDeviceLogging
43
+ this.enableDebugLogging = platform.config.debug
44
+ break
45
+ }
46
+
47
+ // Check the sensor is valid if defined by the user
48
+ if (deviceConf.sensorId) {
49
+ this.definedSensor = true
50
+ }
51
+
52
+ // If the accessory has a switch service then remove it
53
+ if (this.accessory.getService(this.hapServ.Switch)) {
54
+ this.accessory.removeService(this.accessory.getService(this.hapServ.Switch))
55
+ }
56
+
57
+ // Add the lock service if it doesn't already exist
58
+ this.service = this.accessory.getService(this.hapServ.LockMechanism)
59
+ || this.accessory.addService(this.hapServ.LockMechanism)
60
+
61
+ // Set up the device type and power readings if necessary
62
+ if (platformConsts.devices.switchSingle.includes(this.accessory.context.eweUIID)) {
63
+ this.setup = 'switchSingle'
64
+ } else if (platformConsts.devices.switchSinglePower.includes(this.accessory.context.eweUIID)) {
65
+ this.setup = 'switchSingle'
66
+
67
+ // Add Eve power characteristics
68
+ this.powerReadings = true
69
+ if (!this.service.testCharacteristic(this.eveChar.CurrentConsumption)) {
70
+ this.service.addCharacteristic(this.eveChar.CurrentConsumption)
71
+ }
72
+ if (this.accessory.context.eweUIID === 32) {
73
+ if (!this.service.testCharacteristic(this.eveChar.ElectricCurrent)) {
74
+ this.service.addCharacteristic(this.eveChar.ElectricCurrent)
75
+ }
76
+ if (!this.service.testCharacteristic(this.eveChar.Voltage)) {
77
+ this.service.addCharacteristic(this.eveChar.Voltage)
78
+ }
79
+ }
80
+ } else if (platformConsts.devices.switchMulti.includes(this.accessory.context.eweUIID)) {
81
+ this.setup = 'switchMulti'
82
+ if (platformConsts.devices.switchMultiPower.includes(this.accessory.context.eweUIID)) {
83
+ // Add Eve power characteristics
84
+ this.powerReadings = true
85
+ if (!this.service.testCharacteristic(this.eveChar.CurrentConsumption)) {
86
+ this.service.addCharacteristic(this.eveChar.CurrentConsumption)
87
+ }
88
+ if (!this.service.testCharacteristic(this.eveChar.ElectricCurrent)) {
89
+ this.service.addCharacteristic(this.eveChar.ElectricCurrent)
90
+ }
91
+ if (!this.service.testCharacteristic(this.eveChar.Voltage)) {
92
+ this.service.addCharacteristic(this.eveChar.Voltage)
93
+ }
94
+ this.isDualR3 = true
95
+ }
96
+ } else if (platformConsts.devices.switchSCM.includes(this.accessory.context.eweUIID)) {
97
+ this.setup = 'switchMulti'
98
+ } else if (platformConsts.devices.switchSCMPower.includes(this.accessory.context.eweUIID)) {
99
+ // Could do power here
100
+ this.setup = 'switchMulti'
101
+ }
102
+
103
+ // Add the set handler to the lock target state characteristic
104
+ this.service.getCharacteristic(this.hapChar.LockTargetState).onSet(async (value) => {
105
+ if (this.isManual) {
106
+ await this.internalManualUpdate(value)
107
+ } else {
108
+ // We don't use await as we want the callback to be run straight away
109
+ this.internalTimedUpdate(value)
110
+ }
111
+ })
112
+
113
+ // Add the get handlers only if the user hasn't disabled the disableNoResponse setting
114
+ if (!platform.config.disableNoResponse) {
115
+ this.service.getCharacteristic(this.hapChar.LockCurrentState).onGet(() => {
116
+ if (!this.isOnline) {
117
+ throw new this.hapErr(-70402)
118
+ }
119
+ return this.service.getCharacteristic(this.hapChar.LockCurrentState).value
120
+ })
121
+ this.service.getCharacteristic(this.hapChar.LockTargetState).onGet(() => {
122
+ if (!this.isOnline) {
123
+ throw new this.hapErr(-70402)
124
+ }
125
+ return this.service.getCharacteristic(this.hapChar.LockTargetState).value
126
+ })
127
+ }
128
+
129
+ // Always show the accessory as locked on Homebridge restart
130
+ this.service
131
+ .updateCharacteristic(this.hapChar.LockCurrentState, 1)
132
+ .updateCharacteristic(this.hapChar.LockTargetState, 1)
133
+ this.accessory.context.contactDetected = true
134
+
135
+ // Set up an interval to get eWeLink to send power updates
136
+ if (
137
+ this.powerReadings
138
+ && (!this.isDualR3 || (this.isDualR3 && platform.config.mode !== 'lan'))
139
+ ) {
140
+ setTimeout(() => {
141
+ this.internalUIUpdate()
142
+ this.intervalPoll = setInterval(() => this.internalUIUpdate(), 120000)
143
+ }, 5000)
144
+
145
+ // Stop the intervals on Homebridge shutdown
146
+ platform.api.on('shutdown', () => clearInterval(this.intervalPoll))
147
+ }
148
+
149
+ // Output the customised options to the log
150
+ const normalLogging = this.enableLogging ? 'standard' : 'disable'
151
+ const opts = JSON.stringify({
152
+ logging: this.enableDebugLogging ? 'debug' : normalLogging,
153
+ operationTime: this.operationTime,
154
+ showAs: 'lock',
155
+ })
156
+ this.log('[%s] %s %s.', this.name, this.lang.devInitOpts, opts)
157
+ }
158
+
159
+ async internalTimedUpdate(value) {
160
+ try {
161
+ if (value === 1) {
162
+ this.service.updateCharacteristic(this.hapChar.LockCurrentState, 1)
163
+ return
164
+ }
165
+
166
+ // This model may need a close command before opening again
167
+ if (this.accessory.context.eweModel === '0185') {
168
+ await this.platform.sendDeviceUpdate(this.accessory, {
169
+ switch: 'off',
170
+ })
171
+ await sleep(500)
172
+ }
173
+
174
+ const params = {}
175
+ switch (this.setup) {
176
+ case 'switchSingle':
177
+ params.switch = 'on'
178
+ break
179
+ case 'switchMulti':
180
+ params.switches = [
181
+ {
182
+ switch: 'on',
183
+ outlet: 0,
184
+ },
185
+ ]
186
+ break
187
+ default:
188
+ return
189
+ }
190
+ this.inUse = true
191
+ await this.platform.sendDeviceUpdate(this.accessory, params)
192
+ this.service.updateCharacteristic(this.hapChar.LockCurrentState, 0)
193
+ if (this.enableLogging) {
194
+ this.log('[%s] %s [%s].', this.name, this.lang.curState, this.lang.lockUnlocked)
195
+ }
196
+ if (this.definedSensor) {
197
+ this.internalSensorCheck()
198
+ return
199
+ }
200
+ await sleep(Math.max(this.operationTime * 100, 1000))
201
+ this.service.updateCharacteristic(this.hapChar.LockTargetState, 1)
202
+ this.service.updateCharacteristic(this.hapChar.LockCurrentState, 1)
203
+ this.inUse = false
204
+ if (this.enableLogging) {
205
+ this.log('[%s] %s [%s].', this.name, this.lang.curState, this.lang.lockLocked)
206
+ }
207
+ } catch (err) {
208
+ this.inUse = false
209
+ this.platform.deviceUpdateError(this.accessory, err, true)
210
+ setTimeout(() => {
211
+ this.service.updateCharacteristic(this.hapChar.LockTargetState, 1)
212
+ }, 2000)
213
+ this.service.updateCharacteristic(this.hapChar.LockTargetState, new this.hapErr(-70402))
214
+ }
215
+ }
216
+
217
+ async internalManualUpdate(value) {
218
+ try {
219
+ const newValue = value === 1 ? 'off' : 'on'
220
+ const newLang = value === 1 ? this.lang.lockLocked : this.lang.lockUnlocked
221
+
222
+ const params = {}
223
+ switch (this.setup) {
224
+ case 'switchSingle':
225
+ params.switch = newValue
226
+ break
227
+ case 'switchMulti':
228
+ params.switches = [
229
+ {
230
+ switch: newValue,
231
+ outlet: 0,
232
+ },
233
+ ]
234
+ break
235
+ default:
236
+ return
237
+ }
238
+
239
+ await this.platform.sendDeviceUpdate(this.accessory, params)
240
+ if (this.enableLogging) {
241
+ this.log('[%s] %s [%s].', this.name, this.lang.curState, newLang)
242
+ }
243
+ } catch (err) {
244
+ this.platform.deviceUpdateError(this.accessory, err, true)
245
+ setTimeout(() => {
246
+ this.service.updateCharacteristic(this.hapChar.LockTargetState, 1)
247
+ }, 2000)
248
+ this.service.updateCharacteristic(this.hapChar.LockTargetState, new this.hapErr(-70402))
249
+ }
250
+ }
251
+
252
+ async internalUIUpdate() {
253
+ try {
254
+ // Skip polling if device isn't online
255
+ if (!this.isOnline) {
256
+ return
257
+ }
258
+
259
+ // Send the params to request the updates
260
+ if (this.isDualR3) {
261
+ await this.platform.sendDeviceUpdate(this.accessory, { uiActive: { outlet: 0, time: 120 } })
262
+ } else {
263
+ await this.platform.sendDeviceUpdate(this.accessory, { uiActive: 120 })
264
+ }
265
+ } catch (err) {
266
+ // Suppress errors here
267
+ }
268
+ }
269
+
270
+ internalSensorCheck() {
271
+ if (this.timeoutInterval) {
272
+ clearTimeout(this.timeoutInterval)
273
+ }
274
+ this.timeoutInterval = setTimeout(() => {
275
+ if (this.accessory.context.contactDetected) {
276
+ this.service.updateCharacteristic(this.hapChar.LockCurrentState, 1)
277
+ this.service.updateCharacteristic(this.hapChar.LockTargetState, 1)
278
+ this.inUse = false
279
+ if (this.enableLogging) {
280
+ this.log('[%s] %s [%s].', this.name, this.lang.curState, this.lang.lockLocked)
281
+ }
282
+ }
283
+ }, this.operationTime * 100 + 50)
284
+ }
285
+
286
+ async externalUpdate(params) {
287
+ try {
288
+ if (!this.inUse && !this.isManual) {
289
+ if (
290
+ (this.setup === 'switchMulti' && params.switches && params.switches[0].switch === 'on')
291
+ || (this.setup === 'switchSingle' && params.switch && params.switch === 'on')
292
+ ) {
293
+ if (this.definedSensor) {
294
+ this.internalSensorCheck()
295
+ } else {
296
+ this.inUse = true
297
+ this.service.updateCharacteristic(this.hapChar.LockCurrentState, 0)
298
+ this.service.updateCharacteristic(this.hapChar.LockTargetState, 0)
299
+ if (params.updateSource && this.enableLogging) {
300
+ this.log('[%s] %s [%s].', this.name, this.lang.curState, this.lang.lockUnlocked)
301
+ }
302
+ await sleep(Math.max(this.operationTime * 100, 1000))
303
+ this.service.updateCharacteristic(this.hapChar.LockCurrentState, 1)
304
+ this.service.updateCharacteristic(this.hapChar.LockTargetState, 1)
305
+ this.inUse = false
306
+ if (params.updateSource && this.enableLogging) {
307
+ this.log('[%s] %s [%s].', this.name, this.lang.curState, this.lang.lockLocked)
308
+ }
309
+ }
310
+ }
311
+ }
312
+
313
+ // Get the power readings given by certain devices
314
+ if (!this.powerReadings) {
315
+ return
316
+ }
317
+ let logger = false
318
+ let power
319
+ let voltage
320
+ let current
321
+ if (hasProperty(params, 'actPow_00')) {
322
+ power = Number.parseInt(params.actPow_00, 10) / 100
323
+ this.service.updateCharacteristic(this.eveChar.CurrentConsumption, power)
324
+ logger = true
325
+ } else if (hasProperty(params, 'power')) {
326
+ power = Number.parseFloat(params.power)
327
+ this.service.updateCharacteristic(this.eveChar.CurrentConsumption, power)
328
+ logger = true
329
+ }
330
+ if (hasProperty(params, 'voltage_00')) {
331
+ voltage = Number.parseInt(params.voltage_00, 10) / 100
332
+ this.service.updateCharacteristic(this.eveChar.Voltage, voltage)
333
+ logger = true
334
+ } else if (hasProperty(params, 'voltage')) {
335
+ voltage = Number.parseFloat(params.voltage)
336
+ this.service.updateCharacteristic(this.eveChar.Voltage, voltage)
337
+ logger = true
338
+ }
339
+ if (hasProperty(params, 'current_00')) {
340
+ current = Number.parseInt(params.current_00, 10) / 100
341
+ this.service.updateCharacteristic(this.eveChar.ElectricCurrent, current)
342
+ logger = true
343
+ } else if (hasProperty(params, 'current')) {
344
+ current = Number.parseFloat(params.current)
345
+ this.service.updateCharacteristic(this.eveChar.ElectricCurrent, current)
346
+ logger = true
347
+ }
348
+ if (params.updateSource && logger && this.enableLogging) {
349
+ this.log(
350
+ '[%s] %s%s%s.',
351
+ this.name,
352
+ power !== undefined ? `${this.lang.curPower} [${power}W]` : '',
353
+ voltage !== undefined ? ` ${this.lang.curVolt} [${voltage}V]` : '',
354
+ current !== undefined ? ` ${this.lang.curCurr} [${current}A]` : '',
355
+ )
356
+ }
357
+ } catch (err) {
358
+ this.inUse = false
359
+ this.platform.deviceUpdateError(this.accessory, err, false)
360
+ }
361
+ }
362
+
363
+ markStatus(isOnline) {
364
+ this.isOnline = isOnline
365
+ }
366
+ }
@@ -0,0 +1,223 @@
1
+ import platformConsts from '../../utils/constants.js'
2
+ import { hasProperty } from '../../utils/functions.js'
3
+
4
+ export default class {
5
+ constructor(platform, accessory) {
6
+ // Set up variables from the platform
7
+ this.eveChar = platform.eveChar
8
+ this.hapChar = platform.api.hap.Characteristic
9
+ this.hapErr = platform.api.hap.HapStatusError
10
+ this.hapServ = platform.api.hap.Service
11
+ this.lang = platform.lang
12
+ this.log = platform.log
13
+ this.platform = platform
14
+
15
+ // Set up variables from the accessory
16
+ this.name = accessory.displayName
17
+ this.accessory = accessory
18
+
19
+ // Initially set the online flag as true (to be then updated as false if necessary)
20
+ this.isOnline = true
21
+
22
+ // Set up custom variables for this device type
23
+ const deviceConf = platform.deviceConf[accessory.context.eweDeviceId] || {}
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
+ // If the accessory has a switch service then remove it
46
+ if (this.accessory.getService(this.hapServ.Switch)) {
47
+ this.accessory.removeService(this.accessory.getService(this.hapServ.Switch))
48
+ }
49
+
50
+ // Add the stateless programmable switch service if it doesn't already exist
51
+ this.service = this.accessory.getService(this.hapServ.StatelessProgrammableSwitch)
52
+ || this.accessory.addService(this.hapServ.StatelessProgrammableSwitch)
53
+
54
+ // Remove the double and long press options
55
+ this.service.getCharacteristic(this.hapChar.ProgrammableSwitchEvent).setProps({
56
+ validValues: [0],
57
+ })
58
+
59
+ // Set up the device type and power readings if necessary
60
+ if (platformConsts.devices.switchSingle.includes(this.accessory.context.eweUIID)) {
61
+ this.setup = 'switchSingle'
62
+ } else if (platformConsts.devices.switchSinglePower.includes(this.accessory.context.eweUIID)) {
63
+ this.setup = 'switchSingle'
64
+
65
+ // Add Eve power characteristics
66
+ this.powerReadings = true
67
+ if (!this.service.testCharacteristic(this.eveChar.CurrentConsumption)) {
68
+ this.service.addCharacteristic(this.eveChar.CurrentConsumption)
69
+ }
70
+ if (this.accessory.context.eweUIID === 32) {
71
+ if (!this.service.testCharacteristic(this.eveChar.ElectricCurrent)) {
72
+ this.service.addCharacteristic(this.eveChar.ElectricCurrent)
73
+ }
74
+ if (!this.service.testCharacteristic(this.eveChar.Voltage)) {
75
+ this.service.addCharacteristic(this.eveChar.Voltage)
76
+ }
77
+ }
78
+ } else if (platformConsts.devices.switchMulti.includes(this.accessory.context.eweUIID)) {
79
+ this.setup = 'switchMulti'
80
+ if (platformConsts.devices.switchMultiPower.includes(this.accessory.context.eweUIID)) {
81
+ // Add Eve power characteristics
82
+ this.powerReadings = true
83
+ if (!this.service.testCharacteristic(this.eveChar.CurrentConsumption)) {
84
+ this.service.addCharacteristic(this.eveChar.CurrentConsumption)
85
+ }
86
+ if (!this.service.testCharacteristic(this.eveChar.ElectricCurrent)) {
87
+ this.service.addCharacteristic(this.eveChar.ElectricCurrent)
88
+ }
89
+ if (!this.service.testCharacteristic(this.eveChar.Voltage)) {
90
+ this.service.addCharacteristic(this.eveChar.Voltage)
91
+ }
92
+ this.isDualR3 = true
93
+ }
94
+ } else if (platformConsts.devices.switchSCM.includes(this.accessory.context.eweUIID)) {
95
+ this.setup = 'switchMulti'
96
+ } else if (platformConsts.devices.switchSCMPower.includes(this.accessory.context.eweUIID)) {
97
+ // Could do power here
98
+ this.setup = 'switchMulti'
99
+ }
100
+
101
+ // Add the get handlers only if the user hasn't disabled the disableNoResponse setting
102
+ if (!platform.config.disableNoResponse) {
103
+ this.service.getCharacteristic(this.hapChar.ProgrammableSwitchEvent).onGet(() => {
104
+ if (!this.isOnline) {
105
+ throw new this.hapErr(-70402)
106
+ }
107
+ return this.service.getCharacteristic(this.hapChar.ProgrammableSwitchEvent).value
108
+ })
109
+ }
110
+
111
+ // Set up an interval to get eWeLink to send power updates
112
+ if (
113
+ this.powerReadings
114
+ && (!this.isDualR3 || (this.isDualR3 && platform.config.mode !== 'lan'))
115
+ ) {
116
+ setTimeout(() => {
117
+ this.internalUIUpdate()
118
+ this.intervalPoll = setInterval(() => this.internalUIUpdate(), 120000)
119
+ }, 5000)
120
+
121
+ // Stop the intervals on Homebridge shutdown
122
+ platform.api.on('shutdown', () => clearInterval(this.intervalPoll))
123
+ }
124
+
125
+ // Output the customised options to the log
126
+ const normalLogging = this.enableLogging ? 'standard' : 'disable'
127
+ const opts = JSON.stringify({
128
+ logging: this.enableDebugLogging ? 'debug' : normalLogging,
129
+ showAs: 'p_button',
130
+ })
131
+ this.log('[%s] %s %s.', this.name, this.lang.devInitOpts, opts)
132
+ }
133
+
134
+ async internalUIUpdate() {
135
+ try {
136
+ // Skip polling if device isn't online
137
+ if (!this.isOnline) {
138
+ return
139
+ }
140
+
141
+ // Send the params to request the updates
142
+ if (this.isDualR3) {
143
+ await this.platform.sendDeviceUpdate(this.accessory, { uiActive: { outlet: 0, time: 120 } })
144
+ } else {
145
+ await this.platform.sendDeviceUpdate(this.accessory, { uiActive: 120 })
146
+ }
147
+ } catch (err) {
148
+ // Suppress errors here
149
+ }
150
+ }
151
+
152
+ async externalUpdate(params) {
153
+ try {
154
+ if (!this.inUse) {
155
+ if (
156
+ (this.setup === 'switchMulti' && params.switches && params.switches[0].switch === 'on')
157
+ || (this.setup === 'switchSingle' && params.switch && params.switch === 'on')
158
+ ) {
159
+ this.inUse = true
160
+ setTimeout(() => {
161
+ this.inUse = false
162
+ }, 2000)
163
+ this.service.updateCharacteristic(this.hapChar.ProgrammableSwitchEvent, 0)
164
+ if (params.updateSource && this.enableLogging) {
165
+ this.log('[%s] %s [%s].', this.name, this.lang.curState, this.lang.buttonSingle)
166
+ }
167
+ }
168
+ }
169
+
170
+ // Get the power readings given by certain devices
171
+ if (!this.powerReadings) {
172
+ return
173
+ }
174
+ let logger = false
175
+ let power
176
+ let voltage
177
+ let current
178
+ if (hasProperty(params, 'actPow_00')) {
179
+ power = Number.parseInt(params.actPow_00, 10) / 100
180
+ this.service.updateCharacteristic(this.eveChar.CurrentConsumption, power)
181
+ logger = true
182
+ } else if (hasProperty(params, 'power')) {
183
+ power = Number.parseFloat(params.power)
184
+ this.service.updateCharacteristic(this.eveChar.CurrentConsumption, power)
185
+ logger = true
186
+ }
187
+ if (hasProperty(params, 'voltage_00')) {
188
+ voltage = Number.parseInt(params.voltage_00, 10) / 100
189
+ this.service.updateCharacteristic(this.eveChar.Voltage, voltage)
190
+ logger = true
191
+ } else if (hasProperty(params, 'voltage')) {
192
+ voltage = Number.parseFloat(params.voltage)
193
+ this.service.updateCharacteristic(this.eveChar.Voltage, voltage)
194
+ logger = true
195
+ }
196
+ if (hasProperty(params, 'current_00')) {
197
+ current = Number.parseInt(params.current_00, 10) / 100
198
+ this.service.updateCharacteristic(this.eveChar.ElectricCurrent, current)
199
+ logger = true
200
+ } else if (hasProperty(params, 'current')) {
201
+ current = Number.parseFloat(params.current)
202
+ this.service.updateCharacteristic(this.eveChar.ElectricCurrent, current)
203
+ logger = true
204
+ }
205
+ if (params.updateSource && logger && this.enableLogging) {
206
+ this.log(
207
+ '[%s] %s%s%s.',
208
+ this.name,
209
+ power !== undefined ? `${this.lang.curPower} [${power}W]` : '',
210
+ voltage !== undefined ? ` ${this.lang.curVolt} [${voltage}V]` : '',
211
+ current !== undefined ? ` ${this.lang.curCurr} [${current}A]` : '',
212
+ )
213
+ }
214
+ } catch (err) {
215
+ this.inUse = false
216
+ this.platform.deviceUpdateError(this.accessory, err, false)
217
+ }
218
+ }
219
+
220
+ markStatus(isOnline) {
221
+ this.isOnline = isOnline
222
+ }
223
+ }