@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,140 @@
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
+ // Set up custom variables for this device type
19
+ const deviceConf = platform.deviceConf[accessory.context.eweDeviceId] || {}
20
+ this.lowBattThreshold = deviceConf.lowBattThreshold
21
+ ? Math.min(deviceConf.lowBattThreshold, 100)
22
+ : platformConsts.defaultValues.lowBattThreshold
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 leak sensor service then remove it
45
+ if (this.accessory.getService(this.hapServ.LeakSensor)) {
46
+ this.accessory.removeService(this.accessory.getService(this.hapServ.LeakSensor))
47
+ }
48
+
49
+ // Add the contact sensor service if it doesn't already exist
50
+ this.service = this.accessory.getService(this.hapServ.ContactSensor)
51
+ if (!this.service) {
52
+ this.service = this.accessory.addService(this.hapServ.ContactSensor)
53
+ this.service.addCharacteristic(this.eveChar.LastActivation)
54
+ this.service.addCharacteristic(this.eveChar.ResetTotal)
55
+ this.service.addCharacteristic(this.eveChar.OpenDuration)
56
+ this.service.addCharacteristic(this.eveChar.ClosedDuration)
57
+ this.service.addCharacteristic(this.eveChar.TimesOpened)
58
+ }
59
+
60
+ // Add the set handler to the contact sensor reset total characteristic
61
+ this.service.getCharacteristic(this.eveChar.ResetTotal).onSet(() => {
62
+ this.service.updateCharacteristic(this.eveChar.TimesOpened, 0)
63
+ })
64
+
65
+ // Add the battery service if it doesn't already exist
66
+ this.batteryService = this.accessory.getService(this.hapServ.Battery)
67
+ || this.accessory.addService(this.hapServ.Battery)
68
+
69
+ // Pass the accessory to Fakegato to set up with Eve
70
+ this.accessory.eveService = new platform.eveService('door', this.accessory, {
71
+ log: () => {},
72
+ })
73
+ this.accessory.eveService.addEntry({
74
+ status: this.service.getCharacteristic(this.hapChar.ContactSensorState).value,
75
+ })
76
+
77
+ // Output the customised options to the log
78
+ const normalLogging = this.enableLogging ? 'standard' : 'disable'
79
+ const opts = JSON.stringify({
80
+ logging: this.enableDebugLogging ? 'debug' : normalLogging,
81
+ lowBattThreshold: this.lowBattThreshold,
82
+ showAs: 'default',
83
+ })
84
+ this.log('[%s] %s %s.', this.name, this.lang.devInitOpts, opts)
85
+ }
86
+
87
+ async externalUpdate(params) {
88
+ try {
89
+ if (hasProperty(params, 'battery') && params.battery !== this.cacheBatt) {
90
+ this.cacheBatt = params.battery
91
+ if (this.accessory.context.eweUIID === 154) {
92
+ // No scaling needed for this model as provided as a %
93
+ this.cacheBattScaled = this.cacheBatt
94
+ } else {
95
+ // Scaling needed for UIID 102 as provided as a voltage rather than a %
96
+ this.cacheBattScaled = Math.min(Math.max(this.cacheBatt, 2), 3)
97
+ this.cacheBattScaled = Math.round((this.cacheBattScaled - 2) * 100)
98
+ }
99
+
100
+ this.batteryService.updateCharacteristic(this.hapChar.BatteryLevel, this.cacheBattScaled)
101
+ this.batteryService.updateCharacteristic(
102
+ this.hapChar.StatusLowBattery,
103
+ this.cacheBattScaled < this.lowBattThreshold ? 1 : 0,
104
+ )
105
+ if (params.updateSource && this.enableLogging) {
106
+ this.log('[%s] %s [%s%].', this.name, this.lang.curBatt, this.cacheBattScaled)
107
+ }
108
+ }
109
+ if (!params.switch || params.switch === this.cacheState) {
110
+ return
111
+ }
112
+ this.cacheState = params.switch
113
+ const newState = params.switch === 'on' ? 1 : 0
114
+ if (newState === 1) {
115
+ this.service.updateCharacteristic(this.hapChar.ContactSensorState, 1)
116
+ this.accessory.eveService.addEntry({ status: 1 })
117
+ const initialTime = this.accessory.eveService.getInitialTime()
118
+ this.service.updateCharacteristic(
119
+ this.eveChar.LastActivation,
120
+ Math.round(new Date().valueOf() / 1000) - initialTime,
121
+ )
122
+ const newTO = this.service.getCharacteristic(this.eveChar.TimesOpened).value + 1
123
+ this.service.updateCharacteristic(this.eveChar.TimesOpened, newTO)
124
+ } else {
125
+ this.service.updateCharacteristic(this.hapChar.ContactSensorState, 0)
126
+ this.accessory.eveService.addEntry({ status: 0 })
127
+ }
128
+ if (params.updateSource && this.enableLogging) {
129
+ this.log(
130
+ '[%s] %s [%s].',
131
+ this.name,
132
+ this.lang.curState,
133
+ newState === 0 ? this.lang.contactYes : this.lang.contactNo,
134
+ )
135
+ }
136
+ } catch (err) {
137
+ this.platform.deviceUpdateError(this.accessory, err, false)
138
+ }
139
+ }
140
+ }
@@ -0,0 +1,182 @@
1
+ import platformConsts from '../utils/constants.js'
2
+ import { hasProperty, parseError } 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.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.tempOffset = deviceConf.offset || platformConsts.defaultValues.offset
23
+ this.tempOffsetFactor = deviceConf.offsetFactor
24
+ this.humiOffset = deviceConf && deviceConf.humidityOffset
25
+ ? Number.parseInt(deviceConf.humidityOffset, 10)
26
+ : platformConsts.defaultValues.humidityOffset
27
+ this.humiOffsetFactor = deviceConf.humidityOffsetFactor
28
+
29
+ // Set the correct logging variables for this accessory
30
+ switch (deviceConf.overrideLogging) {
31
+ case 'standard':
32
+ this.enableLogging = true
33
+ this.enableDebugLogging = false
34
+ break
35
+ case 'debug':
36
+ this.enableLogging = true
37
+ this.enableDebugLogging = true
38
+ break
39
+ case 'disable':
40
+ this.enableLogging = false
41
+ this.enableDebugLogging = false
42
+ break
43
+ default:
44
+ this.enableLogging = !platform.config.disableDeviceLogging
45
+ this.enableDebugLogging = platform.config.debug
46
+ break
47
+ }
48
+
49
+ // Add the temperature sensor service if it doesn't already exist
50
+ this.tempService = this.accessory.getService(this.hapServ.TemperatureSensor)
51
+ || this.accessory.addService(this.hapServ.TemperatureSensor)
52
+
53
+ // Set custom properties of the current temperature characteristic
54
+ this.tempService.getCharacteristic(this.hapChar.CurrentTemperature).setProps({
55
+ minStep: 0.1,
56
+ })
57
+ this.cacheTemp = this.tempService.getCharacteristic(this.hapChar.CurrentTemperature).value
58
+ this.updateCache()
59
+
60
+ // Add the humidity sensor service if it doesn't already exist
61
+ this.humiService = this.accessory.getService(this.hapServ.HumiditySensor)
62
+ || this.accessory.addService(this.hapServ.HumiditySensor)
63
+
64
+ // Add the get handlers only if the user hasn't disabled the disableNoResponse setting
65
+ if (!platform.config.disableNoResponse) {
66
+ this.tempService
67
+ .getCharacteristic(this.hapChar.CurrentTemperature)
68
+ .setProps({
69
+ minStep: 0.1,
70
+ })
71
+ .onGet(() => {
72
+ if (!this.isOnline) {
73
+ throw new this.hapErr(-70402)
74
+ }
75
+ return this.tempService.getCharacteristic(this.hapChar.CurrentTemperature).value
76
+ })
77
+ this.humiService.getCharacteristic(this.hapChar.CurrentRelativeHumidity).onGet(() => {
78
+ if (!this.isOnline) {
79
+ throw new this.hapErr(-70402)
80
+ }
81
+ return this.humiService.getCharacteristic(this.hapChar.CurrentRelativeHumidity).value
82
+ })
83
+ }
84
+
85
+ // Pass the accessory to Fakegato to set up with Eve
86
+ this.accessory.eveService = new platform.eveService('custom', this.accessory, {
87
+ log: () => {},
88
+ })
89
+
90
+ // Output the customised options to the log
91
+ const normalLogging = this.enableLogging ? 'standard' : 'disable'
92
+ const opts = JSON.stringify({
93
+ humidityOffset: this.humiOffset,
94
+ humidityOffsetFactor: this.humiOffsetFactor,
95
+ logging: this.enableDebugLogging ? 'debug' : normalLogging,
96
+ offset: this.tempOffset,
97
+ offsetFactor: this.tempOffsetFactor,
98
+ })
99
+ this.log('[%s] %s %s.', this.name, this.lang.devInitOpts, opts)
100
+ }
101
+
102
+ async externalUpdate(params) {
103
+ try {
104
+ if (hasProperty(params, 'temperature')) {
105
+ let newTemp = Number(params.temperature)
106
+ if (this.tempOffsetFactor) {
107
+ newTemp *= this.tempOffset
108
+ } else {
109
+ newTemp += this.tempOffset
110
+ }
111
+ if (newTemp !== this.cacheTemp) {
112
+ this.cacheTemp = newTemp
113
+ this.tempService.updateCharacteristic(this.hapChar.CurrentTemperature, this.cacheTemp)
114
+ this.accessory.eveService.addEntry({ temp: this.cacheTemp })
115
+ if (params.updateSource && this.enableLogging) {
116
+ this.log('[%s] %s [%s°C].', this.name, this.lang.curTemp, this.cacheTemp)
117
+ }
118
+
119
+ // Update the cache file with the new temperature
120
+ this.updateCache()
121
+ }
122
+ }
123
+ if (hasProperty(params, 'humidity')) {
124
+ let newHumi = Number.parseInt(params.humidity, 10)
125
+ if (this.humiOffsetFactor) {
126
+ newHumi *= this.humiOffset
127
+ } else {
128
+ newHumi += this.humiOffset
129
+ }
130
+ newHumi = Math.max(Math.min(Number.parseInt(newHumi, 10), 100), 0)
131
+ if (newHumi !== this.cacheHumi) {
132
+ this.cacheHumi = newHumi
133
+ this.humiService.updateCharacteristic(
134
+ this.hapChar.CurrentRelativeHumidity,
135
+ this.cacheHumi,
136
+ )
137
+ this.accessory.eveService.addEntry({ humidity: this.cacheHumi })
138
+ if (params.updateSource && this.enableLogging) {
139
+ this.log('[%s] %s [%s%].', this.name, this.lang.curHumi, this.cacheHumi)
140
+ }
141
+ }
142
+ }
143
+ } catch (err) {
144
+ this.platform.deviceUpdateError(this.accessory, err, false)
145
+ }
146
+ }
147
+
148
+ async updateCache() {
149
+ // Don't continue if the storage client hasn't initialised properly
150
+ if (!this.platform.storageClientData) {
151
+ return
152
+ }
153
+
154
+ // Attempt to save the new temperature to the cache
155
+ try {
156
+ await this.platform.storageData.setItem(
157
+ `${this.accessory.context.eweDeviceId}_temp`,
158
+ this.cacheTemp,
159
+ )
160
+ } catch (err) {
161
+ if (this.enableLogging) {
162
+ this.log.warn('[%s] %s %s.', this.name, this.lang.storageWriteErr, parseError(err))
163
+ }
164
+ }
165
+ }
166
+
167
+ currentState() {
168
+ const toReturn = {}
169
+ toReturn.services = ['temperature', 'humidity']
170
+ toReturn.temperature = {
171
+ current: this.tempService.getCharacteristic(this.hapChar.CurrentTemperature).value,
172
+ }
173
+ toReturn.humidity = {
174
+ current: this.humiService.getCharacteristic(this.hapChar.CurrentRelativeHumidity).value,
175
+ }
176
+ return toReturn
177
+ }
178
+
179
+ markStatus(isOnline) {
180
+ this.isOnline = isOnline
181
+ }
182
+ }
@@ -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 window covering service if it doesn't already exist
55
+ this.service = this.accessory.getService(this.hapServ.WindowCovering)
56
+ if (!this.service) {
57
+ this.service = this.accessory.addService(this.hapServ.WindowCovering)
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: 'blind',
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
+ }