@homebridge-plugins/homebridge-govee 11.32.2-beta.2 → 11.32.2-beta.21

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 (73) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/config.schema.json +1 -1
  3. package/lib/connection/ble.js +26 -1
  4. package/lib/connection/openapi.js +18 -0
  5. package/lib/device/appliance-basic.js +377 -0
  6. package/lib/device/dehumidifier-H7150.js +9 -3
  7. package/lib/device/diffuser-H7161.js +7 -1
  8. package/lib/device/fan-H1370.js +7 -1
  9. package/lib/device/fan-H7100.js +36 -4
  10. package/lib/device/fan-H7105.js +7 -1
  11. package/lib/device/fan-H7107.js +7 -1
  12. package/lib/device/heater1a.js +52 -12
  13. package/lib/device/heater1b.js +14 -3
  14. package/lib/device/heater2.js +7 -1
  15. package/lib/device/humidifier-H7140.js +7 -1
  16. package/lib/device/humidifier-H7141.js +7 -1
  17. package/lib/device/humidifier-H7142.js +7 -1
  18. package/lib/device/humidifier-H7143.js +7 -1
  19. package/lib/device/humidifier-H7160.js +7 -1
  20. package/lib/device/ice-maker-H7172.js +19 -7
  21. package/lib/device/index.js +44 -51
  22. package/lib/device/kettle.js +7 -1
  23. package/lib/device/outlet-single.js +7 -1
  24. package/lib/device/purifier-H7120.js +14 -25
  25. package/lib/device/purifier-H7122.js +7 -1
  26. package/lib/device/purifier-H7123.js +9 -3
  27. package/lib/device/purifier-H7126.js +7 -1
  28. package/lib/device/{sensor-button.js → sensor-basic.js} +14 -2
  29. package/lib/device/sensor-presence.js +7 -1
  30. package/lib/device/sensor-thermo4.js +13 -2
  31. package/lib/device/switch-double.js +34 -15
  32. package/lib/device/switch-triple.js +36 -17
  33. package/lib/device/template.js +15 -2
  34. package/lib/platform.js +83 -799
  35. package/lib/utils/capabilities.js +220 -0
  36. package/lib/utils/command-builder.js +6 -4
  37. package/lib/utils/config-parser.js +280 -0
  38. package/lib/utils/constants.js +120 -8
  39. package/lib/utils/decode.js +4 -1
  40. package/lib/utils/device-capabilities.js +77 -3
  41. package/lib/utils/device-context.js +179 -0
  42. package/lib/utils/device-merge.js +251 -0
  43. package/lib/utils/dispatch.js +159 -0
  44. package/lib/utils/functions.js +9 -0
  45. package/lib/utils/lang-en.js +0 -2
  46. package/lib/utils/report-unknown.js +156 -0
  47. package/package.json +1 -1
  48. package/lib/device/dehumidifier-H7151.js +0 -189
  49. package/lib/device/dehumidifier-H7152.js +0 -180
  50. package/lib/device/diffuser-H7162.js +0 -123
  51. package/lib/device/fan-H1310.js +0 -284
  52. package/lib/device/fan-H7101.js +0 -340
  53. package/lib/device/fan-H7102.js +0 -284
  54. package/lib/device/fan-H7106.js +0 -284
  55. package/lib/device/fan-H7111.js +0 -345
  56. package/lib/device/humidifier-H7145.js +0 -187
  57. package/lib/device/humidifier-H7147.js +0 -187
  58. package/lib/device/humidifier-H7148.js +0 -187
  59. package/lib/device/humidifier-H7149.js +0 -187
  60. package/lib/device/humidifier-H714E.js +0 -187
  61. package/lib/device/ice-maker-H717D.js +0 -218
  62. package/lib/device/ice-maker-H8120.js +0 -218
  63. package/lib/device/outlet-double.js +0 -188
  64. package/lib/device/outlet-triple.js +0 -160
  65. package/lib/device/purifier-H7121.js +0 -406
  66. package/lib/device/purifier-H7124.js +0 -504
  67. package/lib/device/purifier-H7127.js +0 -359
  68. package/lib/device/purifier-H7128.js +0 -359
  69. package/lib/device/purifier-H7129.js +0 -359
  70. package/lib/device/purifier-H712C.js +0 -359
  71. package/lib/device/sensor-contact.js +0 -22
  72. package/lib/utils/ble-timeouts.test.js +0 -44
  73. package/lib/utils/functions.test.js +0 -292
@@ -1,284 +0,0 @@
1
- import {
2
- base64ToHex,
3
- fanSpeedToHkPercent,
4
- getTwoItemPosition,
5
- hexToTwoItems,
6
- hkPercentToFanSpeed,
7
- parseError,
8
- } from '../utils/functions.js'
9
- import platformLang from '../utils/lang-en.js'
10
-
11
- export default class {
12
- constructor(platform, accessory) {
13
- // Set up variables from the platform
14
- this.hapChar = platform.api.hap.Characteristic
15
- this.hapErr = platform.api.hap.HapStatusError
16
- this.hapServ = platform.api.hap.Service
17
- this.platform = platform
18
-
19
- // Set up variables from the accessory
20
- this.accessory = accessory
21
-
22
- // Codes etc
23
- this.speedCodes = {
24
- 1: 'MwUBAQAAAAAAAAAAAAAAAAAAADY=',
25
- 2: 'MwUBAgAAAAAAAAAAAAAAAAAAADU=',
26
- 3: 'MwUBAwAAAAAAAAAAAAAAAAAAADQ=',
27
- 4: 'MwUBBAAAAAAAAAAAAAAAAAAAADM=',
28
- 5: 'MwUBBQAAAAAAAAAAAAAAAAAAADI=',
29
- 6: 'MwUBBgAAAAAAAAAAAAAAAAAAADE=',
30
- 7: 'MwUBBwAAAAAAAAAAAAAAAAAAADA=',
31
- 8: 'MwUBCAAAAAAAAAAAAAAAAAAAAD8=',
32
- 9: 'MwUAAwAAAAAAAAAAAAAAAAAAADU=', // auto mode
33
- }
34
- this.autoSpeed = 9
35
- // Real speed steps, excluding auto - HomeKit percentages map onto these
36
- this.speedSteps = 8
37
-
38
- // Remove any old original Fan services
39
- if (this.accessory.getService(this.hapServ.Fan)) {
40
- this.accessory.removeService(this.accessory.getService(this.hapServ.Fan))
41
- }
42
-
43
- // Rebuild the fan service if it was cached under an older speed scale, as
44
- // HomeKit keeps the old props until the service itself is replaced
45
- const existingService = this.accessory.getService(this.hapServ.Fanv2)
46
- if (existingService) {
47
- const { props } = existingService.getCharacteristic(this.hapChar.RotationSpeed)
48
- if (props.unit === 'percentage' || props.maxValue !== 100) {
49
- this.accessory.removeService(existingService)
50
- }
51
- }
52
-
53
- // Add the fan service for the fan if it doesn't already exist
54
- this.service = this.accessory.getService(this.hapServ.Fanv2) || this.accessory.addService(this.hapServ.Fanv2)
55
-
56
- // Add the set handler to the fan on/off characteristic
57
- this.service
58
- .getCharacteristic(this.hapChar.Active)
59
- .onSet(async value => this.internalStateUpdate(value))
60
- this.cacheState = this.service.getCharacteristic(this.hapChar.Active).value ? 'on' : 'off'
61
-
62
- // Add the set handler to the fan rotation speed characteristic
63
- this.service
64
- .getCharacteristic(this.hapChar.RotationSpeed)
65
- .setProps({
66
- maxValue: 100,
67
- minStep: 1,
68
- minValue: 0,
69
- unit: 'unitless',
70
- })
71
- .onSet(async value => this.internalSpeedUpdate(value))
72
- this.cacheSpeed = this.service.getCharacteristic(this.hapChar.RotationSpeed).value
73
-
74
- // Add the set handler to the fan swing mode
75
- this.service
76
- .getCharacteristic(this.hapChar.SwingMode)
77
- .onSet(async value => this.internalSwingUpdate(value))
78
- this.cacheSwing = this.service.getCharacteristic(this.hapChar.SwingMode).value === 1 ? 'on' : 'off'
79
-
80
- // Output the customised options to the log
81
- const opts = JSON.stringify({})
82
- platform.log('[%s] %s %s.', accessory.displayName, platformLang.devInitOpts, opts)
83
- }
84
-
85
- async internalStateUpdate(value) {
86
- try {
87
- const newValue = value ? 'on' : 'off'
88
-
89
- // Don't continue if the new value is the same as before
90
- if (this.cacheState === newValue) {
91
- return
92
- }
93
-
94
- // Send the request to the platform sender function
95
- await this.platform.sendDeviceUpdate(this.accessory, {
96
- cmd: 'ptReal',
97
- value: value ? 'MwEBAAAAAAAAAAAAAAAAAAAAADM=' : 'MwEAAAAAAAAAAAAAAAAAAAAAADI=',
98
- })
99
-
100
- // Cache the new state and log if appropriate
101
- if (this.cacheState !== newValue) {
102
- this.cacheState = newValue
103
- this.accessory.log(`${platformLang.curState} [${newValue}]`)
104
- }
105
- } catch (err) {
106
- // Catch any errors during the process
107
- this.accessory.logWarn(`${platformLang.devNotUpdated} ${parseError(err)}`)
108
-
109
- // Throw a 'no response' error and set a timeout to revert this after 2 seconds
110
- setTimeout(() => {
111
- this.service.updateCharacteristic(this.hapChar.Active, this.cacheState === 'on' ? 1 : 0)
112
- }, 2000)
113
- throw new this.hapErr(-70402)
114
- }
115
- }
116
-
117
- async internalSpeedUpdate(value) {
118
- try {
119
- // Don't continue if the value is 0
120
- if (value === 0) {
121
- return
122
- }
123
-
124
- // HomeKit sends a percentage - map it onto this model's real speed steps
125
- value = hkPercentToFanSpeed(value, this.speedSteps)
126
-
127
- // Don't continue if the new value is the same as before
128
- if (this.cacheSpeed === value) {
129
- return
130
- }
131
-
132
- const codeToSend = this.speedCodes[value]
133
-
134
- const isAuto = value === this.autoSpeed
135
- await this.platform.sendDeviceUpdate(this.accessory, {
136
- cmd: 'ptReal',
137
- value: codeToSend,
138
- openApi: this.accessory.context.openApiCapabilities?.workMode
139
- ? { instance: 'workMode', capabilityType: 'devices.capabilities.work_mode', value: isAuto ? { workMode: 3 } : { workMode: 1, modeValue: value } }
140
- : undefined,
141
- })
142
-
143
- // Cache the new state and log if appropriate
144
- if (this.cacheSpeed !== value) {
145
- this.cacheSpeed = value
146
- this.accessory.log(`${platformLang.curSpeed} [${value}]`)
147
- }
148
- } catch (err) {
149
- // Catch any errors during the process
150
- this.accessory.logWarn(`${platformLang.devNotUpdated} ${parseError(err)}`)
151
-
152
- // Throw a 'no response' error and set a timeout to revert this after 2 seconds
153
- setTimeout(() => {
154
- this.service.updateCharacteristic(this.hapChar.RotationSpeed, fanSpeedToHkPercent(this.cacheSpeed, this.speedSteps, this.autoSpeed))
155
- }, 2000)
156
- throw new this.hapErr(-70402)
157
- }
158
- }
159
-
160
- async internalSwingUpdate(value) {
161
- try {
162
- const newValue = value ? 'on' : 'off'
163
- // Don't continue if the new value is the same as before
164
- if (this.cacheSwing === value) {
165
- return
166
- }
167
-
168
- await this.platform.sendDeviceUpdate(this.accessory, {
169
- cmd: 'ptReal',
170
- value: value ? 'Mx8BAQAAAAAAAAAAAAAAAAAAACw=' : 'Mx8BAAAAAAAAAAAAAAAAAAAAAC0=',
171
- openApi: this.accessory.context.openApiCapabilities?.oscillationToggle
172
- ? { instance: 'oscillationToggle', capabilityType: 'devices.capabilities.toggle', value: value ? 1 : 0 }
173
- : undefined,
174
- })
175
-
176
- // Cache the new state and log if appropriate
177
- if (this.cacheSwing !== newValue) {
178
- this.cacheSwing = newValue
179
- this.accessory.log(`${platformLang.curSwing} [${newValue}]`)
180
- }
181
- } catch (err) {
182
- // Catch any errors during the process
183
- this.accessory.logWarn(`${platformLang.devNotUpdated} ${parseError(err)}`)
184
-
185
- // Throw a 'no response' error and set a timeout to revert this after 2 seconds
186
- setTimeout(() => {
187
- this.service.updateCharacteristic(this.hapChar.SwingMode, this.cacheSwing === 'on' ? 1 : 0)
188
- }, 2000)
189
- throw new this.hapErr(-70402)
190
- }
191
- }
192
-
193
- externalUpdate(params) {
194
- // Update the active characteristic
195
- if (params.state && params.state !== this.cacheState) {
196
- this.cacheState = params.state
197
- this.service.updateCharacteristic(this.hapChar.Active, this.cacheState === 'on' ? 1 : 0)
198
- this.accessory.log(`${platformLang.curState} [${this.cacheState}]`)
199
- }
200
-
201
- // Handle OpenAPI workMode (speed or auto)
202
- if (params.workMode) {
203
- let newSpeed
204
- if (params.workMode.workMode === 3) {
205
- newSpeed = this.autoSpeed
206
- } else {
207
- newSpeed = params.workMode.modeValue
208
- }
209
- if (Number.isFinite(newSpeed) && newSpeed >= 1 && newSpeed <= this.autoSpeed && this.cacheSpeed !== newSpeed) {
210
- this.cacheSpeed = newSpeed
211
- const hkSpeed = fanSpeedToHkPercent(newSpeed, this.speedSteps, this.autoSpeed)
212
- this.service.updateCharacteristic(this.hapChar.RotationSpeed, hkSpeed)
213
- this.accessory.log(`${platformLang.curSpeed} [${newSpeed} -> ${hkSpeed}%]`)
214
- }
215
- }
216
-
217
- // Handle OpenAPI toggles
218
- if (params.toggles?.oscillationToggle !== undefined) {
219
- const newSwing = params.toggles.oscillationToggle ? 'on' : 'off'
220
- if (this.cacheSwing !== newSwing) {
221
- this.cacheSwing = newSwing
222
- this.service.updateCharacteristic(this.hapChar.SwingMode, this.cacheSwing === 'on' ? 1 : 0)
223
- this.accessory.log(`${platformLang.curSwing} [${this.cacheSwing}]`)
224
- }
225
- }
226
-
227
- // Check for some other scene/mode change
228
- (params.commands || []).forEach((command) => {
229
- const hexString = base64ToHex(command)
230
- const hexParts = hexToTwoItems(hexString)
231
-
232
- // Return now if not a device query update code
233
- if (getTwoItemPosition(hexParts, 1) !== 'aa') {
234
- return
235
- }
236
-
237
- if (getTwoItemPosition(hexParts, 2) === '08') {
238
- // Sensor Attached?
239
- const dev = hexString.substring(4, hexString.length - 24)
240
- this.accessory.context.sensorAttached = dev !== '000000000000'
241
- return
242
- }
243
-
244
- const deviceFunction = `${getTwoItemPosition(hexParts, 2)}${getTwoItemPosition(hexParts, 3)}`
245
-
246
- switch (deviceFunction) {
247
- case '0501': {
248
- // Fan speed
249
- const newSpeed = Number.parseInt(getTwoItemPosition(hexParts, 4), 16)
250
- if (newSpeed >= 1 && newSpeed <= this.speedSteps && this.cacheSpeed !== newSpeed) {
251
- this.cacheSpeed = newSpeed
252
- const hkSpeed = fanSpeedToHkPercent(newSpeed, this.speedSteps, this.autoSpeed)
253
- this.service.updateCharacteristic(this.hapChar.RotationSpeed, hkSpeed)
254
- this.accessory.log(`${platformLang.curSpeed} [${newSpeed} -> ${hkSpeed}%]`)
255
- }
256
- break
257
- }
258
- case '0500': {
259
- // Mode change (auto = 0x03)
260
- if (getTwoItemPosition(hexParts, 4) === '03' && this.cacheSpeed !== this.autoSpeed) {
261
- this.cacheSpeed = this.autoSpeed
262
- // Cache auto so we can tell it apart from "user asked for max speed"
263
- this.service.updateCharacteristic(this.hapChar.RotationSpeed, 100)
264
- this.accessory.log(`${platformLang.curSpeed} [auto]`)
265
- }
266
- break
267
- }
268
- case '1f01': {
269
- // Swing Mode
270
- const newSwing = getTwoItemPosition(hexParts, 4) === '01' ? 'on' : 'off'
271
- if (this.cacheSwing !== newSwing) {
272
- this.cacheSwing = newSwing
273
- this.service.updateCharacteristic(this.hapChar.SwingMode, this.cacheSwing === 'on' ? 1 : 0)
274
- this.accessory.log(`${platformLang.curSwing} [${this.cacheSwing}]`)
275
- }
276
- break
277
- }
278
- default:
279
- this.accessory.logDebugWarn(`${platformLang.newScene}: [${command}] [${hexString}]`)
280
- break
281
- }
282
- })
283
- }
284
- }
@@ -1,284 +0,0 @@
1
- import {
2
- base64ToHex,
3
- fanSpeedToHkPercent,
4
- getTwoItemPosition,
5
- hexToTwoItems,
6
- hkPercentToFanSpeed,
7
- parseError,
8
- } from '../utils/functions.js'
9
- import platformLang from '../utils/lang-en.js'
10
-
11
- export default class {
12
- constructor(platform, accessory) {
13
- // Set up variables from the platform
14
- this.hapChar = platform.api.hap.Characteristic
15
- this.hapErr = platform.api.hap.HapStatusError
16
- this.hapServ = platform.api.hap.Service
17
- this.platform = platform
18
-
19
- // Set up variables from the accessory
20
- this.accessory = accessory
21
-
22
- // Codes etc
23
- this.speedCodes = {
24
- 1: 'MwUBAQAAAAAAAAAAAAAAAAAAADY=',
25
- 2: 'MwUBAgAAAAAAAAAAAAAAAAAAADU=',
26
- 3: 'MwUBAwAAAAAAAAAAAAAAAAAAADQ=',
27
- 4: 'MwUBBAAAAAAAAAAAAAAAAAAAADM=',
28
- 5: 'MwUBBQAAAAAAAAAAAAAAAAAAADI=',
29
- 6: 'MwUBBgAAAAAAAAAAAAAAAAAAADE=',
30
- 7: 'MwUBBwAAAAAAAAAAAAAAAAAAADA=',
31
- 8: 'MwUBCAAAAAAAAAAAAAAAAAAAAD8=',
32
- 9: 'MwUAAwAAAAAAAAAAAAAAAAAAADU=', // auto mode
33
- }
34
- this.autoSpeed = 9
35
- // Real speed steps, excluding auto - HomeKit percentages map onto these
36
- this.speedSteps = 8
37
-
38
- // Remove any old original Fan services
39
- if (this.accessory.getService(this.hapServ.Fan)) {
40
- this.accessory.removeService(this.accessory.getService(this.hapServ.Fan))
41
- }
42
-
43
- // Rebuild the fan service if it was cached under an older speed scale, as
44
- // HomeKit keeps the old props until the service itself is replaced
45
- const existingService = this.accessory.getService(this.hapServ.Fanv2)
46
- if (existingService) {
47
- const { props } = existingService.getCharacteristic(this.hapChar.RotationSpeed)
48
- if (props.unit === 'percentage' || props.maxValue !== 100) {
49
- this.accessory.removeService(existingService)
50
- }
51
- }
52
-
53
- // Add the fan service for the fan if it doesn't already exist
54
- this.service = this.accessory.getService(this.hapServ.Fanv2) || this.accessory.addService(this.hapServ.Fanv2)
55
-
56
- // Add the set handler to the fan on/off characteristic
57
- this.service
58
- .getCharacteristic(this.hapChar.Active)
59
- .onSet(async value => this.internalStateUpdate(value))
60
- this.cacheState = this.service.getCharacteristic(this.hapChar.Active).value ? 'on' : 'off'
61
-
62
- // Add the set handler to the fan rotation speed characteristic
63
- this.service
64
- .getCharacteristic(this.hapChar.RotationSpeed)
65
- .setProps({
66
- maxValue: 100,
67
- minStep: 1,
68
- minValue: 0,
69
- unit: 'unitless',
70
- })
71
- .onSet(async value => this.internalSpeedUpdate(value))
72
- this.cacheSpeed = this.service.getCharacteristic(this.hapChar.RotationSpeed).value
73
-
74
- // Add the set handler to the fan swing mode
75
- this.service
76
- .getCharacteristic(this.hapChar.SwingMode)
77
- .onSet(async value => this.internalSwingUpdate(value))
78
- this.cacheSwing = this.service.getCharacteristic(this.hapChar.SwingMode).value === 1 ? 'on' : 'off'
79
-
80
- // Output the customised options to the log
81
- const opts = JSON.stringify({})
82
- platform.log('[%s] %s %s.', accessory.displayName, platformLang.devInitOpts, opts)
83
- }
84
-
85
- async internalStateUpdate(value) {
86
- try {
87
- const newValue = value ? 'on' : 'off'
88
-
89
- // Don't continue if the new value is the same as before
90
- if (this.cacheState === newValue) {
91
- return
92
- }
93
-
94
- // Send the request to the platform sender function
95
- await this.platform.sendDeviceUpdate(this.accessory, {
96
- cmd: 'ptReal',
97
- value: value ? 'MwEBAAAAAAAAAAAAAAAAAAAAADM=' : 'MwEAAAAAAAAAAAAAAAAAAAAAADI=',
98
- })
99
-
100
- // Cache the new state and log if appropriate
101
- if (this.cacheState !== newValue) {
102
- this.cacheState = newValue
103
- this.accessory.log(`${platformLang.curState} [${newValue}]`)
104
- }
105
- } catch (err) {
106
- // Catch any errors during the process
107
- this.accessory.logWarn(`${platformLang.devNotUpdated} ${parseError(err)}`)
108
-
109
- // Throw a 'no response' error and set a timeout to revert this after 2 seconds
110
- setTimeout(() => {
111
- this.service.updateCharacteristic(this.hapChar.Active, this.cacheState === 'on' ? 1 : 0)
112
- }, 2000)
113
- throw new this.hapErr(-70402)
114
- }
115
- }
116
-
117
- async internalSpeedUpdate(value) {
118
- try {
119
- // Don't continue if the value is 0
120
- if (value === 0) {
121
- return
122
- }
123
-
124
- // HomeKit sends a percentage - map it onto this model's real speed steps
125
- value = hkPercentToFanSpeed(value, this.speedSteps)
126
-
127
- // Don't continue if the new value is the same as before
128
- if (this.cacheSpeed === value) {
129
- return
130
- }
131
-
132
- const codeToSend = this.speedCodes[value]
133
-
134
- const isAuto = value === this.autoSpeed
135
- await this.platform.sendDeviceUpdate(this.accessory, {
136
- cmd: 'ptReal',
137
- value: codeToSend,
138
- openApi: this.accessory.context.openApiCapabilities?.workMode
139
- ? { instance: 'workMode', capabilityType: 'devices.capabilities.work_mode', value: isAuto ? { workMode: 3 } : { workMode: 1, modeValue: value } }
140
- : undefined,
141
- })
142
-
143
- // Cache the new state and log if appropriate
144
- if (this.cacheSpeed !== value) {
145
- this.cacheSpeed = value
146
- this.accessory.log(`${platformLang.curSpeed} [${value}]`)
147
- }
148
- } catch (err) {
149
- // Catch any errors during the process
150
- this.accessory.logWarn(`${platformLang.devNotUpdated} ${parseError(err)}`)
151
-
152
- // Throw a 'no response' error and set a timeout to revert this after 2 seconds
153
- setTimeout(() => {
154
- this.service.updateCharacteristic(this.hapChar.RotationSpeed, fanSpeedToHkPercent(this.cacheSpeed, this.speedSteps, this.autoSpeed))
155
- }, 2000)
156
- throw new this.hapErr(-70402)
157
- }
158
- }
159
-
160
- async internalSwingUpdate(value) {
161
- try {
162
- const newValue = value ? 'on' : 'off'
163
- // Don't continue if the new value is the same as before
164
- if (this.cacheSwing === value) {
165
- return
166
- }
167
-
168
- await this.platform.sendDeviceUpdate(this.accessory, {
169
- cmd: 'ptReal',
170
- value: value ? 'Mx8BAQAAAAAAAAAAAAAAAAAAACw=' : 'Mx8BAAAAAAAAAAAAAAAAAAAAAC0=',
171
- openApi: this.accessory.context.openApiCapabilities?.oscillationToggle
172
- ? { instance: 'oscillationToggle', capabilityType: 'devices.capabilities.toggle', value: value ? 1 : 0 }
173
- : undefined,
174
- })
175
-
176
- // Cache the new state and log if appropriate
177
- if (this.cacheSwing !== newValue) {
178
- this.cacheSwing = newValue
179
- this.accessory.log(`${platformLang.curSwing} [${newValue}]`)
180
- }
181
- } catch (err) {
182
- // Catch any errors during the process
183
- this.accessory.logWarn(`${platformLang.devNotUpdated} ${parseError(err)}`)
184
-
185
- // Throw a 'no response' error and set a timeout to revert this after 2 seconds
186
- setTimeout(() => {
187
- this.service.updateCharacteristic(this.hapChar.SwingMode, this.cacheSwing === 'on' ? 1 : 0)
188
- }, 2000)
189
- throw new this.hapErr(-70402)
190
- }
191
- }
192
-
193
- externalUpdate(params) {
194
- // Update the active characteristic
195
- if (params.state && params.state !== this.cacheState) {
196
- this.cacheState = params.state
197
- this.service.updateCharacteristic(this.hapChar.Active, this.cacheState === 'on' ? 1 : 0)
198
- this.accessory.log(`${platformLang.curState} [${this.cacheState}]`)
199
- }
200
-
201
- // Handle OpenAPI workMode (speed or auto)
202
- if (params.workMode) {
203
- let newSpeed
204
- if (params.workMode.workMode === 3) {
205
- newSpeed = this.autoSpeed
206
- } else {
207
- newSpeed = params.workMode.modeValue
208
- }
209
- if (Number.isFinite(newSpeed) && newSpeed >= 1 && newSpeed <= this.autoSpeed && this.cacheSpeed !== newSpeed) {
210
- this.cacheSpeed = newSpeed
211
- const hkSpeed = fanSpeedToHkPercent(newSpeed, this.speedSteps, this.autoSpeed)
212
- this.service.updateCharacteristic(this.hapChar.RotationSpeed, hkSpeed)
213
- this.accessory.log(`${platformLang.curSpeed} [${newSpeed} -> ${hkSpeed}%]`)
214
- }
215
- }
216
-
217
- // Handle OpenAPI toggles
218
- if (params.toggles?.oscillationToggle !== undefined) {
219
- const newSwing = params.toggles.oscillationToggle ? 'on' : 'off'
220
- if (this.cacheSwing !== newSwing) {
221
- this.cacheSwing = newSwing
222
- this.service.updateCharacteristic(this.hapChar.SwingMode, this.cacheSwing === 'on' ? 1 : 0)
223
- this.accessory.log(`${platformLang.curSwing} [${this.cacheSwing}]`)
224
- }
225
- }
226
-
227
- // Check for some other scene/mode change
228
- (params.commands || []).forEach((command) => {
229
- const hexString = base64ToHex(command)
230
- const hexParts = hexToTwoItems(hexString)
231
-
232
- // Return now if not a device query update code
233
- if (getTwoItemPosition(hexParts, 1) !== 'aa') {
234
- return
235
- }
236
-
237
- if (getTwoItemPosition(hexParts, 2) === '08') {
238
- // Sensor Attached?
239
- const dev = hexString.substring(4, hexString.length - 24)
240
- this.accessory.context.sensorAttached = dev !== '000000000000'
241
- return
242
- }
243
-
244
- const deviceFunction = `${getTwoItemPosition(hexParts, 2)}${getTwoItemPosition(hexParts, 3)}`
245
-
246
- switch (deviceFunction) {
247
- case '0501': {
248
- // Fan speed
249
- const newSpeed = Number.parseInt(getTwoItemPosition(hexParts, 4), 16)
250
- if (newSpeed >= 1 && newSpeed <= this.speedSteps && this.cacheSpeed !== newSpeed) {
251
- this.cacheSpeed = newSpeed
252
- const hkSpeed = fanSpeedToHkPercent(newSpeed, this.speedSteps, this.autoSpeed)
253
- this.service.updateCharacteristic(this.hapChar.RotationSpeed, hkSpeed)
254
- this.accessory.log(`${platformLang.curSpeed} [${newSpeed} -> ${hkSpeed}%]`)
255
- }
256
- break
257
- }
258
- case '0500': {
259
- // Mode change (auto = 0x03)
260
- if (getTwoItemPosition(hexParts, 4) === '03' && this.cacheSpeed !== this.autoSpeed) {
261
- this.cacheSpeed = this.autoSpeed
262
- // Cache auto so we can tell it apart from "user asked for max speed"
263
- this.service.updateCharacteristic(this.hapChar.RotationSpeed, 100)
264
- this.accessory.log(`${platformLang.curSpeed} [auto]`)
265
- }
266
- break
267
- }
268
- case '1f01': {
269
- // Swing Mode
270
- const newSwing = getTwoItemPosition(hexParts, 4) === '01' ? 'on' : 'off'
271
- if (this.cacheSwing !== newSwing) {
272
- this.cacheSwing = newSwing
273
- this.service.updateCharacteristic(this.hapChar.SwingMode, this.cacheSwing === 'on' ? 1 : 0)
274
- this.accessory.log(`${platformLang.curSwing} [${this.cacheSwing}]`)
275
- }
276
- break
277
- }
278
- default:
279
- this.accessory.logDebugWarn(`${platformLang.newScene}: [${command}] [${hexString}]`)
280
- break
281
- }
282
- })
283
- }
284
- }