@homebridge-plugins/homebridge-govee 11.32.2-beta.31 → 11.32.2-beta.32
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 +1 -0
- package/README.md +1 -1
- package/lib/connection/ble.js +46 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,7 @@ All notable changes to `@homebridge-plugins/homebridge-govee` will be documented
|
|
|
7
7
|
### Changed
|
|
8
8
|
|
|
9
9
|
- fix: stop shipping the test files to npm, since they are only needed in the repository
|
|
10
|
+
- fix: BLE device control on macOS by resolving peripherals via advertised name (#1336) (@Perafan18)
|
|
10
11
|
- fix: implement the H7107's oscillation toggle, which threw a not-implemented error when tapped (#1334)
|
|
11
12
|
- fix: also send the H7107's oscillation command as the multiSync frame the fan itself uses, since the first shape only turned it off sometimes (#1334)
|
|
12
13
|
- fix: send the H7107's oscillation-off command without the swing-range bytes, matching the zero-tailed frame the fan echoes back (#1334)
|
package/README.md
CHANGED
|
@@ -29,7 +29,7 @@ Homebridge plugin to integrate Govee devices into HomeKit
|
|
|
29
29
|
- To use this plugin, you will need to already have:
|
|
30
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
|
-
- 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,
|
|
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, and has not been tested on Windows. On macOS, the plugin resolves BLE devices via their advertised name (macOS does not expose bluetooth MAC addresses), and the `node` binary running Homebridge needs Bluetooth permission in System Settings → Privacy & Security → Bluetooth.
|
|
33
33
|
|
|
34
34
|
### Setup
|
|
35
35
|
|
package/lib/connection/ble.js
CHANGED
|
@@ -390,7 +390,9 @@ export default class BLEConnection {
|
|
|
390
390
|
let timeoutId
|
|
391
391
|
try {
|
|
392
392
|
return await Promise.race([
|
|
393
|
-
|
|
393
|
+
process.platform === 'darwin'
|
|
394
|
+
? this.connectByNameDarwin(address, timeout)
|
|
395
|
+
: btClient.connectAsync(address),
|
|
394
396
|
new Promise((_, reject) => {
|
|
395
397
|
timeoutId = setTimeout(() => reject(new Error('Connection timeout')), timeout)
|
|
396
398
|
}),
|
|
@@ -400,6 +402,49 @@ export default class BLEConnection {
|
|
|
400
402
|
}
|
|
401
403
|
}
|
|
402
404
|
|
|
405
|
+
// macOS: CoreBluetooth never exposes MAC addresses, so connect-by-address can
|
|
406
|
+
// never resolve. Govee devices advertise a local name whose suffix is the last
|
|
407
|
+
// two bytes of their MAC (e.g. Govee_H617A_325A for ...:32:5A), so scan and
|
|
408
|
+
// match on that instead, then connect to the discovered peripheral directly.
|
|
409
|
+
async connectByNameDarwin(address, timeout) {
|
|
410
|
+
const suffix = address.replace(/:/g, '').slice(-4).toLowerCase()
|
|
411
|
+
this.darwinPeripheralCache = this.darwinPeripheralCache ?? new Map()
|
|
412
|
+
const cached = this.darwinPeripheralCache.get(suffix)
|
|
413
|
+
if (cached) {
|
|
414
|
+
try {
|
|
415
|
+
await cached.connectAsync()
|
|
416
|
+
return cached
|
|
417
|
+
} catch (err) {
|
|
418
|
+
this.darwinPeripheralCache.delete(suffix)
|
|
419
|
+
this.log.debug('[BLE] cached peripheral for %s failed (%s), rescanning.', suffix, err.message)
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
const peripheral = await new Promise((resolve, reject) => {
|
|
423
|
+
let done = false
|
|
424
|
+
function onDiscover(p) {
|
|
425
|
+
const name = (p.advertisement?.localName ?? '').toLowerCase()
|
|
426
|
+
if (name.endsWith(suffix) && (name.startsWith('govee') || name.startsWith('ihoment'))) {
|
|
427
|
+
finish(resolve, p)
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
function finish(fn, value) {
|
|
431
|
+
if (done) {
|
|
432
|
+
return
|
|
433
|
+
}
|
|
434
|
+
done = true
|
|
435
|
+
btClient.removeListener('discover', onDiscover)
|
|
436
|
+
btClient.stopScanningAsync().catch(() => {})
|
|
437
|
+
fn(value)
|
|
438
|
+
}
|
|
439
|
+
btClient.on('discover', onDiscover)
|
|
440
|
+
btClient.startScanningAsync([], true).catch(err => finish(reject, err))
|
|
441
|
+
setTimeout(() => finish(reject, new Error(`no peripheral advertising name suffix ${suffix} found in scan`)), Math.max(timeout - 1000, 4000))
|
|
442
|
+
})
|
|
443
|
+
this.darwinPeripheralCache.set(suffix, peripheral)
|
|
444
|
+
await peripheral.connectAsync()
|
|
445
|
+
return peripheral
|
|
446
|
+
}
|
|
447
|
+
|
|
403
448
|
async writeWithTimeout(characteristic, buffer, timeout) {
|
|
404
449
|
let timeoutId
|
|
405
450
|
try {
|
package/package.json
CHANGED