@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,332 @@
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.cusChar = platform.cusChar
8
+ this.eveChar = platform.eveChar
9
+ this.hapChar = platform.api.hap.Characteristic
10
+ this.hapErr = platform.api.hap.HapStatusError
11
+ this.hapServ = platform.api.hap.Service
12
+ this.lang = platform.lang
13
+ this.log = platform.log
14
+ this.platform = platform
15
+
16
+ // Set up variables from the accessory
17
+ this.name = accessory.displayName
18
+ this.accessory = accessory
19
+
20
+ // Initially set the online flag as true (to be then updated as false if necessary)
21
+ this.isOnline = true
22
+
23
+ /*
24
+ UIID 1/6/14/24/27/112/1009/1256/7004: single switch, no power readings
25
+ UIID 5: single switch, with wattage readings
26
+ UIID 32: single switch, with wattage, voltage and amp readings
27
+ UIID 77/78/81/107/112/138/160: single switch but firmware uses multiple channels (only need CH0)
28
+ UIID 182/190: single switch but multiple channels with wattage, voltage and amp readings
29
+ */
30
+
31
+ // Set up custom variables for this device type
32
+ const deviceConf = platform.deviceConf[accessory.context.eweDeviceId] || {}
33
+ this.inUsePowerThreshold = deviceConf.inUsePowerThreshold || platformConsts.defaultValues.inUsePowerThreshold
34
+
35
+ // Set the correct logging variables for this accessory
36
+ switch (deviceConf.overrideLogging) {
37
+ case 'standard':
38
+ this.enableLogging = true
39
+ this.enableDebugLogging = false
40
+ break
41
+ case 'debug':
42
+ this.enableLogging = true
43
+ this.enableDebugLogging = true
44
+ break
45
+ case 'disable':
46
+ this.enableLogging = false
47
+ this.enableDebugLogging = false
48
+ break
49
+ default:
50
+ this.enableLogging = !platform.config.disableDeviceLogging
51
+ this.enableDebugLogging = platform.config.debug
52
+ break
53
+ }
54
+
55
+ // If the accessory has a outlet service then remove it
56
+ if (this.accessory.getService(this.hapServ.Outlet)) {
57
+ this.accessory.removeService(this.accessory.getService(this.hapServ.Outlet))
58
+ }
59
+
60
+ // Add the switch service if it doesn't already exist
61
+ this.service = this.accessory.getService(this.hapServ.Switch)
62
+ || this.accessory.addService(this.hapServ.Switch)
63
+
64
+ switch (this.accessory.context.eweUIID) {
65
+ case 5:
66
+ // Add Eve power characteristics
67
+ this.powerReadings = true
68
+ if (!this.service.testCharacteristic(this.hapChar.OutletInUse)) {
69
+ this.service.addCharacteristic(this.hapChar.OutletInUse)
70
+ }
71
+ if (!this.service.testCharacteristic(this.eveChar.CurrentConsumption)) {
72
+ this.service.addCharacteristic(this.eveChar.CurrentConsumption)
73
+ }
74
+
75
+ // Remove unused Eve characteristics
76
+ if (this.service.testCharacteristic(this.eveChar.ElectricCurrent)) {
77
+ this.service.removeCharacteristic(
78
+ this.service.getCharacteristic(this.eveChar.ElectricCurrent),
79
+ )
80
+ }
81
+ if (this.service.testCharacteristic(this.eveChar.Voltage)) {
82
+ this.service.removeCharacteristic(this.service.getCharacteristic(this.eveChar.Voltage))
83
+ }
84
+ break
85
+ case 32:
86
+ case 182:
87
+ case 190:
88
+ // Add Eve power characteristics
89
+ this.powerReadings = true
90
+ if (!this.service.testCharacteristic(this.hapChar.OutletInUse)) {
91
+ this.service.addCharacteristic(this.hapChar.OutletInUse)
92
+ }
93
+ if (!this.service.testCharacteristic(this.eveChar.CurrentConsumption)) {
94
+ this.service.addCharacteristic(this.eveChar.CurrentConsumption)
95
+ }
96
+ if (!this.service.testCharacteristic(this.eveChar.ElectricCurrent)) {
97
+ this.service.addCharacteristic(this.eveChar.ElectricCurrent)
98
+ }
99
+ if (!this.service.testCharacteristic(this.eveChar.Voltage)) {
100
+ this.service.addCharacteristic(this.eveChar.Voltage)
101
+ }
102
+ break
103
+ default:
104
+ // Remove unused Eve characteristics
105
+ if (this.service.testCharacteristic(this.eveChar.CurrentConsumption)) {
106
+ this.service.removeCharacteristic(
107
+ this.service.getCharacteristic(this.eveChar.CurrentConsumption),
108
+ )
109
+ }
110
+ if (this.service.testCharacteristic(this.eveChar.ElectricCurrent)) {
111
+ this.service.removeCharacteristic(
112
+ this.service.getCharacteristic(this.eveChar.ElectricCurrent),
113
+ )
114
+ }
115
+ if (this.service.testCharacteristic(this.eveChar.Voltage)) {
116
+ this.service.removeCharacteristic(this.service.getCharacteristic(this.eveChar.Voltage))
117
+ }
118
+ break
119
+ }
120
+
121
+ // Set a flag for devices with hardware that use multi-channel format
122
+ if (
123
+ platformConsts.devices.switchSCM.includes(this.accessory.context.eweUIID)
124
+ || platformConsts.devices.switchSCMPower.includes(this.accessory.context.eweUIID)
125
+ ) {
126
+ this.isSCM = true
127
+ }
128
+
129
+ // Add the set handler to the switch on/off characteristic
130
+ this.service
131
+ .getCharacteristic(this.hapChar.On)
132
+ .onSet(async value => this.internalStateUpdate(value))
133
+ this.cacheState = this.service.getCharacteristic(this.hapChar.On).value ? 'on' : 'off'
134
+
135
+ // Add a custom characteristic for inverting the switch
136
+ if (!this.service.testCharacteristic(this.cusChar.InvertSwitch)) {
137
+ this.service.addCharacteristic(this.cusChar.InvertSwitch)
138
+ }
139
+ this.service.updateCharacteristic(this.cusChar.InvertSwitch, this.cacheState === 'on')
140
+
141
+ // Add the set handler to invert the switch
142
+ this.service.getCharacteristic(this.cusChar.InvertSwitch).onSet((value) => {
143
+ this.service.updateCharacteristic(this.hapChar.On, value)
144
+ this.cacheState = value ? 'on' : 'off'
145
+ this.log('[%s] %s [%s].', this.name, this.lang.curState, this.cacheState)
146
+ })
147
+
148
+ // Add the get handlers only if the user hasn't disabled the disableNoResponse setting
149
+ if (!platform.config.disableNoResponse) {
150
+ this.service.getCharacteristic(this.hapChar.On).onGet(() => {
151
+ if (!this.isOnline) {
152
+ throw new this.hapErr(-70402)
153
+ }
154
+ return this.service.getCharacteristic(this.hapChar.On).value
155
+ })
156
+ }
157
+
158
+ // Pass the accessory to Fakegato to set up with Eve
159
+ this.accessory.eveService = new platform.eveService('switch', this.accessory, {
160
+ log: () => {},
161
+ })
162
+
163
+ // Set up extra features for outlets that provide power readings
164
+ if (this.powerReadings) {
165
+ // Set up an interval to get eWeLink to send power updates
166
+ setTimeout(() => {
167
+ this.internalUIUpdate()
168
+ this.intervalPoll = setInterval(() => this.internalUIUpdate(), 120000)
169
+ }, 5000)
170
+
171
+ // Stop the intervals on Homebridge shutdown
172
+ platform.api.on('shutdown', () => clearInterval(this.intervalPoll))
173
+ }
174
+
175
+ // Output the customised options to the log
176
+ const normalLogging = this.enableLogging ? 'standard' : 'disable'
177
+ const opts = JSON.stringify({
178
+ inUsePowerThreshold: this.inUsePowerThreshold,
179
+ isInched: true,
180
+ logging: this.enableDebugLogging ? 'debug' : normalLogging,
181
+ showAs: 'default',
182
+ })
183
+ this.log('[%s] %s %s.', this.name, this.lang.devInitOpts, opts)
184
+ }
185
+
186
+ async internalStateUpdate(value) {
187
+ try {
188
+ const newValue = this.cacheState === 'on' ? 'off' : 'on'
189
+ const params = {}
190
+ if (this.isSCM) {
191
+ params.switches = [{ switch: 'on', outlet: 0 }]
192
+ } else {
193
+ params.switch = 'on'
194
+ }
195
+ this.ignoreUpdates = true
196
+ setTimeout(() => {
197
+ this.ignoreUpdates = false
198
+ }, 1500)
199
+ await this.platform.sendDeviceUpdate(this.accessory, params)
200
+ this.cacheState = newValue
201
+ this.service.updateCharacteristic(this.cusChar.InvertSwitch, value)
202
+ this.accessory.eveService.addEntry({ status: this.cacheState === 'on' ? 1 : 0 })
203
+ if (this.enableLogging) {
204
+ this.log('[%s] %s [%s].', this.name, this.lang.curState, this.cacheState)
205
+ }
206
+ } catch (err) {
207
+ this.platform.deviceUpdateError(this.accessory, err, true)
208
+ setTimeout(() => {
209
+ this.service.updateCharacteristic(this.hapChar.On, this.cacheState === 'on')
210
+ }, 2000)
211
+ throw new this.hapErr(-70402)
212
+ }
213
+ }
214
+
215
+ async internalUIUpdate() {
216
+ try {
217
+ // Skip polling if device isn't online
218
+ if (!this.isOnline) {
219
+ return
220
+ }
221
+
222
+ // Send the params to request the updates
223
+ await this.platform.sendDeviceUpdate(this.accessory, { uiActive: 120 })
224
+ } catch (err) {
225
+ // Suppress errors here
226
+ }
227
+ }
228
+
229
+ async externalUpdate(params) {
230
+ try {
231
+ if (!this.isSCM && params.switch === 'on') {
232
+ if (!this.ignoreUpdates) {
233
+ this.ignoreUpdates = true
234
+ setTimeout(() => {
235
+ this.ignoreUpdates = false
236
+ }, 1500)
237
+ this.cacheState = this.cacheState === 'on' ? 'off' : 'on'
238
+ this.service.updateCharacteristic(this.hapChar.On, this.cacheState === 'on')
239
+ this.service.updateCharacteristic(this.cusChar.InvertSwitch, this.cacheState === 'on')
240
+ this.accessory.eveService.addEntry({ status: this.cacheState === 'on' ? 1 : 0 })
241
+ if (params.updateSource && this.enableLogging) {
242
+ this.log('[%s] %s [%s].', this.name, this.lang.curState, this.cacheState)
243
+ }
244
+ }
245
+ }
246
+ if (this.isSCM && params.switches && params.switches[0].switch === 'on') {
247
+ if (!this.ignoreUpdates) {
248
+ this.ignoreUpdates = true
249
+ setTimeout(() => {
250
+ this.ignoreUpdates = false
251
+ }, 1500)
252
+ this.cacheState = this.cacheState === 'on' ? 'off' : 'on'
253
+ this.service.updateCharacteristic(this.hapChar.On, this.cacheState === 'on')
254
+ this.service.updateCharacteristic(this.cusChar.InvertSwitch, this.cacheState === 'on')
255
+ this.accessory.eveService.addEntry({ status: this.cacheState === 'on' ? 1 : 0 })
256
+ if (params.updateSource && this.enableLogging) {
257
+ this.log('[%s] %s [%s].', this.name, this.lang.curState, this.cacheState)
258
+ }
259
+ }
260
+ }
261
+ if (!this.powerReadings) {
262
+ return
263
+ }
264
+ let logger = false
265
+ if (hasProperty(params, 'power')) {
266
+ this.service.updateCharacteristic(this.eveChar.CurrentConsumption, Number.parseFloat(params.power))
267
+ this.service.updateCharacteristic(
268
+ this.hapChar.OutletInUse,
269
+ this.cacheState === 'on' && Number.parseFloat(params.power) > this.inUsePowerThreshold,
270
+ )
271
+ logger = true
272
+ }
273
+ if (hasProperty(params, 'voltage')) {
274
+ this.service.updateCharacteristic(this.eveChar.Voltage, Number.parseFloat(params.voltage))
275
+ logger = true
276
+ }
277
+ if (hasProperty(params, 'current')) {
278
+ this.service.updateCharacteristic(this.eveChar.ElectricCurrent, Number.parseFloat(params.current))
279
+ logger = true
280
+ }
281
+ if (params.updateSource && logger && this.enableLogging) {
282
+ this.log(
283
+ '[%s] %s%s%s.',
284
+ this.name,
285
+ hasProperty(params, 'power')
286
+ ? `${this.lang.curPower} [${params.power}W]`
287
+ : '',
288
+ hasProperty(params, 'voltage')
289
+ ? ` ${this.lang.curVolt} [${params.voltage}V]`
290
+ : '',
291
+ hasProperty(params, 'current')
292
+ ? ` ${this.lang.curCurr} [${params.current}A]`
293
+ : '',
294
+ )
295
+ }
296
+ } catch (err) {
297
+ this.platform.deviceUpdateError(this.accessory, err, false)
298
+ }
299
+ }
300
+
301
+ markStatus(isOnline) {
302
+ this.isOnline = isOnline
303
+ }
304
+
305
+ async currentState() {
306
+ const toReturn = {}
307
+ toReturn.services = ['switch']
308
+ toReturn.switch = {
309
+ state: this.service.getCharacteristic(this.hapChar.On).value ? 'on' : 'off',
310
+ }
311
+ if (this.powerReadings) {
312
+ try {
313
+ toReturn.services.push('power')
314
+ toReturn.power = {
315
+ state: await this.platform.sendDeviceUpdate(this.accessory, { hundredDaysKwh: 'get' }),
316
+ voltage: this.service.testCharacteristic(this.eveChar.Voltage)
317
+ ? this.service.getCharacteristic(this.eveChar.Voltage).value
318
+ : undefined,
319
+ power: this.service.testCharacteristic(this.eveChar.CurrentConsumption)
320
+ ? this.service.getCharacteristic(this.eveChar.CurrentConsumption).value
321
+ : undefined,
322
+ current: this.service.testCharacteristic(this.eveChar.ElectricCurrent)
323
+ ? this.service.getCharacteristic(this.eveChar.ElectricCurrent).value
324
+ : undefined,
325
+ }
326
+ } catch (err) {
327
+ // Suppress errors here
328
+ }
329
+ }
330
+ return toReturn
331
+ }
332
+ }
@@ -0,0 +1,307 @@
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
+ /*
23
+ UIID 1/6/14/24/27/112/1009/1256/7004: single switch, no power readings
24
+ UIID 5: single switch, with wattage readings
25
+ UIID 32: single switch, with wattage, voltage and amp readings
26
+ UIID 77/78/81/107/112/138/160: single switch but firmware uses multiple channels (only need CH0)
27
+ UIID 182/190: single switch but multiple channels with wattage, voltage and amp readings
28
+ */
29
+
30
+ // Set up custom variables for this device type
31
+ const deviceConf = platform.deviceConf[accessory.context.eweDeviceId] || {}
32
+ this.inUsePowerThreshold = deviceConf.inUsePowerThreshold || platformConsts.defaultValues.inUsePowerThreshold
33
+
34
+ // Set the correct logging variables for this accessory
35
+ switch (deviceConf.overrideLogging) {
36
+ case 'standard':
37
+ this.enableLogging = true
38
+ this.enableDebugLogging = false
39
+ break
40
+ case 'debug':
41
+ this.enableLogging = true
42
+ this.enableDebugLogging = true
43
+ break
44
+ case 'disable':
45
+ this.enableLogging = false
46
+ this.enableDebugLogging = false
47
+ break
48
+ default:
49
+ this.enableLogging = !platform.config.disableDeviceLogging
50
+ this.enableDebugLogging = platform.config.debug
51
+ break
52
+ }
53
+
54
+ // If the accessory has a outlet service then remove it
55
+ if (this.accessory.getService(this.hapServ.Outlet)) {
56
+ this.accessory.removeService(this.accessory.getService(this.hapServ.Outlet))
57
+ }
58
+
59
+ // Add the switch service if it doesn't already exist
60
+ this.service = this.accessory.getService(this.hapServ.Switch)
61
+ || this.accessory.addService(this.hapServ.Switch)
62
+
63
+ // Some models provide a power reading in different decimals
64
+ this.divisor = 1
65
+
66
+ switch (this.accessory.context.eweUIID) {
67
+ case 5:
68
+ // Add Eve power characteristics
69
+ this.powerReadings = true
70
+ if (!this.service.testCharacteristic(this.hapChar.OutletInUse)) {
71
+ this.service.addCharacteristic(this.hapChar.OutletInUse)
72
+ }
73
+ if (!this.service.testCharacteristic(this.eveChar.CurrentConsumption)) {
74
+ this.service.addCharacteristic(this.eveChar.CurrentConsumption)
75
+ }
76
+
77
+ // Remove unused Eve characteristics
78
+ if (this.service.testCharacteristic(this.eveChar.ElectricCurrent)) {
79
+ this.service.removeCharacteristic(
80
+ this.service.getCharacteristic(this.eveChar.ElectricCurrent),
81
+ )
82
+ }
83
+ if (this.service.testCharacteristic(this.eveChar.Voltage)) {
84
+ this.service.removeCharacteristic(this.service.getCharacteristic(this.eveChar.Voltage))
85
+ }
86
+ break
87
+ case 32:
88
+ case 182:
89
+ case 190:
90
+ // Add Eve power characteristics
91
+ this.powerReadings = true
92
+ if (!this.service.testCharacteristic(this.hapChar.OutletInUse)) {
93
+ this.service.addCharacteristic(this.hapChar.OutletInUse)
94
+ }
95
+ if (!this.service.testCharacteristic(this.eveChar.CurrentConsumption)) {
96
+ this.service.addCharacteristic(this.eveChar.CurrentConsumption)
97
+ }
98
+ if (!this.service.testCharacteristic(this.eveChar.ElectricCurrent)) {
99
+ this.service.addCharacteristic(this.eveChar.ElectricCurrent)
100
+ }
101
+ if (!this.service.testCharacteristic(this.eveChar.Voltage)) {
102
+ this.service.addCharacteristic(this.eveChar.Voltage)
103
+ }
104
+
105
+ if (this.accessory.context.eweUIID === 190) {
106
+ this.divisor = 100
107
+ }
108
+ break
109
+ default:
110
+ // Remove unused Eve characteristics
111
+ if (this.service.testCharacteristic(this.eveChar.CurrentConsumption)) {
112
+ this.service.removeCharacteristic(
113
+ this.service.getCharacteristic(this.eveChar.CurrentConsumption),
114
+ )
115
+ }
116
+ if (this.service.testCharacteristic(this.eveChar.ElectricCurrent)) {
117
+ this.service.removeCharacteristic(
118
+ this.service.getCharacteristic(this.eveChar.ElectricCurrent),
119
+ )
120
+ }
121
+ if (this.service.testCharacteristic(this.eveChar.Voltage)) {
122
+ this.service.removeCharacteristic(this.service.getCharacteristic(this.eveChar.Voltage))
123
+ }
124
+ break
125
+ }
126
+
127
+ // Set a flag for devices with hardware that use multi-channel format
128
+ if (
129
+ platformConsts.devices.switchSCM.includes(this.accessory.context.eweUIID)
130
+ || platformConsts.devices.switchSCMPower.includes(this.accessory.context.eweUIID)
131
+ ) {
132
+ this.isSCM = true
133
+ }
134
+
135
+ // Add the set handler to the switch on/off characteristic
136
+ this.service
137
+ .getCharacteristic(this.hapChar.On)
138
+ .onSet(async value => this.internalStateUpdate(value))
139
+
140
+ // Add the get handlers only if the user hasn't disabled the disableNoResponse setting
141
+ if (!platform.config.disableNoResponse) {
142
+ this.service.getCharacteristic(this.hapChar.On).onGet(() => {
143
+ if (!this.isOnline) {
144
+ throw new this.hapErr(-70402)
145
+ }
146
+ return this.service.getCharacteristic(this.hapChar.On).value
147
+ })
148
+ }
149
+
150
+ // Pass the accessory to Fakegato to set up with Eve
151
+ this.accessory.eveService = new platform.eveService('switch', this.accessory, {
152
+ log: () => {},
153
+ })
154
+
155
+ // Set up extra features for outlets that provide power readings
156
+ if (this.powerReadings) {
157
+ // Set up an interval to get eWeLink to send power updates
158
+ setTimeout(() => {
159
+ this.internalUIUpdate()
160
+ this.intervalPoll = setInterval(() => this.internalUIUpdate(), 120000)
161
+ }, 5000)
162
+
163
+ // Stop the intervals on Homebridge shutdown
164
+ platform.api.on('shutdown', () => clearInterval(this.intervalPoll))
165
+ }
166
+
167
+ // Output the customised options to the log
168
+ const normalLogging = this.enableLogging ? 'standard' : 'disable'
169
+ const opts = JSON.stringify({
170
+ inUsePowerThreshold: this.inUsePowerThreshold,
171
+ logging: this.enableDebugLogging ? 'debug' : normalLogging,
172
+ showAs: 'default',
173
+ })
174
+ this.log('[%s] %s %s.', this.name, this.lang.devInitOpts, opts)
175
+ }
176
+
177
+ async internalStateUpdate(value) {
178
+ try {
179
+ const newValue = value ? 'on' : 'off'
180
+ if (newValue === this.cacheState) {
181
+ return
182
+ }
183
+ const params = {}
184
+ if (this.isSCM) {
185
+ params.switches = [{ switch: newValue, outlet: 0 }]
186
+ } else {
187
+ params.switch = newValue
188
+ }
189
+ await this.platform.sendDeviceUpdate(this.accessory, params)
190
+ this.cacheState = newValue
191
+ this.accessory.eveService.addEntry({ status: value ? 1 : 0 })
192
+ if (this.enableLogging) {
193
+ this.log('[%s] %s [%s].', this.name, this.lang.curState, this.cacheState)
194
+ }
195
+ } catch (err) {
196
+ this.platform.deviceUpdateError(this.accessory, err, true)
197
+ setTimeout(() => {
198
+ this.service.updateCharacteristic(this.hapChar.On, this.cacheState === 'on')
199
+ }, 2000)
200
+ throw new this.hapErr(-70402)
201
+ }
202
+ }
203
+
204
+ async internalUIUpdate() {
205
+ try {
206
+ // Skip polling if device isn't online
207
+ if (!this.isOnline) {
208
+ return
209
+ }
210
+
211
+ // Send the params to request the updates
212
+ await this.platform.sendDeviceUpdate(this.accessory, { uiActive: 120 })
213
+ } catch (err) {
214
+ // Suppress errors here
215
+ }
216
+ }
217
+
218
+ async externalUpdate(params) {
219
+ try {
220
+ if (!this.isSCM && params.switch && params.switch !== this.cacheState) {
221
+ this.cacheState = params.switch
222
+ this.service.updateCharacteristic(this.hapChar.On, this.cacheState === 'on')
223
+ this.accessory.eveService.addEntry({ status: this.cacheState === 'on' ? 1 : 0 })
224
+ if (params.updateSource && this.enableLogging) {
225
+ this.log('[%s] %s [%s].', this.name, this.lang.curState, this.cacheState)
226
+ }
227
+ }
228
+ if (this.isSCM && params.switches && params.switches[0].switch !== this.cacheState) {
229
+ this.cacheState = params.switches[0].switch
230
+ this.service.updateCharacteristic(this.hapChar.On, this.cacheState === 'on')
231
+ this.accessory.eveService.addEntry({ status: this.cacheState === 'on' ? 1 : 0 })
232
+ if (params.updateSource && this.enableLogging) {
233
+ this.log('[%s] %s [%s].', this.name, this.lang.curState, this.cacheState)
234
+ }
235
+ }
236
+ if (!this.powerReadings) {
237
+ return
238
+ }
239
+ let logger = false
240
+ let power
241
+ let voltage
242
+ let current
243
+ if (hasProperty(params, 'power')) {
244
+ power = Math.round((Number.parseFloat(params.power) * 100) / this.divisor) / 100
245
+ this.service.updateCharacteristic(this.eveChar.CurrentConsumption, power)
246
+ this.service.updateCharacteristic(
247
+ this.hapChar.OutletInUse,
248
+ this.cacheState === 'on' && Number.parseFloat(params.power) > this.inUsePowerThreshold,
249
+ )
250
+ logger = true
251
+ }
252
+ if (hasProperty(params, 'voltage')) {
253
+ voltage = Math.round((Number.parseFloat(params.voltage) * 100) / this.divisor) / 100
254
+ this.service.updateCharacteristic(this.eveChar.Voltage, voltage)
255
+ logger = true
256
+ }
257
+ if (hasProperty(params, 'current')) {
258
+ current = Math.round((Number.parseFloat(params.current) * 100) / this.divisor) / 100
259
+ this.service.updateCharacteristic(this.eveChar.ElectricCurrent, current)
260
+ logger = true
261
+ }
262
+ if (params.updateSource && logger && this.enableLogging) {
263
+ this.log(
264
+ '[%s] %s%s%s.',
265
+ this.name,
266
+ power !== undefined ? `${this.lang.curPower} [${power}W]` : '',
267
+ voltage !== undefined ? ` ${this.lang.curVolt} [${voltage}V]` : '',
268
+ current !== undefined ? ` ${this.lang.curCurr} [${current}A]` : '',
269
+ )
270
+ }
271
+ } catch (err) {
272
+ this.platform.deviceUpdateError(this.accessory, err, false)
273
+ }
274
+ }
275
+
276
+ markStatus(isOnline) {
277
+ this.isOnline = isOnline
278
+ }
279
+
280
+ async currentState() {
281
+ const toReturn = {}
282
+ toReturn.services = ['switch']
283
+ toReturn.switch = {
284
+ state: this.service.getCharacteristic(this.hapChar.On).value ? 'on' : 'off',
285
+ }
286
+ if (this.powerReadings) {
287
+ try {
288
+ toReturn.services.push('power')
289
+ toReturn.power = {
290
+ state: await this.platform.sendDeviceUpdate(this.accessory, { hundredDaysKwh: 'get' }),
291
+ voltage: this.service.testCharacteristic(this.eveChar.Voltage)
292
+ ? this.service.getCharacteristic(this.eveChar.Voltage).value
293
+ : undefined,
294
+ power: this.service.testCharacteristic(this.eveChar.CurrentConsumption)
295
+ ? this.service.getCharacteristic(this.eveChar.CurrentConsumption).value
296
+ : undefined,
297
+ current: this.service.testCharacteristic(this.eveChar.ElectricCurrent)
298
+ ? this.service.getCharacteristic(this.eveChar.ElectricCurrent).value
299
+ : undefined,
300
+ }
301
+ } catch (err) {
302
+ // Suppress errors here
303
+ }
304
+ }
305
+ return toReturn
306
+ }
307
+ }
@@ -0,0 +1,43 @@
1
+ export default class {
2
+ constructor(platform, accessory) {
3
+ // Set up variables from the platform
4
+ this.eveChar = platform.eveChar
5
+ this.hapChar = platform.api.hap.Characteristic
6
+ this.hapErr = platform.api.hap.HapStatusError
7
+ this.hapServ = platform.api.hap.Service
8
+ this.lang = platform.lang
9
+ this.log = platform.log
10
+ this.platform = platform
11
+
12
+ // Set up variables from the accessory
13
+ this.name = accessory.displayName
14
+ this.accessory = accessory
15
+
16
+ // Initially set the online flag as true (to be then updated as false if necessary)
17
+ this.isOnline = true
18
+
19
+ // Set the correct logging variables for this accessory
20
+ this.enableLogging = true
21
+ this.enableDebugLogging = true
22
+
23
+ // Output the customised options to the log
24
+ const normalLogging = this.enableLogging ? 'standard' : 'disable'
25
+ const opts = JSON.stringify({
26
+ logging: this.enableDebugLogging ? 'debug' : normalLogging,
27
+ })
28
+ this.log('[%s] %s %s.', this.name, this.lang.devInitOpts, opts)
29
+ }
30
+
31
+ async externalUpdate(params) {
32
+ try {
33
+ this.log.warn('New Command Received:')
34
+ this.log(JSON.stringify(params))
35
+ } catch (err) {
36
+ this.platform.deviceUpdateError(this.accessory, err, false)
37
+ }
38
+ }
39
+
40
+ markStatus(isOnline) {
41
+ this.isOnline = isOnline
42
+ }
43
+ }