@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,272 @@
1
+ import { hs2rgb, rgb2hs } from '../utils/colour.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
+ this.offlineAsOff = deviceConf.offlineAsOff
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 lightbulb service if it doesn't already exist
46
+ this.service = this.accessory.getService(this.hapServ.Lightbulb)
47
+ || this.accessory.addService(this.hapServ.Lightbulb)
48
+
49
+ // Add the set handler to the lightbulb on/off characteristic
50
+ this.service
51
+ .getCharacteristic(this.hapChar.On)
52
+ .onSet(async value => this.internalStateUpdate(value))
53
+
54
+ // Add the set handler to the lightbulb brightness characteristic
55
+ this.service
56
+ .getCharacteristic(this.hapChar.Brightness)
57
+ .setProps({ minStep: 100 })
58
+ .onSet(async value => this.internalBrightnessUpdate(value))
59
+
60
+ // Add the set handler to the lightbulb hue characteristic
61
+ this.service
62
+ .getCharacteristic(this.hapChar.Hue)
63
+ .onSet(async value => this.internalColourUpdate(value))
64
+ this.cacheSat = this.service.getCharacteristic(this.hapChar.Saturation).value
65
+
66
+ // Add the get handlers only if the user hasn't disabled the disableNoResponse setting
67
+ if (!platform.config.disableNoResponse) {
68
+ this.service.getCharacteristic(this.hapChar.On).onGet(() => {
69
+ if (!this.isOnline) {
70
+ throw new this.hapErr(-70402)
71
+ }
72
+ return this.service.getCharacteristic(this.hapChar.On).value
73
+ })
74
+ this.service
75
+ .getCharacteristic(this.hapChar.Brightness)
76
+ .onGet(() => {
77
+ if (!this.isOnline) {
78
+ throw new this.hapErr(-70402)
79
+ }
80
+ return this.service.getCharacteristic(this.hapChar.Brightness).value
81
+ })
82
+ this.service.getCharacteristic(this.hapChar.Hue).onGet(() => {
83
+ if (!this.isOnline) {
84
+ throw new this.hapErr(-70402)
85
+ }
86
+ return this.service.getCharacteristic(this.hapChar.Hue).value
87
+ })
88
+ }
89
+
90
+ // Output the customised options to the log
91
+ const normalLogging = this.enableLogging ? 'standard' : 'disable'
92
+ const opts = JSON.stringify({
93
+ logging: this.enableDebugLogging ? 'debug' : normalLogging,
94
+ offlineAsOff: !!this.offlineAsOff,
95
+ })
96
+ this.log('[%s] %s %s.', this.name, this.lang.devInitOpts, opts)
97
+ }
98
+
99
+ async internalStateUpdate(value) {
100
+ try {
101
+ const params = {}
102
+ const newValue = value ? 'on' : 'off'
103
+ if (this.cacheState === newValue) {
104
+ return
105
+ }
106
+ params.state = newValue
107
+ const timerKey = generateRandomString(5)
108
+ this.updateTimeout = timerKey
109
+ setTimeout(() => {
110
+ if (this.updateTimeout === timerKey) {
111
+ this.updateTimeout = false
112
+ }
113
+ }, 5000)
114
+ await this.platform.sendDeviceUpdate(this.accessory, params)
115
+ this.cacheState = newValue
116
+ if (this.enableLogging) {
117
+ this.log('[%s] %s [%s].', this.name, this.lang.curState, this.cacheState)
118
+ }
119
+ } catch (err) {
120
+ this.platform.deviceUpdateError(this.accessory, err, true)
121
+ setTimeout(() => {
122
+ this.service.updateCharacteristic(this.hapChar.On, this.cacheState === 'on')
123
+ }, 2000)
124
+ throw new this.hapErr(-70402)
125
+ }
126
+ }
127
+
128
+ async internalBrightnessUpdate(value) {
129
+ try {
130
+ // B1 doesn't support brightness
131
+ this.cacheBright = value
132
+ } catch (err) {
133
+ this.platform.deviceUpdateError(this.accessory, err, true)
134
+ setTimeout(() => {
135
+ this.service.updateCharacteristic(this.hapChar.Brightness, this.cacheBright)
136
+ }, 2000)
137
+ throw new this.hapErr(-70402)
138
+ }
139
+ }
140
+
141
+ async internalColourUpdate(value) {
142
+ try {
143
+ if (this.cacheHue === value) {
144
+ return
145
+ }
146
+ const updateKeyColour = generateRandomString(5)
147
+ this.updateKeyColour = updateKeyColour
148
+ await sleep(400)
149
+ if (updateKeyColour !== this.updateKeyColour) {
150
+ return
151
+ }
152
+ this.updateTimeout = updateKeyColour
153
+ setTimeout(() => {
154
+ if (this.updateTimeout === updateKeyColour) {
155
+ this.updateTimeout = false
156
+ }
157
+ }, 5000)
158
+ const saturation = this.service.getCharacteristic(this.hapChar.Saturation).value
159
+ const newRGB = hs2rgb(value, saturation)
160
+ const params = {
161
+ zyx_mode: 2,
162
+ type: 'middle',
163
+ channel0: '0',
164
+ channel1: '0',
165
+ channel2: newRGB[0].toString(),
166
+ channel3: newRGB[1].toString(),
167
+ channel4: newRGB[2].toString(),
168
+ }
169
+ await this.platform.sendDeviceUpdate(this.accessory, params)
170
+ this.cacheHue = value;
171
+ [this.cacheR, this.cacheG, this.cacheB] = newRGB
172
+ if (this.enableLogging) {
173
+ this.log(
174
+ '[%s] %s [rgb %s].',
175
+ this.name,
176
+ this.lang.curColour,
177
+ `${this.cacheR} ${this.cacheG} ${this.cacheB}`,
178
+ )
179
+ }
180
+ } catch (err) {
181
+ this.platform.deviceUpdateError(this.accessory, err, true)
182
+ setTimeout(() => {
183
+ this.service.updateCharacteristic(this.hapChar.Hue, this.cacheHue)
184
+ }, 2000)
185
+ throw new this.hapErr(-70402)
186
+ }
187
+ }
188
+
189
+ async externalUpdate(params) {
190
+ try {
191
+ if (this.updateTimeout) {
192
+ return
193
+ }
194
+ if (params.state && params.state !== this.cacheState) {
195
+ this.cacheState = params.state
196
+ this.service.updateCharacteristic(this.hapChar.On, this.cacheState === 'on')
197
+ this.service.updateCharacteristic(
198
+ this.hapChar.Brightness,
199
+ this.cacheState === 'on' ? 100 : 0,
200
+ )
201
+ if (params.updateSource && this.enableLogging) {
202
+ this.log('[%s] %s [%s].', this.name, this.lang.curState, this.cacheState)
203
+ }
204
+ }
205
+ let hs
206
+ let mode
207
+ if (params.zyx_mode) {
208
+ mode = Number.parseInt(params.zyx_mode, 10)
209
+ } else if (
210
+ hasProperty(params, 'channel0')
211
+ && Number.parseInt(params.channel0, 10) + Number.parseInt(params.channel1, 10) > 0
212
+ ) {
213
+ mode = 1
214
+ } else {
215
+ mode = 2
216
+ }
217
+ if (mode === 2) {
218
+ if (hasProperty(params, 'channel2')) {
219
+ if (
220
+ params.channel2 !== (this.cacheR || 0).toString()
221
+ || params.channel3 !== (this.cacheG || 0).toString()
222
+ || params.channel4 !== (this.cacheB || 0).toString()
223
+ ) {
224
+ this.cacheR = Number.parseInt(params.channel2, 10)
225
+ this.cacheG = Number.parseInt(params.channel3, 10)
226
+ this.cacheB = Number.parseInt(params.channel4, 10)
227
+ hs = rgb2hs(this.cacheR, this.cacheG, this.cacheB);
228
+ [this.cacheHue] = hs
229
+ this.service.updateCharacteristic(this.hapChar.Hue, this.cacheHue)
230
+ this.service.updateCharacteristic(this.hapChar.Saturation, 100)
231
+ this.service.updateCharacteristic(this.hapChar.Brightness, 100)
232
+ if (params.updateSource && this.enableLogging) {
233
+ this.log(
234
+ '[%s] %s [rgb %s].',
235
+ this.name,
236
+ this.lang.curColour,
237
+ `${this.cacheR} ${this.cacheG} ${this.cacheB}`,
238
+ )
239
+ }
240
+ }
241
+ }
242
+ }
243
+ } catch (err) {
244
+ this.platform.deviceUpdateError(this.accessory, err, false)
245
+ }
246
+ }
247
+
248
+ markStatus(isOnline) {
249
+ this.isOnline = isOnline
250
+
251
+ // Show as off if offlineAsOff is enabled
252
+ if (this.offlineAsOff && !isOnline && this.cacheState !== 'off') {
253
+ this.service.updateCharacteristic(this.hapChar.On, false)
254
+ this.cacheState = 'off'
255
+ if (this.enableLogging) {
256
+ this.log('[%s] %s [%s - offline]', this.name, this.lang.curState, this.cacheState)
257
+ }
258
+ }
259
+ }
260
+
261
+ currentState() {
262
+ const toReturn = {}
263
+ toReturn.services = ['light']
264
+ toReturn.light = {
265
+ state: this.service.getCharacteristic(this.hapChar.On).value ? 'on' : 'off',
266
+ brightness: this.service.getCharacteristic(this.hapChar.Brightness).value,
267
+ hue: this.service.getCharacteristic(this.hapChar.Hue).value,
268
+ saturation: this.service.getCharacteristic(this.hapChar.Saturation).value,
269
+ }
270
+ return toReturn
271
+ }
272
+ }
@@ -0,0 +1,363 @@
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
+ /*
23
+ This is for the DUALR3 using motor mode
24
+ This device's parameters are:
25
+ motorTurn: 1=OPEN, 0=STOP, 2=CLOSE (not needed by plugin)
26
+ location: 0=CLOSED, 100=OPEN
27
+ currLocation: 0=CLOSED, 100=OPEN
28
+ */
29
+
30
+ // Set up custom variables for this device type
31
+ const deviceConf = platform.deviceConf[accessory.context.eweDeviceId] || {}
32
+ const showAsMotor = deviceConf.showAsMotor || platformConsts.defaultValues.showAsMotor
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
+ // Add the window covering service if it doesn't already exist
55
+ let service
56
+ switch (showAsMotor) {
57
+ case 'door':
58
+ service = this.hapServ.Door
59
+ if (this.accessory.getService(this.hapServ.GarageDoorOpener)) {
60
+ this.accessory.removeService(this.accessory.getService(this.hapServ.GarageDoorOpener))
61
+ }
62
+ if (this.accessory.getService(this.hapServ.Window)) {
63
+ this.accessory.removeService(this.accessory.getService(this.hapServ.Window))
64
+ }
65
+ if (this.accessory.getService(this.hapServ.WindowCovering)) {
66
+ this.accessory.removeService(this.accessory.getService(this.hapServ.WindowCovering))
67
+ }
68
+ break
69
+ case 'garage':
70
+ service = this.hapServ.GarageDoorOpener
71
+ this.isGarage = true
72
+ if (this.accessory.getService(this.hapServ.Door)) {
73
+ this.accessory.removeService(this.accessory.getService(this.hapServ.Door))
74
+ }
75
+ if (this.accessory.getService(this.hapServ.Window)) {
76
+ this.accessory.removeService(this.accessory.getService(this.hapServ.Window))
77
+ }
78
+ if (this.accessory.getService(this.hapServ.WindowCovering)) {
79
+ this.accessory.removeService(this.accessory.getService(this.hapServ.WindowCovering))
80
+ }
81
+ break
82
+ case 'window':
83
+ service = this.hapServ.Window
84
+ if (this.accessory.getService(this.hapServ.Door)) {
85
+ this.accessory.removeService(this.accessory.getService(this.hapServ.Door))
86
+ }
87
+ if (this.accessory.getService(this.hapServ.GarageDoorOpener)) {
88
+ this.accessory.removeService(this.accessory.getService(this.hapServ.GarageDoorOpener))
89
+ }
90
+ if (this.accessory.getService(this.hapServ.WindowCovering)) {
91
+ this.accessory.removeService(this.accessory.getService(this.hapServ.WindowCovering))
92
+ }
93
+ break
94
+ default:
95
+ service = this.hapServ.WindowCovering
96
+ if (this.accessory.getService(this.hapServ.Door)) {
97
+ this.accessory.removeService(this.accessory.getService(this.hapServ.Door))
98
+ }
99
+ if (this.accessory.getService(this.hapServ.GarageDoorOpener)) {
100
+ this.accessory.removeService(this.accessory.getService(this.hapServ.GarageDoorOpener))
101
+ }
102
+ if (this.accessory.getService(this.hapServ.Window)) {
103
+ this.accessory.removeService(this.accessory.getService(this.hapServ.Window))
104
+ }
105
+ break
106
+ }
107
+ this.service = this.accessory.getService(service) || this.accessory.addService(service)
108
+
109
+ // Add Eve power characteristics
110
+ if (!this.service.testCharacteristic(this.eveChar.CurrentConsumption)) {
111
+ this.service.addCharacteristic(this.eveChar.CurrentConsumption)
112
+ }
113
+ if (!this.service.testCharacteristic(this.eveChar.ElectricCurrent)) {
114
+ this.service.addCharacteristic(this.eveChar.ElectricCurrent)
115
+ }
116
+ if (!this.service.testCharacteristic(this.eveChar.Voltage)) {
117
+ this.service.addCharacteristic(this.eveChar.Voltage)
118
+ }
119
+
120
+ // Add the set handler to the target position characteristic
121
+ if (this.isGarage) {
122
+ this.service
123
+ .getCharacteristic(this.hapChar.TargetDoorState)
124
+ .onSet(async value => this.internalTargetUpdate(value))
125
+ } else {
126
+ this.service
127
+ .getCharacteristic(this.hapChar.TargetPosition)
128
+ .onSet(async value => this.internalPositionUpdate(value))
129
+ }
130
+
131
+ // Add the get handlers only if the user hasn't disabled the disableNoResponse setting
132
+ if (!platform.config.disableNoResponse) {
133
+ if (this.isGarage) {
134
+ this.service.getCharacteristic(this.hapChar.CurrentDoorState).onGet(() => {
135
+ if (!this.isOnline) {
136
+ throw new this.hapErr(-70402)
137
+ }
138
+ return this.service.getCharacteristic(this.hapChar.CurrentDoorState).value
139
+ })
140
+ this.service.getCharacteristic(this.hapChar.TargetDoorState).onGet(() => {
141
+ if (!this.isOnline) {
142
+ throw new this.hapErr(-70402)
143
+ }
144
+ return this.service.getCharacteristic(this.hapChar.TargetDoorState).value
145
+ })
146
+ } else {
147
+ this.service.getCharacteristic(this.hapChar.CurrentPosition).onGet(() => {
148
+ if (!this.isOnline) {
149
+ throw new this.hapErr(-70402)
150
+ }
151
+ return this.service.getCharacteristic(this.hapChar.CurrentPosition).value
152
+ })
153
+ this.service.getCharacteristic(this.hapChar.TargetPosition).onGet(() => {
154
+ if (!this.isOnline) {
155
+ throw new this.hapErr(-70402)
156
+ }
157
+ return this.service.getCharacteristic(this.hapChar.TargetPosition).value
158
+ })
159
+ }
160
+ }
161
+
162
+ if (platform.config.mode !== 'lan') {
163
+ // Set up an interval to get eWeLink to send power updates
164
+ setTimeout(() => {
165
+ this.internalUIUpdate()
166
+ this.intervalPoll = setInterval(() => this.internalUIUpdate(), 120000)
167
+ }, 5000)
168
+
169
+ // Stop the intervals on Homebridge shutdown
170
+ platform.api.on('shutdown', () => clearInterval(this.intervalPoll))
171
+ }
172
+
173
+ // Output the customised options to the log
174
+ const normalLogging = this.enableLogging ? 'standard' : 'disable'
175
+ const opts = JSON.stringify({
176
+ logging: this.enableDebugLogging ? 'debug' : normalLogging,
177
+ showAsMotor,
178
+ })
179
+ this.log('[%s] %s %s.', this.name, this.lang.devInitOpts, opts)
180
+ }
181
+
182
+ async internalPositionUpdate(value) {
183
+ try {
184
+ if (this.cachePos === value) {
185
+ return
186
+ }
187
+ const updateKey = generateRandomString(5)
188
+ this.updateKey = updateKey
189
+ await sleep(500)
190
+ if (updateKey !== this.updateKey) {
191
+ return
192
+ }
193
+ const params = { location: value }
194
+ await this.platform.sendDeviceUpdate(this.accessory, params)
195
+ this.cacheTarg = value
196
+ if (this.enableLogging) {
197
+ this.log('[%s] %s [%s%].', this.name, this.lang.curTarg, this.cacheTarg)
198
+ }
199
+ } catch (err) {
200
+ // Catch any errors and let the platform display them
201
+ this.platform.deviceUpdateError(this.accessory, err, true)
202
+ setTimeout(() => {
203
+ this.service.updateCharacteristic(this.hapChar.TargetPosition, this.cacheTarg)
204
+ }, 2000)
205
+ throw new this.hapErr(-70402)
206
+ }
207
+ }
208
+
209
+ async internalTargetUpdate(value) {
210
+ try {
211
+ // 0 for open, 1 for closed
212
+ // this.cachePos is 0 for closed and >0 for open
213
+
214
+ const params = { location: value === 1 ? 0 : 100 }
215
+ await this.platform.sendDeviceUpdate(this.accessory, params)
216
+ this.cacheTarg = value === 1 ? 0 : 100
217
+ if (this.enableLogging) {
218
+ this.log('[%s] %s [%s%].', this.name, this.lang.curTarg, this.cacheTarg)
219
+ }
220
+ } catch (err) {
221
+ // Catch any errors and let the platform display them
222
+ this.platform.deviceUpdateError(this.accessory, err, true)
223
+ setTimeout(() => {
224
+ this.service.updateCharacteristic(this.hapChar.TargetDoorState, this.cacheTarg)
225
+ }, 2000)
226
+ throw new this.hapErr(-70402)
227
+ }
228
+ }
229
+
230
+ async internalUIUpdate() {
231
+ try {
232
+ // Skip polling if device isn't online
233
+ if (!this.isOnline) {
234
+ return
235
+ }
236
+
237
+ // Send the params to request the updates
238
+ await this.platform.sendDeviceUpdate(this.accessory, { uiActive: { outlet: 0, time: 120 } })
239
+ } catch (err) {
240
+ this.log.error(err)
241
+ }
242
+ }
243
+
244
+ async externalUpdate(params) {
245
+ try {
246
+ let locationParams = false
247
+
248
+ // currLocation is the current position of the motor
249
+ if (hasProperty(params, 'currLocation')) {
250
+ locationParams = true
251
+ if (params.currLocation !== this.cachePos) {
252
+ this.cachePos = params.currLocation
253
+ if (!this.isGarage) {
254
+ this.service.updateCharacteristic(this.hapChar.CurrentPosition, this.cachePos)
255
+ }
256
+ if (params.updateSource && this.enableLogging) {
257
+ this.log('[%s] %s [%s%].', this.name, this.lang.curPos, this.cachePos)
258
+ }
259
+ }
260
+ }
261
+
262
+ // location is the target position of the motor
263
+ if (hasProperty(params, 'location')) {
264
+ locationParams = true
265
+ if (params.location !== this.cacheTarg) {
266
+ this.cacheTarg = params.location
267
+ if (!this.isGarage) {
268
+ this.service.updateCharacteristic(this.hapChar.TargetPosition, this.cacheTarg)
269
+ }
270
+ if (params.updateSource && this.enableLogging) {
271
+ this.log('[%s] %s [%s%].', this.name, this.lang.curTarg, this.cacheTarg)
272
+ }
273
+ }
274
+ }
275
+
276
+ if (locationParams) {
277
+ // Get the target door state characteristic for use later
278
+ const targetChar = this.isGarage
279
+ ? this.service.getCharacteristic(this.hapChar.TargetDoorState)
280
+ : this.service.getCharacteristic(this.hapChar.TargetPosition)
281
+
282
+ // If the two are equal then the motor must have stopped at this position
283
+ if (this.cacheTarg === this.cachePos) {
284
+ if (this.isGarage) {
285
+ if (this.cachePos === 0) {
286
+ // CLOSED
287
+ this.service.updateCharacteristic(this.hapChar.CurrentDoorState, 1)
288
+ if (targetChar.value !== 1) {
289
+ targetChar.updateValue(1)
290
+ }
291
+ } else {
292
+ // OPEN
293
+ this.service.updateCharacteristic(this.hapChar.CurrentDoorState, 0)
294
+ if (targetChar.value !== 0) {
295
+ targetChar.updateValue(0)
296
+ }
297
+ }
298
+ } else {
299
+ // PositionState 2 === STOPPED
300
+ this.service.updateCharacteristic(this.hapChar.PositionState, 2)
301
+ }
302
+ } else if (this.cacheTarg > this.cachePos) {
303
+ if (this.isGarage) {
304
+ // OPENING
305
+ this.service.updateCharacteristic(this.hapChar.CurrentDoorState, 2)
306
+ if (targetChar.value !== 0) {
307
+ targetChar.updateValue(0)
308
+ }
309
+ } else {
310
+ // PositionState 1 === INCREASING
311
+ this.service.updateCharacteristic(this.hapChar.PositionState, 1)
312
+ }
313
+ } else if (this.isGarage) {
314
+ // CLOSING
315
+ this.service.updateCharacteristic(this.hapChar.CurrentDoorState, 3)
316
+ if (targetChar.value !== 1) {
317
+ targetChar.updateValue(1)
318
+ }
319
+ } else {
320
+ // PositionState 0 === DECREASING
321
+ this.service.updateCharacteristic(this.hapChar.PositionState, 0)
322
+ }
323
+ }
324
+
325
+ // Update power information if given
326
+ let logger = false
327
+ let power
328
+ let voltage
329
+ let current
330
+ if (hasProperty(params, 'actPow_00')) {
331
+ power = Number.parseInt(params.actPow_00, 10) / 100
332
+ this.service.updateCharacteristic(this.eveChar.CurrentConsumption, power)
333
+ logger = true
334
+ }
335
+ if (hasProperty(params, 'voltage_00')) {
336
+ voltage = Number.parseInt(params.voltage_00, 10) / 100
337
+ this.service.updateCharacteristic(this.eveChar.Voltage, voltage)
338
+ logger = true
339
+ }
340
+ if (hasProperty(params, 'current_00')) {
341
+ current = Number.parseInt(params.current_00, 10) / 100
342
+ this.service.updateCharacteristic(this.eveChar.ElectricCurrent, current)
343
+ logger = true
344
+ }
345
+ if (params.updateSource && logger && this.enableLogging) {
346
+ this.log(
347
+ '[%s] %s%s%s.',
348
+ this.name,
349
+ power !== undefined ? `${this.lang.curPower} [${power}W]` : '',
350
+ voltage !== undefined ? ` ${this.lang.curVolt} [${voltage}V]` : '',
351
+ current !== undefined ? ` ${this.lang.curCurr} [${current}A]` : '',
352
+ )
353
+ }
354
+ } catch (err) {
355
+ // Catch any errors and let the platform display them
356
+ this.platform.deviceUpdateError(this.accessory, err, false)
357
+ }
358
+ }
359
+
360
+ markStatus(isOnline) {
361
+ this.isOnline = isOnline
362
+ }
363
+ }