@homebridge-plugins/homebridge-govee 11.32.0 → 11.32.2-beta.0

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
@@ -2,6 +2,19 @@
2
2
 
3
3
  All notable changes to `@homebridge-plugins/homebridge-govee` will be documented in this file.
4
4
 
5
+ ## v11.32.2 (Pending Release)
6
+
7
+ ### Changed
8
+
9
+ - fix: implement the H7107's oscillation toggle, which threw a not-implemented error when tapped (#1334)
10
+
11
+ ## v11.32.1 (2026-08-02)
12
+
13
+ ### Changed
14
+
15
+ - docs: add node 26 to the supported node versions
16
+ - fix: read the H5106 monitor's temperature and humidity from the http device list too, so accounts whose aws channel never delivers still get readings (#1322)
17
+
5
18
  ## v11.32.0 (2026-08-02)
6
19
 
7
20
  ### Changed
package/README.md CHANGED
@@ -27,7 +27,7 @@ Homebridge plugin to integrate Govee devices into HomeKit
27
27
  ### Prerequisites
28
28
 
29
29
  - To use this plugin, you will need to already have:
30
- - [Node](https://nodejs.org): latest version of `v22` or `v24` - any other major version is not supported.
30
+ - [Node](https://nodejs.org): latest version of `v22`, `v24` or `v26` - any other major version is not supported.
31
31
  - [Homebridge](https://homebridge.io): `v1.6` or above - refer to link for more information and installation instructions.
32
32
  - For bluetooth connectivity, it may be necessary to install extra packages on your system, see [Bluetooth Control](https://github.com/homebridge-plugins/homebridge-govee/wiki/Bluetooth-Control). Bluetooth works best when using a Raspberry Pi, not been tested on Windows, and Mac devices are unsupported.
33
33
 
@@ -204,33 +204,33 @@ export default class {
204
204
 
205
205
  async internalSwingUpdate(value) {
206
206
  try {
207
+ const newValue = value ? 'on' : 'off'
207
208
  // Don't continue if the new value is the same as before
208
- if (this.cacheSwing === value) {
209
+ if (this.cacheSwing === newValue) {
209
210
  return
210
211
  }
211
212
 
212
- throw new Error('Swing mode update not implemented yet')
213
-
214
- // const newValue = value ? 'on' : 'off'
215
- // The existing cacheSwingCode might be something like aa1d0101960384000000000000000000000000a6
216
- // We need to change the third hex value to 00 for off or 01 for on
217
- // const hexValues = [
218
- // 0x3A,
219
- // 0x1D,
220
- // value ? 0x01 : 0x00,
221
- // ...this.cacheSwingCode.slice(6, 14).match(/.{1,2}/g).map(byte => Number.parseInt(byte, 16)),
222
- // ]
223
- //
224
- // await this.platform.sendDeviceUpdate(this.accessory, {
225
- // cmd: 'multiSync',
226
- // value: generateCodeFromHexValues(hexValues),
227
- // })
213
+ // The AWS code mirrors the device's own `aa1d..` oscillation report,
214
+ // carrying over the extra bytes from the last report seen (#1334).
215
+ // Mirroring a status code is not guaranteed on every model, so the
216
+ // documented OpenAPI oscillation toggle is also sent when the device
217
+ // advertises it
218
+ const tailBytes = this.cacheSwingCode
219
+ ? this.cacheSwingCode.slice(6, 14).match(/.{1,2}/g).map(byte => Number.parseInt(byte, 16))
220
+ : []
221
+ await this.platform.sendDeviceUpdate(this.accessory, {
222
+ cmd: 'ptReal',
223
+ value: generateCodeFromHexValues([0x33, 0x1D, value ? 0x01 : 0x00, ...tailBytes]),
224
+ openApi: this.accessory.context.openApiCapabilities?.oscillationToggle
225
+ ? { instance: 'oscillationToggle', capabilityType: 'devices.capabilities.toggle', value: value ? 1 : 0 }
226
+ : undefined,
227
+ })
228
228
 
229
229
  // Cache the new state and log if appropriate
230
- // if (this.cacheSwing !== newValue) {
231
- // this.cacheSwing = newValue
232
- // this.accessory.log(`${platformLang.curSwing} [${newValue}]`)
233
- // }
230
+ if (this.cacheSwing !== newValue) {
231
+ this.cacheSwing = newValue
232
+ this.accessory.log(`${platformLang.curSwing} [${newValue}]`)
233
+ }
234
234
  } catch (err) {
235
235
  // Catch any errors during the process
236
236
  this.accessory.logWarn(`${platformLang.devNotUpdated} ${parseError(err)}`)
@@ -3,6 +3,7 @@ import {
3
3
  base64ToHex,
4
4
  cenToFar,
5
5
  getTwoItemPosition,
6
+ hasProperty,
6
7
  hexToDecimal,
7
8
  hexToTwoItems,
8
9
  parseError,
@@ -61,6 +62,39 @@ export default class {
61
62
  }
62
63
 
63
64
  async externalUpdate(params) {
65
+ // Readings can also arrive from the HTTP device list (#1322), for accounts
66
+ // where the AWS channel never delivers for this model. The fields use the
67
+ // same semantics as the thermo-hygrometer sensors: hundredths of a degree
68
+ // and hundredths of a percent
69
+ if (hasProperty(params, 'temperature')) {
70
+ let newTemp = Number.parseInt(params.temperature + this.accessory.context.offTemp, 10)
71
+ newTemp /= 100
72
+ if (Number.isFinite(newTemp) && newTemp !== this.cacheTemp) {
73
+ this.cacheTemp = newTemp
74
+ this.tempService.updateCharacteristic(this.hapChar.CurrentTemperature, this.cacheTemp)
75
+ this.accessory.eveService.addEntry({ temp: this.cacheTemp })
76
+
77
+ // Log the change
78
+ this.accessory.log(`${platformLang.curTemp} [${this.cacheTemp}°C / ${cenToFar(this.cacheTemp)}°F]`)
79
+
80
+ // Update the cache file with the new temperature
81
+ this.updateCache()
82
+ }
83
+ }
84
+ if (hasProperty(params, 'humidity')) {
85
+ let newHumi = Number.parseInt(params.humidity + this.accessory.context.offHumi, 10)
86
+ newHumi /= 100
87
+ newHumi = Math.max(Math.min(newHumi, 100), 0)
88
+ if (Number.isFinite(newHumi) && newHumi !== this.cacheHumi) {
89
+ this.cacheHumi = newHumi
90
+ this.humiService.updateCharacteristic(this.hapChar.CurrentRelativeHumidity, this.cacheHumi)
91
+ this.accessory.eveService.addEntry({ humidity: this.cacheHumi })
92
+
93
+ // Log the change
94
+ this.accessory.log(`${platformLang.curHumi} [${this.cacheHumi}%]`)
95
+ }
96
+ }
97
+
64
98
  // Check for some other scene/mode change
65
99
  (params.commands || []).forEach((command) => {
66
100
  const hexString = base64ToHex(command)
@@ -246,7 +246,7 @@
246
246
  <ul>
247
247
  <li>To use this plugin, you will need to already have:</li>
248
248
  <ul>
249
- <li><a href="https://nodejs.org" target="_blank">Node</a>: latest version of <code>v22</code> or <code>v24</code> - any other major version is not supported.</li>
249
+ <li><a href="https://nodejs.org" target="_blank">Node</a>: latest version of <code>v22</code>, <code>v24</code> or <code>v26</code> - any other major version is not supported.</li>
250
250
  <li><a href="https://homebridge.io" target="_blank">Homebridge</a>: <code>v1.6</code> or above - refer to link for more information and installation instructions.</li>
251
251
  <li>For bluetooth connectivity, it may be necessary to install extra packages on your system, see <a href="https://github.com/homebridge-plugins/homebridge-govee/wiki/Bluetooth-Control" target="_blank">Bluetooth Control</a>. Bluetooth works best when using a Raspberry Pi, not been tested on Windows, and Mac devices are unsupported.</li>
252
252
  </ul>
package/lib/platform.js CHANGED
@@ -1576,7 +1576,7 @@ export default class {
1576
1576
 
1577
1577
  // Filter those which are leak sensors
1578
1578
  for (const device1 of devices
1579
- .filter(device => [...platformConsts.models.sensorLeak, ...platformConsts.models.sensorThermo].includes(device.sku))) {
1579
+ .filter(device => [...platformConsts.models.sensorLeak, ...platformConsts.models.sensorThermo, ...platformConsts.models.sensorMonitor].includes(device.sku))) {
1580
1580
  try {
1581
1581
  // Reformat the device id
1582
1582
  if (!device1.device.includes(':')) {
@@ -1650,6 +1650,27 @@ export default class {
1650
1650
  // distinguishes those accounts before converting anything.
1651
1651
  accessory.logDebug(`[HTTP] raw sensor data: ${JSON.stringify(parsedData)}`)
1652
1652
 
1653
+ if (hasProperty(parsedSettings, 'battery')) {
1654
+ toReturn.battery = parsedSettings.battery
1655
+ }
1656
+ if (hasProperty(parsedData, 'tem')) {
1657
+ toReturn.temperature = parsedData.tem
1658
+ }
1659
+ if (hasProperty(parsedData, 'hum')) {
1660
+ toReturn.humidity = parsedData.hum
1661
+ }
1662
+ if (hasProperty(parsedData, 'online')) {
1663
+ toReturn.online = parsedData.online
1664
+ }
1665
+ } else if (platformConsts.models.sensorMonitor.includes(device1.sku)) {
1666
+ // The H5106 normally reports over AWS, but some accounts never
1667
+ // receive those messages, leaving the readings at zero (#1322).
1668
+ // The HTTP device list carries the same readings, so use it as a
1669
+ // second source. Every field is guarded and the raw payload is
1670
+ // logged, since the format for this model is not confirmed on
1671
+ // every account
1672
+ accessory.logDebug(`[HTTP] raw sensor data: ${JSON.stringify(parsedData)}`)
1673
+
1653
1674
  if (hasProperty(parsedSettings, 'battery')) {
1654
1675
  toReturn.battery = parsedSettings.battery
1655
1676
  }
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.32.0",
5
+ "version": "11.32.2-beta.0",
6
6
  "description": "Homebridge plugin to integrate Govee devices into HomeKit.",
7
7
  "author": {
8
8
  "name": "bwp91",