@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,286 @@
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.tempOffset = deviceConf.offset || platformConsts.defaultValues.offset
24
+ this.tempOffsetFactor = deviceConf.offsetFactor
25
+
26
+ // Set the correct logging variables for this accessory
27
+ switch (deviceConf.overrideLogging) {
28
+ case 'standard':
29
+ this.enableLogging = true
30
+ this.enableDebugLogging = false
31
+ break
32
+ case 'debug':
33
+ this.enableLogging = true
34
+ this.enableDebugLogging = true
35
+ break
36
+ case 'disable':
37
+ this.enableLogging = false
38
+ this.enableDebugLogging = false
39
+ break
40
+ default:
41
+ this.enableLogging = !platform.config.disableDeviceLogging
42
+ this.enableDebugLogging = platform.config.debug
43
+ break
44
+ }
45
+
46
+ /*
47
+ **************
48
+ *** PARAMS ***
49
+ **************
50
+ "volatility": 1, no plan to implement
51
+ "targetTemp": 20, implemented; will set mode in ewelink to C
52
+ "workMode": 1, implemented 1; 1=manual, 2=programmed 3=economical
53
+ "switch": "on", implemented
54
+ "temperature": 29, implemented; F will be converted to C
55
+ "fault": 0, no plan to implemented
56
+ "workState": 2, implemented 1&2; 1=heating, 2=auto
57
+ "tempScale": "c", implemented c; no plan to implement f
58
+ "childLock": "off", no plan to implement
59
+ "mon": "016800c801e0009602b20096032a009603fc00dc05280096", no
60
+ "tues": "016800c801e0009602b20096032a009603fc00dc05280096", plans
61
+ "wed": "016800c801e0009602b20096032a009603fc00dc05280096", to
62
+ "thur": "016800c801e0009602b20096032a009603fc00dc05280096", implement
63
+ "fri": "016800c801e0009602b20096032a009603fc00dc05280096", the
64
+ "sat": "016800c801e000c802b200c8032a00c803fc00c805280096", schedule
65
+ "sun": "016800c801e000c802b200c8032a00c803fc00c805280096", program
66
+ */
67
+
68
+ // Add the thermostat service if it doesn't already exist
69
+ this.service = this.accessory.getService(this.hapServ.Thermostat)
70
+ || this.accessory.addService(this.hapServ.Thermostat)
71
+
72
+ // Set custom properties of the current temperature characteristic
73
+ this.service.getCharacteristic(this.hapChar.CurrentTemperature).setProps({
74
+ minStep: 0.1,
75
+ })
76
+ this.cacheTemp = this.service.getCharacteristic(this.hapChar.CurrentTemperature).value
77
+ this.updateCache()
78
+
79
+ // Add the set handler to the target state characteristic
80
+ this.service
81
+ .getCharacteristic(this.hapChar.TargetHeatingCoolingState)
82
+ .setProps({
83
+ minValue: 0,
84
+ maxValue: 1,
85
+ validValues: [0, 1],
86
+ })
87
+ .onSet(async value => this.internalStateUpdate(value))
88
+
89
+ // Add the set handler to the target temperature characteristic
90
+ this.service
91
+ .getCharacteristic(this.hapChar.TargetTemperature)
92
+ .setProps({
93
+ minValue: 5,
94
+ maxValue: 45,
95
+ minStep: 0.5,
96
+ })
97
+ .onSet(async value => this.internalTargetUpdate(value))
98
+
99
+ // Add the get handlers only if the user hasn't disabled the disableNoResponse setting
100
+ if (!platform.config.disableNoResponse) {
101
+ this.service.getCharacteristic(this.hapChar.CurrentTemperature).onGet(() => {
102
+ if (!this.isOnline) {
103
+ throw new this.hapErr(-70402)
104
+ }
105
+ return this.service.getCharacteristic(this.hapChar.CurrentTemperature).value
106
+ })
107
+ this.service.getCharacteristic(this.hapChar.CurrentHeatingCoolingState).onGet(() => {
108
+ if (!this.isOnline) {
109
+ throw new this.hapErr(-70402)
110
+ }
111
+ return this.service.getCharacteristic(this.hapChar.CurrentHeatingCoolingState).value
112
+ })
113
+ this.service.getCharacteristic(this.hapChar.TargetHeatingCoolingState).onGet(() => {
114
+ if (!this.isOnline) {
115
+ throw new this.hapErr(-70402)
116
+ }
117
+ return this.service.getCharacteristic(this.hapChar.TargetHeatingCoolingState).value
118
+ })
119
+ this.service.getCharacteristic(this.hapChar.TargetTemperature).onGet(() => {
120
+ if (!this.isOnline) {
121
+ throw new this.hapErr(-70402)
122
+ }
123
+ return this.service.getCharacteristic(this.hapChar.TargetTemperature).value
124
+ })
125
+ }
126
+
127
+ // Pass the accessory to Fakegato to set up with Eve
128
+ this.accessory.eveService = new platform.eveService('custom', this.accessory, {
129
+ log: () => {},
130
+ })
131
+
132
+ // Output the customised options to the log
133
+ const normalLogging = this.enableLogging ? 'standard' : 'disable'
134
+ const opts = JSON.stringify({
135
+ logging: this.enableDebugLogging ? 'debug' : normalLogging,
136
+ offset: this.tempOffset,
137
+ offsetFactor: this.tempOffsetFactor,
138
+ })
139
+ this.log('[%s] %s %s.', this.name, this.lang.devInitOpts, opts)
140
+ }
141
+
142
+ async internalStateUpdate(value) {
143
+ try {
144
+ const newValue = value !== 0 ? 'on' : 'off'
145
+ const params = {
146
+ switch: newValue,
147
+ }
148
+ await this.platform.sendDeviceUpdate(this.accessory, params)
149
+ if (value === 0) {
150
+ this.service.updateCharacteristic(this.hapChar.CurrentHeatingCoolingState, 0)
151
+ }
152
+ this.cacheState = newValue
153
+ if (this.enableLogging) {
154
+ this.log('[%s] %s [%s].', this.name, this.lang.curState, this.cacheState)
155
+ }
156
+ } catch (err) {
157
+ this.platform.deviceUpdateError(this.accessory, err, true)
158
+ setTimeout(() => {
159
+ this.service.updateCharacteristic(
160
+ this.hapChar.TargetHeatingCoolingState,
161
+ this.cacheState === 'on' ? 1 : 0,
162
+ )
163
+ }, 2000)
164
+ throw new this.hapErr(-70402)
165
+ }
166
+ }
167
+
168
+ async internalTargetUpdate(value) {
169
+ try {
170
+ const params = {
171
+ workMode: 1,
172
+ targetTemp: value,
173
+ tempScale: 'c',
174
+ }
175
+ await this.platform.sendDeviceUpdate(this.accessory, params)
176
+ this.cacheTarg = value
177
+ if (this.enableLogging) {
178
+ this.log('[%s] %s [%s°C].', this.name, this.lang.curTarg, this.cacheTarg)
179
+ }
180
+ } catch (err) {
181
+ this.platform.deviceUpdateError(this.accessory, err, true)
182
+ setTimeout(() => {
183
+ this.service.updateCharacteristic(this.hapChar.TargetTemperature, this.cacheTarg)
184
+ }, 2000)
185
+ throw new this.hapErr(-70402)
186
+ }
187
+ }
188
+
189
+ async externalUpdate(params) {
190
+ try {
191
+ if (params.switch && params.switch !== this.cacheState) {
192
+ this.cacheState = params.switch
193
+ if (this.cacheState === 'off') {
194
+ this.service.updateCharacteristic(this.hapChar.CurrentHeatingCoolingState, 0)
195
+ }
196
+ this.service.updateCharacteristic(
197
+ this.hapChar.TargetHeatingCoolingState,
198
+ this.cacheState === 'on' ? 1 : 0,
199
+ )
200
+ if (params.updateSource && this.enableLogging) {
201
+ this.log('[%s] %s [%s].', this.name, this.lang.curState, this.cacheState)
202
+ }
203
+ }
204
+
205
+ if (params.workState) {
206
+ const workState = params.workState === 1 ? 'on' : 'off'
207
+ if (this.cacheHeat !== workState) {
208
+ this.cacheHeat = workState
209
+ this.service.updateCharacteristic(
210
+ this.hapChar.CurrentHeatingCoolingState,
211
+ this.cacheHeat === 'on' ? 1 : 0,
212
+ )
213
+ if (params.updateSource && this.enableLogging) {
214
+ this.log('[%s] %s [%s].', this.name, this.lang.curHeat, this.cacheHeat)
215
+ }
216
+ }
217
+ }
218
+
219
+ if (hasProperty(params, 'targetTemp')) {
220
+ const targetTemp = Number(params.targetTemp)
221
+ if (this.cacheTarg !== targetTemp) {
222
+ this.cacheTarg = targetTemp
223
+ this.service.updateCharacteristic(this.hapChar.TargetTemperature, this.cacheTarg)
224
+ if (params.updateSource && this.enableLogging) {
225
+ this.log('[%s] %s [%s°C].', this.name, this.lang.curTarg, this.cacheTarg)
226
+ }
227
+ }
228
+ }
229
+
230
+ if (hasProperty(params, 'temperature')) {
231
+ let currentTemp
232
+ if (params.tempScale && params.tempScale === 'f') {
233
+ // Convert to celcius
234
+ currentTemp = ((Number(params.temperature) - 32) * 5) / 9
235
+
236
+ // Round to nearest 0.5
237
+ currentTemp = Math.round(currentTemp * 2) / 2
238
+ } else {
239
+ currentTemp = Number(params.temperature)
240
+ }
241
+ if (this.tempOffsetFactor) {
242
+ currentTemp *= this.tempOffset
243
+ } else {
244
+ currentTemp += this.tempOffset
245
+ }
246
+
247
+ if (this.cacheTemp !== currentTemp) {
248
+ this.cacheTemp = currentTemp
249
+ this.service.updateCharacteristic(this.hapChar.CurrentTemperature, this.cacheTemp)
250
+ this.accessory.eveService.addEntry({ temp: this.cacheTemp })
251
+ if (params.updateSource && this.enableLogging) {
252
+ this.log('[%s] %s [%s°C].', this.name, this.lang.curTemp, this.cacheTemp)
253
+ }
254
+
255
+ // Update the cache file with the new temperature
256
+ this.updateCache()
257
+ }
258
+ }
259
+ } catch (err) {
260
+ this.platform.deviceUpdateError(this.accessory, err, false)
261
+ }
262
+ }
263
+
264
+ async updateCache() {
265
+ // Don't continue if the storage client hasn't initialised properly
266
+ if (!this.platform.storageClientData) {
267
+ return
268
+ }
269
+
270
+ // Attempt to save the new temperature to the cache
271
+ try {
272
+ await this.platform.storageData.setItem(
273
+ `${this.accessory.context.eweDeviceId}_temp`,
274
+ this.cacheTemp,
275
+ )
276
+ } catch (err) {
277
+ if (this.enableLogging) {
278
+ this.log.warn('[%s] %s %s.', this.name, this.lang.storageWriteErr, parseError(err))
279
+ }
280
+ }
281
+ }
282
+
283
+ markStatus(isOnline) {
284
+ this.isOnline = isOnline
285
+ }
286
+ }
@@ -0,0 +1,27 @@
1
+ import deviceLightCCT from './light-cct.js'
2
+ import deviceLightDimmer from './light-dimmer.js'
3
+ import deviceLightRGBCCT from './light-rgb-cct.js'
4
+ import deviceMotor from './motor.js'
5
+ import deviceSensorAmbient from './sensor-ambient.js'
6
+ import deviceSensorContact from './sensor-contact.js'
7
+ import deviceSensorLeak from './sensor-leak.js'
8
+ import deviceSensorMotion from './sensor-motion.js'
9
+ import deviceSensorOccupancy from './sensor-occupancy.js'
10
+ import deviceSensorSmoke from './sensor-smoke.js'
11
+ import deviceSwitchStateless from './switch-stateless.js'
12
+ import deviceThermostat from './thermostat.js'
13
+
14
+ export default {
15
+ deviceLightCCT,
16
+ deviceLightRGBCCT,
17
+ deviceLightDimmer,
18
+ deviceMotor,
19
+ deviceSensorAmbient,
20
+ deviceSensorContact,
21
+ deviceSensorLeak,
22
+ deviceSensorMotion,
23
+ deviceSensorOccupancy,
24
+ deviceSensorSmoke,
25
+ deviceSwitchStateless,
26
+ deviceThermostat,
27
+ }
@@ -0,0 +1,263 @@
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.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
+ // Set up custom variables for this device type
19
+ const deviceConf = platform.deviceConf[accessory.context.eweDeviceId] || {}
20
+ this.brightStep = deviceConf.brightnessStep
21
+ ? Math.min(deviceConf.brightnessStep, 100)
22
+ : platformConsts.defaultValues.brightnessStep
23
+ this.alShift = deviceConf.adaptiveLightingShift || platformConsts.defaultValues.adaptiveLightingShift
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
+ // Different bulbs have different colour temperature ranges
46
+ this.minK = 2200
47
+ this.maxK = 4000
48
+
49
+ // Add the lightbulb service if it doesn't already exist
50
+ this.service = this.accessory.getService(this.hapServ.Lightbulb)
51
+ || this.accessory.addService(this.hapServ.Lightbulb)
52
+
53
+ // If adaptive lighting has just been disabled then remove and re-add service to hide AL icon
54
+ if (this.alShift === -1 && this.accessory.context.adaptiveLighting) {
55
+ this.accessory.removeService(this.service)
56
+ this.service = this.accessory.addService(this.hapServ.Lightbulb)
57
+ this.accessory.context.adaptiveLighting = false
58
+ }
59
+
60
+ // Add the get/set handler to the lightbulb on/off characteristic
61
+ this.service
62
+ .getCharacteristic(this.hapChar.On)
63
+ .onSet(async value => this.internalStateUpdate(value))
64
+
65
+ // Add the set handler to the lightbulb brightness characteristic
66
+ this.service
67
+ .getCharacteristic(this.hapChar.Brightness)
68
+ .setProps({ minStep: this.brightStep })
69
+ .onSet(async value => this.internalBrightnessUpdate(value))
70
+
71
+ // This is needed as sometimes we need to send the brightness with a cct update
72
+ this.cacheBright = this.service.getCharacteristic(this.hapChar.Brightness).value
73
+
74
+ // Add the set handler to the lightbulb colour temperature characteristic
75
+ this.service.getCharacteristic(this.hapChar.ColorTemperature).onSet(async value => this.internalCTUpdate(value))
76
+
77
+ // Set up the adaptive lighting controller if not disabled by user
78
+ if (this.alShift !== -1) {
79
+ this.accessory.alController = new platform.api.hap.AdaptiveLightingController(this.service, {
80
+ customTemperatureAdjustment: this.alShift,
81
+ })
82
+ this.accessory.configureController(this.accessory.alController)
83
+ }
84
+
85
+ // Add the get handlers only if the user hasn't disabled the disableNoResponse setting
86
+ if (!platform.config.disableNoResponse) {
87
+ this.service.getCharacteristic(this.hapChar.On).onGet(() => {
88
+ if (!this.isOnline) {
89
+ throw new this.hapErr(-70402)
90
+ }
91
+ return this.service.getCharacteristic(this.hapChar.On).value
92
+ })
93
+ this.service
94
+ .getCharacteristic(this.hapChar.Brightness)
95
+ .onGet(() => {
96
+ if (!this.isOnline) {
97
+ throw new this.hapErr(-70402)
98
+ }
99
+ return this.service.getCharacteristic(this.hapChar.Brightness).value
100
+ })
101
+ this.service.getCharacteristic(this.hapChar.ColorTemperature).onGet(() => {
102
+ if (!this.isOnline) {
103
+ throw new this.hapErr(-70402)
104
+ }
105
+ return this.service.getCharacteristic(this.hapChar.ColorTemperature).value
106
+ })
107
+ }
108
+
109
+ // Output the customised options to the log
110
+ const normalLogging = this.enableLogging ? 'standard' : 'disable'
111
+ const opts = JSON.stringify({
112
+ adaptiveLightingShift: this.alShift,
113
+ brightnessStep: this.brightStep,
114
+ logging: this.enableDebugLogging ? 'debug' : normalLogging,
115
+ })
116
+ this.log('[%s] %s %s.', this.name, this.lang.devInitOpts, opts)
117
+ }
118
+
119
+ async internalStateUpdate(value) {
120
+ try {
121
+ const newValue = value ? 'on' : 'off'
122
+ await this.platform.sendDeviceUpdate(this.accessory, {
123
+ switch: newValue,
124
+ })
125
+ this.cacheState = newValue
126
+ if (this.enableLogging) {
127
+ this.log('[%s] %s [%s].', this.name, this.lang.curState, this.cacheState)
128
+ }
129
+ } catch (err) {
130
+ this.platform.deviceUpdateError(this.accessory, err, true)
131
+ setTimeout(() => {
132
+ this.service.updateCharacteristic(this.hapChar.On, this.cacheState === 'on')
133
+ }, 2000)
134
+ throw new this.hapErr(-70402)
135
+ }
136
+ }
137
+
138
+ async internalBrightnessUpdate(value) {
139
+ try {
140
+ if (this.cacheBright === value || value === 0) {
141
+ return
142
+ }
143
+ const updateKey = generateRandomString(5)
144
+ this.updateKeyBright = updateKey
145
+ await sleep(500)
146
+ if (updateKey !== this.updateKeyBright) {
147
+ return
148
+ }
149
+ const params = {
150
+ switch: 'on',
151
+ brightness: value,
152
+ }
153
+ await this.platform.sendDeviceUpdate(this.accessory, params)
154
+ this.cacheBright = value
155
+ if (this.enableLogging) {
156
+ this.log('[%s] %s [%s%].', this.name, this.lang.curBright, this.cacheBright)
157
+ }
158
+ } catch (err) {
159
+ this.platform.deviceUpdateError(this.accessory, err, true)
160
+ setTimeout(() => {
161
+ this.service.updateCharacteristic(this.hapChar.Brightness, this.cacheBright)
162
+ }, 2000)
163
+ throw new this.hapErr(-70402)
164
+ }
165
+ }
166
+
167
+ async internalCTUpdate(value) {
168
+ try {
169
+ if (this.cacheMired === value) {
170
+ return
171
+ }
172
+ if (
173
+ this.accessory.alController
174
+ && this.accessory.alController.isAdaptiveLightingActive()
175
+ && (this.cacheState !== 'on' || !this.isOnline)
176
+ ) {
177
+ return
178
+ }
179
+ const updateKey = generateRandomString(5)
180
+ this.updateKeyCT = updateKey
181
+ await sleep(400)
182
+ if (updateKey !== this.updateKeyCT) {
183
+ return
184
+ }
185
+ const kelvin = Math.round(1000000 / value)
186
+ const scaledK = Math.max(Math.min(kelvin, this.maxK), this.minK)
187
+ const scaledCT = Math.round(((scaledK - this.minK) / (this.maxK - this.minK)) * 100)
188
+ const params = {
189
+ switch: 'on',
190
+ colorTemp: scaledCT,
191
+ }
192
+ await this.platform.sendDeviceUpdate(this.accessory, params)
193
+ this.cacheMired = value
194
+ this.cacheCT = scaledCT
195
+ if (this.enableLogging) {
196
+ if (this.accessory.alController && this.accessory.alController.isAdaptiveLightingActive()) {
197
+ this.log('[%s] %s [%sK] %s.', this.name, this.lang.curColour, scaledK, this.lang.viaAL)
198
+ } else {
199
+ this.log('[%s] %s [%sK].', this.name, this.lang.curColour, scaledK)
200
+ }
201
+ }
202
+ } catch (err) {
203
+ this.platform.deviceUpdateError(this.accessory, err, true)
204
+ setTimeout(() => {
205
+ this.service.updateCharacteristic(this.hapChar.ColorTemperature, this.cacheMired)
206
+ }, 2000)
207
+ throw new this.hapErr(-70402)
208
+ }
209
+ }
210
+
211
+ async externalUpdate(params) {
212
+ try {
213
+ if (params.switch && params.switch !== this.cacheState) {
214
+ this.cacheState = params.switch
215
+ this.service.updateCharacteristic(this.hapChar.On, this.cacheState === 'on')
216
+ if (params.updateSource && this.enableLogging) {
217
+ this.log('[%s] %s [%s].', this.name, this.lang.curState, this.cacheState)
218
+ }
219
+ }
220
+ if (hasProperty(params, 'brightness')) {
221
+ if (params.brightness !== this.cacheBright) {
222
+ this.cacheBright = params.brightness
223
+ this.service.updateCharacteristic(this.hapChar.Brightness, this.cacheBright)
224
+ if (params.updateSource && this.enableLogging) {
225
+ this.log('[%s] %s [%s%].', this.name, this.lang.curBright, this.cacheBright)
226
+ }
227
+ }
228
+ }
229
+ if (hasProperty(params, 'colorTemp')) {
230
+ if (params.colorTemp !== this.cacheCT) {
231
+ const ctDiff = Math.abs(params.colorTemp - this.cacheCT)
232
+ this.cacheCT = params.colorTemp
233
+ const kelvin = (this.cacheCT / 100) * (this.maxK - this.minK) + this.minK
234
+ const scaledK = Math.round(kelvin)
235
+ this.cacheMired = Math.min(Math.max(Math.round(1000000 / scaledK), 140), 500)
236
+ this.service.updateCharacteristic(this.hapChar.ColorTemperature, this.cacheMired)
237
+ if (params.updateSource) {
238
+ if (this.enableLogging) {
239
+ this.log('[%s] %s [%sK].', this.name, this.lang.curColour, scaledK)
240
+ }
241
+ if (
242
+ this.accessory.alController
243
+ && this.accessory.alController.isAdaptiveLightingActive()
244
+ && ctDiff > 20
245
+ ) {
246
+ // Look for a variation greater than twenty
247
+ this.accessory.alController.disableAdaptiveLighting()
248
+ if (this.enableLogging) {
249
+ this.log('[%s] %s.', this.name, this.lang.disabledAL)
250
+ }
251
+ }
252
+ }
253
+ }
254
+ }
255
+ } catch (err) {
256
+ this.platform.deviceUpdateError(this.accessory, err, false)
257
+ }
258
+ }
259
+
260
+ markStatus(isOnline) {
261
+ this.isOnline = isOnline
262
+ }
263
+ }