@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,327 @@
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
+
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 garage door service if it doesn't already exist
52
+ this.service = this.accessory.getService(this.hapServ.GarageDoorOpener)
53
+ if (!this.service) {
54
+ this.service = this.accessory.addService(this.hapServ.GarageDoorOpener)
55
+ this.service.updateCharacteristic(this.hapChar.CurrentDoorState, 1)
56
+ this.service.updateCharacteristic(this.hapChar.TargetDoorState, 1)
57
+ this.service.updateCharacteristic(this.hapChar.ObstructionDetected, false)
58
+ this.service.addCharacteristic(this.eveChar.LastActivation)
59
+ this.service.addCharacteristic(this.eveChar.ResetTotal)
60
+ this.service.addCharacteristic(this.eveChar.TimesOpened)
61
+ }
62
+
63
+ // Set up the device type and power readings if necessary
64
+ if (platformConsts.devices.switchSingle.includes(this.accessory.context.eweUIID)) {
65
+ this.setup = 'switchSingle'
66
+ } else if (platformConsts.devices.switchSinglePower.includes(this.accessory.context.eweUIID)) {
67
+ this.setup = 'switchSingle'
68
+
69
+ // Add Eve power characteristics
70
+ this.powerReadings = true
71
+ if (!this.service.testCharacteristic(this.eveChar.CurrentConsumption)) {
72
+ this.service.addCharacteristic(this.eveChar.CurrentConsumption)
73
+ }
74
+ if (this.accessory.context.eweUIID === 32) {
75
+ if (!this.service.testCharacteristic(this.eveChar.ElectricCurrent)) {
76
+ this.service.addCharacteristic(this.eveChar.ElectricCurrent)
77
+ }
78
+ if (!this.service.testCharacteristic(this.eveChar.Voltage)) {
79
+ this.service.addCharacteristic(this.eveChar.Voltage)
80
+ }
81
+ }
82
+ } else if (platformConsts.devices.switchMulti.includes(this.accessory.context.eweUIID)) {
83
+ this.setup = 'switchMulti'
84
+ if (platformConsts.devices.switchMultiPower.includes(this.accessory.context.eweUIID)) {
85
+ // Add Eve power characteristics
86
+ this.powerReadings = true
87
+ if (!this.service.testCharacteristic(this.eveChar.CurrentConsumption)) {
88
+ this.service.addCharacteristic(this.eveChar.CurrentConsumption)
89
+ }
90
+ if (!this.service.testCharacteristic(this.eveChar.ElectricCurrent)) {
91
+ this.service.addCharacteristic(this.eveChar.ElectricCurrent)
92
+ }
93
+ if (!this.service.testCharacteristic(this.eveChar.Voltage)) {
94
+ this.service.addCharacteristic(this.eveChar.Voltage)
95
+ }
96
+ this.isDualR3 = true
97
+ }
98
+ } else if (platformConsts.devices.switchSCM.includes(this.accessory.context.eweUIID)) {
99
+ this.setup = 'switchMulti'
100
+ } else if (platformConsts.devices.switchSCMPower.includes(this.accessory.context.eweUIID)) {
101
+ // Could do power here
102
+ this.setup = 'switchMulti'
103
+ }
104
+
105
+ // Add the set handler to the garage door reset total characteristic
106
+ this.service.getCharacteristic(this.eveChar.ResetTotal).onSet(() => {
107
+ this.service.updateCharacteristic(this.eveChar.TimesOpened, 0)
108
+ })
109
+
110
+ // Add the set handler to the target position characteristic
111
+ this.service.getCharacteristic(this.hapChar.TargetDoorState).onSet((value) => {
112
+ // We don't use await as we want the callback to be run straight away
113
+ this.internalStateUpdate(value)
114
+ })
115
+
116
+ // Add the get handlers only if the user hasn't disabled the disableNoResponse setting
117
+ if (!platform.config.disableNoResponse) {
118
+ this.service.getCharacteristic(this.hapChar.CurrentDoorState).onGet(() => {
119
+ if (!this.isOnline) {
120
+ throw new this.hapErr(-70402)
121
+ }
122
+ return this.service.getCharacteristic(this.hapChar.CurrentDoorState).value
123
+ })
124
+ this.service.getCharacteristic(this.hapChar.TargetDoorState).onGet(() => {
125
+ if (!this.isOnline) {
126
+ throw new this.hapErr(-70402)
127
+ }
128
+ return this.service.getCharacteristic(this.hapChar.TargetDoorState).value
129
+ })
130
+ }
131
+
132
+ // Update the obstruction detected to false on Homebridge restart
133
+ this.service.updateCharacteristic(this.hapChar.ObstructionDetected, false)
134
+
135
+ // Pass the accessory to Fakegato to set up with Eve
136
+ this.accessory.eveService = new platform.eveService('door', this.accessory, {
137
+ log: () => {},
138
+ })
139
+ this.accessory.eveService.addEntry({
140
+ status: this.service.getCharacteristic(this.hapChar.CurrentDoorState).value === 0 ? 0 : 1,
141
+ })
142
+
143
+ // Set up an interval to get eWeLink to send power updates
144
+ if (
145
+ this.powerReadings
146
+ && (!this.isDualR3 || (this.isDualR3 && platform.config.mode !== 'lan'))
147
+ ) {
148
+ setTimeout(() => {
149
+ this.internalUIUpdate()
150
+ this.intervalPoll = setInterval(() => this.internalUIUpdate(), 120000)
151
+ }, 5000)
152
+
153
+ // Stop the intervals on Homebridge shutdown
154
+ platform.api.on('shutdown', () => clearInterval(this.intervalPoll))
155
+ }
156
+
157
+ // Output the customised options to the log
158
+ const normalLogging = this.enableLogging ? 'standard' : 'disable'
159
+ const opts = JSON.stringify({
160
+ logging: this.enableDebugLogging ? 'debug' : normalLogging,
161
+ operationTime: this.operationTime,
162
+ showAs: 'gate',
163
+ })
164
+ this.log('[%s] %s %s.', this.name, this.lang.devInitOpts, opts)
165
+ }
166
+
167
+ async internalStateUpdate(value) {
168
+ try {
169
+ if (value === 1) {
170
+ this.service.updateCharacteristic(this.hapChar.CurrentDoorState, 1)
171
+ return
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.CurrentDoorState, 0)
193
+ this.accessory.eveService.addEntry({ status: 0 })
194
+ this.service.updateCharacteristic(
195
+ this.eveChar.LastActivation,
196
+ Math.round(new Date().valueOf() / 1000) - this.accessory.eveService.getInitialTime(),
197
+ )
198
+ this.service.updateCharacteristic(
199
+ this.eveChar.TimesOpened,
200
+ this.service.getCharacteristic(this.eveChar.TimesOpened).value + 1,
201
+ )
202
+ if (this.enableLogging) {
203
+ this.log('[%s] %s [%s].', this.name, this.lang.curState, this.lang.lockUnlocked)
204
+ }
205
+ await sleep(Math.max(this.operationTime * 100, 1000))
206
+ this.service.updateCharacteristic(this.hapChar.TargetDoorState, 1)
207
+ this.service.updateCharacteristic(this.hapChar.CurrentDoorState, 1)
208
+ this.accessory.eveService.addEntry({ status: 1 })
209
+ this.inUse = false
210
+ if (this.enableLogging) {
211
+ this.log('[%s] %s [%s].', this.name, this.lang.curState, this.lang.lockLocked)
212
+ }
213
+ } catch (err) {
214
+ this.inUse = false
215
+ this.platform.deviceUpdateError(this.accessory, err, true)
216
+ setTimeout(() => {
217
+ this.service.updateCharacteristic(this.hapChar.LockTargetState, 1)
218
+ }, 2000)
219
+ this.service.updateCharacteristic(this.hapChar.LockTargetState, new this.hapErr(-70402))
220
+ }
221
+ }
222
+
223
+ async internalUIUpdate() {
224
+ try {
225
+ // Skip polling if device isn't online
226
+ if (!this.isOnline) {
227
+ return
228
+ }
229
+
230
+ // Send the params to request the updates
231
+ if (this.isDualR3) {
232
+ await this.platform.sendDeviceUpdate(this.accessory, { uiActive: { outlet: 0, time: 120 } })
233
+ } else {
234
+ await this.platform.sendDeviceUpdate(this.accessory, { uiActive: 120 })
235
+ }
236
+ } catch (err) {
237
+ // Suppress errors here
238
+ }
239
+ }
240
+
241
+ async externalUpdate(params) {
242
+ try {
243
+ if (!this.inUse) {
244
+ if (
245
+ (this.setup === 'switchMulti' && params.switches && params.switches[0].switch === 'on')
246
+ || (this.setup === 'switchSingle' && params.switch && params.switch === 'on')
247
+ ) {
248
+ this.inUse = true
249
+ this.service.updateCharacteristic(this.hapChar.TargetDoorState, 0)
250
+ this.service.updateCharacteristic(this.hapChar.CurrentDoorState, 0)
251
+ this.accessory.eveService.addEntry({ status: 0 })
252
+ this.service.updateCharacteristic(
253
+ this.eveChar.LastActivation,
254
+ Math.round(new Date().valueOf() / 1000) - this.accessory.eveService.getInitialTime(),
255
+ )
256
+ this.service.updateCharacteristic(
257
+ this.eveChar.TimesOpened,
258
+ this.service.getCharacteristic(this.eveChar.TimesOpened).value + 1,
259
+ )
260
+ if (params.updateSource && this.enableLogging) {
261
+ this.log('[%s] %s [%s].', this.name, this.lang.curState, this.lang.lockUnlocked)
262
+ }
263
+ await sleep(Math.max(this.operationTime * 100, 1000))
264
+ this.service.updateCharacteristic(this.hapChar.TargetDoorState, 1)
265
+ this.service.updateCharacteristic(this.hapChar.CurrentDoorState, 1)
266
+ this.accessory.eveService.addEntry({ status: 1 })
267
+ this.inUse = false
268
+ if (params.updateSource && this.enableLogging) {
269
+ this.log('[%s] %s [%s].', this.name, this.lang.curState, this.lang.lockLocked)
270
+ }
271
+ }
272
+ }
273
+
274
+ // Get the power readings given by certain devices
275
+ if (!this.powerReadings) {
276
+ return
277
+ }
278
+ let logger = false
279
+ let power
280
+ let voltage
281
+ let current
282
+ if (hasProperty(params, 'actPow_00')) {
283
+ power = Number.parseInt(params.actPow_00, 10) / 100
284
+ this.service.updateCharacteristic(this.eveChar.CurrentConsumption, power)
285
+ logger = true
286
+ } else if (hasProperty(params, 'power')) {
287
+ power = Number.parseFloat(params.power)
288
+ this.service.updateCharacteristic(this.eveChar.CurrentConsumption, power)
289
+ logger = true
290
+ }
291
+ if (hasProperty(params, 'voltage_00')) {
292
+ voltage = Number.parseInt(params.voltage_00, 10) / 100
293
+ this.service.updateCharacteristic(this.eveChar.Voltage, voltage)
294
+ logger = true
295
+ } else if (hasProperty(params, 'voltage')) {
296
+ voltage = Number.parseFloat(params.voltage)
297
+ this.service.updateCharacteristic(this.eveChar.Voltage, voltage)
298
+ logger = true
299
+ }
300
+ if (hasProperty(params, 'current_00')) {
301
+ current = Number.parseInt(params.current_00, 10) / 100
302
+ this.service.updateCharacteristic(this.eveChar.ElectricCurrent, current)
303
+ logger = true
304
+ } else if (hasProperty(params, 'current')) {
305
+ current = Number.parseFloat(params.current)
306
+ this.service.updateCharacteristic(this.eveChar.ElectricCurrent, current)
307
+ logger = true
308
+ }
309
+ if (params.updateSource && logger && this.enableLogging) {
310
+ this.log(
311
+ '[%s] %s%s%s.',
312
+ this.name,
313
+ power !== undefined ? `${this.lang.curPower} [${power}W]` : '',
314
+ voltage !== undefined ? ` ${this.lang.curVolt} [${voltage}V]` : '',
315
+ current !== undefined ? ` ${this.lang.curCurr} [${current}A]` : '',
316
+ )
317
+ }
318
+ } catch (err) {
319
+ this.inUse = false
320
+ this.platform.deviceUpdateError(this.accessory, err, false)
321
+ }
322
+ }
323
+
324
+ markStatus(isOnline) {
325
+ this.isOnline = isOnline
326
+ }
327
+ }