@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,125 @@
1
+ export default class {
2
+ constructor(platform, accessory) {
3
+ // Set up variables from the platform
4
+ this.eveChar = platform.eveChar
5
+ this.hapChar = platform.api.hap.Characteristic
6
+ this.hapErr = platform.api.hap.HapStatusError
7
+ this.hapServ = platform.api.hap.Service
8
+ this.lang = platform.lang
9
+ this.log = platform.log
10
+ this.platform = platform
11
+
12
+ // Set up variables from the accessory
13
+ this.name = accessory.displayName
14
+ this.accessory = accessory
15
+
16
+ // Initially set the online flag as true (to be then updated as false if necessary)
17
+ this.isOnline = true
18
+
19
+ // Set up custom variables for this device type
20
+ const deviceConf = platform.rfSubdevices[accessory.context.hbDeviceId] || {}
21
+
22
+ // Set the correct logging variables for this accessory
23
+ switch (deviceConf.overrideLogging) {
24
+ case 'standard':
25
+ this.enableLogging = true
26
+ this.enableDebugLogging = false
27
+ break
28
+ case 'debug':
29
+ this.enableLogging = true
30
+ this.enableDebugLogging = true
31
+ break
32
+ case 'disable':
33
+ this.enableLogging = false
34
+ this.enableDebugLogging = false
35
+ break
36
+ default:
37
+ this.enableLogging = !platform.config.disableDeviceLogging
38
+ this.enableDebugLogging = platform.config.debug
39
+ break
40
+ }
41
+
42
+ // If the accessory has a window covering service (from an old simulation) then remove it
43
+ if (this.accessory.getService(this.hapServ.WindowCovering)) {
44
+ this.accessory.removeService(this.accessory.getService(this.hapServ.WindowCovering))
45
+ }
46
+
47
+ // If the accessory has a door service (from an old simulation) then remove it
48
+ if (this.accessory.getService(this.hapServ.Door)) {
49
+ this.accessory.removeService(this.accessory.getService(this.hapServ.Door))
50
+ }
51
+
52
+ // If the accessory has a window service (from an old simulation) then remove it
53
+ if (this.accessory.getService(this.hapServ.Window)) {
54
+ this.accessory.removeService(this.accessory.getService(this.hapServ.Window))
55
+ }
56
+
57
+ // This instance is a remote control with buttons or curtain control
58
+ Object.entries(this.accessory.context.buttons).forEach(([chan, name]) => {
59
+ // For each curtain/button we create a separate switch service
60
+
61
+ // Add the switch service if it doesn't already exist
62
+ if (!this.accessory.getService(name)) {
63
+ this.accessory.addService(this.hapServ.Switch, name, `switch${chan}`)
64
+ }
65
+
66
+ // Always start with the buttons off (useful when restarting Homebridge)
67
+ this.accessory.getService(name).updateCharacteristic(this.hapChar.On, false)
68
+
69
+ // Add the set handler to the switch on/off characteristic
70
+ this.accessory
71
+ .getService(name)
72
+ .getCharacteristic(this.hapChar.On)
73
+ .onSet(async value => this.internalPressUpdate(chan, name, value))
74
+
75
+ // Add the get handlers only if the user hasn't disabled the disableNoResponse setting
76
+ if (!platform.config.disableNoResponse) {
77
+ this.accessory
78
+ .getService(name)
79
+ .getCharacteristic(this.hapChar.On)
80
+ .onGet(() => {
81
+ if (!this.isOnline) {
82
+ throw new this.hapErr(-70402)
83
+ }
84
+ return this.accessory.getService(name).getCharacteristic(this.hapChar.On).value
85
+ })
86
+ }
87
+ })
88
+
89
+ // Output the customised options to the log
90
+ const normalLogging = this.enableLogging ? 'standard' : 'disable'
91
+ const opts = JSON.stringify({
92
+ logging: this.enableDebugLogging ? 'debug' : normalLogging,
93
+ })
94
+ this.log('[%s] %s %s.', this.name, this.lang.devInitOpts, opts)
95
+ }
96
+
97
+ async internalPressUpdate(rfChl, service, value) {
98
+ try {
99
+ if (!value) {
100
+ return
101
+ }
102
+ const params = {
103
+ cmd: 'transmit',
104
+ rfChl: Number.parseInt(rfChl, 10),
105
+ }
106
+ await this.platform.sendDeviceUpdate(this.accessory, params)
107
+ if (this.enableLogging) {
108
+ this.log('[%s] %s [%s].', this.name, this.lang.curState, this.lang.buttonTrig)
109
+ }
110
+ setTimeout(() => {
111
+ this.accessory.getService(service).updateCharacteristic(this.hapChar.On, false)
112
+ }, 1000)
113
+ } catch (err) {
114
+ this.platform.deviceUpdateError(this.accessory, err, true)
115
+ setTimeout(() => {
116
+ this.accessory.getService(service).updateCharacteristic(this.hapChar.On, false)
117
+ }, 2000)
118
+ throw new this.hapErr(-70402)
119
+ }
120
+ }
121
+
122
+ markStatus(isOnline) {
123
+ this.isOnline = isOnline
124
+ }
125
+ }
@@ -0,0 +1,173 @@
1
+ import platformConsts from '../utils/constants.js'
2
+
3
+ export default class {
4
+ constructor(platform, accessory) {
5
+ // Set up variables from the platform
6
+ this.eveChar = platform.eveChar
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
+ // Initially set the online flag as true (to be then updated as false if necessary)
15
+ this.isOnline = true
16
+
17
+ // Set up custom variables for this device type
18
+ const deviceConf = platform.rfSubdevices[accessory.context.hbDeviceId] || {}
19
+ this.sensorTimeLength = deviceConf.sensorTimeLength || platformConsts.defaultValues.sensorTimeLength
20
+ this.sensorTimeDifference = deviceConf.sensorTimeDifference || platformConsts.defaultValues.sensorTimeDifference
21
+ this.sensorType = deviceConf.type ? deviceConf.type : 'motion'
22
+
23
+ // Set the correct logging variables for this accessory
24
+ switch (deviceConf.overrideLogging) {
25
+ case 'standard':
26
+ this.enableLogging = true
27
+ this.enableDebugLogging = false
28
+ break
29
+ case 'debug':
30
+ this.enableLogging = true
31
+ this.enableDebugLogging = true
32
+ break
33
+ case 'disable':
34
+ this.enableLogging = false
35
+ this.enableDebugLogging = false
36
+ break
37
+ default:
38
+ this.enableLogging = !platform.config.disableDeviceLogging
39
+ this.enableDebugLogging = platform.config.debug
40
+ break
41
+ }
42
+
43
+ // This instance is a sensor which the user can define as different types
44
+ let serv
45
+ let char
46
+ let eveType
47
+ let addLACharacteristic = false
48
+
49
+ // Create an array of hap sensor services to for later to check sensor type hasn't changed
50
+ let hapServList = [
51
+ this.hapServ.LeakSensor,
52
+ this.hapServ.SmokeSensor,
53
+ this.hapServ.CarbonMonoxideSensor,
54
+ this.hapServ.CarbonDioxideSensor,
55
+ this.hapServ.ContactSensor,
56
+ this.hapServ.OccupancySensor,
57
+ this.hapServ.MotionSensor,
58
+ this.hapServ.StatelessProgrammableSwitch,
59
+ this.hapServ.Doorbell,
60
+ ]
61
+
62
+ // Check which type this sensor is and get the correct service/characteristic
63
+ switch (this.sensorType) {
64
+ case 'water':
65
+ serv = this.hapServ.LeakSensor
66
+ char = this.hapChar.LeakDetected
67
+ eveType = 'motion'
68
+ break
69
+ case 'fire':
70
+ case 'smoke':
71
+ serv = this.hapServ.SmokeSensor
72
+ char = this.hapChar.SmokeDetected
73
+ eveType = 'motion'
74
+ break
75
+ case 'co':
76
+ serv = this.hapServ.CarbonMonoxideSensor
77
+ char = this.hapChar.CarbonMonoxideDetected
78
+ eveType = 'motion'
79
+ break
80
+ case 'co2':
81
+ serv = this.hapServ.CarbonDioxideSensor
82
+ char = this.hapChar.CarbonDioxideDetected
83
+ eveType = 'motion'
84
+ break
85
+ case 'contact':
86
+ serv = this.hapServ.ContactSensor
87
+ char = this.hapChar.ContactSensorState
88
+ eveType = 'door'
89
+ addLACharacteristic = true
90
+ break
91
+ case 'occupancy':
92
+ serv = this.hapServ.OccupancySensor
93
+ char = this.hapChar.OccupancyDetected
94
+ eveType = 'motion'
95
+ break
96
+ case 'p_button':
97
+ serv = this.hapServ.StatelessProgrammableSwitch
98
+ char = this.hapChar.ProgrammableSwitchEvent
99
+ break
100
+ case 'doorbell':
101
+ serv = this.hapServ.Doorbell
102
+ char = this.hapChar.ProgrammableSwitchEvent
103
+ break
104
+ default:
105
+ serv = this.hapServ.MotionSensor
106
+ char = this.hapChar.MotionDetected
107
+ eveType = 'motion'
108
+ addLACharacteristic = true
109
+ break
110
+ }
111
+
112
+ // Remove wanted sensor from hap sensor type list
113
+ hapServList = hapServList.filter(el => el !== serv)
114
+
115
+ // Check and remove and redundant hap sensor types
116
+ hapServList.forEach((hapSensor) => {
117
+ if (accessory.getService(hapSensor)) {
118
+ accessory.removeService(accessory.getService(hapSensor))
119
+ }
120
+ })
121
+
122
+ // Add the sensor if it doesn't already exist
123
+ const service = accessory.getService(serv) || accessory.addService(serv)
124
+
125
+ // Remove double and long press from Button and Doorbell service
126
+ if (char === this.hapChar.ProgrammableSwitchEvent) {
127
+ service.getCharacteristic(this.hapChar.ProgrammableSwitchEvent).setProps({
128
+ validValues: [0],
129
+ })
130
+ } else {
131
+ // Always start with the sensor off (useful when restarting Homebridge, except Doorbell)
132
+ service.updateCharacteristic(char, 0)
133
+ }
134
+
135
+ // See if we need to add or remove the Last Activation characteristic
136
+ if (addLACharacteristic) {
137
+ if (!service.testCharacteristic(this.eveChar.LastActivation)) {
138
+ service.addCharacteristic(this.eveChar.LastActivation)
139
+ }
140
+ } else if (service.testCharacteristic(this.eveChar.LastActivation)) {
141
+ service.removeCharacteristic(service.getCharacteristic(this.eveChar.LastActivation))
142
+ }
143
+
144
+ // Add the get handlers only if the user hasn't disabled the disableNoResponse setting
145
+ if (!platform.config.disableNoResponse) {
146
+ service.getCharacteristic(char).onGet(() => {
147
+ if (!this.isOnline) {
148
+ throw new this.hapErr(-70402)
149
+ }
150
+ return service.getCharacteristic(char).value
151
+ })
152
+ }
153
+
154
+ // Pass the accessory to Fakegato to set up with Eve
155
+ accessory.eveService = new platform.eveService(eveType, accessory, {
156
+ log: () => {},
157
+ })
158
+
159
+ // Output the customised options to the log
160
+ const normalLogging = this.enableLogging ? 'standard' : 'disable'
161
+ const opts = JSON.stringify({
162
+ logging: this.enableDebugLogging ? 'debug' : normalLogging,
163
+ sensorTimeDifference: this.sensorTimeDifference,
164
+ sensorTimeLength: this.sensorTimeLength,
165
+ type: this.sensorType,
166
+ })
167
+ this.log('[%s] %s %s.', accessory.displayName, this.lang.devInitOpts, opts)
168
+ }
169
+
170
+ markStatus(isOnline) {
171
+ this.isOnline = isOnline
172
+ }
173
+ }
@@ -0,0 +1,311 @@
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.hapErr = platform.api.hap.HapStatusError
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.hideSwitch = deviceConf.hideSwitch
24
+ this.tempOffset = deviceConf.offset || platformConsts.defaultValues.offset
25
+ this.tempOffsetFactor = deviceConf.offsetFactor
26
+ this.humiOffset = deviceConf.humidityOffset
27
+ ? Number.parseInt(deviceConf.humidityOffset, 10)
28
+ : platformConsts.defaultValues.humidityOffset
29
+ this.humiOffsetFactor = deviceConf.humidityOffsetFactor
30
+
31
+ // Set the correct logging variables for this accessory
32
+ switch (deviceConf.overrideLogging) {
33
+ case 'standard':
34
+ this.enableLogging = true
35
+ this.enableDebugLogging = false
36
+ break
37
+ case 'debug':
38
+ this.enableLogging = true
39
+ this.enableDebugLogging = true
40
+ break
41
+ case 'disable':
42
+ this.enableLogging = false
43
+ this.enableDebugLogging = false
44
+ break
45
+ default:
46
+ this.enableLogging = !platform.config.disableDeviceLogging
47
+ this.enableDebugLogging = platform.config.debug
48
+ break
49
+ }
50
+
51
+ // If the accessory has a thermostat service then remove it
52
+ if (this.accessory.getService(this.hapServ.Thermostat)) {
53
+ this.accessory.removeService(this.accessory.getService(this.hapServ.Thermostat))
54
+ }
55
+
56
+ // If the accessory has a heater service then remove it
57
+ if (this.accessory.getService(this.hapServ.HeaterCooler)) {
58
+ this.accessory.removeService(this.accessory.getService(this.hapServ.HeaterCooler))
59
+ }
60
+
61
+ // If the accessory has a humidifier service then remove it
62
+ if (this.accessory.getService(this.hapServ.HumidifierDehumidifier)) {
63
+ this.accessory.removeService(this.accessory.getService(this.hapServ.HumidifierDehumidifier))
64
+ }
65
+
66
+ // The user can choose to hide the switch service if they desire
67
+ if (this.hideSwitch) {
68
+ // User has hidden the switch service so remove it if it exists
69
+ if (this.accessory.getService(this.hapServ.Switch)) {
70
+ this.accessory.removeService(this.accessory.getService(this.hapServ.Switch))
71
+ }
72
+ } else {
73
+ // User has not hidden the switch service so add it if it doesn't already exist
74
+ this.switchService = this.accessory.getService(this.hapServ.Switch)
75
+ || this.accessory.addService(this.hapServ.Switch)
76
+
77
+ // Add the set handler to the switch on/off characteristic
78
+ this.switchService
79
+ .getCharacteristic(this.hapChar.On)
80
+ .onSet(async value => this.internalStateUpdate(value))
81
+ }
82
+
83
+ // Add the temperature sensor service if it doesn't already exist
84
+ this.tempService = this.accessory.getService(this.hapServ.TemperatureSensor)
85
+ || this.accessory.addService(this.hapServ.TemperatureSensor)
86
+
87
+ // Set custom properties of the current temperature characteristic
88
+ this.tempService.getCharacteristic(this.hapChar.CurrentTemperature).setProps({
89
+ minStep: 0.1,
90
+ })
91
+ this.cacheTemp = this.tempService.getCharacteristic(this.hapChar.CurrentTemperature).value
92
+ this.updateCache()
93
+
94
+ // The DS18B20 sensor does not provide humidity readings
95
+ if (this.accessory.context.sensorType === 'DS18B20') {
96
+ if (this.accessory.getService(this.hapServ.HumiditySensor)) {
97
+ this.accessory.removeService(this.accessory.getService(this.hapServ.HumiditySensor))
98
+ }
99
+ } else {
100
+ // Add the humidity sensor service if it doesn't already exist
101
+ this.humiService = this.accessory.getService(this.hapServ.HumiditySensor)
102
+ || this.accessory.addService(this.hapServ.HumiditySensor)
103
+ }
104
+
105
+ // Add the get handlers only if the user hasn't disabled the disableNoResponse setting
106
+ if (!platform.config.disableNoResponse) {
107
+ if (this.switchService) {
108
+ this.switchService.getCharacteristic(this.hapChar.On).onGet(() => {
109
+ if (!this.isOnline) {
110
+ throw new this.hapErr(-70402)
111
+ }
112
+ return this.switchService.getCharacteristic(this.hapChar.On).value
113
+ })
114
+ }
115
+ this.tempService.getCharacteristic(this.hapChar.CurrentTemperature).onGet(() => {
116
+ if (!this.isOnline) {
117
+ throw new this.hapErr(-70402)
118
+ }
119
+ return this.tempService.getCharacteristic(this.hapChar.CurrentTemperature).value
120
+ })
121
+ if (this.humiService) {
122
+ this.humiService.getCharacteristic(this.hapChar.CurrentRelativeHumidity).onGet(() => {
123
+ if (!this.isOnline) {
124
+ throw new this.hapErr(-70402)
125
+ }
126
+ return this.humiService.getCharacteristic(this.hapChar.CurrentRelativeHumidity).value
127
+ })
128
+ }
129
+ }
130
+
131
+ // The switch as the primary service ensures the status is reflected in the Home icon
132
+ if (this.switchService) {
133
+ this.switchService.setPrimaryService()
134
+ }
135
+
136
+ // Pass the accessory to Fakegato to set up with Eve
137
+ this.accessory.eveService = new platform.eveService('custom', this.accessory, {
138
+ log: () => {},
139
+ })
140
+
141
+ // Set up an interval to get eWeLink to send regular temperature/humidity updates
142
+ if (platform.config.mode !== 'lan') {
143
+ setTimeout(() => {
144
+ this.internalUIUpdate()
145
+ this.intervalPoll = setInterval(() => this.internalUIUpdate(), 120000)
146
+ }, 5000)
147
+
148
+ // Stop the intervals on Homebridge shutdown
149
+ platform.api.on('shutdown', () => clearInterval(this.intervalPoll))
150
+ }
151
+
152
+ // Output the customised options to the log
153
+ const normalLogging = this.enableLogging ? 'standard' : 'disable'
154
+ const opts = JSON.stringify({
155
+ hideSwitch: this.hideSwitch,
156
+ humidityOffset: this.humiOffset,
157
+ humidityOffsetFactor: this.humiOffsetFactor,
158
+ logging: this.enableDebugLogging ? 'debug' : normalLogging,
159
+ offset: this.tempOffset,
160
+ offsetFactor: this.tempOffsetFactor,
161
+ showAs: 'default',
162
+ })
163
+ this.log('[%s] %s %s.', this.name, this.lang.devInitOpts, opts)
164
+ }
165
+
166
+ async internalStateUpdate(value) {
167
+ try {
168
+ const newValue = value ? 'on' : 'off'
169
+ if (newValue === this.cacheState) {
170
+ return
171
+ }
172
+ const params = {
173
+ switch: newValue,
174
+ mainSwitch: newValue,
175
+ deviceType: 'normal',
176
+ }
177
+ await this.platform.sendDeviceUpdate(this.accessory, params)
178
+ this.cacheState = newValue
179
+ if (this.enableLogging) {
180
+ this.log('[%s] %s [%s].', this.name, this.lang.curState, this.cacheState)
181
+ }
182
+ } catch (err) {
183
+ this.platform.deviceUpdateError(this.accessory, err, true)
184
+ setTimeout(() => {
185
+ this.switchService.updateCharacteristic(this.hapChar.On, this.cacheState === 'on')
186
+ }, 2000)
187
+ throw new this.hapErr(-70402)
188
+ }
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
+ await this.platform.sendDeviceUpdate(this.accessory, { uiActive: 120 })
200
+ } catch (err) {
201
+ // Suppress errors here
202
+ }
203
+ }
204
+
205
+ async externalUpdate(params) {
206
+ try {
207
+ if (!this.hideSwitch && params.switch) {
208
+ const newState = params.switch
209
+ if (this.cacheState !== newState) {
210
+ this.cacheState = newState
211
+ this.switchService.updateCharacteristic(this.hapChar.On, this.cacheState === 'on')
212
+ this.accessory.eveService.addEntry({
213
+ status: this.cacheState === 'on' ? 1 : 0,
214
+ })
215
+ if (params.updateSource && this.enableLogging) {
216
+ this.log('[%s] %s [%s].', this.name, this.lang.curState, this.cacheState)
217
+ }
218
+ }
219
+ }
220
+ if (
221
+ hasProperty(params, 'currentTemperature')
222
+ && params.currentTemperature !== 'unavailable'
223
+ ) {
224
+ let newTemp = Number(params.currentTemperature)
225
+ if (this.tempOffsetFactor) {
226
+ newTemp *= this.tempOffset
227
+ } else {
228
+ newTemp += this.tempOffset
229
+ }
230
+ if (newTemp !== this.cacheTemp) {
231
+ this.cacheTemp = newTemp
232
+ this.tempService.updateCharacteristic(this.hapChar.CurrentTemperature, this.cacheTemp)
233
+ this.accessory.eveService.addEntry({ temp: this.cacheTemp })
234
+ if (params.updateSource && this.enableLogging) {
235
+ this.log('[%s] %s [%s°C].', this.name, this.lang.curTemp, this.cacheTemp)
236
+ }
237
+
238
+ // Update the cache file with the new temperature
239
+ this.updateCache()
240
+ }
241
+ }
242
+ if (
243
+ hasProperty(params, 'currentHumidity')
244
+ && params.currentHumidity !== 'unavailable'
245
+ && this.humiService
246
+ ) {
247
+ let newHumi = Number.parseInt(params.currentHumidity, 10)
248
+ if (this.humiOffsetFactor) {
249
+ newHumi *= this.humiOffset
250
+ } else {
251
+ newHumi += this.humiOffset
252
+ }
253
+ newHumi = Math.max(Math.min(Number.parseInt(newHumi, 10), 100), 0)
254
+ if (newHumi !== this.cacheHumi) {
255
+ this.cacheHumi = newHumi
256
+ this.humiService.updateCharacteristic(
257
+ this.hapChar.CurrentRelativeHumidity,
258
+ this.cacheHumi,
259
+ )
260
+ this.accessory.eveService.addEntry({ humidity: this.cacheHumi })
261
+ if (params.updateSource && this.enableLogging) {
262
+ this.log('[%s] %s [%s%].', this.name, this.lang.curHumi, this.cacheHumi)
263
+ }
264
+ }
265
+ }
266
+ } catch (err) {
267
+ this.platform.deviceUpdateError(this.accessory, err, false)
268
+ }
269
+ }
270
+
271
+ async updateCache() {
272
+ // Don't continue if the storage client hasn't initialised properly
273
+ if (!this.platform.storageClientData) {
274
+ return
275
+ }
276
+
277
+ // Attempt to save the new temperature to the cache
278
+ try {
279
+ await this.platform.storageData.setItem(
280
+ `${this.accessory.context.eweDeviceId}_temp`,
281
+ this.cacheTemp,
282
+ )
283
+ } catch (err) {
284
+ if (this.enableLogging) {
285
+ this.log.warn('[%s] %s %s.', this.name, this.lang.storageWriteErr, parseError(err))
286
+ }
287
+ }
288
+ }
289
+
290
+ currentState() {
291
+ const toReturn = {}
292
+ toReturn.services = ['switch', 'temperature']
293
+ toReturn.switch = {
294
+ state: this.cacheState,
295
+ }
296
+ toReturn.temperature = {
297
+ current: this.tempService.getCharacteristic(this.hapChar.CurrentTemperature).value,
298
+ }
299
+ if (this.humiService) {
300
+ toReturn.services.push('humidity')
301
+ toReturn.humidity = {
302
+ current: this.humiService.getCharacteristic(this.hapChar.CurrentRelativeHumidity).value,
303
+ }
304
+ }
305
+ return toReturn
306
+ }
307
+
308
+ markStatus(isOnline) {
309
+ this.isOnline = isOnline
310
+ }
311
+ }