@homebridge-plugins/homebridge-govee 11.36.1-beta.0 → 11.36.1-beta.2

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 CHANGED
@@ -7,6 +7,8 @@ All notable changes to `@homebridge-plugins/homebridge-govee` will be documented
7
7
  ### Changed
8
8
 
9
9
  - fix: give the H1310 and R1310 ceiling fans their own handler, with the light they were missing (#1352)
10
+ - fix: scale the H1310 and R1310 fan speed to the six steps they have, not the H1370's twelve (#1352)
11
+ - fix: stop a fan ignoring the first speed asked of it after a restart
10
12
 
11
13
  ## v11.36.0 (2026-08-11)
12
14
 
@@ -1,3 +1,4 @@
1
+ import { getDeviceCapabilities } from '../utils/device-capabilities.js'
1
2
  import {
2
3
  base64ToHex,
3
4
  fanSpeedToHkPercent,
@@ -15,10 +16,13 @@ import GoveeDevice from './base.js'
15
16
  /*
16
17
  Codes below were decoded from a real device's AWS status reports in
17
18
  https://github.com/homebridge-plugins/homebridge-govee/issues/1307
18
- Status aa 31 01 [speed] = fan speed (1-12)
19
+ Status aa 31 01 [speed] = fan speed (1 to the model's step count)
19
20
  Status aa 36 01 01 / aa 36 00 00 = fan power on/off
20
21
  The light reports through the standard state/brightness/kelvin fields
21
22
  (colour temperature only, 2700-6500K)
23
+
24
+ The H1310 and R1310 share this handler. They report six speeds against the
25
+ H1370's twelve, so the scale comes from the capabilities table (#1352)
22
26
  */
23
27
  export default class GoveeFanH1370 extends GoveeDevice {
24
28
  constructor(platform, accessory) {
@@ -46,8 +50,9 @@ export default class GoveeFanH1370 extends GoveeDevice {
46
50
  .onSet(async value => this.internalStateUpdate(value))
47
51
  this.cacheState = this.service.getCharacteristic(this.hapChar.Active).value ? 'on' : 'off'
48
52
 
49
- // Real speed steps - HomeKit percentages map onto these
50
- this.speedSteps = 12
53
+ // Real speed steps - HomeKit percentages map onto these, and they differ
54
+ // per model, so the scale comes from the capabilities table
55
+ this.speedSteps = getDeviceCapabilities(accessory.context.gvModel).fanSpeedSteps
51
56
 
52
57
  // Add the set handler to the fan rotation speed characteristic
53
58
  this.service
@@ -59,7 +64,13 @@ export default class GoveeFanH1370 extends GoveeDevice {
59
64
  unit: 'unitless',
60
65
  })
61
66
  .onSet(async value => this.internalSpeedUpdate(value))
62
- this.cacheSpeed = this.service.getCharacteristic(this.hapChar.RotationSpeed).value
67
+
68
+ // cacheSpeed holds a device speed step everywhere else, but the restored
69
+ // characteristic is a HomeKit percentage, so it has to be converted back.
70
+ // Left as a percentage it would sometimes equal a real step and silently
71
+ // swallow the first speed the owner asked for.
72
+ const restoredPercent = this.service.getCharacteristic(this.hapChar.RotationSpeed).value
73
+ this.cacheSpeed = restoredPercent ? hkPercentToFanSpeed(restoredPercent, this.speedSteps) : 0
63
74
 
64
75
  if (this.hideLight) {
65
76
  if (this.accessory.getService(this.hapServ.Lightbulb)) {
@@ -78,7 +78,15 @@ export default class GoveeFanH7100 extends GoveeDevice {
78
78
  unit: 'unitless',
79
79
  })
80
80
  .onSet(async value => this.internalSpeedUpdate(value))
81
- this.cacheSpeed = this.service.getCharacteristic(this.hapChar.RotationSpeed).value
81
+
82
+ // cacheSpeed holds a device speed step everywhere else, but the restored
83
+ // characteristic is a HomeKit percentage, so it has to be converted back.
84
+ // Left as a percentage it would sometimes equal a real step and silently
85
+ // swallow the first speed the owner asked for. A restored 100% stays
86
+ // ambiguous between auto and top speed - both report 100 - so it settles on
87
+ // top speed rather than guessing.
88
+ const restoredPercent = this.service.getCharacteristic(this.hapChar.RotationSpeed).value
89
+ this.cacheSpeed = restoredPercent ? hkPercentToFanSpeed(restoredPercent, this.speedSteps) : 0
82
90
 
83
91
  // Add the set handler to the fan swing mode
84
92
  this.service
@@ -75,7 +75,15 @@ export default class extends GoveeDevice {
75
75
  unit: 'unitless', // This is actually from HAP for Bluetooth LE Specification, but fits
76
76
  })
77
77
  .onSet(async value => this.internalSpeedUpdate(value))
78
- this.cacheSpeed = this.service.getCharacteristic(this.hapChar.RotationSpeed).value
78
+
79
+ // cacheSpeed holds a device speed step everywhere else, but the restored
80
+ // characteristic is a HomeKit percentage, so it has to be converted back.
81
+ // Left as a percentage it would sometimes equal a real step and silently
82
+ // swallow the first speed the owner asked for. A restored 100% stays
83
+ // ambiguous between auto and top speed - both report 100 - so it settles on
84
+ // top speed rather than guessing.
85
+ const restoredPercent = this.service.getCharacteristic(this.hapChar.RotationSpeed).value
86
+ this.cacheSpeed = restoredPercent ? hkPercentToFanSpeed(restoredPercent, this.speedSteps) : 0
79
87
 
80
88
  // Add the set handler to the fan swing mode
81
89
  this.service
@@ -75,7 +75,15 @@ export default class extends GoveeDevice {
75
75
  unit: 'unitless', // This is actually from HAP for Bluetooth LE Specification, but fits
76
76
  })
77
77
  .onSet(async value => this.internalSpeedUpdate(value))
78
- this.cacheSpeed = this.service.getCharacteristic(this.hapChar.RotationSpeed).value
78
+
79
+ // cacheSpeed holds a device speed step everywhere else, but the restored
80
+ // characteristic is a HomeKit percentage, so it has to be converted back.
81
+ // Left as a percentage it would sometimes equal a real step and silently
82
+ // swallow the first speed the owner asked for. A restored 100% stays
83
+ // ambiguous between auto and top speed - both report 100 - so it settles on
84
+ // top speed rather than guessing.
85
+ const restoredPercent = this.service.getCharacteristic(this.hapChar.RotationSpeed).value
86
+ this.cacheSpeed = restoredPercent ? hkPercentToFanSpeed(restoredPercent, this.speedSteps) : 0
79
87
 
80
88
  // Add the set handler to the fan swing mode
81
89
  this.service
@@ -40,6 +40,13 @@ const modelOverrides = {
40
40
  H8121: { iceSizeAscending: true },
41
41
  H8122: { iceSizeAscending: true },
42
42
 
43
+ // The H1310 shares the H1370's ceiling fan handler but is a different
44
+ // product - Govee's own catalogue gives it goodsType 359 against the
45
+ // H1370's 368. Its owner reports six fan speeds in the app rather than
46
+ // twelve, so the two need separate scales (#1352)
47
+ H1310: { fanSpeedSteps: 6 },
48
+ R1310: { fanSpeedSteps: 6 },
49
+
43
50
  // AWS outlet uses 17/16 for on/off instead of 1/0
44
51
  H5080: { awsPowerOn: 17, awsPowerOff: 16 },
45
52
  H5083: { awsPowerOn: 17, awsPowerOff: 16 },
@@ -130,6 +137,9 @@ const defaults = {
130
137
  awsBrightnessNoScale: false,
131
138
  readsSwingStatus: true,
132
139
  iceSizeAscending: false,
140
+ // Ceiling fan speed steps. 12 is what the H1370 reports, from a real
141
+ // device's status in #1307
142
+ fanSpeedSteps: 12,
133
143
  // false for the great majority of models, which take the plain 20-byte frame.
134
144
  // 'v2' selects the AES-128-GCM transport in ble-crypto.js.
135
145
  bleEncryption: false,
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@homebridge-plugins/homebridge-govee",
3
3
  "alias": "Govee",
4
4
  "type": "module",
5
- "version": "11.36.1-beta.0",
5
+ "version": "11.36.1-beta.2",
6
6
  "description": "Homebridge plugin to integrate Govee devices into HomeKit.",
7
7
  "author": {
8
8
  "name": "bwp91",