@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,340 +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
- /*
12
- H7101
13
- {
14
- "mode": {
15
- "options": [
16
- {
17
- "name": "Custom",
18
- "value": 2
19
- },
20
- {
21
- "name": "Auto",
22
- "value": 3
23
- },
24
- {
25
- "name": "Sleep",
26
- "value": 5
27
- },
28
- {
29
- "name": "Nature",
30
- "value": 6
31
- }
32
- ]
33
- },
34
- "gear": {
35
- "options": [
36
- {
37
- "name": "gear",
38
- "value": [
39
- 1,
40
- 2,
41
- 3,
42
- 4,
43
- 5,
44
- 6,
45
- 7,
46
- 8
47
- ]
48
- }
49
- ]
50
- }
51
- }
52
-
53
- // NOTES
54
- H7101 -> Sleep, Nature, Turbo, Custom, Auto
55
-
56
- sleep
57
- [31/10/2022, 20:52:08] [Govee] [Device1] [AWS] receiving update {"source":"AWS","result":1,"commands":["qgUFAAAAAAAAAAAAAAAAAAAAAKo=","qgUABQAAAAAAAAAAAAAAAAAAAKo="]}.
58
- [31/10/2022, 20:52:08] [Govee] [Device1] new scene code: [qgUFAAAAAAAAAAAAAAAAAAAAAKo=] [aa050500000000000000000000000000000000aa].
59
- [31/10/2022, 20:52:08] [Govee] [Device1] new scene code: [qgUABQAAAAAAAAAAAAAAAAAAAKo=] [aa050005000000000000000000000000000000aa].
60
-
61
- nature
62
- [31/10/2022, 20:52:43] [Govee] [Device1] [AWS] receiving update {"source":"AWS","result":1,"commands":["qgUGAAAAAAAAAAAAAAAAAAAAAKk=","qgUABgAAAAAAAAAAAAAAAAAAAKk="]}.
63
- [31/10/2022, 20:52:43] [Govee] [Device1] new scene code: [qgUGAAAAAAAAAAAAAAAAAAAAAKk=] [aa050600000000000000000000000000000000a9].
64
- [31/10/2022, 20:52:43] [Govee] [Device1] new scene code: [qgUABgAAAAAAAAAAAAAAAAAAAKk=] [aa050006000000000000000000000000000000a9].
65
- */
66
-
67
- export default class {
68
- constructor(platform, accessory) {
69
- // Set up variables from the platform
70
- this.hapChar = platform.api.hap.Characteristic
71
- this.hapErr = platform.api.hap.HapStatusError
72
- this.hapServ = platform.api.hap.Service
73
- this.platform = platform
74
-
75
- // Set up variables from the accessory
76
- this.accessory = accessory
77
-
78
- // Codes etc
79
- this.speedCodes = {
80
- 1: 'MwUBAQAAAAAAAAAAAAAAAAAAADY=',
81
- 2: 'MwUBAgAAAAAAAAAAAAAAAAAAADU=',
82
- 3: 'MwUBAwAAAAAAAAAAAAAAAAAAADQ=',
83
- 4: 'MwUBBAAAAAAAAAAAAAAAAAAAADM=',
84
- 5: 'MwUBBQAAAAAAAAAAAAAAAAAAADI=',
85
- 6: 'MwUBBgAAAAAAAAAAAAAAAAAAADE=',
86
- 7: 'MwUBBwAAAAAAAAAAAAAAAAAAADA=',
87
- 8: 'MwUBCAAAAAAAAAAAAAAAAAAAAD8=',
88
- 9: 'MwUAAwAAAAAAAAAAAAAAAAAAADU=', // auto mode
89
- }
90
- this.autoSpeed = 9
91
- // Real speed steps, excluding auto - HomeKit percentages map onto these
92
- this.speedSteps = 8
93
-
94
- // Remove any old original Fan services
95
- if (this.accessory.getService(this.hapServ.Fan)) {
96
- this.accessory.removeService(this.accessory.getService(this.hapServ.Fan))
97
- }
98
-
99
- // Rebuild the fan service if it was cached under an older speed scale, as
100
- // HomeKit keeps the old props until the service itself is replaced
101
- const existingService = this.accessory.getService(this.hapServ.Fanv2)
102
- if (existingService) {
103
- const { props } = existingService.getCharacteristic(this.hapChar.RotationSpeed)
104
- if (props.unit === 'percentage' || props.maxValue !== 100) {
105
- this.accessory.removeService(existingService)
106
- }
107
- }
108
-
109
- // Add the fan service for the fan if it doesn't already exist
110
- this.service = this.accessory.getService(this.hapServ.Fanv2) || this.accessory.addService(this.hapServ.Fanv2)
111
-
112
- // Add the set handler to the fan on/off characteristic
113
- this.service
114
- .getCharacteristic(this.hapChar.Active)
115
- .onSet(async value => this.internalStateUpdate(value))
116
- this.cacheState = this.service.getCharacteristic(this.hapChar.Active).value ? 'on' : 'off'
117
-
118
- // Add the set handler to the fan rotation speed characteristic
119
- this.service
120
- .getCharacteristic(this.hapChar.RotationSpeed)
121
- .setProps({
122
- maxValue: 100,
123
- minStep: 1,
124
- minValue: 0,
125
- unit: 'unitless',
126
- })
127
- .onSet(async value => this.internalSpeedUpdate(value))
128
- this.cacheSpeed = this.service.getCharacteristic(this.hapChar.RotationSpeed).value
129
-
130
- // Add the set handler to the fan swing mode
131
- this.service
132
- .getCharacteristic(this.hapChar.SwingMode)
133
- .onSet(async value => this.internalSwingUpdate(value))
134
- this.cacheSwing = this.service.getCharacteristic(this.hapChar.SwingMode).value === 1 ? 'on' : 'off'
135
-
136
- // Output the customised options to the log
137
- const opts = JSON.stringify({})
138
- platform.log('[%s] %s %s.', accessory.displayName, platformLang.devInitOpts, opts)
139
- }
140
-
141
- async internalStateUpdate(value) {
142
- try {
143
- const newValue = value ? 'on' : 'off'
144
-
145
- // Don't continue if the new value is the same as before
146
- if (this.cacheState === newValue) {
147
- return
148
- }
149
-
150
- // Send the request to the platform sender function
151
- await this.platform.sendDeviceUpdate(this.accessory, {
152
- cmd: 'ptReal',
153
- value: value ? 'MwEBAAAAAAAAAAAAAAAAAAAAADM=' : 'MwEAAAAAAAAAAAAAAAAAAAAAADI=',
154
- })
155
-
156
- // Cache the new state and log if appropriate
157
- if (this.cacheState !== newValue) {
158
- this.cacheState = newValue
159
- this.accessory.log(`${platformLang.curState} [${newValue}]`)
160
- }
161
- } catch (err) {
162
- // Catch any errors during the process
163
- this.accessory.logWarn(`${platformLang.devNotUpdated} ${parseError(err)}`)
164
-
165
- // Throw a 'no response' error and set a timeout to revert this after 2 seconds
166
- setTimeout(() => {
167
- this.service.updateCharacteristic(this.hapChar.Active, this.cacheState === 'on' ? 1 : 0)
168
- }, 2000)
169
- throw new this.hapErr(-70402)
170
- }
171
- }
172
-
173
- async internalSpeedUpdate(value) {
174
- try {
175
- // Don't continue if the value is 0
176
- if (value === 0) {
177
- return
178
- }
179
-
180
- // HomeKit sends a percentage - map it onto this model's real speed steps
181
- value = hkPercentToFanSpeed(value, this.speedSteps)
182
-
183
- // Don't continue if the new value is the same as before
184
- if (this.cacheSpeed === value) {
185
- return
186
- }
187
-
188
- const codeToSend = this.speedCodes[value]
189
-
190
- const isAuto = value === this.autoSpeed
191
- await this.platform.sendDeviceUpdate(this.accessory, {
192
- cmd: 'ptReal',
193
- value: codeToSend,
194
- openApi: this.accessory.context.openApiCapabilities?.workMode
195
- ? { instance: 'workMode', capabilityType: 'devices.capabilities.work_mode', value: isAuto ? { workMode: 3 } : { workMode: 1, modeValue: value } }
196
- : undefined,
197
- })
198
-
199
- // Cache the new state and log if appropriate
200
- if (this.cacheSpeed !== value) {
201
- this.cacheSpeed = value
202
- this.accessory.log(`${platformLang.curSpeed} [${value}]`)
203
- }
204
- } catch (err) {
205
- // Catch any errors during the process
206
- this.accessory.logWarn(`${platformLang.devNotUpdated} ${parseError(err)}`)
207
-
208
- // Throw a 'no response' error and set a timeout to revert this after 2 seconds
209
- setTimeout(() => {
210
- this.service.updateCharacteristic(this.hapChar.RotationSpeed, fanSpeedToHkPercent(this.cacheSpeed, this.speedSteps, this.autoSpeed))
211
- }, 2000)
212
- throw new this.hapErr(-70402)
213
- }
214
- }
215
-
216
- async internalSwingUpdate(value) {
217
- try {
218
- const newValue = value ? 'on' : 'off'
219
- // Don't continue if the new value is the same as before
220
- if (this.cacheSwing === value) {
221
- return
222
- }
223
-
224
- await this.platform.sendDeviceUpdate(this.accessory, {
225
- cmd: 'ptReal',
226
- value: value ? 'Mx8BAQAAAAAAAAAAAAAAAAAAACw=' : 'Mx8BAAAAAAAAAAAAAAAAAAAAAC0=',
227
- openApi: this.accessory.context.openApiCapabilities?.oscillationToggle
228
- ? { instance: 'oscillationToggle', capabilityType: 'devices.capabilities.toggle', value: value ? 1 : 0 }
229
- : undefined,
230
- })
231
-
232
- // Cache the new state and log if appropriate
233
- if (this.cacheSwing !== newValue) {
234
- this.cacheSwing = newValue
235
- this.accessory.log(`${platformLang.curSwing} [${newValue}]`)
236
- }
237
- } catch (err) {
238
- // Catch any errors during the process
239
- this.accessory.logWarn(`${platformLang.devNotUpdated} ${parseError(err)}`)
240
-
241
- // Throw a 'no response' error and set a timeout to revert this after 2 seconds
242
- setTimeout(() => {
243
- this.service.updateCharacteristic(this.hapChar.SwingMode, this.cacheSwing === 'on' ? 1 : 0)
244
- }, 2000)
245
- throw new this.hapErr(-70402)
246
- }
247
- }
248
-
249
- externalUpdate(params) {
250
- // Update the active characteristic
251
- if (params.state && params.state !== this.cacheState) {
252
- this.cacheState = params.state
253
- this.service.updateCharacteristic(this.hapChar.Active, this.cacheState === 'on' ? 1 : 0)
254
- this.accessory.log(`${platformLang.curState} [${this.cacheState}]`)
255
- }
256
-
257
- // Handle OpenAPI workMode (speed or auto)
258
- if (params.workMode) {
259
- let newSpeed
260
- if (params.workMode.workMode === 3) {
261
- newSpeed = this.autoSpeed
262
- } else {
263
- newSpeed = params.workMode.modeValue
264
- }
265
- if (Number.isFinite(newSpeed) && newSpeed >= 1 && newSpeed <= this.autoSpeed && this.cacheSpeed !== newSpeed) {
266
- this.cacheSpeed = newSpeed
267
- const hkSpeed = fanSpeedToHkPercent(newSpeed, this.speedSteps, this.autoSpeed)
268
- this.service.updateCharacteristic(this.hapChar.RotationSpeed, hkSpeed)
269
- this.accessory.log(`${platformLang.curSpeed} [${newSpeed} -> ${hkSpeed}%]`)
270
- }
271
- }
272
-
273
- // Handle OpenAPI toggles
274
- if (params.toggles?.oscillationToggle !== undefined) {
275
- const newSwing = params.toggles.oscillationToggle ? 'on' : 'off'
276
- if (this.cacheSwing !== newSwing) {
277
- this.cacheSwing = newSwing
278
- this.service.updateCharacteristic(this.hapChar.SwingMode, this.cacheSwing === 'on' ? 1 : 0)
279
- this.accessory.log(`${platformLang.curSwing} [${this.cacheSwing}]`)
280
- }
281
- }
282
-
283
- // Check for some other scene/mode change
284
- (params.commands || []).forEach((command) => {
285
- const hexString = base64ToHex(command)
286
- const hexParts = hexToTwoItems(hexString)
287
-
288
- // Return now if not a device query update code
289
- if (getTwoItemPosition(hexParts, 1) !== 'aa') {
290
- return
291
- }
292
-
293
- if (getTwoItemPosition(hexParts, 2) === '08') {
294
- // Sensor Attached?
295
- const dev = hexString.substring(4, hexString.length - 24)
296
- this.accessory.context.sensorAttached = dev !== '000000000000'
297
- return
298
- }
299
-
300
- const deviceFunction = `${getTwoItemPosition(hexParts, 2)}${getTwoItemPosition(hexParts, 3)}`
301
-
302
- switch (deviceFunction) {
303
- case '0501': {
304
- // Fan speed
305
- const newSpeed = Number.parseInt(getTwoItemPosition(hexParts, 4), 16)
306
- if (newSpeed >= 1 && newSpeed <= this.speedSteps && this.cacheSpeed !== newSpeed) {
307
- this.cacheSpeed = newSpeed
308
- const hkSpeed = fanSpeedToHkPercent(newSpeed, this.speedSteps, this.autoSpeed)
309
- this.service.updateCharacteristic(this.hapChar.RotationSpeed, hkSpeed)
310
- this.accessory.log(`${platformLang.curSpeed} [${newSpeed} -> ${hkSpeed}%]`)
311
- }
312
- break
313
- }
314
- case '0500': {
315
- // Mode change (auto = 0x03)
316
- if (getTwoItemPosition(hexParts, 4) === '03' && this.cacheSpeed !== this.autoSpeed) {
317
- this.cacheSpeed = this.autoSpeed
318
- // Cache auto so we can tell it apart from "user asked for max speed"
319
- this.service.updateCharacteristic(this.hapChar.RotationSpeed, 100)
320
- this.accessory.log(`${platformLang.curSpeed} [auto]`)
321
- }
322
- break
323
- }
324
- case '1f01': {
325
- // Swing Mode
326
- const newSwing = getTwoItemPosition(hexParts, 4) === '01' ? 'on' : 'off'
327
- if (this.cacheSwing !== newSwing) {
328
- this.cacheSwing = newSwing
329
- this.service.updateCharacteristic(this.hapChar.SwingMode, this.cacheSwing === 'on' ? 1 : 0)
330
- this.accessory.log(`${platformLang.curSwing} [${this.cacheSwing}]`)
331
- }
332
- break
333
- }
334
- default:
335
- this.accessory.logDebugWarn(`${platformLang.newScene}: [${command}] [${hexString}]`)
336
- break
337
- }
338
- })
339
- }
340
- }