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