@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,312 @@
1
+ import { hasProperty, parseError } from '../../utils/functions.js'
2
+
3
+ export default class {
4
+ constructor(platform, accessory) {
5
+ // Set up variables from the platform
6
+ this.hapChar = platform.api.hap.Characteristic
7
+ this.hapErr = platform.api.hap.HapStatusError
8
+ this.hapServ = platform.api.hap.Service
9
+ this.lang = platform.lang
10
+ this.log = platform.log
11
+ this.platform = platform
12
+
13
+ // Set up variables from the accessory
14
+ this.name = accessory.displayName
15
+ this.accessory = accessory
16
+
17
+ // Initially set the online flag as true (to be then updated as false if necessary)
18
+ this.isOnline = true
19
+
20
+ // Set up custom variables for this device type
21
+ const deviceConf = platform.deviceConf[accessory.context.eweDeviceId] || {}
22
+ this.temperatureSource = deviceConf.temperatureSource
23
+
24
+ // Set the correct logging variables for this accessory
25
+ switch (deviceConf.overrideLogging) {
26
+ case 'standard':
27
+ this.enableLogging = true
28
+ this.enableDebugLogging = false
29
+ break
30
+ case 'debug':
31
+ this.enableLogging = true
32
+ this.enableDebugLogging = true
33
+ break
34
+ case 'disable':
35
+ this.enableLogging = false
36
+ this.enableDebugLogging = false
37
+ break
38
+ default:
39
+ this.enableLogging = !platform.config.disableDeviceLogging
40
+ this.enableDebugLogging = platform.config.debug
41
+ break
42
+ }
43
+
44
+ // If the accessory has a switch service then remove it
45
+ if (this.accessory.getService(this.hapServ.Switch)) {
46
+ this.accessory.removeService(this.accessory.getService(this.hapServ.Switch))
47
+ }
48
+
49
+ // Set up the accessory with default target temp when added the first time
50
+ if (!hasProperty(this.accessory.context, 'cacheTarget')) {
51
+ this.accessory.context.cacheTarget = 20
52
+ }
53
+
54
+ // Check to make sure user has not switched from cooler to heater
55
+ if (this.accessory.context.cacheType !== 'cooler') {
56
+ // Remove and re-setup as a HeaterCooler
57
+ if (this.accessory.getService(this.hapServ.HeaterCooler)) {
58
+ this.accessory.removeService(this.accessory.getService(this.hapServ.HeaterCooler))
59
+ }
60
+ this.accessory.context.cacheType = 'cooler'
61
+ this.accessory.context.cacheTarget = 20
62
+ }
63
+
64
+ // Add the heater service if it doesn't already exist
65
+ this.service = this.accessory.getService(this.hapServ.HeaterCooler)
66
+ || this.accessory.addService(this.hapServ.HeaterCooler)
67
+
68
+ // Set custom properties of the current temperature characteristic
69
+ this.service.getCharacteristic(this.hapChar.CurrentTemperature).setProps({
70
+ minStep: 0.1,
71
+ })
72
+ this.cacheTemp = this.service.getCharacteristic(this.hapChar.CurrentTemperature).value
73
+
74
+ // Add the set handler to the heater active characteristic
75
+ this.service
76
+ .getCharacteristic(this.hapChar.Active)
77
+ .onSet(async value => this.internalStateUpdate(value))
78
+
79
+ // Add options to the target state characteristic
80
+ this.service.getCharacteristic(this.hapChar.TargetHeaterCoolerState).setProps({
81
+ minValue: 0,
82
+ maxValue: 0,
83
+ validValues: [0],
84
+ })
85
+
86
+ // Add the set handler to the target temperature characteristic
87
+ this.service
88
+ .getCharacteristic(this.hapChar.CoolingThresholdTemperature)
89
+ .updateValue(this.accessory.context.cacheTarget)
90
+ .setProps({ minStep: 0.5 })
91
+ .onSet(async value => this.internalTargetTempUpdate(value))
92
+
93
+ // Add the get handlers only if the user hasn't disabled the disableNoResponse setting
94
+ if (!platform.config.disableNoResponse) {
95
+ this.service.getCharacteristic(this.hapChar.CurrentTemperature).onGet(() => {
96
+ if (!this.isOnline) {
97
+ throw new this.hapErr(-70402)
98
+ }
99
+ return this.service.getCharacteristic(this.hapChar.CurrentTemperature).value
100
+ })
101
+ this.service.getCharacteristic(this.hapChar.Active).onGet(() => {
102
+ if (!this.isOnline) {
103
+ throw new this.hapErr(-70402)
104
+ }
105
+ return this.service.getCharacteristic(this.hapChar.Active).value
106
+ })
107
+ this.service.getCharacteristic(this.hapChar.TargetHeaterCoolerState).onGet(() => {
108
+ if (!this.isOnline) {
109
+ throw new this.hapErr(-70402)
110
+ }
111
+ return this.service.getCharacteristic(this.hapChar.TargetHeaterCoolerState).value
112
+ })
113
+ this.service.getCharacteristic(this.hapChar.CurrentHeaterCoolerState).onGet(() => {
114
+ if (!this.isOnline) {
115
+ throw new this.hapErr(-70402)
116
+ }
117
+ return this.service.getCharacteristic(this.hapChar.CurrentHeaterCoolerState).value
118
+ })
119
+ this.service.getCharacteristic(this.hapChar.CoolingThresholdTemperature).onGet(() => {
120
+ if (!this.isOnline) {
121
+ throw new this.hapErr(-70402)
122
+ }
123
+ return this.service.getCharacteristic(this.hapChar.CoolingThresholdTemperature).value
124
+ })
125
+ }
126
+
127
+ // Initialise these caches now since they aren't determined by the initial externalUpdate()
128
+ this.cacheState = this.service.getCharacteristic(this.hapChar.Active).value === 1 ? 'on' : 'off'
129
+ this.cacheCool = this.cacheState === 'on'
130
+ && this.service.getCharacteristic(this.hapChar.CurrentHeaterCoolerState).value === 3
131
+ ? 'on'
132
+ : 'off'
133
+
134
+ // Pass the accessory to Fakegato to set up with Eve
135
+ this.accessory.eveService = new platform.eveService('custom', this.accessory, {
136
+ log: () => {},
137
+ })
138
+
139
+ // Set up an interval to get regular temperature updates
140
+ setTimeout(() => {
141
+ this.getTemperature()
142
+ this.intervalPoll = setInterval(() => this.getTemperature(), 120000)
143
+ }, 5000)
144
+
145
+ // Stop the intervals on Homebridge shutdown
146
+ platform.api.on('shutdown', () => {
147
+ clearInterval(this.intervalPoll)
148
+ })
149
+
150
+ // Output the customised options to the log
151
+ const normalLogging = this.enableLogging ? 'standard' : 'disable'
152
+ const opts = JSON.stringify({
153
+ logging: this.enableDebugLogging ? 'debug' : normalLogging,
154
+ showAs: 'cooler',
155
+ temperatureSource: this.temperatureSource,
156
+ })
157
+ this.log('[%s] %s %s.', this.name, this.lang.devInitOpts, opts)
158
+ }
159
+
160
+ async internalStateUpdate(value) {
161
+ try {
162
+ let newState
163
+ let newCool
164
+ const params = {}
165
+ if (value === 0) {
166
+ params.switch = 'off'
167
+ newState = 'off'
168
+ newCool = 'off'
169
+ } else if (this.cacheTemp > this.accessory.context.cacheTarget) {
170
+ params.switch = 'on'
171
+ newState = 'on'
172
+ newCool = 'on'
173
+ } else {
174
+ params.switch = 'off'
175
+ newState = 'on'
176
+ newCool = 'off'
177
+ }
178
+
179
+ // Only send the update if either:
180
+ // * The new value (state) is OFF and the cacheCool was ON
181
+ // * The new value (state) is ON and newCool is 'on'
182
+ if ((value === 0 && this.cacheCool === 'on') || (value === 1 && newCool === 'on')) {
183
+ await this.platform.sendDeviceUpdate(this.accessory, params)
184
+ }
185
+ if (newState !== this.cacheState) {
186
+ this.cacheState = newState
187
+ if (this.enableLogging) {
188
+ this.log('[%s] %s [%s].', this.name, this.lang.curState, this.cacheState)
189
+ }
190
+ }
191
+ if (newCool !== this.cacheCool) {
192
+ this.cacheCool = newCool
193
+ if (this.enableLogging) {
194
+ this.log('[%s] %s [%s].', this.name, this.lang.curCool, this.cacheCool)
195
+ }
196
+ }
197
+ const hapState = this.cacheCool === 'on' ? 3 : 1
198
+ this.service.updateCharacteristic(
199
+ this.hapChar.CurrentHeaterCoolerState,
200
+ value === 1 ? hapState : 0,
201
+ )
202
+ } catch (err) {
203
+ this.platform.deviceUpdateError(this.accessory, err, true)
204
+ setTimeout(() => {
205
+ this.service.updateCharacteristic(this.hapChar.Active, this.cacheState === 'on' ? 1 : 0)
206
+ }, 2000)
207
+ throw new this.hapErr(-70402)
208
+ }
209
+ }
210
+
211
+ async internalTargetTempUpdate(value) {
212
+ try {
213
+ if (value === this.accessory.context.cacheTarget) {
214
+ return
215
+ }
216
+ this.accessory.context.cacheTarget = value
217
+ if (this.enableLogging) {
218
+ this.log('[%s] %s [%s°C].', this.name, this.lang.curTarg, value)
219
+ }
220
+ if (this.cacheState === 'off') {
221
+ return
222
+ }
223
+ const params = {}
224
+ let newCool
225
+ if (this.cacheTemp > value) {
226
+ params.switch = 'on'
227
+ newCool = 'on'
228
+ } else {
229
+ params.switch = 'off'
230
+ newCool = 'off'
231
+ }
232
+ if (newCool === this.cacheCool) {
233
+ return
234
+ }
235
+ await this.platform.sendDeviceUpdate(this.accessory, params)
236
+ this.cacheCool = newCool
237
+ if (this.enableLogging) {
238
+ this.log('[%s] %s [%s].', this.name, this.lang.curCool, this.cacheCool)
239
+ }
240
+ this.service.updateCharacteristic(
241
+ this.hapChar.CurrentHeaterCoolerState,
242
+ this.cacheCool === 'on' ? 3 : 1,
243
+ )
244
+ } catch (err) {
245
+ this.platform.deviceUpdateError(this.accessory, err, true)
246
+ setTimeout(() => {
247
+ this.service.updateCharacteristic(
248
+ this.hapChar.CoolingThresholdTemperature,
249
+ this.accessory.context.cacheTarget,
250
+ )
251
+ }, 2000)
252
+ throw new this.hapErr(-70402)
253
+ }
254
+ }
255
+
256
+ async internalCurrentTempUpdate() {
257
+ try {
258
+ if (this.cacheState === 'off') {
259
+ return
260
+ }
261
+ const params = {}
262
+ let newCool
263
+ if (this.cacheTemp > this.accessory.context.cacheTarget) {
264
+ params.switch = 'on'
265
+ newCool = 'on'
266
+ } else {
267
+ params.switch = 'off'
268
+ newCool = 'off'
269
+ }
270
+ if (newCool === this.cacheCool) {
271
+ return
272
+ }
273
+ await this.platform.sendDeviceUpdate(this.accessory, params)
274
+ this.cacheCool = newCool
275
+ if (this.enableLogging) {
276
+ this.log('[%s] %s [%s].', this.name, this.lang.curCool, this.cacheCool)
277
+ }
278
+ this.service.updateCharacteristic(
279
+ this.hapChar.CurrentHeaterCoolerState,
280
+ this.cacheCool === 'on' ? 3 : 1,
281
+ )
282
+ } catch (err) {
283
+ this.log.warn('[%s] %s.', this.name, parseError(err))
284
+ }
285
+ }
286
+
287
+ async getTemperature() {
288
+ try {
289
+ // Skip polling if device isn't online or if the storage hasn't initialised properly
290
+ if (!this.isOnline || !this.platform.storageClientData) {
291
+ return
292
+ }
293
+
294
+ const newTemp = await this.platform.storageData.getItem(`${this.temperatureSource}_temp`)
295
+ if (newTemp && newTemp !== this.cacheTemp) {
296
+ this.cacheTemp = newTemp
297
+ this.service.updateCharacteristic(this.hapChar.CurrentTemperature, this.cacheTemp)
298
+ this.accessory.eveService.addEntry({ temp: this.cacheTemp })
299
+ if (this.enableLogging) {
300
+ this.log('[%s] %s [%s°C].', this.name, this.lang.curTemp, this.cacheTemp)
301
+ }
302
+ this.internalCurrentTempUpdate()
303
+ }
304
+ } catch (err) {
305
+ this.log.warn('[%s] %s.', this.name, parseError(err))
306
+ }
307
+ }
308
+
309
+ markStatus(isOnline) {
310
+ this.isOnline = isOnline
311
+ }
312
+ }
@@ -0,0 +1,253 @@
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.eveChar = platform.eveChar
8
+ this.hapChar = platform.api.hap.Characteristic
9
+ this.hapErr = platform.api.hap.HapStatusError
10
+ this.hapServ = platform.api.hap.Service
11
+ this.lang = platform.lang
12
+ this.log = platform.log
13
+ this.platform = platform
14
+
15
+ // Set up variables from the accessory
16
+ this.name = accessory.displayName
17
+ this.accessory = accessory
18
+
19
+ // Initially set the online flag as true (to be then updated as false if necessary)
20
+ this.isOnline = true
21
+
22
+ // Set up custom variables for this device type
23
+ const deviceConf = platform.deviceConf[accessory.context.eweDeviceId] || {}
24
+ this.operationTimeUp = deviceConf.operationTime || platformConsts.defaultValues.operationTime
25
+ this.operationTimeDown = deviceConf.operationTimeDown || this.operationTimeUp
26
+
27
+ // Set the correct logging variables for this accessory
28
+ switch (deviceConf.overrideLogging) {
29
+ case 'standard':
30
+ this.enableLogging = true
31
+ this.enableDebugLogging = false
32
+ break
33
+ case 'debug':
34
+ this.enableLogging = true
35
+ this.enableDebugLogging = true
36
+ break
37
+ case 'disable':
38
+ this.enableLogging = false
39
+ this.enableDebugLogging = false
40
+ break
41
+ default:
42
+ this.enableLogging = !platform.config.disableDeviceLogging
43
+ this.enableDebugLogging = platform.config.debug
44
+ break
45
+ }
46
+
47
+ // Set up the accessory with default positions when added the first time
48
+ if (!hasProperty(this.accessory.context, 'cacheCurrentPosition')) {
49
+ this.accessory.context.cacheCurrentPosition = 0
50
+ this.accessory.context.cachePositionState = 2
51
+ this.accessory.context.cacheTargetPosition = 0
52
+ }
53
+
54
+ // Add the door service if it doesn't already exist
55
+ this.service = this.accessory.getService(this.hapServ.Door)
56
+ if (!this.service) {
57
+ this.service = this.accessory.addService(this.hapServ.Door)
58
+ this.service.updateCharacteristic(this.hapChar.CurrentPosition, 0)
59
+ this.service.updateCharacteristic(this.hapChar.TargetPosition, 0)
60
+ this.service.updateCharacteristic(this.hapChar.PositionState, 2)
61
+ }
62
+
63
+ // Certain devices give power readings
64
+ if (platformConsts.devices.switchMultiPower.includes(this.accessory.context.eweUIID)) {
65
+ // Add Eve power characteristics
66
+ this.powerReadings = true
67
+ if (!this.service.testCharacteristic(this.eveChar.CurrentConsumption)) {
68
+ this.service.addCharacteristic(this.eveChar.CurrentConsumption)
69
+ }
70
+ if (!this.service.testCharacteristic(this.eveChar.ElectricCurrent)) {
71
+ this.service.addCharacteristic(this.eveChar.ElectricCurrent)
72
+ }
73
+ if (!this.service.testCharacteristic(this.eveChar.Voltage)) {
74
+ this.service.addCharacteristic(this.eveChar.Voltage)
75
+ }
76
+ }
77
+
78
+ // Add the set handler to the target position characteristic
79
+ this.service.getCharacteristic(this.hapChar.TargetPosition).onSet((value) => {
80
+ // We don't use await as we want the callback to be run straight away
81
+ this.internalPositionUpdate(value)
82
+ })
83
+
84
+ // Add the get handlers only if the user hasn't disabled the disableNoResponse setting
85
+ if (!platform.config.disableNoResponse) {
86
+ this.service.getCharacteristic(this.hapChar.CurrentPosition).onGet(() => {
87
+ if (!this.isOnline) {
88
+ throw new this.hapErr(-70402)
89
+ }
90
+ return this.service.getCharacteristic(this.hapChar.CurrentPosition).value
91
+ })
92
+ this.service.getCharacteristic(this.hapChar.TargetPosition).onGet(() => {
93
+ if (!this.isOnline) {
94
+ throw new this.hapErr(-70402)
95
+ }
96
+ return this.service.getCharacteristic(this.hapChar.TargetPosition).value
97
+ })
98
+ }
99
+
100
+ // Set up an interval to get eWeLink to send power updates
101
+ if (this.powerReadings && platform.config.mode !== 'lan') {
102
+ setTimeout(() => {
103
+ this.internalUIUpdate()
104
+ this.intervalPoll = setInterval(() => this.internalUIUpdate(), 120000)
105
+ }, 5000)
106
+
107
+ // Stop the intervals on Homebridge shutdown
108
+ platform.api.on('shutdown', () => clearInterval(this.intervalPoll))
109
+ }
110
+
111
+ // Output the customised options to the log
112
+ const normalLogging = this.enableLogging ? 'standard' : 'disable'
113
+ const opts = JSON.stringify({
114
+ logging: this.enableDebugLogging ? 'debug' : normalLogging,
115
+ operationTimeDown: this.operationTimeDown,
116
+ operationTimeUp: this.operationTimeUp,
117
+ showAs: 'door',
118
+ })
119
+ this.log('[%s] %s %s.', this.name, this.lang.devInitOpts, opts)
120
+ }
121
+
122
+ async internalPositionUpdate(value) {
123
+ try {
124
+ let prevPosition = this.accessory.context.cacheCurrentPosition
125
+ if (value === prevPosition) {
126
+ return
127
+ }
128
+ const params = {
129
+ switches: [],
130
+ }
131
+ const prevState = this.accessory.context.cachePositionState
132
+ const percentStepUpPerDS = this.operationTimeUp / 100
133
+ const percentStepDownPerDS = this.operationTimeDown / 100
134
+ const updateKey = generateRandomString(5)
135
+ this.updateKey = updateKey
136
+ if (prevState !== 2) {
137
+ params.switches.push({ switch: 'off', outlet: 0 })
138
+ params.switches.push({ switch: 'off', outlet: 1 })
139
+ await this.platform.sendDeviceUpdate(this.accessory, params)
140
+ params.switches = []
141
+ const posPercentChange = Math.floor(Date.now() / 100) - this.accessory.context.cacheLastStartTime
142
+ const posPercentChangeUp = Math.floor(percentStepUpPerDS * posPercentChange)
143
+ const posPercentChangeDown = Math.floor(percentStepDownPerDS * posPercentChange)
144
+ if (prevState === 0) {
145
+ // Was going down
146
+ prevPosition -= posPercentChangeDown
147
+ } else {
148
+ // Was going up
149
+ prevPosition += posPercentChangeUp
150
+ }
151
+ prevPosition = Math.min(Math.max(prevPosition, 0), 100)
152
+ this.service.updateCharacteristic(this.hapChar.CurrentPosition, prevPosition)
153
+ this.accessory.context.cacheCurrentPosition = prevPosition
154
+ }
155
+ const diffPosition = value - prevPosition
156
+ const setToMoveUp = diffPosition > 0
157
+ let decisecondsToMove
158
+ if (setToMoveUp) {
159
+ decisecondsToMove = Math.round(Math.abs(diffPosition) * percentStepUpPerDS)
160
+ params.switches.push({ switch: 'on', outlet: 0 })
161
+ } else {
162
+ decisecondsToMove = Math.round(Math.abs(diffPosition) * percentStepDownPerDS)
163
+ params.switches.push({ switch: 'on', outlet: 1 })
164
+ }
165
+ await this.platform.sendDeviceUpdate(this.accessory, params)
166
+ params.switches = []
167
+ this.accessory.context.cacheTargetPosition = value
168
+ this.accessory.context.cachePositionState = setToMoveUp ? 1 : 0
169
+ this.accessory.context.cacheLastStartTime = Math.floor(Date.now() / 100)
170
+ await sleep(decisecondsToMove * 100)
171
+ if (this.updateKey !== updateKey) {
172
+ return
173
+ }
174
+ params.switches.push({
175
+ switch: 'off',
176
+ outlet: setToMoveUp ? 0 : 1,
177
+ })
178
+ await this.platform.sendDeviceUpdate(this.accessory, params)
179
+ this.service.updateCharacteristic(this.hapChar.PositionState, 2)
180
+ this.service.updateCharacteristic(this.hapChar.CurrentPosition, value)
181
+ this.accessory.context.cachePositionState = 2
182
+ this.accessory.context.cacheCurrentPosition = value
183
+ if (this.enableLogging) {
184
+ this.log('[%s] %s [%s%]', this.name, this.lang.curPos, value)
185
+ }
186
+ } catch (err) {
187
+ this.platform.deviceUpdateError(this.accessory, err, true)
188
+ setTimeout(() => {
189
+ this.service.updateCharacteristic(
190
+ this.hapChar.TargetPosition,
191
+ this.accessory.context.cacheTargetPosition,
192
+ )
193
+ }, 2000)
194
+ this.service.updateCharacteristic(this.hapChar.TargetPosition, new this.hapErr(-70402))
195
+ }
196
+ }
197
+
198
+ async internalUIUpdate() {
199
+ try {
200
+ // Skip polling if device isn't online
201
+ if (!this.isOnline) {
202
+ return
203
+ }
204
+
205
+ // Send the params to request the updates
206
+ await this.platform.sendDeviceUpdate(this.accessory, { uiActive: { outlet: 0, time: 120 } })
207
+ } catch (err) {
208
+ // Suppress errors here
209
+ }
210
+ }
211
+
212
+ async externalUpdate(params) {
213
+ try {
214
+ if (!this.powerReadings) {
215
+ return
216
+ }
217
+ let logger = false
218
+ let power
219
+ let voltage
220
+ let current
221
+ if (hasProperty(params, 'actPow_00')) {
222
+ power = Number.parseInt(params.actPow_00, 10) / 100
223
+ this.service.updateCharacteristic(this.eveChar.CurrentConsumption, power)
224
+ logger = true
225
+ }
226
+ if (hasProperty(params, 'voltage_00')) {
227
+ voltage = Number.parseInt(params.voltage_00, 10) / 100
228
+ this.service.updateCharacteristic(this.eveChar.Voltage, voltage)
229
+ logger = true
230
+ }
231
+ if (hasProperty(params, 'current_00')) {
232
+ current = Number.parseInt(params.current_00, 10) / 100
233
+ this.service.updateCharacteristic(this.eveChar.ElectricCurrent, current)
234
+ logger = true
235
+ }
236
+ if (params.updateSource && logger && this.enableLogging) {
237
+ this.log(
238
+ '[%s] %s%s%s.',
239
+ this.name,
240
+ power !== undefined ? `${this.lang.curPower} [${power}W]` : '',
241
+ voltage !== undefined ? ` ${this.lang.curVolt} [${voltage}V]` : '',
242
+ current !== undefined ? ` ${this.lang.curCurr} [${current}A]` : '',
243
+ )
244
+ }
245
+ } catch (err) {
246
+ this.platform.deviceUpdateError(this.accessory, err, false)
247
+ }
248
+ }
249
+
250
+ markStatus(isOnline) {
251
+ this.isOnline = isOnline
252
+ }
253
+ }