@matter-server/ble-proxy 0.0.1
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/README.md +116 -0
- package/dist/esm/BleProxyHandler.d.ts +39 -0
- package/dist/esm/BleProxyHandler.d.ts.map +1 -0
- package/dist/esm/BleProxyHandler.js +256 -0
- package/dist/esm/BleProxyHandler.js.map +6 -0
- package/dist/esm/BleProxyProtocol.d.ts +230 -0
- package/dist/esm/BleProxyProtocol.d.ts.map +1 -0
- package/dist/esm/BleProxyProtocol.js +82 -0
- package/dist/esm/BleProxyProtocol.js.map +6 -0
- package/dist/esm/ProxyBle.d.ts +24 -0
- package/dist/esm/ProxyBle.d.ts.map +1 -0
- package/dist/esm/ProxyBle.js +50 -0
- package/dist/esm/ProxyBle.js.map +6 -0
- package/dist/esm/ProxyBleChannel.d.ts +38 -0
- package/dist/esm/ProxyBleChannel.d.ts.map +1 -0
- package/dist/esm/ProxyBleChannel.js +314 -0
- package/dist/esm/ProxyBleChannel.js.map +6 -0
- package/dist/esm/ProxyBleClient.d.ts +32 -0
- package/dist/esm/ProxyBleClient.d.ts.map +1 -0
- package/dist/esm/ProxyBleClient.js +100 -0
- package/dist/esm/ProxyBleClient.js.map +6 -0
- package/dist/esm/ProxyBleScanner.d.ts +27 -0
- package/dist/esm/ProxyBleScanner.d.ts.map +1 -0
- package/dist/esm/ProxyBleScanner.js +23 -0
- package/dist/esm/ProxyBleScanner.js.map +6 -0
- package/dist/esm/example/NobleBleProxyClient.d.ts +12 -0
- package/dist/esm/example/NobleBleProxyClient.d.ts.map +1 -0
- package/dist/esm/example/NobleBleProxyClient.js +520 -0
- package/dist/esm/example/NobleBleProxyClient.js.map +6 -0
- package/dist/esm/example/noble-ble-proxy.d.ts +7 -0
- package/dist/esm/example/noble-ble-proxy.d.ts.map +1 -0
- package/dist/esm/example/noble-ble-proxy.js +45 -0
- package/dist/esm/example/noble-ble-proxy.js.map +6 -0
- package/dist/esm/index.d.ts +15 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js +12 -0
- package/dist/esm/index.js.map +6 -0
- package/dist/esm/package.json +3 -0
- package/package.json +46 -0
- package/src/BleProxyHandler.ts +345 -0
- package/src/BleProxyProtocol.ts +287 -0
- package/src/ProxyBle.ts +64 -0
- package/src/ProxyBleChannel.ts +407 -0
- package/src/ProxyBleClient.ts +136 -0
- package/src/ProxyBleScanner.ts +38 -0
- package/src/example/NobleBleProxyClient.ts +679 -0
- package/src/example/noble-ble-proxy.ts +62 -0
- package/src/index.ts +16 -0
- package/src/tsconfig.json +15 -0
- package/src/tsconfig.tsbuildinfo +1 -0
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2025-2026 Open Home Foundation
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
import { Logger } from "@matter/main";
|
|
7
|
+
import { MatterBle } from "@matter/main/protocol";
|
|
8
|
+
import { BleProxyCommand, BleProxyEvent } from "./BleProxyProtocol.js";
|
|
9
|
+
const logger = Logger.get("ProxyBleClient");
|
|
10
|
+
class ProxyBleClient {
|
|
11
|
+
#handler;
|
|
12
|
+
#discoveredPeripherals = /* @__PURE__ */ new Map();
|
|
13
|
+
#deviceDiscoveredCallback;
|
|
14
|
+
#isScanning = false;
|
|
15
|
+
#eventObserver = (event, data) => {
|
|
16
|
+
if (event === BleProxyEvent.DeviceDiscovered) {
|
|
17
|
+
this.#handleDeviceDiscovered(data);
|
|
18
|
+
} else if (event === BleProxyEvent.ScanStopped) {
|
|
19
|
+
logger.info(`Scan stopped by proxy client: ${data.reason ?? "unknown"}`);
|
|
20
|
+
this.#isScanning = false;
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
constructor(handler) {
|
|
24
|
+
this.#handler = handler;
|
|
25
|
+
this.#handler.eventReceived.on(this.#eventObserver);
|
|
26
|
+
}
|
|
27
|
+
setDiscoveryCallback(callback) {
|
|
28
|
+
this.#deviceDiscoveredCallback = callback;
|
|
29
|
+
for (const { peripheral, matterServiceData } of this.#discoveredPeripherals.values()) {
|
|
30
|
+
this.#deviceDiscoveredCallback(peripheral, matterServiceData);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
async startScanning() {
|
|
34
|
+
if (this.#isScanning) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
if (!this.#handler.connected) {
|
|
38
|
+
logger.info("BLE proxy not connected, deferring scan start");
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
logger.debug("Start BLE scanning via proxy ...");
|
|
42
|
+
await this.#handler.sendCommand(BleProxyCommand.StartScan, {
|
|
43
|
+
service_uuids: ["fff6"],
|
|
44
|
+
allow_duplicates: true
|
|
45
|
+
});
|
|
46
|
+
this.#isScanning = true;
|
|
47
|
+
}
|
|
48
|
+
async stopScanning() {
|
|
49
|
+
if (!this.#isScanning) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
if (!this.#handler.connected) {
|
|
53
|
+
this.#isScanning = false;
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
logger.debug("Stop BLE scanning via proxy ...");
|
|
57
|
+
await this.#handler.sendCommand(BleProxyCommand.StopScan);
|
|
58
|
+
this.#isScanning = false;
|
|
59
|
+
}
|
|
60
|
+
close() {
|
|
61
|
+
this.#isScanning = false;
|
|
62
|
+
this.#handler.eventReceived.off(this.#eventObserver);
|
|
63
|
+
}
|
|
64
|
+
#handleDeviceDiscovered(data) {
|
|
65
|
+
const { address, name, rssi, connectable, service_data } = data;
|
|
66
|
+
const serviceData = /* @__PURE__ */ new Map();
|
|
67
|
+
let matterServiceData;
|
|
68
|
+
if (service_data) {
|
|
69
|
+
for (const [uuid, base64Value] of Object.entries(service_data)) {
|
|
70
|
+
const bytes = Buffer.from(base64Value, "base64");
|
|
71
|
+
serviceData.set(uuid, bytes);
|
|
72
|
+
if (MatterBle.isServiceUuid(uuid)) {
|
|
73
|
+
matterServiceData = bytes;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
const peripheral = {
|
|
78
|
+
address,
|
|
79
|
+
name,
|
|
80
|
+
rssi,
|
|
81
|
+
connectable,
|
|
82
|
+
serviceData
|
|
83
|
+
};
|
|
84
|
+
if (!connectable) {
|
|
85
|
+
logger.debug(`Peripheral ${address} is not connectable, ignoring`);
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
if (matterServiceData === void 0 || matterServiceData.length !== 8) {
|
|
89
|
+
logger.debug(`Peripheral ${address} does not advertise valid Matter service data, ignoring`);
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
logger.debug(`Discovered device ${address} (${name ?? "unnamed"}) via proxy`);
|
|
93
|
+
this.#discoveredPeripherals.set(address, { peripheral, matterServiceData });
|
|
94
|
+
this.#deviceDiscoveredCallback?.(peripheral, matterServiceData);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
export {
|
|
98
|
+
ProxyBleClient
|
|
99
|
+
};
|
|
100
|
+
//# sourceMappingURL=ProxyBleClient.js.map
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/ProxyBleClient.ts"],
|
|
4
|
+
"mappings": "AAAA;AAAA;AAAA;AAAA;AAAA;AAMA,SAAS,cAAc;AACvB,SAAS,iBAAiB;AAE1B,SAAS,iBAAiB,qBAAgD;AAE1E,MAAM,SAAS,OAAO,IAAI,gBAAgB;AAoBnC,MAAM,eAAe;AAAA,EACf;AAAA,EACA,yBAAyB,oBAAI,IAA4E;AAAA,EAClH;AAAA,EACA,cAAc;AAAA,EAEL,iBAAiB,CAAC,OAAe,SAAkC;AACxE,QAAI,UAAU,cAAc,kBAAkB;AAC1C,WAAK,wBAAwB,IAAuC;AAAA,IACxE,WAAW,UAAU,cAAc,aAAa;AAC5C,aAAO,KAAK,iCAAkC,KAA6B,UAAU,SAAS,EAAE;AAChG,WAAK,cAAc;AAAA,IACvB;AAAA,EACJ;AAAA,EAEA,YAAY,SAA0B;AAClC,SAAK,WAAW;AAChB,SAAK,SAAS,cAAc,GAAG,KAAK,cAAc;AAAA,EACtD;AAAA,EAEA,qBAAqB,UAAsF;AACvG,SAAK,4BAA4B;AACjC,eAAW,EAAE,YAAY,kBAAkB,KAAK,KAAK,uBAAuB,OAAO,GAAG;AAClF,WAAK,0BAA0B,YAAY,iBAAiB;AAAA,IAChE;AAAA,EACJ;AAAA,EAEA,MAAM,gBAA+B;AACjC,QAAI,KAAK,aAAa;AAClB;AAAA,IACJ;AAEA,QAAI,CAAC,KAAK,SAAS,WAAW;AAC1B,aAAO,KAAK,+CAA+C;AAC3D;AAAA,IACJ;AAEA,WAAO,MAAM,kCAAkC;AAC/C,UAAM,KAAK,SAAS,YAAY,gBAAgB,WAAW;AAAA,MACvD,eAAe,CAAC,MAAM;AAAA,MACtB,kBAAkB;AAAA,IACtB,CAAC;AACD,SAAK,cAAc;AAAA,EACvB;AAAA,EAEA,MAAM,eAA8B;AAChC,QAAI,CAAC,KAAK,aAAa;AACnB;AAAA,IACJ;AAEA,QAAI,CAAC,KAAK,SAAS,WAAW;AAC1B,WAAK,cAAc;AACnB;AAAA,IACJ;AAEA,WAAO,MAAM,iCAAiC;AAC9C,UAAM,KAAK,SAAS,YAAY,gBAAgB,QAAQ;AACxD,SAAK,cAAc;AAAA,EACvB;AAAA,EAEA,QAAc;AACV,SAAK,cAAc;AACnB,SAAK,SAAS,cAAc,IAAI,KAAK,cAAc;AAAA,EACvD;AAAA,EAEA,wBAAwB,MAAkC;AACtD,UAAM,EAAE,SAAS,MAAM,MAAM,aAAa,aAAa,IAAI;AAI3D,UAAM,cAAc,oBAAI,IAAwB;AAChD,QAAI;AACJ,QAAI,cAAc;AACd,iBAAW,CAAC,MAAM,WAAW,KAAK,OAAO,QAAQ,YAAY,GAAG;AAC5D,cAAM,QAAQ,OAAO,KAAK,aAAa,QAAQ;AAC/C,oBAAY,IAAI,MAAM,KAAK;AAC3B,YAAI,UAAU,cAAc,IAAI,GAAG;AAC/B,8BAAoB;AAAA,QACxB;AAAA,MACJ;AAAA,IACJ;AAEA,UAAM,aAA8B;AAAA,MAChC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACJ;AAEA,QAAI,CAAC,aAAa;AACd,aAAO,MAAM,cAAc,OAAO,+BAA+B;AACjE;AAAA,IACJ;AAEA,QAAI,sBAAsB,UAAa,kBAAkB,WAAW,GAAG;AACnE,aAAO,MAAM,cAAc,OAAO,yDAAyD;AAC3F;AAAA,IACJ;AAEA,WAAO,MAAM,qBAAqB,OAAO,KAAK,QAAQ,SAAS,aAAa;AAC5E,SAAK,uBAAuB,IAAI,SAAS,EAAE,YAAY,kBAAkB,CAAC;AAC1E,SAAK,4BAA4B,YAAY,iBAAiB;AAAA,EAClE;AACJ;",
|
|
5
|
+
"names": []
|
|
6
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2025-2026 Open Home Foundation
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
import { BleScanner as BaseBleScanner, type DiscoveredBleDevice } from "@matter/main/protocol";
|
|
7
|
+
import type { ProxyBleClient, ProxyPeripheral } from "./ProxyBleClient.js";
|
|
8
|
+
export type { DiscoveredBleDevice } from "@matter/main/protocol";
|
|
9
|
+
export type DiscoveredProxyBleDevice = Omit<DiscoveredBleDevice, "peripheral"> & {
|
|
10
|
+
peripheral: ProxyPeripheral;
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* BLE scanner that discovers Matter devices through the BLE proxy.
|
|
14
|
+
*
|
|
15
|
+
* Extends matter.js's base `BleScanner`, which already handles the
|
|
16
|
+
* `findCommissionableDevicesContinuously` waiter loop, advertisement parsing,
|
|
17
|
+
* and cancellation semantics. We only narrow the `getDiscoveredDevice` return
|
|
18
|
+
* type to expose the proxy-side `ProxyPeripheral` and route `closeClient`
|
|
19
|
+
* through `ProxyBleClient.close()`.
|
|
20
|
+
*/
|
|
21
|
+
export declare class ProxyBleScanner extends BaseBleScanner {
|
|
22
|
+
#private;
|
|
23
|
+
constructor(proxyClient: ProxyBleClient);
|
|
24
|
+
getDiscoveredDevice(address: string): DiscoveredProxyBleDevice;
|
|
25
|
+
protected closeClient(): void;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=ProxyBleScanner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ProxyBleScanner.d.ts","sourceRoot":"","sources":["../../src/ProxyBleScanner.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,UAAU,IAAI,cAAc,EAAE,KAAK,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC/F,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAE3E,YAAY,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAEjE,MAAM,MAAM,wBAAwB,GAAG,IAAI,CAAC,mBAAmB,EAAE,YAAY,CAAC,GAAG;IAAE,UAAU,EAAE,eAAe,CAAA;CAAE,CAAC;AAEjH;;;;;;;;GAQG;AACH,qBAAa,eAAgB,SAAQ,cAAc;;IAG/C,YAAY,WAAW,EAAE,cAAc,EAGtC;IAEQ,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,wBAAwB,CAEtE;IAED,UAAmB,WAAW,IAAI,IAAI,CAErC;CACJ"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2025-2026 Open Home Foundation
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
import { BleScanner as BaseBleScanner } from "@matter/main/protocol";
|
|
7
|
+
class ProxyBleScanner extends BaseBleScanner {
|
|
8
|
+
#proxyClient;
|
|
9
|
+
constructor(proxyClient) {
|
|
10
|
+
super(proxyClient);
|
|
11
|
+
this.#proxyClient = proxyClient;
|
|
12
|
+
}
|
|
13
|
+
getDiscoveredDevice(address) {
|
|
14
|
+
return super.getDiscoveredDevice(address);
|
|
15
|
+
}
|
|
16
|
+
closeClient() {
|
|
17
|
+
this.#proxyClient.close();
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
export {
|
|
21
|
+
ProxyBleScanner
|
|
22
|
+
};
|
|
23
|
+
//# sourceMappingURL=ProxyBleScanner.js.map
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/ProxyBleScanner.ts"],
|
|
4
|
+
"mappings": "AAAA;AAAA;AAAA;AAAA;AAAA;AAMA,SAAS,cAAc,sBAAgD;AAgBhE,MAAM,wBAAwB,eAAe;AAAA,EACvC;AAAA,EAET,YAAY,aAA6B;AACrC,UAAM,WAAW;AACjB,SAAK,eAAe;AAAA,EACxB;AAAA,EAES,oBAAoB,SAA2C;AACpE,WAAO,MAAM,oBAAoB,OAAO;AAAA,EAC5C;AAAA,EAEmB,cAAoB;AACnC,SAAK,aAAa,MAAM;AAAA,EAC5B;AACJ;",
|
|
5
|
+
"names": []
|
|
6
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2025-2026 Open Home Foundation
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
export declare class NobleBleProxyClient {
|
|
7
|
+
#private;
|
|
8
|
+
constructor(serverUrl: string, hciId?: number);
|
|
9
|
+
connect(): Promise<void>;
|
|
10
|
+
close(): void;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=NobleBleProxyClient.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NobleBleProxyClient.d.ts","sourceRoot":"","sources":["../../../src/example/NobleBleProxyClient.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AA6EH,qBAAa,mBAAmB;;IAY5B,YAAY,SAAS,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,EAI5C;IAEK,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAsE7B;IAED,KAAK,IAAI,IAAI,CAeZ;CA4eJ"}
|