@homebridge-plugins/homebridge-govee 11.32.0-beta.2 → 11.32.0-beta.20
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.
- package/CHANGELOG.md +11 -2
- package/lib/device/fan-H1310.js +18 -8
- package/lib/device/fan-H1370.js +14 -5
- package/lib/device/fan-H7100.js +18 -8
- package/lib/device/fan-H7101.js +18 -8
- package/lib/device/fan-H7102.js +18 -8
- package/lib/device/fan-H7105.js +20 -6
- package/lib/device/fan-H7106.js +18 -8
- package/lib/device/fan-H7107.js +20 -6
- package/lib/device/fan-H7111.js +17 -20
- package/lib/device/outlet-double.js +13 -4
- package/lib/device/switch-double.js +13 -4
- package/lib/homebridge-ui/public/index.html +167 -142
- package/lib/homebridge-ui/server.js +7 -0
- package/lib/platform.js +32 -0
- package/lib/utils/constants.js +6 -3
- package/lib/utils/functions.js +36 -0
- package/lib/utils/lang-en.js +1 -0
- package/package.json +9 -5
package/CHANGELOG.md
CHANGED
|
@@ -7,9 +7,18 @@ All notable changes to `@homebridge-plugins/homebridge-govee` will be documented
|
|
|
7
7
|
### Changed
|
|
8
8
|
|
|
9
9
|
- chore(github): use the shared homebridge action to deprecate past pre-releases
|
|
10
|
-
- feat(ui): add and remove devices from the config via the my devices tab (#1323)
|
|
11
10
|
- feat(ui): hide or show a device in homekit from the my devices tab
|
|
12
|
-
-
|
|
11
|
+
- chore(deps): dependency updates
|
|
12
|
+
- style(ui): standardise the custom ui layout and sync the support tab with the readme
|
|
13
|
+
- chore(deps): override help-me to v5 to clear the high brace-expansion security advisory from the aws-iot dependency chain
|
|
14
|
+
- feat(ui): add a remove all devices action to the my devices tab (#1323)
|
|
15
|
+
- feat: add support for the H5089 smart plug, exposing its outlet and built-in light as separate switches (#1323)
|
|
16
|
+
- chore: declare the supports-hap transport keyword for the homebridge ui
|
|
17
|
+
- feat: add support for the H60B3 uplighter as an rgb light (#1325)
|
|
18
|
+
- feat: add support for the H5901 water timer through the govee openapi (#1324)
|
|
19
|
+
- fix(fans): map rotation speed as a percentage on every fan model, so homekit stops showing speeds like 7% and the top of the slider means full power (#1326)
|
|
20
|
+
- chore: log what each device can do according to the govee openapi, in debug mode, to make working out new device support quicker
|
|
21
|
+
- chore: decode the status codes a device reports into readable hex in debug mode, so support for new device features can be worked out from a normal log
|
|
13
22
|
|
|
14
23
|
## v11.31.0 (2026-07-24)
|
|
15
24
|
|
package/lib/device/fan-H1310.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
base64ToHex,
|
|
3
|
+
fanSpeedToHkPercent,
|
|
3
4
|
getTwoItemPosition,
|
|
4
5
|
hexToTwoItems,
|
|
6
|
+
hkPercentToFanSpeed,
|
|
5
7
|
parseError,
|
|
6
8
|
} from '../utils/functions.js'
|
|
7
9
|
import platformLang from '../utils/lang-en.js'
|
|
@@ -30,6 +32,8 @@ export default class {
|
|
|
30
32
|
9: 'MwUAAwAAAAAAAAAAAAAAAAAAADU=', // auto mode
|
|
31
33
|
}
|
|
32
34
|
this.autoSpeed = 9
|
|
35
|
+
// Real speed steps, excluding auto - HomeKit percentages map onto these
|
|
36
|
+
this.speedSteps = 8
|
|
33
37
|
|
|
34
38
|
// Remove any old original Fan services
|
|
35
39
|
if (this.accessory.getService(this.hapServ.Fan)) {
|
|
@@ -57,7 +61,7 @@ export default class {
|
|
|
57
61
|
this.service
|
|
58
62
|
.getCharacteristic(this.hapChar.RotationSpeed)
|
|
59
63
|
.setProps({
|
|
60
|
-
maxValue:
|
|
64
|
+
maxValue: 100,
|
|
61
65
|
minStep: 1,
|
|
62
66
|
minValue: 0,
|
|
63
67
|
unit: 'unitless',
|
|
@@ -115,6 +119,9 @@ export default class {
|
|
|
115
119
|
return
|
|
116
120
|
}
|
|
117
121
|
|
|
122
|
+
// HomeKit sends a percentage - map it onto this model's real speed steps
|
|
123
|
+
value = hkPercentToFanSpeed(value, this.speedSteps)
|
|
124
|
+
|
|
118
125
|
// Don't continue if the new value is the same as before
|
|
119
126
|
if (this.cacheSpeed === value) {
|
|
120
127
|
return
|
|
@@ -142,7 +149,7 @@ export default class {
|
|
|
142
149
|
|
|
143
150
|
// Throw a 'no response' error and set a timeout to revert this after 2 seconds
|
|
144
151
|
setTimeout(() => {
|
|
145
|
-
this.service.updateCharacteristic(this.hapChar.RotationSpeed, this.cacheSpeed)
|
|
152
|
+
this.service.updateCharacteristic(this.hapChar.RotationSpeed, fanSpeedToHkPercent(this.cacheSpeed, this.speedSteps, this.autoSpeed))
|
|
146
153
|
}, 2000)
|
|
147
154
|
throw new this.hapErr(-70402)
|
|
148
155
|
}
|
|
@@ -199,8 +206,9 @@ export default class {
|
|
|
199
206
|
}
|
|
200
207
|
if (Number.isFinite(newSpeed) && newSpeed >= 1 && newSpeed <= this.autoSpeed && this.cacheSpeed !== newSpeed) {
|
|
201
208
|
this.cacheSpeed = newSpeed
|
|
202
|
-
|
|
203
|
-
this.
|
|
209
|
+
const hkSpeed = fanSpeedToHkPercent(newSpeed, this.speedSteps, this.autoSpeed)
|
|
210
|
+
this.service.updateCharacteristic(this.hapChar.RotationSpeed, hkSpeed)
|
|
211
|
+
this.accessory.log(`${platformLang.curSpeed} [${newSpeed} -> ${hkSpeed}%]`)
|
|
204
212
|
}
|
|
205
213
|
}
|
|
206
214
|
|
|
@@ -237,10 +245,11 @@ export default class {
|
|
|
237
245
|
case '0501': {
|
|
238
246
|
// Fan speed
|
|
239
247
|
const newSpeed = Number.parseInt(getTwoItemPosition(hexParts, 4), 16)
|
|
240
|
-
if (newSpeed >= 1 && newSpeed <=
|
|
248
|
+
if (newSpeed >= 1 && newSpeed <= this.speedSteps && this.cacheSpeed !== newSpeed) {
|
|
241
249
|
this.cacheSpeed = newSpeed
|
|
242
|
-
|
|
243
|
-
this.
|
|
250
|
+
const hkSpeed = fanSpeedToHkPercent(newSpeed, this.speedSteps, this.autoSpeed)
|
|
251
|
+
this.service.updateCharacteristic(this.hapChar.RotationSpeed, hkSpeed)
|
|
252
|
+
this.accessory.log(`${platformLang.curSpeed} [${newSpeed} -> ${hkSpeed}%]`)
|
|
244
253
|
}
|
|
245
254
|
break
|
|
246
255
|
}
|
|
@@ -248,7 +257,8 @@ export default class {
|
|
|
248
257
|
// Mode change (auto = 0x03)
|
|
249
258
|
if (getTwoItemPosition(hexParts, 4) === '03' && this.cacheSpeed !== this.autoSpeed) {
|
|
250
259
|
this.cacheSpeed = this.autoSpeed
|
|
251
|
-
|
|
260
|
+
// Cache auto so we can tell it apart from "user asked for max speed"
|
|
261
|
+
this.service.updateCharacteristic(this.hapChar.RotationSpeed, 100)
|
|
252
262
|
this.accessory.log(`${platformLang.curSpeed} [auto]`)
|
|
253
263
|
}
|
|
254
264
|
break
|
package/lib/device/fan-H1370.js
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
base64ToHex,
|
|
3
|
+
fanSpeedToHkPercent,
|
|
3
4
|
generateCodeFromHexValues,
|
|
4
5
|
generateRandomString,
|
|
5
6
|
getTwoItemPosition,
|
|
6
7
|
hexToTwoItems,
|
|
8
|
+
hkPercentToFanSpeed,
|
|
7
9
|
parseError,
|
|
8
10
|
sleep,
|
|
9
11
|
} from '../utils/functions.js'
|
|
@@ -41,11 +43,14 @@ export default class {
|
|
|
41
43
|
.onSet(async value => this.internalStateUpdate(value))
|
|
42
44
|
this.cacheState = this.service.getCharacteristic(this.hapChar.Active).value ? 'on' : 'off'
|
|
43
45
|
|
|
46
|
+
// Real speed steps - HomeKit percentages map onto these
|
|
47
|
+
this.speedSteps = 12
|
|
48
|
+
|
|
44
49
|
// Add the set handler to the fan rotation speed characteristic
|
|
45
50
|
this.service
|
|
46
51
|
.getCharacteristic(this.hapChar.RotationSpeed)
|
|
47
52
|
.setProps({
|
|
48
|
-
maxValue:
|
|
53
|
+
maxValue: 100,
|
|
49
54
|
minStep: 1,
|
|
50
55
|
minValue: 0,
|
|
51
56
|
unit: 'unitless',
|
|
@@ -140,6 +145,9 @@ export default class {
|
|
|
140
145
|
return
|
|
141
146
|
}
|
|
142
147
|
|
|
148
|
+
// HomeKit sends a percentage - map it onto this model's real speed steps
|
|
149
|
+
value = hkPercentToFanSpeed(value, this.speedSteps)
|
|
150
|
+
|
|
143
151
|
// Don't continue if the new value is the same as before
|
|
144
152
|
if (this.cacheSpeed === value) {
|
|
145
153
|
return
|
|
@@ -162,7 +170,7 @@ export default class {
|
|
|
162
170
|
|
|
163
171
|
// Throw a 'no response' error and set a timeout to revert this after 2 seconds
|
|
164
172
|
setTimeout(() => {
|
|
165
|
-
this.service.updateCharacteristic(this.hapChar.RotationSpeed, this.cacheSpeed)
|
|
173
|
+
this.service.updateCharacteristic(this.hapChar.RotationSpeed, fanSpeedToHkPercent(this.cacheSpeed, this.speedSteps))
|
|
166
174
|
}, 2000)
|
|
167
175
|
throw new this.hapErr(-70402)
|
|
168
176
|
}
|
|
@@ -320,10 +328,11 @@ export default class {
|
|
|
320
328
|
case '3101': {
|
|
321
329
|
// Fan speed
|
|
322
330
|
const newSpeed = Number.parseInt(getTwoItemPosition(hexParts, 4), 16)
|
|
323
|
-
if (newSpeed >= 1 && newSpeed <=
|
|
331
|
+
if (newSpeed >= 1 && newSpeed <= this.speedSteps && this.cacheSpeed !== newSpeed) {
|
|
324
332
|
this.cacheSpeed = newSpeed
|
|
325
|
-
|
|
326
|
-
this.
|
|
333
|
+
const hkSpeed = fanSpeedToHkPercent(newSpeed, this.speedSteps)
|
|
334
|
+
this.service.updateCharacteristic(this.hapChar.RotationSpeed, hkSpeed)
|
|
335
|
+
this.accessory.log(`${platformLang.curSpeed} [${newSpeed} -> ${hkSpeed}%]`)
|
|
327
336
|
}
|
|
328
337
|
break
|
|
329
338
|
}
|
package/lib/device/fan-H7100.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
base64ToHex,
|
|
3
|
+
fanSpeedToHkPercent,
|
|
3
4
|
getTwoItemPosition,
|
|
4
5
|
hexToTwoItems,
|
|
6
|
+
hkPercentToFanSpeed,
|
|
5
7
|
parseError,
|
|
6
8
|
} from '../utils/functions.js'
|
|
7
9
|
import platformLang from '../utils/lang-en.js'
|
|
@@ -30,6 +32,8 @@ export default class {
|
|
|
30
32
|
9: 'MwUAAwAAAAAAAAAAAAAAAAAAADU=', // auto mode
|
|
31
33
|
}
|
|
32
34
|
this.autoSpeed = 9
|
|
35
|
+
// Real speed steps, excluding auto - HomeKit percentages map onto these
|
|
36
|
+
this.speedSteps = 8
|
|
33
37
|
|
|
34
38
|
// Remove any old original Fan services
|
|
35
39
|
if (this.accessory.getService(this.hapServ.Fan)) {
|
|
@@ -57,7 +61,7 @@ export default class {
|
|
|
57
61
|
this.service
|
|
58
62
|
.getCharacteristic(this.hapChar.RotationSpeed)
|
|
59
63
|
.setProps({
|
|
60
|
-
maxValue:
|
|
64
|
+
maxValue: 100,
|
|
61
65
|
minStep: 1,
|
|
62
66
|
minValue: 0,
|
|
63
67
|
unit: 'unitless',
|
|
@@ -115,6 +119,9 @@ export default class {
|
|
|
115
119
|
return
|
|
116
120
|
}
|
|
117
121
|
|
|
122
|
+
// HomeKit sends a percentage - map it onto this model's real speed steps
|
|
123
|
+
value = hkPercentToFanSpeed(value, this.speedSteps)
|
|
124
|
+
|
|
118
125
|
// Don't continue if the new value is the same as before
|
|
119
126
|
if (this.cacheSpeed === value) {
|
|
120
127
|
return
|
|
@@ -142,7 +149,7 @@ export default class {
|
|
|
142
149
|
|
|
143
150
|
// Throw a 'no response' error and set a timeout to revert this after 2 seconds
|
|
144
151
|
setTimeout(() => {
|
|
145
|
-
this.service.updateCharacteristic(this.hapChar.RotationSpeed, this.cacheSpeed)
|
|
152
|
+
this.service.updateCharacteristic(this.hapChar.RotationSpeed, fanSpeedToHkPercent(this.cacheSpeed, this.speedSteps, this.autoSpeed))
|
|
146
153
|
}, 2000)
|
|
147
154
|
throw new this.hapErr(-70402)
|
|
148
155
|
}
|
|
@@ -199,8 +206,9 @@ export default class {
|
|
|
199
206
|
}
|
|
200
207
|
if (Number.isFinite(newSpeed) && newSpeed >= 1 && newSpeed <= this.autoSpeed && this.cacheSpeed !== newSpeed) {
|
|
201
208
|
this.cacheSpeed = newSpeed
|
|
202
|
-
|
|
203
|
-
this.
|
|
209
|
+
const hkSpeed = fanSpeedToHkPercent(newSpeed, this.speedSteps, this.autoSpeed)
|
|
210
|
+
this.service.updateCharacteristic(this.hapChar.RotationSpeed, hkSpeed)
|
|
211
|
+
this.accessory.log(`${platformLang.curSpeed} [${newSpeed} -> ${hkSpeed}%]`)
|
|
204
212
|
}
|
|
205
213
|
}
|
|
206
214
|
|
|
@@ -237,10 +245,11 @@ export default class {
|
|
|
237
245
|
case '0501': {
|
|
238
246
|
// Fan speed
|
|
239
247
|
const newSpeed = Number.parseInt(getTwoItemPosition(hexParts, 4), 16)
|
|
240
|
-
if (newSpeed >= 1 && newSpeed <=
|
|
248
|
+
if (newSpeed >= 1 && newSpeed <= this.speedSteps && this.cacheSpeed !== newSpeed) {
|
|
241
249
|
this.cacheSpeed = newSpeed
|
|
242
|
-
|
|
243
|
-
this.
|
|
250
|
+
const hkSpeed = fanSpeedToHkPercent(newSpeed, this.speedSteps, this.autoSpeed)
|
|
251
|
+
this.service.updateCharacteristic(this.hapChar.RotationSpeed, hkSpeed)
|
|
252
|
+
this.accessory.log(`${platformLang.curSpeed} [${newSpeed} -> ${hkSpeed}%]`)
|
|
244
253
|
}
|
|
245
254
|
break
|
|
246
255
|
}
|
|
@@ -248,7 +257,8 @@ export default class {
|
|
|
248
257
|
// Mode change (auto = 0x03)
|
|
249
258
|
if (getTwoItemPosition(hexParts, 4) === '03' && this.cacheSpeed !== this.autoSpeed) {
|
|
250
259
|
this.cacheSpeed = this.autoSpeed
|
|
251
|
-
|
|
260
|
+
// Cache auto so we can tell it apart from "user asked for max speed"
|
|
261
|
+
this.service.updateCharacteristic(this.hapChar.RotationSpeed, 100)
|
|
252
262
|
this.accessory.log(`${platformLang.curSpeed} [auto]`)
|
|
253
263
|
}
|
|
254
264
|
break
|
package/lib/device/fan-H7101.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
base64ToHex,
|
|
3
|
+
fanSpeedToHkPercent,
|
|
3
4
|
getTwoItemPosition,
|
|
4
5
|
hexToTwoItems,
|
|
6
|
+
hkPercentToFanSpeed,
|
|
5
7
|
parseError,
|
|
6
8
|
} from '../utils/functions.js'
|
|
7
9
|
import platformLang from '../utils/lang-en.js'
|
|
@@ -86,6 +88,8 @@ export default class {
|
|
|
86
88
|
9: 'MwUAAwAAAAAAAAAAAAAAAAAAADU=', // auto mode
|
|
87
89
|
}
|
|
88
90
|
this.autoSpeed = 9
|
|
91
|
+
// Real speed steps, excluding auto - HomeKit percentages map onto these
|
|
92
|
+
this.speedSteps = 8
|
|
89
93
|
|
|
90
94
|
// Remove any old original Fan services
|
|
91
95
|
if (this.accessory.getService(this.hapServ.Fan)) {
|
|
@@ -113,7 +117,7 @@ export default class {
|
|
|
113
117
|
this.service
|
|
114
118
|
.getCharacteristic(this.hapChar.RotationSpeed)
|
|
115
119
|
.setProps({
|
|
116
|
-
maxValue:
|
|
120
|
+
maxValue: 100,
|
|
117
121
|
minStep: 1,
|
|
118
122
|
minValue: 0,
|
|
119
123
|
unit: 'unitless',
|
|
@@ -171,6 +175,9 @@ export default class {
|
|
|
171
175
|
return
|
|
172
176
|
}
|
|
173
177
|
|
|
178
|
+
// HomeKit sends a percentage - map it onto this model's real speed steps
|
|
179
|
+
value = hkPercentToFanSpeed(value, this.speedSteps)
|
|
180
|
+
|
|
174
181
|
// Don't continue if the new value is the same as before
|
|
175
182
|
if (this.cacheSpeed === value) {
|
|
176
183
|
return
|
|
@@ -198,7 +205,7 @@ export default class {
|
|
|
198
205
|
|
|
199
206
|
// Throw a 'no response' error and set a timeout to revert this after 2 seconds
|
|
200
207
|
setTimeout(() => {
|
|
201
|
-
this.service.updateCharacteristic(this.hapChar.RotationSpeed, this.cacheSpeed)
|
|
208
|
+
this.service.updateCharacteristic(this.hapChar.RotationSpeed, fanSpeedToHkPercent(this.cacheSpeed, this.speedSteps, this.autoSpeed))
|
|
202
209
|
}, 2000)
|
|
203
210
|
throw new this.hapErr(-70402)
|
|
204
211
|
}
|
|
@@ -255,8 +262,9 @@ export default class {
|
|
|
255
262
|
}
|
|
256
263
|
if (Number.isFinite(newSpeed) && newSpeed >= 1 && newSpeed <= this.autoSpeed && this.cacheSpeed !== newSpeed) {
|
|
257
264
|
this.cacheSpeed = newSpeed
|
|
258
|
-
|
|
259
|
-
this.
|
|
265
|
+
const hkSpeed = fanSpeedToHkPercent(newSpeed, this.speedSteps, this.autoSpeed)
|
|
266
|
+
this.service.updateCharacteristic(this.hapChar.RotationSpeed, hkSpeed)
|
|
267
|
+
this.accessory.log(`${platformLang.curSpeed} [${newSpeed} -> ${hkSpeed}%]`)
|
|
260
268
|
}
|
|
261
269
|
}
|
|
262
270
|
|
|
@@ -293,10 +301,11 @@ export default class {
|
|
|
293
301
|
case '0501': {
|
|
294
302
|
// Fan speed
|
|
295
303
|
const newSpeed = Number.parseInt(getTwoItemPosition(hexParts, 4), 16)
|
|
296
|
-
if (newSpeed >= 1 && newSpeed <=
|
|
304
|
+
if (newSpeed >= 1 && newSpeed <= this.speedSteps && this.cacheSpeed !== newSpeed) {
|
|
297
305
|
this.cacheSpeed = newSpeed
|
|
298
|
-
|
|
299
|
-
this.
|
|
306
|
+
const hkSpeed = fanSpeedToHkPercent(newSpeed, this.speedSteps, this.autoSpeed)
|
|
307
|
+
this.service.updateCharacteristic(this.hapChar.RotationSpeed, hkSpeed)
|
|
308
|
+
this.accessory.log(`${platformLang.curSpeed} [${newSpeed} -> ${hkSpeed}%]`)
|
|
300
309
|
}
|
|
301
310
|
break
|
|
302
311
|
}
|
|
@@ -304,7 +313,8 @@ export default class {
|
|
|
304
313
|
// Mode change (auto = 0x03)
|
|
305
314
|
if (getTwoItemPosition(hexParts, 4) === '03' && this.cacheSpeed !== this.autoSpeed) {
|
|
306
315
|
this.cacheSpeed = this.autoSpeed
|
|
307
|
-
|
|
316
|
+
// Cache auto so we can tell it apart from "user asked for max speed"
|
|
317
|
+
this.service.updateCharacteristic(this.hapChar.RotationSpeed, 100)
|
|
308
318
|
this.accessory.log(`${platformLang.curSpeed} [auto]`)
|
|
309
319
|
}
|
|
310
320
|
break
|
package/lib/device/fan-H7102.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
base64ToHex,
|
|
3
|
+
fanSpeedToHkPercent,
|
|
3
4
|
getTwoItemPosition,
|
|
4
5
|
hexToTwoItems,
|
|
6
|
+
hkPercentToFanSpeed,
|
|
5
7
|
parseError,
|
|
6
8
|
} from '../utils/functions.js'
|
|
7
9
|
import platformLang from '../utils/lang-en.js'
|
|
@@ -30,6 +32,8 @@ export default class {
|
|
|
30
32
|
9: 'MwUAAwAAAAAAAAAAAAAAAAAAADU=', // auto mode
|
|
31
33
|
}
|
|
32
34
|
this.autoSpeed = 9
|
|
35
|
+
// Real speed steps, excluding auto - HomeKit percentages map onto these
|
|
36
|
+
this.speedSteps = 8
|
|
33
37
|
|
|
34
38
|
// Remove any old original Fan services
|
|
35
39
|
if (this.accessory.getService(this.hapServ.Fan)) {
|
|
@@ -57,7 +61,7 @@ export default class {
|
|
|
57
61
|
this.service
|
|
58
62
|
.getCharacteristic(this.hapChar.RotationSpeed)
|
|
59
63
|
.setProps({
|
|
60
|
-
maxValue:
|
|
64
|
+
maxValue: 100,
|
|
61
65
|
minStep: 1,
|
|
62
66
|
minValue: 0,
|
|
63
67
|
unit: 'unitless',
|
|
@@ -115,6 +119,9 @@ export default class {
|
|
|
115
119
|
return
|
|
116
120
|
}
|
|
117
121
|
|
|
122
|
+
// HomeKit sends a percentage - map it onto this model's real speed steps
|
|
123
|
+
value = hkPercentToFanSpeed(value, this.speedSteps)
|
|
124
|
+
|
|
118
125
|
// Don't continue if the new value is the same as before
|
|
119
126
|
if (this.cacheSpeed === value) {
|
|
120
127
|
return
|
|
@@ -142,7 +149,7 @@ export default class {
|
|
|
142
149
|
|
|
143
150
|
// Throw a 'no response' error and set a timeout to revert this after 2 seconds
|
|
144
151
|
setTimeout(() => {
|
|
145
|
-
this.service.updateCharacteristic(this.hapChar.RotationSpeed, this.cacheSpeed)
|
|
152
|
+
this.service.updateCharacteristic(this.hapChar.RotationSpeed, fanSpeedToHkPercent(this.cacheSpeed, this.speedSteps, this.autoSpeed))
|
|
146
153
|
}, 2000)
|
|
147
154
|
throw new this.hapErr(-70402)
|
|
148
155
|
}
|
|
@@ -199,8 +206,9 @@ export default class {
|
|
|
199
206
|
}
|
|
200
207
|
if (Number.isFinite(newSpeed) && newSpeed >= 1 && newSpeed <= this.autoSpeed && this.cacheSpeed !== newSpeed) {
|
|
201
208
|
this.cacheSpeed = newSpeed
|
|
202
|
-
|
|
203
|
-
this.
|
|
209
|
+
const hkSpeed = fanSpeedToHkPercent(newSpeed, this.speedSteps, this.autoSpeed)
|
|
210
|
+
this.service.updateCharacteristic(this.hapChar.RotationSpeed, hkSpeed)
|
|
211
|
+
this.accessory.log(`${platformLang.curSpeed} [${newSpeed} -> ${hkSpeed}%]`)
|
|
204
212
|
}
|
|
205
213
|
}
|
|
206
214
|
|
|
@@ -237,10 +245,11 @@ export default class {
|
|
|
237
245
|
case '0501': {
|
|
238
246
|
// Fan speed
|
|
239
247
|
const newSpeed = Number.parseInt(getTwoItemPosition(hexParts, 4), 16)
|
|
240
|
-
if (newSpeed >= 1 && newSpeed <=
|
|
248
|
+
if (newSpeed >= 1 && newSpeed <= this.speedSteps && this.cacheSpeed !== newSpeed) {
|
|
241
249
|
this.cacheSpeed = newSpeed
|
|
242
|
-
|
|
243
|
-
this.
|
|
250
|
+
const hkSpeed = fanSpeedToHkPercent(newSpeed, this.speedSteps, this.autoSpeed)
|
|
251
|
+
this.service.updateCharacteristic(this.hapChar.RotationSpeed, hkSpeed)
|
|
252
|
+
this.accessory.log(`${platformLang.curSpeed} [${newSpeed} -> ${hkSpeed}%]`)
|
|
244
253
|
}
|
|
245
254
|
break
|
|
246
255
|
}
|
|
@@ -248,7 +257,8 @@ export default class {
|
|
|
248
257
|
// Mode change (auto = 0x03)
|
|
249
258
|
if (getTwoItemPosition(hexParts, 4) === '03' && this.cacheSpeed !== this.autoSpeed) {
|
|
250
259
|
this.cacheSpeed = this.autoSpeed
|
|
251
|
-
|
|
260
|
+
// Cache auto so we can tell it apart from "user asked for max speed"
|
|
261
|
+
this.service.updateCharacteristic(this.hapChar.RotationSpeed, 100)
|
|
252
262
|
this.accessory.log(`${platformLang.curSpeed} [auto]`)
|
|
253
263
|
}
|
|
254
264
|
break
|
package/lib/device/fan-H7105.js
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { hs2rgb, rgb2hs } from '../utils/colour.js'
|
|
2
2
|
import {
|
|
3
3
|
base64ToHex,
|
|
4
|
+
fanSpeedToHkPercent,
|
|
4
5
|
generateCodeFromHexValues,
|
|
5
6
|
generateRandomString,
|
|
6
7
|
getTwoItemPosition,
|
|
7
8
|
hexToDecimal,
|
|
8
9
|
hexToTwoItems,
|
|
10
|
+
hkPercentToFanSpeed,
|
|
9
11
|
parseError,
|
|
10
12
|
sleep,
|
|
11
13
|
} from '../utils/functions.js'
|
|
@@ -43,6 +45,8 @@ export default class {
|
|
|
43
45
|
13: 'MwUAAgAAAAAAAAAAAAAAAAAAADQ=', // auto mode
|
|
44
46
|
}
|
|
45
47
|
this.autoSpeed = 13
|
|
48
|
+
// Real speed steps, excluding auto - HomeKit percentages map onto these
|
|
49
|
+
this.speedSteps = 12
|
|
46
50
|
|
|
47
51
|
// Remove any old original Fan services
|
|
48
52
|
if (this.accessory.getService(this.hapServ.Fan)) {
|
|
@@ -70,7 +74,7 @@ export default class {
|
|
|
70
74
|
this.service
|
|
71
75
|
.getCharacteristic(this.hapChar.RotationSpeed)
|
|
72
76
|
.setProps({
|
|
73
|
-
maxValue:
|
|
77
|
+
maxValue: 100,
|
|
74
78
|
minStep: 1,
|
|
75
79
|
minValue: 0,
|
|
76
80
|
unit: 'unitless', // This is actually from HAP for Bluetooth LE Specification, but fits
|
|
@@ -157,8 +161,16 @@ export default class {
|
|
|
157
161
|
|
|
158
162
|
async internalSpeedUpdate(value) {
|
|
159
163
|
try {
|
|
164
|
+
// Don't continue if the fan is being turned off
|
|
165
|
+
if (value === 0) {
|
|
166
|
+
return
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// HomeKit sends a percentage - map it onto this model's real speed steps
|
|
170
|
+
value = hkPercentToFanSpeed(value, this.speedSteps)
|
|
171
|
+
|
|
160
172
|
// Don't continue if the new value is the same as before
|
|
161
|
-
if (this.cacheSpeed === value
|
|
173
|
+
if (this.cacheSpeed === value) {
|
|
162
174
|
return
|
|
163
175
|
}
|
|
164
176
|
|
|
@@ -182,7 +194,7 @@ export default class {
|
|
|
182
194
|
|
|
183
195
|
// Throw a 'no response' error and set a timeout to revert this after 2 seconds
|
|
184
196
|
setTimeout(() => {
|
|
185
|
-
this.service.updateCharacteristic(this.hapChar.RotationSpeed, this.cacheSpeed)
|
|
197
|
+
this.service.updateCharacteristic(this.hapChar.RotationSpeed, fanSpeedToHkPercent(this.cacheSpeed, this.speedSteps, this.autoSpeed))
|
|
186
198
|
}, 2000)
|
|
187
199
|
throw new this.hapErr(-70402)
|
|
188
200
|
}
|
|
@@ -380,8 +392,9 @@ export default class {
|
|
|
380
392
|
}
|
|
381
393
|
if (Number.isFinite(newSpeed) && newSpeed >= 1 && newSpeed <= this.autoSpeed && this.cacheSpeed !== newSpeed) {
|
|
382
394
|
this.cacheSpeed = newSpeed
|
|
383
|
-
|
|
384
|
-
this.
|
|
395
|
+
const hkSpeed = fanSpeedToHkPercent(newSpeed, this.speedSteps, this.autoSpeed)
|
|
396
|
+
this.service.updateCharacteristic(this.hapChar.RotationSpeed, hkSpeed)
|
|
397
|
+
this.accessory.log(`${platformLang.curSpeed} [${newSpeed} -> ${hkSpeed}%]`)
|
|
385
398
|
}
|
|
386
399
|
}
|
|
387
400
|
|
|
@@ -430,7 +443,8 @@ export default class {
|
|
|
430
443
|
// Mode change (auto = 0x02)
|
|
431
444
|
if (getTwoItemPosition(hexParts, 4) === '02' && this.cacheSpeed !== this.autoSpeed) {
|
|
432
445
|
this.cacheSpeed = this.autoSpeed
|
|
433
|
-
|
|
446
|
+
// Cache auto so we can tell it apart from "user asked for max speed"
|
|
447
|
+
this.service.updateCharacteristic(this.hapChar.RotationSpeed, 100)
|
|
434
448
|
this.accessory.log(`${platformLang.curSpeed} [auto]`)
|
|
435
449
|
}
|
|
436
450
|
break
|
package/lib/device/fan-H7106.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
base64ToHex,
|
|
3
|
+
fanSpeedToHkPercent,
|
|
3
4
|
getTwoItemPosition,
|
|
4
5
|
hexToTwoItems,
|
|
6
|
+
hkPercentToFanSpeed,
|
|
5
7
|
parseError,
|
|
6
8
|
} from '../utils/functions.js'
|
|
7
9
|
import platformLang from '../utils/lang-en.js'
|
|
@@ -30,6 +32,8 @@ export default class {
|
|
|
30
32
|
9: 'MwUAAwAAAAAAAAAAAAAAAAAAADU=', // auto mode
|
|
31
33
|
}
|
|
32
34
|
this.autoSpeed = 9
|
|
35
|
+
// Real speed steps, excluding auto - HomeKit percentages map onto these
|
|
36
|
+
this.speedSteps = 8
|
|
33
37
|
|
|
34
38
|
// Remove any old original Fan services
|
|
35
39
|
if (this.accessory.getService(this.hapServ.Fan)) {
|
|
@@ -57,7 +61,7 @@ export default class {
|
|
|
57
61
|
this.service
|
|
58
62
|
.getCharacteristic(this.hapChar.RotationSpeed)
|
|
59
63
|
.setProps({
|
|
60
|
-
maxValue:
|
|
64
|
+
maxValue: 100,
|
|
61
65
|
minStep: 1,
|
|
62
66
|
minValue: 0,
|
|
63
67
|
unit: 'unitless',
|
|
@@ -115,6 +119,9 @@ export default class {
|
|
|
115
119
|
return
|
|
116
120
|
}
|
|
117
121
|
|
|
122
|
+
// HomeKit sends a percentage - map it onto this model's real speed steps
|
|
123
|
+
value = hkPercentToFanSpeed(value, this.speedSteps)
|
|
124
|
+
|
|
118
125
|
// Don't continue if the new value is the same as before
|
|
119
126
|
if (this.cacheSpeed === value) {
|
|
120
127
|
return
|
|
@@ -142,7 +149,7 @@ export default class {
|
|
|
142
149
|
|
|
143
150
|
// Throw a 'no response' error and set a timeout to revert this after 2 seconds
|
|
144
151
|
setTimeout(() => {
|
|
145
|
-
this.service.updateCharacteristic(this.hapChar.RotationSpeed, this.cacheSpeed)
|
|
152
|
+
this.service.updateCharacteristic(this.hapChar.RotationSpeed, fanSpeedToHkPercent(this.cacheSpeed, this.speedSteps, this.autoSpeed))
|
|
146
153
|
}, 2000)
|
|
147
154
|
throw new this.hapErr(-70402)
|
|
148
155
|
}
|
|
@@ -199,8 +206,9 @@ export default class {
|
|
|
199
206
|
}
|
|
200
207
|
if (Number.isFinite(newSpeed) && newSpeed >= 1 && newSpeed <= this.autoSpeed && this.cacheSpeed !== newSpeed) {
|
|
201
208
|
this.cacheSpeed = newSpeed
|
|
202
|
-
|
|
203
|
-
this.
|
|
209
|
+
const hkSpeed = fanSpeedToHkPercent(newSpeed, this.speedSteps, this.autoSpeed)
|
|
210
|
+
this.service.updateCharacteristic(this.hapChar.RotationSpeed, hkSpeed)
|
|
211
|
+
this.accessory.log(`${platformLang.curSpeed} [${newSpeed} -> ${hkSpeed}%]`)
|
|
204
212
|
}
|
|
205
213
|
}
|
|
206
214
|
|
|
@@ -237,10 +245,11 @@ export default class {
|
|
|
237
245
|
case '0501': {
|
|
238
246
|
// Fan speed
|
|
239
247
|
const newSpeed = Number.parseInt(getTwoItemPosition(hexParts, 4), 16)
|
|
240
|
-
if (newSpeed >= 1 && newSpeed <=
|
|
248
|
+
if (newSpeed >= 1 && newSpeed <= this.speedSteps && this.cacheSpeed !== newSpeed) {
|
|
241
249
|
this.cacheSpeed = newSpeed
|
|
242
|
-
|
|
243
|
-
this.
|
|
250
|
+
const hkSpeed = fanSpeedToHkPercent(newSpeed, this.speedSteps, this.autoSpeed)
|
|
251
|
+
this.service.updateCharacteristic(this.hapChar.RotationSpeed, hkSpeed)
|
|
252
|
+
this.accessory.log(`${platformLang.curSpeed} [${newSpeed} -> ${hkSpeed}%]`)
|
|
244
253
|
}
|
|
245
254
|
break
|
|
246
255
|
}
|
|
@@ -248,7 +257,8 @@ export default class {
|
|
|
248
257
|
// Mode change (auto = 0x03)
|
|
249
258
|
if (getTwoItemPosition(hexParts, 4) === '03' && this.cacheSpeed !== this.autoSpeed) {
|
|
250
259
|
this.cacheSpeed = this.autoSpeed
|
|
251
|
-
|
|
260
|
+
// Cache auto so we can tell it apart from "user asked for max speed"
|
|
261
|
+
this.service.updateCharacteristic(this.hapChar.RotationSpeed, 100)
|
|
252
262
|
this.accessory.log(`${platformLang.curSpeed} [auto]`)
|
|
253
263
|
}
|
|
254
264
|
break
|
package/lib/device/fan-H7107.js
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { hs2rgb, rgb2hs } from '../utils/colour.js'
|
|
2
2
|
import {
|
|
3
3
|
base64ToHex,
|
|
4
|
+
fanSpeedToHkPercent,
|
|
4
5
|
generateCodeFromHexValues,
|
|
5
6
|
generateRandomString,
|
|
6
7
|
getTwoItemPosition,
|
|
7
8
|
hexToDecimal,
|
|
8
9
|
hexToTwoItems,
|
|
10
|
+
hkPercentToFanSpeed,
|
|
9
11
|
parseError,
|
|
10
12
|
sleep,
|
|
11
13
|
} from '../utils/functions.js'
|
|
@@ -43,6 +45,8 @@ export default class {
|
|
|
43
45
|
13: 'MwUAAgAAAAAAAAAAAAAAAAAAADQ=', // auto mode
|
|
44
46
|
}
|
|
45
47
|
this.autoSpeed = 13
|
|
48
|
+
// Real speed steps, excluding auto - HomeKit percentages map onto these
|
|
49
|
+
this.speedSteps = 12
|
|
46
50
|
|
|
47
51
|
// Remove any old original Fan services
|
|
48
52
|
if (this.accessory.getService(this.hapServ.Fan)) {
|
|
@@ -70,7 +74,7 @@ export default class {
|
|
|
70
74
|
this.service
|
|
71
75
|
.getCharacteristic(this.hapChar.RotationSpeed)
|
|
72
76
|
.setProps({
|
|
73
|
-
maxValue:
|
|
77
|
+
maxValue: 100,
|
|
74
78
|
minStep: 1,
|
|
75
79
|
minValue: 0,
|
|
76
80
|
unit: 'unitless', // This is actually from HAP for Bluetooth LE Specification, but fits
|
|
@@ -157,8 +161,16 @@ export default class {
|
|
|
157
161
|
|
|
158
162
|
async internalSpeedUpdate(value) {
|
|
159
163
|
try {
|
|
164
|
+
// Don't continue if the fan is being turned off
|
|
165
|
+
if (value === 0) {
|
|
166
|
+
return
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// HomeKit sends a percentage - map it onto this model's real speed steps
|
|
170
|
+
value = hkPercentToFanSpeed(value, this.speedSteps)
|
|
171
|
+
|
|
160
172
|
// Don't continue if the new value is the same as before
|
|
161
|
-
if (this.cacheSpeed === value
|
|
173
|
+
if (this.cacheSpeed === value) {
|
|
162
174
|
return
|
|
163
175
|
}
|
|
164
176
|
|
|
@@ -182,7 +194,7 @@ export default class {
|
|
|
182
194
|
|
|
183
195
|
// Throw a 'no response' error and set a timeout to revert this after 2 seconds
|
|
184
196
|
setTimeout(() => {
|
|
185
|
-
this.service.updateCharacteristic(this.hapChar.RotationSpeed, this.cacheSpeed)
|
|
197
|
+
this.service.updateCharacteristic(this.hapChar.RotationSpeed, fanSpeedToHkPercent(this.cacheSpeed, this.speedSteps, this.autoSpeed))
|
|
186
198
|
}, 2000)
|
|
187
199
|
throw new this.hapErr(-70402)
|
|
188
200
|
}
|
|
@@ -380,8 +392,9 @@ export default class {
|
|
|
380
392
|
}
|
|
381
393
|
if (Number.isFinite(newSpeed) && newSpeed >= 1 && newSpeed <= this.autoSpeed && this.cacheSpeed !== newSpeed) {
|
|
382
394
|
this.cacheSpeed = newSpeed
|
|
383
|
-
|
|
384
|
-
this.
|
|
395
|
+
const hkSpeed = fanSpeedToHkPercent(newSpeed, this.speedSteps, this.autoSpeed)
|
|
396
|
+
this.service.updateCharacteristic(this.hapChar.RotationSpeed, hkSpeed)
|
|
397
|
+
this.accessory.log(`${platformLang.curSpeed} [${newSpeed} -> ${hkSpeed}%]`)
|
|
385
398
|
}
|
|
386
399
|
}
|
|
387
400
|
|
|
@@ -430,7 +443,8 @@ export default class {
|
|
|
430
443
|
// Mode change (auto = 0x02)
|
|
431
444
|
if (getTwoItemPosition(hexParts, 4) === '02' && this.cacheSpeed !== this.autoSpeed) {
|
|
432
445
|
this.cacheSpeed = this.autoSpeed
|
|
433
|
-
|
|
446
|
+
// Cache auto so we can tell it apart from "user asked for max speed"
|
|
447
|
+
this.service.updateCharacteristic(this.hapChar.RotationSpeed, 100)
|
|
434
448
|
this.accessory.log(`${platformLang.curSpeed} [auto]`)
|
|
435
449
|
}
|
|
436
450
|
break
|