@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,324 @@
1
+ import platformConsts from '../utils/constants.js'
2
+ import { generateRandomString, hasProperty, sleep } from '../utils/functions.js'
3
+
4
+ export default class {
5
+ constructor(platform, accessory) {
6
+ // Set up variables from the platform
7
+ this.hapChar = platform.api.hap.Characteristic
8
+ this.hapErr = platform.api.hap.HapStatusError
9
+ this.hapServ = platform.api.hap.Service
10
+ this.lang = platform.lang
11
+ this.log = platform.log
12
+ this.platform = platform
13
+
14
+ // Set up variables from the accessory
15
+ this.name = accessory.displayName
16
+ this.accessory = accessory
17
+
18
+ // Initially set the online flag as true (to be then updated as false if necessary)
19
+ this.isOnline = true
20
+
21
+ // Set up custom variables for this device type
22
+ const deviceConf = platform.deviceConf[accessory.context.eweDeviceId] || {}
23
+ const showAsMotor = deviceConf.showAsMotor || platformConsts.defaultValues.showAsMotor
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
+ // Add the window covering service if it doesn't already exist
46
+ let service
47
+ switch (showAsMotor) {
48
+ case 'door':
49
+ service = this.hapServ.Door
50
+ if (this.accessory.getService(this.hapServ.GarageDoorOpener)) {
51
+ this.accessory.removeService(this.accessory.getService(this.hapServ.GarageDoorOpener))
52
+ }
53
+ if (this.accessory.getService(this.hapServ.Window)) {
54
+ this.accessory.removeService(this.accessory.getService(this.hapServ.Window))
55
+ }
56
+ if (this.accessory.getService(this.hapServ.WindowCovering)) {
57
+ this.accessory.removeService(this.accessory.getService(this.hapServ.WindowCovering))
58
+ }
59
+ break
60
+ case 'garage':
61
+ service = this.hapServ.GarageDoorOpener
62
+ this.isGarage = true
63
+ if (this.accessory.getService(this.hapServ.Door)) {
64
+ this.accessory.removeService(this.accessory.getService(this.hapServ.Door))
65
+ }
66
+ if (this.accessory.getService(this.hapServ.Window)) {
67
+ this.accessory.removeService(this.accessory.getService(this.hapServ.Window))
68
+ }
69
+ if (this.accessory.getService(this.hapServ.WindowCovering)) {
70
+ this.accessory.removeService(this.accessory.getService(this.hapServ.WindowCovering))
71
+ }
72
+ break
73
+ case 'window':
74
+ service = this.hapServ.Window
75
+ if (this.accessory.getService(this.hapServ.Door)) {
76
+ this.accessory.removeService(this.accessory.getService(this.hapServ.Door))
77
+ }
78
+ if (this.accessory.getService(this.hapServ.GarageDoorOpener)) {
79
+ this.accessory.removeService(this.accessory.getService(this.hapServ.GarageDoorOpener))
80
+ }
81
+ if (this.accessory.getService(this.hapServ.WindowCovering)) {
82
+ this.accessory.removeService(this.accessory.getService(this.hapServ.WindowCovering))
83
+ }
84
+ break
85
+ default:
86
+ service = this.hapServ.WindowCovering
87
+ if (this.accessory.getService(this.hapServ.Door)) {
88
+ this.accessory.removeService(this.accessory.getService(this.hapServ.Door))
89
+ }
90
+ if (this.accessory.getService(this.hapServ.GarageDoorOpener)) {
91
+ this.accessory.removeService(this.accessory.getService(this.hapServ.GarageDoorOpener))
92
+ }
93
+ if (this.accessory.getService(this.hapServ.Window)) {
94
+ this.accessory.removeService(this.accessory.getService(this.hapServ.Window))
95
+ }
96
+ break
97
+ }
98
+ this.service = this.accessory.getService(service) || this.accessory.addService(service)
99
+
100
+ // Add the set handler to the target position characteristic
101
+ if (this.isGarage) {
102
+ this.service
103
+ .getCharacteristic(this.hapChar.TargetDoorState)
104
+ .onSet(async value => this.internalTargetUpdate(value))
105
+ } else {
106
+ this.service
107
+ .getCharacteristic(this.hapChar.TargetPosition)
108
+ .onSet(async value => this.internalPositionUpdate(value))
109
+ }
110
+
111
+ // Add the get handlers only if the user hasn't disabled the disableNoResponse setting
112
+ if (!platform.config.disableNoResponse) {
113
+ if (this.isGarage) {
114
+ this.service.getCharacteristic(this.hapChar.CurrentDoorState).onGet(() => {
115
+ if (!this.isOnline) {
116
+ throw new this.hapErr(-70402)
117
+ }
118
+ return this.service.getCharacteristic(this.hapChar.CurrentDoorState).value
119
+ })
120
+ this.service.getCharacteristic(this.hapChar.TargetDoorState).onGet(() => {
121
+ if (!this.isOnline) {
122
+ throw new this.hapErr(-70402)
123
+ }
124
+ return this.service.getCharacteristic(this.hapChar.TargetDoorState).value
125
+ })
126
+ } else {
127
+ this.service.getCharacteristic(this.hapChar.CurrentPosition).onGet(() => {
128
+ if (!this.isOnline) {
129
+ throw new this.hapErr(-70402)
130
+ }
131
+ return this.service.getCharacteristic(this.hapChar.CurrentPosition).value
132
+ })
133
+ this.service.getCharacteristic(this.hapChar.TargetPosition).onGet(() => {
134
+ if (!this.isOnline) {
135
+ throw new this.hapErr(-70402)
136
+ }
137
+ return this.service.getCharacteristic(this.hapChar.TargetPosition).value
138
+ })
139
+ }
140
+ }
141
+
142
+ // Output the customised options to the log
143
+ const normalLogging = this.enableLogging ? 'standard' : 'disable'
144
+ const opts = JSON.stringify({
145
+ logging: this.enableDebugLogging ? 'debug' : normalLogging,
146
+ showAsMotor,
147
+ })
148
+ this.log('[%s] %s %s.', this.name, this.lang.devInitOpts, opts)
149
+
150
+ /*
151
+ Q1
152
+ {"op":3} -> command to close
153
+ {"op":3,"per":0} -> received when closed
154
+
155
+ {"op":1,} -> command to open
156
+ {"op":1,"per":100} -> received when open
157
+ */
158
+ }
159
+
160
+ async internalPositionUpdate(value) {
161
+ try {
162
+ // This acts like a debounce function when endlessly sliding the slider
163
+ const updateKey = generateRandomString(5)
164
+ this.updateKey = updateKey
165
+ await sleep(500)
166
+ if (updateKey !== this.updateKey) {
167
+ return
168
+ }
169
+
170
+ // Create the params object to send
171
+ const params = {}
172
+
173
+ switch (this.accessory.context.eweUIID) {
174
+ case 11:
175
+ // If we are to fully open/close the curtain we can use the switch param
176
+ if ([0, 100].includes(value)) {
177
+ // 'on' for fully open and 'off' for fully close
178
+ params.switch = value === 100 ? 'on' : 'off'
179
+ } else {
180
+ // Otherwise, for a %-point we can use the 'setclose' param
181
+ params.setclose = Math.abs(100 - value)
182
+ }
183
+ break
184
+ case 67:
185
+ // For a %-point we can use the 'per' param int[0=CLOSED, 100=OPEN]
186
+ params.per = value
187
+ break
188
+ default:
189
+ return
190
+ }
191
+
192
+ // Send the device update
193
+ await this.platform.sendDeviceUpdate(this.accessory, params)
194
+
195
+ // Update the cache with the new position
196
+ this.cachePos = value
197
+
198
+ // Log the update if appropriate
199
+ if (this.enableLogging) {
200
+ this.log('[%s] %s [%s%].', this.name, this.lang.curPos, this.cachePos)
201
+ }
202
+ } catch (err) {
203
+ // Catch any errors and let the platform display them
204
+ this.platform.deviceUpdateError(this.accessory, err, true)
205
+ setTimeout(() => {
206
+ this.service.updateCharacteristic(this.hapChar.TargetPosition, this.cachePos)
207
+ }, 2000)
208
+ throw new this.hapErr(-70402)
209
+ }
210
+ }
211
+
212
+ async internalTargetUpdate(value) {
213
+ try {
214
+ // value is 0 for open and 1 for closed
215
+ const params = {}
216
+ switch (this.accessory.context.eweUIID) {
217
+ case 11:
218
+ params.switch = value === 0 ? 'on' : 'off'
219
+ break
220
+ case 67:
221
+ params.op = value === 0 ? 1 : 3
222
+ break
223
+ default:
224
+ return
225
+ }
226
+ await this.platform.sendDeviceUpdate(this.accessory, params)
227
+ } catch (err) {
228
+ // Catch any errors and let the platform display them
229
+ this.platform.deviceUpdateError(this.accessory, err, true)
230
+ setTimeout(() => {
231
+ this.service.updateCharacteristic(this.hapChar.TargetDoorState, this.cachePos)
232
+ }, 2000)
233
+ throw new this.hapErr(-70402)
234
+ }
235
+ }
236
+
237
+ async externalUpdate(params) {
238
+ try {
239
+ // Don't continue if there are no useful parameters
240
+ if (this.isGarage) {
241
+ switch (this.accessory.context.eweUIID) {
242
+ case 11:
243
+ // Todo
244
+ break
245
+ case 67:
246
+ if (hasProperty(params, 'op') && hasProperty(params, 'per')) {
247
+ if (params.op === 3 && params.per === 0) {
248
+ // closed
249
+ if (this.cachePos !== 1) {
250
+ this.cachePos = 1
251
+ this.service.updateCharacteristic(this.hapChar.CurrentDoorState, 1)
252
+ this.service.updateCharacteristic(this.hapChar.TargetDoorState, 1)
253
+ if (params.updateSource && this.enableLogging) {
254
+ this.log('[%s] %s [%s].', this.name, this.lang.curState, this.lang.doorClosed)
255
+ }
256
+ }
257
+ } else if (params.op === 1 && params.per === 100) {
258
+ // open
259
+ if (this.cachePos !== 0) {
260
+ this.cachePos = 0
261
+ this.service.updateCharacteristic(this.hapChar.CurrentDoorState, 0)
262
+ this.service.updateCharacteristic(this.hapChar.TargetDoorState, 0)
263
+ if (params.updateSource && this.enableLogging) {
264
+ this.log('[%s] %s [%s].', this.name, this.lang.curState, this.lang.doorOpen)
265
+ }
266
+ }
267
+ }
268
+ }
269
+ break
270
+ default:
271
+ }
272
+ } else if (
273
+ params.switch
274
+ || hasProperty(params, 'setclose')
275
+ || hasProperty(params, 'per')
276
+ ) {
277
+ let newPos
278
+ switch (this.accessory.context.eweUIID) {
279
+ case 11:
280
+ // 'setclose' is 0=OPEN 100=CLOSED whereas HomeKit is 0=CLOSED 100=OPEN
281
+ // 'switch' is 'on' for fully open and 'off' for fully close
282
+ if (hasProperty(params, 'setclose')) {
283
+ newPos = Math.abs(100 - params.setclose)
284
+ } else if (params.switch) {
285
+ newPos = params.switch === 'on' ? 100 : 0
286
+ } else {
287
+ return
288
+ }
289
+ break
290
+ case 67:
291
+ // 'per' matches HomeKit status 0=CLOSED 100=OPEN
292
+ if (hasProperty(params, 'per')) {
293
+ newPos = params.per
294
+ } else {
295
+ return
296
+ }
297
+ break
298
+ default:
299
+ return
300
+ }
301
+
302
+ // Update HomeKit with the provided value
303
+ this.service.updateCharacteristic(this.hapChar.TargetPosition, newPos)
304
+ this.service.updateCharacteristic(this.hapChar.CurrentPosition, newPos)
305
+ this.service.updateCharacteristic(this.hapChar.PositionState, 2)
306
+
307
+ // Only update the cache and log if the provided value has changed
308
+ if (params.updateSource && this.cachePos !== newPos) {
309
+ this.cachePos = newPos
310
+ if (this.enableLogging) {
311
+ this.log('[%s] %s [%s%].', this.name, this.lang.curPos, this.cachePos)
312
+ }
313
+ }
314
+ }
315
+ } catch (err) {
316
+ // Catch any errors and let the platform display them
317
+ this.platform.deviceUpdateError(this.accessory, err, false)
318
+ }
319
+ }
320
+
321
+ markStatus(isOnline) {
322
+ this.isOnline = isOnline
323
+ }
324
+ }