@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,394 @@
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.operationTimeUp = deviceConf.operationTime || platformConsts.defaultValues.operationTime
25
+ this.operationTimeDown = deviceConf.operationTimeDown || this.operationTimeUp
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
+ // Set up the accessory with default positions when added the first time
48
+ if (!hasProperty(this.accessory.context, 'cacheCurrentDoorState')) {
49
+ this.accessory.context.cacheOneCurrentDoorState = 1
50
+ this.accessory.context.cacheOneTargetDoorState = 1
51
+ this.accessory.context.cacheTwoCurrentDoorState = 1
52
+ this.accessory.context.cacheTwoTargetDoorState = 1
53
+ }
54
+
55
+ // Certain devices give power readings
56
+ if (platformConsts.devices.switchMultiPower.includes(this.accessory.context.eweUIID)) {
57
+ this.powerReadings = true
58
+ }
59
+
60
+ // We want two garage door services for this accessory
61
+ ['1', '2'].forEach((v) => {
62
+ // Add the garage door service if it doesn't already exist
63
+ let gdService = this.accessory.getService(`Garage ${v}`)
64
+ if (!gdService) {
65
+ gdService = this.accessory.addService(this.hapServ.GarageDoorOpener, `Garage ${v}`, `garage${v}`)
66
+ gdService.updateCharacteristic(this.hapChar.CurrentDoorState, 1)
67
+ gdService.updateCharacteristic(this.hapChar.TargetDoorState, 1)
68
+ gdService.updateCharacteristic(this.hapChar.ObstructionDetected, false)
69
+ }
70
+
71
+ // Add Eve power characteristics
72
+ if (this.powerReadings) {
73
+ if (!gdService.testCharacteristic(this.eveChar.CurrentConsumption)) {
74
+ gdService.addCharacteristic(this.eveChar.CurrentConsumption)
75
+ }
76
+ if (!gdService.testCharacteristic(this.eveChar.ElectricCurrent)) {
77
+ gdService.addCharacteristic(this.eveChar.ElectricCurrent)
78
+ }
79
+ if (!gdService.testCharacteristic(this.eveChar.Voltage)) {
80
+ gdService.addCharacteristic(this.eveChar.Voltage)
81
+ }
82
+ }
83
+
84
+ // Add the set handler to the target position characteristic
85
+ gdService.getCharacteristic(this.hapChar.TargetDoorState).onSet((value) => {
86
+ // We don't use await as we want the callback to be run straight away
87
+ this.internalUpdate(`Garage ${v}`, value)
88
+ })
89
+
90
+ // Add the get handlers only if the user hasn't disabled the disableNoResponse setting
91
+ if (!platform.config.disableNoResponse) {
92
+ gdService.getCharacteristic(this.hapChar.CurrentDoorState).onGet(() => {
93
+ if (!this.isOnline) {
94
+ throw new this.hapErr(-70402)
95
+ }
96
+ return gdService.getCharacteristic(this.hapChar.CurrentDoorState).value
97
+ })
98
+ gdService.getCharacteristic(this.hapChar.TargetDoorState).onGet(() => {
99
+ if (!this.isOnline) {
100
+ throw new this.hapErr(-70402)
101
+ }
102
+ return gdService.getCharacteristic(this.hapChar.TargetDoorState).value
103
+ })
104
+ }
105
+ })
106
+
107
+ // Set up an interval to get eWeLink to send power updates
108
+ if (this.powerReadings && platform.config.mode !== 'lan') {
109
+ setTimeout(() => {
110
+ this.internalUIUpdate()
111
+ this.intervalPoll = setInterval(() => this.internalUIUpdate(), 120000)
112
+ }, 5000)
113
+
114
+ // Stop the intervals on Homebridge shutdown
115
+ platform.api.on('shutdown', () => clearInterval(this.intervalPoll))
116
+ }
117
+
118
+ // Output the customised options to the log
119
+ const normalLogging = this.enableLogging ? 'standard' : 'disable'
120
+ const opts = JSON.stringify({
121
+ logging: this.enableDebugLogging ? 'debug' : normalLogging,
122
+ operationTimeDown: this.operationTimeDown,
123
+ operationTimeUp: this.operationTimeUp,
124
+ showAs: 'garage_two',
125
+ })
126
+ this.log('[%s] %s %s.', this.name, this.lang.devInitOpts, opts)
127
+ }
128
+
129
+ async internalUpdate(garage, value) {
130
+ try {
131
+ const newPos = value
132
+ const params = {
133
+ switches: [],
134
+ }
135
+ const gdService = this.accessory.getService(garage)
136
+ const prevState = garage === 'Garage 1'
137
+ ? this.accessory.context.cacheOneCurrentDoorState
138
+ : this.accessory.context.cacheTwoCurrentDoorState
139
+ if (newPos === prevState % 2) {
140
+ return
141
+ }
142
+ this.inUse = true
143
+ gdService.updateCharacteristic(this.hapChar.TargetDoorState, newPos)
144
+ gdService.updateCharacteristic(this.hapChar.CurrentDoorState, newPos + 2)
145
+ switch (garage) {
146
+ case 'Garage 1': {
147
+ this.accessory.context.cacheOneTargetDoorState = newPos
148
+ this.accessory.context.cacheOneCurrentDoorState = newPos + 2
149
+ params.switches.push({
150
+ switch: newPos === 0 ? 'on' : 'off',
151
+ outlet: 0,
152
+ })
153
+ params.switches.push({
154
+ switch: newPos === 1 ? 'on' : 'off',
155
+ outlet: 1,
156
+ })
157
+ break
158
+ }
159
+ case 'Garage 2': {
160
+ this.accessory.context.cacheTwoTargetDoorState = newPos
161
+ this.accessory.context.cacheTwoCurrentDoorState = newPos + 2
162
+ params.switches.push({
163
+ switch: newPos === 0 ? 'on' : 'off',
164
+ outlet: 2,
165
+ })
166
+ params.switches.push({
167
+ switch: newPos === 1 ? 'on' : 'off',
168
+ outlet: 3,
169
+ })
170
+ break
171
+ }
172
+ default:
173
+ return
174
+ }
175
+ await this.platform.sendDeviceUpdate(this.accessory, params)
176
+ await sleep(2000)
177
+ this.inUse = false
178
+ const operationTime = newPos === 0 ? this.operationTimeUp : this.operationTimeDown
179
+ await sleep(Math.max((operationTime - 20) * 100, 0))
180
+ gdService.updateCharacteristic(this.hapChar.CurrentDoorState, newPos)
181
+ switch (garage) {
182
+ case 'Garage 1': {
183
+ this.accessory.context.cacheOneCurrentDoorState = newPos
184
+ if (this.enableLogging) {
185
+ this.log(
186
+ '[%s] [garage 1] %s [%s].',
187
+ this.name,
188
+ this.lang.curState,
189
+ newPos === 0 ? this.lang.doorOpen : this.lang.doorClosed,
190
+ )
191
+ }
192
+ break
193
+ }
194
+ case 'Garage 2': {
195
+ this.accessory.context.cacheTwoCurrentDoorState = newPos
196
+ if (this.enableLogging) {
197
+ this.log(
198
+ '[%s] [garage 2] %s [%s].',
199
+ this.name,
200
+ this.lang.curState,
201
+ newPos === 0 ? this.lang.doorOpen : this.lang.doorClosed,
202
+ )
203
+ }
204
+ break
205
+ }
206
+ default:
207
+ }
208
+ } catch (err) {
209
+ this.inUse = false
210
+ this.platform.deviceUpdateError(this.accessory, err, true)
211
+ const gdService = this.accessory.getService(garage)
212
+ setTimeout(() => {
213
+ gdService.updateCharacteristic(
214
+ this.hapChar.TargetDoorState,
215
+ this.accessory.context.cacheTargetDoorState,
216
+ )
217
+ }, 2000)
218
+ gdService.updateCharacteristic(this.hapChar.TargetDoorState, new this.hapErr(-70402))
219
+ }
220
+ }
221
+
222
+ async internalUIUpdate() {
223
+ try {
224
+ // Skip polling if device isn't online
225
+ if (!this.isOnline) {
226
+ return
227
+ }
228
+
229
+ // Send the params to request the updates
230
+ await this.platform.sendDeviceUpdate(this.accessory, { uiActive: { outlet: 0, time: 120 } })
231
+ await sleep(2000)
232
+ await this.platform.sendDeviceUpdate(this.accessory, { uiActive: { outlet: 1, time: 120 } })
233
+ } catch (err) {
234
+ // Suppress errors here
235
+ }
236
+ }
237
+
238
+ externalUpdate(params) {
239
+ try {
240
+ if (params.switches && !this.inUse) {
241
+ ['1', '2'].forEach(async (v) => {
242
+ const gcService = this.accessory.getService(`Garage ${v}`)
243
+ const prevState = v === '1'
244
+ ? this.accessory.context.cacheOneCurrentDoorState
245
+ : this.accessory.context.cacheTwoCurrentDoorState
246
+ const newPos = [0, 2].includes(prevState) ? 3 : 2
247
+ switch (v) {
248
+ case '1':
249
+ if (
250
+ params.switches[0].switch === params.switches[1].switch
251
+ || params.switches[prevState % 2].switch === 'on'
252
+ ) {
253
+ return
254
+ }
255
+ break
256
+ case '2':
257
+ if (
258
+ params.switches[2].switch === params.switches[3].switch
259
+ || params.switches[(prevState % 2) + 2].switch === 'on'
260
+ ) {
261
+ return
262
+ }
263
+ break
264
+ default:
265
+ return
266
+ }
267
+ this.inUse = true
268
+ gcService.updateCharacteristic(this.hapChar.TargetDoorState, newPos - 2)
269
+ gcService.updateCharacteristic(this.hapChar.CurrentDoorState, newPos)
270
+ switch (v) {
271
+ case '1':
272
+ this.accessory.context.cacheOneCurrentDoorState = newPos
273
+ this.accessory.context.cacheTwoTargetDoorState = newPos - 2
274
+ break
275
+ case '2':
276
+ this.accessory.context.cacheTwoCurrentDoorState = newPos
277
+ this.accessory.context.cacheTwoTargetDoorState = newPos - 2
278
+ break
279
+ default:
280
+ return
281
+ }
282
+ await sleep(2000)
283
+ this.inUse = false
284
+ const operationTime = newPos === 2 ? this.operationTimeUp : this.operationTimeDown
285
+ await sleep(Math.max((operationTime - 20) * 100, 0))
286
+ gcService.updateCharacteristic(this.hapChar.CurrentDoorState, newPos - 2)
287
+ switch (v) {
288
+ case '1':
289
+ this.accessory.context.cacheOneCurrentDoorState = newPos - 2
290
+ if (params.updateSource && this.enableLogging) {
291
+ this.log(
292
+ '[%s] [garage 1] %s [%s].',
293
+ this.name,
294
+ this.lang.curState,
295
+ newPos === 2 ? this.lang.doorOpen : this.lang.doorClosed,
296
+ )
297
+ }
298
+ break
299
+ case '2':
300
+ this.accessory.context.cacheTwoCurrentDoorState = newPos - 2
301
+ if (params.updateSource && this.enableLogging) {
302
+ this.log(
303
+ '[%s] [garage 2] %s [%s].',
304
+ this.name,
305
+ this.lang.curState,
306
+ newPos === 2 ? this.lang.doorOpen : this.lang.doorClosed,
307
+ )
308
+ }
309
+ break
310
+ default:
311
+ }
312
+ })
313
+ }
314
+
315
+ // Get the power readings given by certain devices
316
+ if (!this.powerReadings) {
317
+ return
318
+ }
319
+ let logger0 = false
320
+ let logger1 = false
321
+ let power0
322
+ let power1
323
+ let voltage0
324
+ let voltage1
325
+ let current0
326
+ let current1
327
+ if (hasProperty(params, 'actPow_00')) {
328
+ power0 = Number.parseInt(params.actPow_00, 10) / 100
329
+ this.accessory
330
+ .getService('Garage 1')
331
+ .updateCharacteristic(this.eveChar.CurrentConsumption, power0)
332
+ logger0 = true
333
+ }
334
+ if (hasProperty(params, 'actPow_01')) {
335
+ power1 = Number.parseInt(params.actPow_01, 10) / 100
336
+ this.accessory
337
+ .getService('Garage 2')
338
+ .updateCharacteristic(this.eveChar.CurrentConsumption, power1)
339
+ logger1 = true
340
+ }
341
+ if (hasProperty(params, 'voltage_00')) {
342
+ voltage0 = Number.parseInt(params.voltage_00, 10) / 100
343
+ this.accessory.getService('Garage 1').updateCharacteristic(this.eveChar.Voltage, voltage0)
344
+ logger0 = true
345
+ }
346
+ if (hasProperty(params, 'voltage_01')) {
347
+ voltage1 = Number.parseInt(params.voltage_01, 10) / 100
348
+ this.accessory.getService('Garage 2').updateCharacteristic(this.eveChar.Voltage, voltage1)
349
+ logger1 = true
350
+ }
351
+ if (hasProperty(params, 'current_00')) {
352
+ current0 = Number.parseInt(params.current_00, 10) / 100
353
+ this.accessory
354
+ .getService('Garage 1')
355
+ .updateCharacteristic(this.eveChar.ElectricCurrent, current0)
356
+ logger0 = true
357
+ }
358
+ if (hasProperty(params, 'current_01')) {
359
+ current1 = Number.parseInt(params.current_01, 10) / 100
360
+ this.accessory
361
+ .getService('Garage 2')
362
+ .updateCharacteristic(this.eveChar.ElectricCurrent, current1)
363
+ logger1 = true
364
+ }
365
+ if (params.updateSource && this.enableLogging) {
366
+ if (logger0) {
367
+ this.log(
368
+ '[%s] [garage 1] %s%s%s.',
369
+ this.name,
370
+ power0 !== undefined ? `${this.lang.curPower} [${power0}W]` : '',
371
+ voltage0 !== undefined ? ` ${this.lang.curVolt} [${voltage0}V]` : '',
372
+ current0 !== undefined ? ` ${this.lang.curCurr} [${current0}A]` : '',
373
+ )
374
+ }
375
+ if (logger1) {
376
+ this.log(
377
+ '[%s] [garage 2] %s%s%s.',
378
+ this.name,
379
+ power1 !== undefined ? `${this.lang.curPower} [${power1}W]` : '',
380
+ voltage1 !== undefined ? ` ${this.lang.curVolt} [${voltage1}V]` : '',
381
+ current1 !== undefined ? ` ${this.lang.curCurr} [${current1}A]` : '',
382
+ )
383
+ }
384
+ }
385
+ } catch (err) {
386
+ this.inUse = false
387
+ this.platform.deviceUpdateError(this.accessory, err, false)
388
+ }
389
+ }
390
+
391
+ markStatus(isOnline) {
392
+ this.isOnline = isOnline
393
+ }
394
+ }