homebridge-pitpat-treadmill 0.1.2 → 0.1.4
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 +13 -0
- package/README.md +2 -0
- package/dist/bluetooth/nobleTransport.d.ts +5 -0
- package/dist/bluetooth/nobleTransport.js +34 -1
- package/dist/platform.js +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file. The project follows Semantic Versioning.
|
|
4
4
|
|
|
5
|
+
## [0.1.4] - 2026-10-09
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- Allow an isolated Homebridge child bridge to use a host BlueZ D-Bus socket via `PITPAT_DBUS_SYSTEM_BUS_ADDRESS` without redirecting Avahi or other container services.
|
|
10
|
+
|
|
11
|
+
## [0.1.3] - 2026-10-09
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
|
|
15
|
+
- Attempt one controlled HCI controller reset when Noble remains outside the `poweredOn` state after a BLE link timeout.
|
|
16
|
+
- Preserve normal reconnect backoff when the adapter cannot recover.
|
|
17
|
+
|
|
5
18
|
## [0.1.2] - 2026-10-09
|
|
6
19
|
|
|
7
20
|
### Fixed
|
package/README.md
CHANGED
|
@@ -130,6 +130,8 @@ HomeKit does not reliably tell a plugin whether a write came from a person, Siri
|
|
|
130
130
|
|
|
131
131
|
The container needs access to the host Bluetooth stack or a dedicated HCI adapter. Device mapping and D-Bus configuration vary by host. Docker operation has not yet been verified and is not currently claimed as supported.
|
|
132
132
|
|
|
133
|
+
When the plugin runs as an isolated child bridge with Noble's D-Bus binding, set `NOBLE_BINDINGS=dbus` and use `PITPAT_DBUS_SYSTEM_BUS_ADDRESS` for a host socket mounted at a non-default path. The plugin copies this value to `DBUS_SYSTEM_BUS_ADDRESS` inside its child process only, so container services such as Avahi continue using the container's own system bus. The D-Bus binding also requires `dbus-next` to be installed in the Homebridge environment.
|
|
134
|
+
|
|
133
135
|
### Common messages
|
|
134
136
|
|
|
135
137
|
- `treadmill ... was not discovered`: verify the exact identifier, power, range, and that the mobile app is closed.
|
|
@@ -1,7 +1,12 @@
|
|
|
1
|
+
import type { Logger } from 'homebridge';
|
|
1
2
|
import type { BleConnection, BleTransport } from './transport.js';
|
|
2
3
|
export declare class NobleTransport implements BleTransport {
|
|
4
|
+
private readonly log;
|
|
3
5
|
private noble?;
|
|
6
|
+
constructor(log: Pick<Logger, 'warn'>);
|
|
4
7
|
private loadNoble;
|
|
5
8
|
connect(deviceIdentifier: string, timeoutMs: number): Promise<BleConnection>;
|
|
9
|
+
private ensurePoweredOn;
|
|
6
10
|
private findPeripheral;
|
|
7
11
|
}
|
|
12
|
+
export declare function configureNobleDbusAddress(env?: NodeJS.ProcessEnv): void;
|
|
@@ -39,9 +39,14 @@ class NobleConnection {
|
|
|
39
39
|
}
|
|
40
40
|
}
|
|
41
41
|
export class NobleTransport {
|
|
42
|
+
log;
|
|
42
43
|
noble;
|
|
44
|
+
constructor(log) {
|
|
45
|
+
this.log = log;
|
|
46
|
+
}
|
|
43
47
|
async loadNoble() {
|
|
44
48
|
if (!this.noble) {
|
|
49
|
+
configureNobleDbusAddress();
|
|
45
50
|
const module = await import('@stoprocent/noble');
|
|
46
51
|
this.noble = module.default;
|
|
47
52
|
}
|
|
@@ -49,7 +54,7 @@ export class NobleTransport {
|
|
|
49
54
|
}
|
|
50
55
|
async connect(deviceIdentifier, timeoutMs) {
|
|
51
56
|
const noble = await this.loadNoble();
|
|
52
|
-
await
|
|
57
|
+
await this.ensurePoweredOn(noble, timeoutMs);
|
|
53
58
|
const peripheral = await this.findPeripheral(noble, deviceIdentifier, timeoutMs);
|
|
54
59
|
await peripheral.connectAsync();
|
|
55
60
|
try {
|
|
@@ -71,6 +76,25 @@ export class NobleTransport {
|
|
|
71
76
|
throw error;
|
|
72
77
|
}
|
|
73
78
|
}
|
|
79
|
+
async ensurePoweredOn(noble, timeoutMs) {
|
|
80
|
+
try {
|
|
81
|
+
await noble.waitForPoweredOnAsync(timeoutMs);
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
catch (error) {
|
|
85
|
+
if (noble.state === 'unauthorized' || noble.state === 'unsupported') {
|
|
86
|
+
throw error;
|
|
87
|
+
}
|
|
88
|
+
this.log.warn(`[PiTPAT] BLE adapter state is ${noble.state}; attempting one controller reset`);
|
|
89
|
+
noble.reset();
|
|
90
|
+
try {
|
|
91
|
+
await noble.waitForPoweredOnAsync(Math.min(timeoutMs, 10_000));
|
|
92
|
+
}
|
|
93
|
+
catch (recoveryError) {
|
|
94
|
+
throw new Error(`BLE adapter did not recover after reset (state ${noble.state}): ${errorMessage(recoveryError)}`, { cause: recoveryError });
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
74
98
|
async findPeripheral(noble, configuredIdentifier, timeoutMs) {
|
|
75
99
|
const expected = normalizeIdentifier(configuredIdentifier);
|
|
76
100
|
return await new Promise((resolve, reject) => {
|
|
@@ -111,3 +135,12 @@ export class NobleTransport {
|
|
|
111
135
|
});
|
|
112
136
|
}
|
|
113
137
|
}
|
|
138
|
+
export function configureNobleDbusAddress(env = process.env) {
|
|
139
|
+
const address = env.PITPAT_DBUS_SYSTEM_BUS_ADDRESS?.trim();
|
|
140
|
+
if (address) {
|
|
141
|
+
env.DBUS_SYSTEM_BUS_ADDRESS = address;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
function errorMessage(error) {
|
|
145
|
+
return error instanceof Error ? error.message : String(error);
|
|
146
|
+
}
|
package/dist/platform.js
CHANGED
|
@@ -40,7 +40,7 @@ export class PitPatPlatform {
|
|
|
40
40
|
accessory = new this.api.platformAccessory(config.name, uuid, 3 /* this.api.hap.Categories.FAN */);
|
|
41
41
|
this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]);
|
|
42
42
|
}
|
|
43
|
-
this.bleManager = new BleManager(config, new NobleTransport(), this.log);
|
|
43
|
+
this.bleManager = new BleManager(config, new NobleTransport(this.log), this.log);
|
|
44
44
|
new TreadmillAccessory(accessory, this.bleManager, config, this.api, this.log);
|
|
45
45
|
void this.bleManager.start().catch(() => undefined);
|
|
46
46
|
const staleAccessories = [...this.cachedAccessories.values()].filter((cached) => cached.UUID !== uuid);
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "homebridge-pitpat-treadmill",
|
|
3
3
|
"displayName": "PitPat Treadmill",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.4",
|
|
5
5
|
"description": "Local Homebridge integration for PitPat treadmills over Bluetooth Low Energy.",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "dist/index.js",
|