@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,345 @@
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
+ this.disableTimer = deviceConf.disableTimer
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
+ // If the accessory has a switch service then remove it
47
+ if (this.accessory.getService(this.hapServ.Switch)) {
48
+ this.accessory.removeService(this.accessory.getService(this.hapServ.Switch))
49
+ }
50
+
51
+ // Add the valve service if it doesn't already exist
52
+ this.service = this.accessory.getService(this.hapServ.Valve)
53
+ if (!this.service) {
54
+ this.service = this.accessory.addService(this.hapServ.Valve)
55
+ this.service.updateCharacteristic(this.hapChar.Active, 0)
56
+ this.service.updateCharacteristic(this.hapChar.InUse, 0)
57
+ this.service.updateCharacteristic(this.hapChar.ValveType, 1)
58
+ this.service.updateCharacteristic(this.hapChar.SetDuration, 120)
59
+ this.service.addCharacteristic(this.hapChar.RemainingDuration)
60
+ }
61
+
62
+ // Set up the device type and power readings if necessary
63
+ if (platformConsts.devices.switchSingle.includes(this.accessory.context.eweUIID)) {
64
+ this.setup = 'switchSingle'
65
+ } else if (platformConsts.devices.switchSinglePower.includes(this.accessory.context.eweUIID)) {
66
+ this.setup = 'switchSingle'
67
+
68
+ // Add Eve power characteristics
69
+ this.powerReadings = true
70
+ if (!this.service.testCharacteristic(this.eveChar.CurrentConsumption)) {
71
+ this.service.addCharacteristic(this.eveChar.CurrentConsumption)
72
+ }
73
+ if (this.accessory.context.eweUIID === 32) {
74
+ if (!this.service.testCharacteristic(this.eveChar.ElectricCurrent)) {
75
+ this.service.addCharacteristic(this.eveChar.ElectricCurrent)
76
+ }
77
+ if (!this.service.testCharacteristic(this.eveChar.Voltage)) {
78
+ this.service.addCharacteristic(this.eveChar.Voltage)
79
+ }
80
+ }
81
+ } else if (platformConsts.devices.switchMulti.includes(this.accessory.context.eweUIID)) {
82
+ this.setup = 'switchMulti'
83
+ if (platformConsts.devices.switchMultiPower.includes(this.accessory.context.eweUIID)) {
84
+ // Add Eve power characteristics
85
+ this.powerReadings = true
86
+ if (!this.service.testCharacteristic(this.eveChar.CurrentConsumption)) {
87
+ this.service.addCharacteristic(this.eveChar.CurrentConsumption)
88
+ }
89
+ if (!this.service.testCharacteristic(this.eveChar.ElectricCurrent)) {
90
+ this.service.addCharacteristic(this.eveChar.ElectricCurrent)
91
+ }
92
+ if (!this.service.testCharacteristic(this.eveChar.Voltage)) {
93
+ this.service.addCharacteristic(this.eveChar.Voltage)
94
+ }
95
+ this.isDualR3 = true
96
+ }
97
+ } else if (platformConsts.devices.switchSCM.includes(this.accessory.context.eweUIID)) {
98
+ this.setup = 'switchMulti'
99
+ } else if (platformConsts.devices.switchSCMPower.includes(this.accessory.context.eweUIID)) {
100
+ // Could do power here
101
+ this.setup = 'switchMulti'
102
+ }
103
+
104
+ // Add the set handler to the valve active characteristic
105
+ this.service
106
+ .getCharacteristic(this.hapChar.Active)
107
+ .onSet(async value => this.internalUpdate(value))
108
+
109
+ // Add the get handlers only if the user hasn't disabled the disableNoResponse setting
110
+ if (!platform.config.disableNoResponse) {
111
+ this.service.getCharacteristic(this.hapChar.Active).onGet(() => {
112
+ if (!this.isOnline) {
113
+ throw new this.hapErr(-70402)
114
+ }
115
+ return this.service.getCharacteristic(this.hapChar.Active).value
116
+ })
117
+ }
118
+
119
+ // Add the set handler to the valve set duration characteristic
120
+ if (this.disableTimer) {
121
+ if (this.service.testCharacteristic(this.hapChar.SetDuration)) {
122
+ this.service.removeCharacteristic(this.service.getCharacteristic(this.hapChar.SetDuration))
123
+ }
124
+ if (this.service.testCharacteristic(this.hapChar.RemainingDuration)) {
125
+ this.service.removeCharacteristic(
126
+ this.service.getCharacteristic(this.hapChar.RemainingDuration),
127
+ )
128
+ }
129
+ } else {
130
+ this.service.getCharacteristic(this.hapChar.SetDuration).onSet((value) => {
131
+ // Check if the valve is currently active
132
+ if (this.service.getCharacteristic(this.hapChar.InUse).value === 1) {
133
+ // Update the remaining duration characteristic with the new value
134
+ this.service.updateCharacteristic(this.hapChar.RemainingDuration, value)
135
+
136
+ // Clear any existing active timers
137
+ clearTimeout(this.timer)
138
+
139
+ // Set a new active timer with the new time amount
140
+ this.timer = setTimeout(
141
+ () => this.service.setCharacteristic(this.hapChar.Active, 0),
142
+ value * 1000,
143
+ )
144
+ }
145
+ })
146
+ }
147
+
148
+ // Set up an interval to get eWeLink to send power updates
149
+ if (
150
+ this.powerReadings
151
+ && (!this.isDualR3 || (this.isDualR3 && platform.config.mode !== 'lan'))
152
+ ) {
153
+ setTimeout(() => {
154
+ this.internalUIUpdate()
155
+ this.intervalPoll = setInterval(() => this.internalUIUpdate(), 120000)
156
+ }, 5000)
157
+
158
+ // Stop the intervals on Homebridge shutdown
159
+ platform.api.on('shutdown', () => clearInterval(this.intervalPoll))
160
+ }
161
+
162
+ // Output the customised options to the log
163
+ const normalLogging = this.enableLogging ? 'standard' : 'disable'
164
+ const opts = JSON.stringify({
165
+ disableTimer: this.disableTimer,
166
+ logging: this.enableDebugLogging ? 'debug' : normalLogging,
167
+ showAs: 'valve',
168
+ })
169
+ this.log('[%s] %s %s.', this.name, this.lang.devInitOpts, opts)
170
+ }
171
+
172
+ async internalUpdate(value) {
173
+ try {
174
+ const params = {}
175
+ switch (this.setup) {
176
+ case 'switchSingle':
177
+ params.switch = value ? 'on' : 'off'
178
+ break
179
+ case 'switchMulti':
180
+ params.switches = [
181
+ {
182
+ switch: value ? 'on' : 'off',
183
+ outlet: 0,
184
+ },
185
+ ]
186
+ break
187
+ default:
188
+ return
189
+ }
190
+ this.service.updateCharacteristic(this.hapChar.InUse, value)
191
+ switch (value) {
192
+ case 0:
193
+ if (!this.disableTimer) {
194
+ this.service.updateCharacteristic(this.hapChar.RemainingDuration, 0)
195
+ clearTimeout(this.timer)
196
+ }
197
+ if (this.enableLogging) {
198
+ this.log('[%s] %s [%s].', this.name, this.lang.curState, this.lang.valveNo)
199
+ }
200
+ break
201
+ case 1: {
202
+ if (!this.disableTimer) {
203
+ const timer = this.service.getCharacteristic(this.hapChar.SetDuration).value
204
+ this.service.updateCharacteristic(this.hapChar.RemainingDuration, timer)
205
+ this.timer = setTimeout(() => {
206
+ this.service.setCharacteristic(this.hapChar.Active, 0)
207
+ }, timer * 1000)
208
+ }
209
+ if (this.enableLogging) {
210
+ this.log('[%s] %s [%s].', this.name, this.lang.curState, this.lang.valveYes)
211
+ }
212
+ break
213
+ }
214
+ default:
215
+ return
216
+ }
217
+ await this.platform.sendDeviceUpdate(this.accessory, params)
218
+ } catch (err) {
219
+ this.platform.deviceUpdateError(this.accessory, err, true)
220
+ setTimeout(() => {
221
+ this.service.updateCharacteristic(this.hapChar.Active, value === 1 ? 0 : 1)
222
+ }, 2000)
223
+ throw new this.hapErr(-70402)
224
+ }
225
+ }
226
+
227
+ async internalUIUpdate() {
228
+ try {
229
+ // Skip polling if device isn't online
230
+ if (!this.isOnline) {
231
+ return
232
+ }
233
+
234
+ // Send the params to request the updates
235
+ if (this.isDualR3) {
236
+ await this.platform.sendDeviceUpdate(this.accessory, { uiActive: { outlet: 0, time: 120 } })
237
+ } else {
238
+ await this.platform.sendDeviceUpdate(this.accessory, { uiActive: 120 })
239
+ }
240
+ } catch (err) {
241
+ // Suppress errors here
242
+ }
243
+ }
244
+
245
+ async externalUpdate(params) {
246
+ try {
247
+ if (
248
+ (this.setup === 'switchMulti' && params.switches)
249
+ || (this.setup === 'switchSingle' && params.switch)
250
+ ) {
251
+ let newState
252
+ if (this.setup === 'switchMulti' && params.switches) {
253
+ newState = params.switches[0].switch
254
+ } else if (this.setup === 'switchSingle' && params.switch) {
255
+ newState = params.switch
256
+ }
257
+ if (newState === 'on') {
258
+ if (this.service.getCharacteristic(this.hapChar.Active).value === 0) {
259
+ this.service.updateCharacteristic(this.hapChar.Active, 1)
260
+ this.service.updateCharacteristic(this.hapChar.InUse, 1)
261
+ if (params.updateSource && this.enableLogging) {
262
+ this.log('[%s] %s [%s].', this.name, this.lang.curState, this.lang.valveYes)
263
+ }
264
+ if (!this.disableTimer) {
265
+ const timer = this.service.getCharacteristic(this.hapChar.SetDuration).value
266
+ this.service.updateCharacteristic(this.hapChar.RemainingDuration, timer)
267
+ this.timer = setTimeout(() => {
268
+ this.service.setCharacteristic(this.hapChar.Active, 0)
269
+ }, timer * 1000)
270
+ }
271
+ }
272
+ } else if (this.service.getCharacteristic(this.hapChar.Active).value === 1) {
273
+ this.service.updateCharacteristic(this.hapChar.Active, 0)
274
+ this.service.updateCharacteristic(this.hapChar.InUse, 0)
275
+ if (!this.disableTimer) {
276
+ this.service.updateCharacteristic(this.hapChar.RemainingDuration, 0)
277
+ clearTimeout(this.timer)
278
+ } else if (params.updateSource && this.enableLogging) {
279
+ this.log('[%s] %s [%s].', this.name, this.lang.curState, this.lang.valveNo)
280
+ }
281
+ }
282
+ }
283
+
284
+ // Get the power readings given by certain devices
285
+ if (!this.powerReadings) {
286
+ return
287
+ }
288
+ let logger = false
289
+ let power
290
+ let voltage
291
+ let current
292
+ if (hasProperty(params, 'actPow_00')) {
293
+ power = Number.parseInt(params.actPow_00, 10) / 100
294
+ this.service.updateCharacteristic(this.eveChar.CurrentConsumption, power)
295
+ logger = true
296
+ } else if (hasProperty(params, 'power')) {
297
+ power = Number.parseFloat(params.power)
298
+ this.service.updateCharacteristic(this.eveChar.CurrentConsumption, power)
299
+ logger = true
300
+ }
301
+ if (hasProperty(params, 'voltage_00')) {
302
+ voltage = Number.parseInt(params.voltage_00, 10) / 100
303
+ this.service.updateCharacteristic(this.eveChar.Voltage, voltage)
304
+ logger = true
305
+ } else if (hasProperty(params, 'voltage')) {
306
+ voltage = Number.parseFloat(params.voltage)
307
+ this.service.updateCharacteristic(this.eveChar.Voltage, voltage)
308
+ logger = true
309
+ }
310
+ if (hasProperty(params, 'current_00')) {
311
+ current = Number.parseInt(params.current_00, 10) / 100
312
+ this.service.updateCharacteristic(this.eveChar.ElectricCurrent, current)
313
+ logger = true
314
+ } else if (hasProperty(params, 'current')) {
315
+ current = Number.parseFloat(params.current)
316
+ this.service.updateCharacteristic(this.eveChar.ElectricCurrent, current)
317
+ logger = true
318
+ }
319
+ if (params.updateSource && logger && this.enableLogging) {
320
+ this.log(
321
+ '[%s] %s%s%s.',
322
+ this.name,
323
+ power !== undefined ? `${this.lang.curPower} [${power}W]` : '',
324
+ voltage !== undefined ? ` ${this.lang.curVolt} [${voltage}V]` : '',
325
+ current !== undefined ? ` ${this.lang.curCurr} [${current}A]` : '',
326
+ )
327
+ }
328
+ } catch (err) {
329
+ this.platform.deviceUpdateError(this.accessory, err, false)
330
+ }
331
+ }
332
+
333
+ currentState() {
334
+ return {
335
+ services: ['valve'],
336
+ valve: {
337
+ state: this.service.getCharacteristic(this.hapChar.Active).value === 1 ? 'on' : 'off',
338
+ },
339
+ }
340
+ }
341
+
342
+ markStatus(isOnline) {
343
+ this.isOnline = isOnline
344
+ }
345
+ }
@@ -0,0 +1,340 @@
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.disableTimer = deviceConf.disableTimer
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
+ // Certain devices give power readings
47
+ if (platformConsts.devices.switchMultiPower.includes(this.accessory.context.eweUIID)) {
48
+ this.powerReadings = true
49
+ }
50
+
51
+ // We want two valve services for this accessory
52
+ ['1', '2'].forEach((v) => {
53
+ // Add the valve service if it doesn't already exist
54
+ let valveService = this.accessory.getService(`Valve ${v}`)
55
+ if (!valveService) {
56
+ valveService = this.accessory.addService(this.hapServ.Valve, `Valve ${v}`, `valve${v}`)
57
+ valveService.updateCharacteristic(this.hapChar.Active, 0)
58
+ valveService.updateCharacteristic(this.hapChar.InUse, 0)
59
+ valveService.updateCharacteristic(this.hapChar.ValveType, 1)
60
+ if (!this.disableTimer) {
61
+ valveService.updateCharacteristic(this.hapChar.SetDuration, 120)
62
+ valveService.addCharacteristic(this.hapChar.RemainingDuration)
63
+ }
64
+ }
65
+
66
+ // Add Eve power characteristics
67
+ if (this.powerReadings) {
68
+ if (!valveService.testCharacteristic(this.eveChar.CurrentConsumption)) {
69
+ valveService.addCharacteristic(this.eveChar.CurrentConsumption)
70
+ }
71
+ if (!valveService.testCharacteristic(this.eveChar.ElectricCurrent)) {
72
+ valveService.addCharacteristic(this.eveChar.ElectricCurrent)
73
+ }
74
+ if (!valveService.testCharacteristic(this.eveChar.Voltage)) {
75
+ valveService.addCharacteristic(this.eveChar.Voltage)
76
+ }
77
+ }
78
+
79
+ // Add the set handler to the valve active characteristic
80
+ valveService
81
+ .getCharacteristic(this.hapChar.Active)
82
+ .onSet(async value => this.internalUpdate(`Valve ${v}`, value))
83
+
84
+ // Add the get handlers only if the user hasn't disabled the disableNoResponse setting
85
+ if (!platform.config.disableNoResponse) {
86
+ valveService.getCharacteristic(this.hapChar.Active).onGet(() => {
87
+ if (!this.isOnline) {
88
+ throw new this.hapErr(-70402)
89
+ }
90
+ return valveService.getCharacteristic(this.hapChar.Active).value
91
+ })
92
+ }
93
+
94
+ // Add the set handler to the valve set duration characteristic
95
+ if (this.disableTimer) {
96
+ if (valveService.testCharacteristic(this.hapChar.SetDuration)) {
97
+ valveService.removeCharacteristic(
98
+ valveService.getCharacteristic(this.hapChar.SetDuration),
99
+ )
100
+ }
101
+ if (valveService.testCharacteristic(this.hapChar.RemainingDuration)) {
102
+ valveService.removeCharacteristic(
103
+ valveService.getCharacteristic(this.hapChar.RemainingDuration),
104
+ )
105
+ }
106
+ } else {
107
+ valveService.getCharacteristic(this.hapChar.SetDuration).onSet((value) => {
108
+ // Check if the valve is currently active
109
+ if (valveService.getCharacteristic(this.hapChar.InUse).value === 1) {
110
+ // Update the remaining duration characteristic with the new value
111
+ valveService.updateCharacteristic(this.hapChar.RemainingDuration, value)
112
+
113
+ // Clear any existing active timers
114
+ clearTimeout(valveService.timer)
115
+
116
+ // Set a new active timer with the new time amount
117
+ valveService.timer = setTimeout(
118
+ () => valveService.setCharacteristic(this.hapChar.Active, 0),
119
+ value * 1000,
120
+ )
121
+ }
122
+ })
123
+ }
124
+ })
125
+
126
+ // Set up an interval to get eWeLink to send power updates
127
+ if (this.powerReadings && platform.config.mode !== 'lan') {
128
+ setTimeout(() => {
129
+ this.internalUIUpdate()
130
+ this.intervalPoll = setInterval(() => this.internalUIUpdate(), 120000)
131
+ }, 5000)
132
+
133
+ // Stop the intervals on Homebridge shutdown
134
+ platform.api.on('shutdown', () => clearInterval(this.intervalPoll))
135
+ }
136
+
137
+ // Output the customised options to the log
138
+ const normalLogging = this.enableLogging ? 'standard' : 'disable'
139
+ const opts = JSON.stringify({
140
+ disableTimer: this.disableTimer,
141
+ logging: this.enableDebugLogging ? 'debug' : normalLogging,
142
+ showAs: 'valve_two',
143
+ })
144
+ this.log('[%s] %s %s.', this.name, this.lang.devInitOpts, opts)
145
+ }
146
+
147
+ async internalUpdate(valve, value) {
148
+ try {
149
+ const params = {
150
+ switches: [],
151
+ }
152
+ const valveService = this.accessory.getService(valve)
153
+ switch (valve) {
154
+ case 'Valve 1':
155
+ params.switches.push({ switch: value ? 'on' : 'off', outlet: 0 })
156
+ break
157
+ case 'Valve 2':
158
+ params.switches.push({ switch: value ? 'on' : 'off', outlet: 1 })
159
+ break
160
+ default:
161
+ return
162
+ }
163
+ valveService.updateCharacteristic(this.hapChar.InUse, value)
164
+ switch (value) {
165
+ case 0:
166
+ if (!this.disableTimer) {
167
+ valveService.updateCharacteristic(this.hapChar.RemainingDuration, 0)
168
+ clearTimeout(this.accessory.getService(valve).timer)
169
+ }
170
+ if (this.enableLogging) {
171
+ this.log('[%s] [%s] %s [%s].', this.name, valve, this.lang.curState, this.lang.valveNo)
172
+ }
173
+ break
174
+ case 1: {
175
+ if (!this.disableTimer) {
176
+ const timer = valveService.getCharacteristic(this.hapChar.SetDuration).value
177
+ valveService.updateCharacteristic(this.hapChar.RemainingDuration, timer)
178
+ valveService.timer = setTimeout(() => {
179
+ valveService.setCharacteristic(this.hapChar.Active, 0)
180
+ }, timer * 1000)
181
+ }
182
+ if (this.enableLogging) {
183
+ this.log('[%s] [%s] %s [%s].', this.name, valve, this.lang.curState, this.lang.valveYes)
184
+ }
185
+ break
186
+ }
187
+ default:
188
+ return
189
+ }
190
+ await this.platform.sendDeviceUpdate(this.accessory, params)
191
+ } catch (err) {
192
+ this.platform.deviceUpdateError(this.accessory, err, true)
193
+ const valveService = this.accessory.getService(valve)
194
+ setTimeout(() => {
195
+ valveService.updateCharacteristic(this.hapChar.Active, value === 1 ? 0 : 1)
196
+ }, 2000)
197
+ throw new this.hapErr(-70402)
198
+ }
199
+ }
200
+
201
+ async internalUIUpdate() {
202
+ try {
203
+ // Skip polling if device isn't online
204
+ if (!this.isOnline) {
205
+ return
206
+ }
207
+
208
+ // Send the params to request the updates
209
+ await this.platform.sendDeviceUpdate(this.accessory, { uiActive: { outlet: 0, time: 120 } })
210
+ await sleep(2000)
211
+ await this.platform.sendDeviceUpdate(this.accessory, { uiActive: { outlet: 1, time: 120 } })
212
+ } catch (err) {
213
+ // Suppress errors here
214
+ }
215
+ }
216
+
217
+ async externalUpdate(params) {
218
+ try {
219
+ if (params.switches) {
220
+ ['1', '2'].forEach((v, k) => {
221
+ const valveService = this.accessory.getService(`Valve ${v}`)
222
+ if (params.switches[k].switch === 'on') {
223
+ if (valveService.getCharacteristic(this.hapChar.Active).value === 0) {
224
+ valveService.updateCharacteristic(this.hapChar.Active, 1)
225
+ valveService.updateCharacteristic(this.hapChar.InUse, 1)
226
+ if (!this.disableTimer) {
227
+ const timer = valveService.getCharacteristic(this.hapChar.SetDuration).value
228
+ valveService.updateCharacteristic(this.hapChar.RemainingDuration, timer)
229
+ valveService.timer = setTimeout(() => {
230
+ valveService.setCharacteristic(this.hapChar.Active, 0)
231
+ }, timer * 1000)
232
+ }
233
+ if (params.updateSource && this.enableLogging) {
234
+ this.log(
235
+ '[%s] [Valve %s] %s [%s].',
236
+ this.name,
237
+ v,
238
+ this.lang.curState,
239
+ this.lang.valveYes,
240
+ )
241
+ }
242
+ }
243
+ } else if (valveService.getCharacteristic(this.hapChar.Active).value === 1) {
244
+ valveService.updateCharacteristic(this.hapChar.Active, 0)
245
+ valveService.updateCharacteristic(this.hapChar.InUse, 0)
246
+ if (!this.disableTimer) {
247
+ valveService.updateCharacteristic(this.hapChar.RemainingDuration, 0)
248
+ clearTimeout(valveService.timer)
249
+ } else if (params.updateSource && this.enableLogging) {
250
+ this.log(
251
+ '[%s] [Valve %s] %s [%s].',
252
+ this.name,
253
+ v,
254
+ this.lang.curState,
255
+ this.lang.valveNo,
256
+ )
257
+ }
258
+ }
259
+ })
260
+ }
261
+
262
+ // Get the power readings given by certain devices
263
+ if (!this.powerReadings) {
264
+ return
265
+ }
266
+ let logger0 = false
267
+ let logger1 = false
268
+ let power0
269
+ let power1
270
+ let voltage0
271
+ let voltage1
272
+ let current0
273
+ let current1
274
+ if (hasProperty(params, 'actPow_00')) {
275
+ power0 = Number.parseInt(params.actPow_00, 10) / 100
276
+ this.accessory
277
+ .getService('Valve 1')
278
+ .updateCharacteristic(this.eveChar.CurrentConsumption, power0)
279
+ logger0 = true
280
+ }
281
+ if (hasProperty(params, 'actPow_01')) {
282
+ power1 = Number.parseInt(params.actPow_01, 10) / 100
283
+ this.accessory
284
+ .getService('Valve 2')
285
+ .updateCharacteristic(this.eveChar.CurrentConsumption, power1)
286
+ logger1 = true
287
+ }
288
+ if (hasProperty(params, 'voltage_00')) {
289
+ voltage0 = Number.parseInt(params.voltage_00, 10) / 100
290
+ this.accessory.getService('Valve 1').updateCharacteristic(this.eveChar.Voltage, voltage0)
291
+ logger0 = true
292
+ }
293
+ if (hasProperty(params, 'voltage_01')) {
294
+ voltage1 = Number.parseInt(params.voltage_01, 10) / 100
295
+ this.accessory.getService('Valve 2').updateCharacteristic(this.eveChar.Voltage, voltage1)
296
+ logger1 = true
297
+ }
298
+ if (hasProperty(params, 'current_00')) {
299
+ current0 = Number.parseInt(params.current_00, 10) / 100
300
+ this.accessory
301
+ .getService('Valve 1')
302
+ .updateCharacteristic(this.eveChar.ElectricCurrent, current0)
303
+ logger0 = true
304
+ }
305
+ if (hasProperty(params, 'current_01')) {
306
+ current1 = Number.parseInt(params.current_01, 10) / 100
307
+ this.accessory
308
+ .getService('Valve 2')
309
+ .updateCharacteristic(this.eveChar.ElectricCurrent, current1)
310
+ logger1 = true
311
+ }
312
+ if (params.updateSource && this.enableLogging) {
313
+ if (logger0) {
314
+ this.log(
315
+ '[%s] [Valve 1] %s%s%s.',
316
+ this.name,
317
+ power0 !== undefined ? `${this.lang.curPower} [${power0}W]` : '',
318
+ voltage0 !== undefined ? ` ${this.lang.curVolt} [${voltage0}V]` : '',
319
+ current0 !== undefined ? ` ${this.lang.curCurr} [${current0}A]` : '',
320
+ )
321
+ }
322
+ if (logger1) {
323
+ this.log(
324
+ '[%s] [Valve 2] %s%s%s.',
325
+ this.name,
326
+ power1 !== undefined ? `${this.lang.curPower} [${power1}W]` : '',
327
+ voltage1 !== undefined ? ` ${this.lang.curVolt} [${voltage1}V]` : '',
328
+ current1 !== undefined ? ` ${this.lang.curCurr} [${current1}A]` : '',
329
+ )
330
+ }
331
+ }
332
+ } catch (err) {
333
+ this.platform.deviceUpdateError(this.accessory, err, false)
334
+ }
335
+ }
336
+
337
+ markStatus(isOnline) {
338
+ this.isOnline = isOnline
339
+ }
340
+ }