@homebridge-plugins/homebridge-govee 11.32.2-beta.27 → 11.32.2-beta.29
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 +2 -1
- package/lib/connection/ble.js +13 -8
- package/lib/device/sensor-co2.js +2 -1
- package/lib/platform.js +17 -0
- package/lib/utils/ble-crypto.js +7 -7
- package/lib/utils/ble-protocol.js +2 -2
- package/lib/utils/device-capabilities.js +2 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -44,7 +44,8 @@ All notable changes to `@homebridge-plugins/homebridge-govee` will be documented
|
|
|
44
44
|
- feat: recognise eleven more meat thermometers, which report what they send so their readings can be worked out, and stop the one already known printing its whole update as a warning
|
|
45
45
|
- feat: add the H5161 power strip and give the H7184 kitchen composter an on and off switch
|
|
46
46
|
- feat: recognise three more sensors, which report what they send, and say plainly in the log why a sensor has no tile yet
|
|
47
|
-
- feat: add ble encryption for the H3001 solar string lights, which silently ignore unencrypted frames (#1328)
|
|
47
|
+
- feat: add ble encryption for the H3001 solar string lights, which silently ignore unencrypted frames (#1328) (@dominick-han)
|
|
48
|
+
- fix: only mention an unrecognised bluetooth broadcast when the device is on your own account, since a scan also hears the neighbours
|
|
48
49
|
|
|
49
50
|
## v11.32.1 (2026-08-02)
|
|
50
51
|
|
package/lib/connection/ble.js
CHANGED
|
@@ -124,17 +124,22 @@ export default class BLEConnection {
|
|
|
124
124
|
try {
|
|
125
125
|
const { uuid, address, rssi, advertisement } = peripheral
|
|
126
126
|
|
|
127
|
-
//
|
|
128
|
-
//
|
|
129
|
-
//
|
|
130
|
-
// for an owner to get hold of it.
|
|
127
|
+
// A broadcast this plugin cannot decode is worth reporting rather than
|
|
128
|
+
// dropping in silence, since the hex is the one thing needed to add a
|
|
129
|
+
// model and an owner has no other way to get hold of it.
|
|
131
130
|
if (!isValidPeripheral(peripheral)) {
|
|
132
131
|
const unknownName = advertisement?.localName
|
|
133
132
|
if (unknownName && unknownName.toLowerCase().startsWith('govee')) {
|
|
134
133
|
const raw = advertisement.manufacturerData
|
|
135
134
|
? advertisement.manufacturerData.toString('hex')
|
|
136
135
|
: 'no manufacturer data'
|
|
137
|
-
|
|
136
|
+
|
|
137
|
+
// Bluetooth is a broadcast medium, so this scan hears every Govee
|
|
138
|
+
// device in range - including a neighbour's, which is not something
|
|
139
|
+
// the owner can do anything about. Only a device on this account is
|
|
140
|
+
// worth putting in front of them.
|
|
141
|
+
const isOurs = this.platform.hasBleDevice(address)
|
|
142
|
+
const line = `[BLE] unrecognised broadcast from a govee device - please include this line if you report it: ${JSON.stringify({
|
|
138
143
|
name: unknownName,
|
|
139
144
|
address,
|
|
140
145
|
source: 'BLE',
|
|
@@ -143,8 +148,8 @@ export default class BLEConnection {
|
|
|
143
148
|
})}`
|
|
144
149
|
|
|
145
150
|
// Say it once so it is actually noticed, then stay quiet about this
|
|
146
|
-
//
|
|
147
|
-
if (isFirstReport(`ble|${address}|${raw}`)) {
|
|
151
|
+
// device for the rest of the session - it rebroadcasts constantly.
|
|
152
|
+
if (isOurs && isFirstReport(`ble|${address}|${raw}`)) {
|
|
148
153
|
this.log.warn(line)
|
|
149
154
|
} else {
|
|
150
155
|
this.log.debug(line)
|
|
@@ -319,7 +324,7 @@ export default class BLEConnection {
|
|
|
319
324
|
* Unlike every other path in this client we need a reply, which arrives as a
|
|
320
325
|
* notification on UUID.NOTIFY. Note that we deliberately do NOT subscribe:
|
|
321
326
|
* these lights push notifications without the client ever writing the client
|
|
322
|
-
* characteristic configuration descriptor
|
|
327
|
+
* characteristic configuration descriptor.
|
|
323
328
|
* Calling subscribeAsync() here makes the descriptor write hang and the light
|
|
324
329
|
* then drops the connection, so listening is both sufficient and required.
|
|
325
330
|
*
|
package/lib/device/sensor-co2.js
CHANGED
|
@@ -9,7 +9,8 @@ import platformLang from '../utils/lang-en.js'
|
|
|
9
9
|
import GoveeDevice from './base.js'
|
|
10
10
|
|
|
11
11
|
// HomeKit triggers "CO2 detected" abnormal flag at this threshold (ppm).
|
|
12
|
-
//
|
|
12
|
+
// 1000 ppm is the usual warning level for these sensors; override it with
|
|
13
|
+
// deviceConf.co2AbnormalThreshold.
|
|
13
14
|
const DEFAULT_CO2_ABNORMAL_PPM = 1000
|
|
14
15
|
|
|
15
16
|
export default class extends GoveeDevice {
|
package/lib/platform.js
CHANGED
|
@@ -1060,6 +1060,23 @@ export default class {
|
|
|
1060
1060
|
}
|
|
1061
1061
|
}
|
|
1062
1062
|
|
|
1063
|
+
/**
|
|
1064
|
+
* Whether a bluetooth address belongs to one of this account's devices.
|
|
1065
|
+
*
|
|
1066
|
+
* Bluetooth is a broadcast medium: a scan hears every Govee device in range,
|
|
1067
|
+
* including a neighbour's. Without this the plugin cannot tell the two apart,
|
|
1068
|
+
* and asking someone to report a device that is not theirs is noise.
|
|
1069
|
+
*/
|
|
1070
|
+
hasBleDevice(address) {
|
|
1071
|
+
if (!address) {
|
|
1072
|
+
return false
|
|
1073
|
+
}
|
|
1074
|
+
const wanted = String(address).toLowerCase()
|
|
1075
|
+
return [...devicesInHB.values()].some(
|
|
1076
|
+
accessory => String(accessory.context.bleAddress || '').toLowerCase() === wanted,
|
|
1077
|
+
)
|
|
1078
|
+
}
|
|
1079
|
+
|
|
1063
1080
|
configureAccessory(accessory) {
|
|
1064
1081
|
// Set the correct firmware version if we can
|
|
1065
1082
|
if (this.api && accessory.context.firmware) {
|
package/lib/utils/ble-crypto.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* The wrapped bluetooth transport that newer Govee devices require.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* Most devices take the plain 20-byte frame. These wrap it in AES-128-GCM and
|
|
5
|
+
* silently ignore anything that is not wrapped, which is why a light like the
|
|
6
|
+
* H3001 appears to accept every command and then does nothing at all.
|
|
7
7
|
*
|
|
8
8
|
* Wire format on 00010203-0405-0607-0809-0a0b0c0d2b11 (write) and ...2b10 (notify):
|
|
9
9
|
*
|
|
@@ -31,12 +31,12 @@
|
|
|
31
31
|
import { Buffer } from 'node:buffer'
|
|
32
32
|
import { createCipheriv, createDecipheriv, randomBytes } from 'node:crypto'
|
|
33
33
|
|
|
34
|
-
//
|
|
35
|
-
//
|
|
34
|
+
// Fixed across every device that uses this transport, rather than being tied
|
|
35
|
+
// to an account or a pairing, so no lookup is needed to talk to one.
|
|
36
36
|
const KEY_HANDSHAKE = Buffer.from('fc03783c7c42cb83e202a1643648aff6', 'hex')
|
|
37
37
|
const KEY_DEVICE = Buffer.from('ae028b630bae6ecc4bff1b249e22f955', 'hex')
|
|
38
38
|
|
|
39
|
-
const TAG_LEN = 12 // 96-bit tag
|
|
39
|
+
const TAG_LEN = 12 // 96-bit tag
|
|
40
40
|
const HDR = { MAGIC0: 0xE7, MAGIC1: 0x11, SUB_REQUEST: 0x01, STATUS_OK: 0x00 }
|
|
41
41
|
|
|
42
42
|
/** True if `data` is an e711 handshake frame rather than a data frame. */
|
|
@@ -74,8 +74,8 @@ export const BLE_STAGE_TIMEOUTS = {
|
|
|
74
74
|
connect: 10000,
|
|
75
75
|
write: 5000,
|
|
76
76
|
// Encrypted models exchange a session key before the first real command (see
|
|
77
|
-
// ble-crypto.js).
|
|
78
|
-
//
|
|
77
|
+
// ble-crypto.js). A light answers in about 30ms, so this is a generous
|
|
78
|
+
// ceiling rather than an expected cost.
|
|
79
79
|
// Models that need no handshake never spend any of it.
|
|
80
80
|
handshake: 5000,
|
|
81
81
|
settle: 100, // let the controller transmit before disconnecting
|
|
@@ -56,8 +56,8 @@ const modelOverrides = {
|
|
|
56
56
|
|
|
57
57
|
// Bluetooth-only solar string lights (#1328). Every frame is wrapped in
|
|
58
58
|
// AES-128-GCM, so this model needs the key handshake in ble-crypto.js before
|
|
59
|
-
// any command is accepted. Its colour and brightness formats
|
|
60
|
-
//
|
|
59
|
+
// any command is accepted. Its colour and brightness formats, observed on
|
|
60
|
+
// the wire:
|
|
61
61
|
// colour 33 05 15 01 RR GG BB 00 00 00 00 00 FF (then zero padding)
|
|
62
62
|
// brightness 33 04 <0-100> e.g. 0x1e for 30%, 0x64 for 100%
|
|
63
63
|
// Writes are unacknowledged, so without the wrapper the light silently
|
package/package.json
CHANGED