@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,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2025-2026 Open Home Foundation
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
const BLE_PROXY_PROTOCOL_VERSION = 1;
|
|
7
|
+
const BleProxyCommand = {
|
|
8
|
+
StartScan: "start_scan",
|
|
9
|
+
StopScan: "stop_scan",
|
|
10
|
+
Connect: "connect",
|
|
11
|
+
Disconnect: "disconnect",
|
|
12
|
+
DiscoverServices: "discover_services",
|
|
13
|
+
DiscoverCharacteristics: "discover_characteristics",
|
|
14
|
+
ReadCharacteristic: "read_characteristic",
|
|
15
|
+
WriteCharacteristic: "write_characteristic",
|
|
16
|
+
SubscribeCharacteristic: "subscribe_characteristic",
|
|
17
|
+
UnsubscribeCharacteristic: "unsubscribe_characteristic",
|
|
18
|
+
RequestMtu: "request_mtu"
|
|
19
|
+
};
|
|
20
|
+
const BleProxyEvent = {
|
|
21
|
+
DeviceDiscovered: "device_discovered",
|
|
22
|
+
Disconnected: "disconnected",
|
|
23
|
+
ScanStopped: "scan_stopped",
|
|
24
|
+
CharacteristicNotification: "characteristic_notification"
|
|
25
|
+
};
|
|
26
|
+
const BleProxyErrorCode = {
|
|
27
|
+
BluetoothUnavailable: "bluetooth_unavailable",
|
|
28
|
+
AlreadyScanning: "already_scanning",
|
|
29
|
+
NotScanning: "not_scanning",
|
|
30
|
+
DeviceNotFound: "device_not_found",
|
|
31
|
+
ConnectionFailed: "connection_failed",
|
|
32
|
+
AlreadyConnected: "already_connected",
|
|
33
|
+
NotConnected: "not_connected",
|
|
34
|
+
Timeout: "timeout",
|
|
35
|
+
ServiceNotFound: "service_not_found",
|
|
36
|
+
CharacteristicNotFound: "characteristic_not_found",
|
|
37
|
+
ReadFailed: "read_failed",
|
|
38
|
+
WriteFailed: "write_failed",
|
|
39
|
+
SubscribeFailed: "subscribe_failed",
|
|
40
|
+
NotSubscribed: "not_subscribed",
|
|
41
|
+
NotifyNotSupported: "notify_not_supported",
|
|
42
|
+
MtuRequestFailed: "mtu_request_failed",
|
|
43
|
+
DiscoveryFailed: "discovery_failed",
|
|
44
|
+
InternalError: "internal_error"
|
|
45
|
+
};
|
|
46
|
+
const BinaryFrameOpcode = {
|
|
47
|
+
/** Server -> Client: write payload to the active write characteristic */
|
|
48
|
+
WriteData: 1,
|
|
49
|
+
/** Client -> Server: notification data from a subscribed characteristic */
|
|
50
|
+
Notification: 2,
|
|
51
|
+
/** Client -> Server: response data for a read_characteristic command */
|
|
52
|
+
ReadResponse: 3
|
|
53
|
+
};
|
|
54
|
+
const BINARY_FRAME_HEADER_SIZE = 3;
|
|
55
|
+
function encodeBinaryFrame(opcode, connectionHandle, payload) {
|
|
56
|
+
const frame = new Uint8Array(BINARY_FRAME_HEADER_SIZE + payload.length);
|
|
57
|
+
frame[0] = opcode & 255;
|
|
58
|
+
frame[1] = connectionHandle >> 8 & 255;
|
|
59
|
+
frame[2] = connectionHandle & 255;
|
|
60
|
+
frame.set(payload, BINARY_FRAME_HEADER_SIZE);
|
|
61
|
+
return frame;
|
|
62
|
+
}
|
|
63
|
+
function decodeBinaryFrame(data) {
|
|
64
|
+
if (data.length < BINARY_FRAME_HEADER_SIZE) {
|
|
65
|
+
throw new Error(`Binary frame too short: ${data.length} bytes, minimum ${BINARY_FRAME_HEADER_SIZE}`);
|
|
66
|
+
}
|
|
67
|
+
return {
|
|
68
|
+
opcode: data[0],
|
|
69
|
+
connectionHandle: data[1] << 8 | data[2],
|
|
70
|
+
payload: data.subarray(BINARY_FRAME_HEADER_SIZE)
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
export {
|
|
74
|
+
BLE_PROXY_PROTOCOL_VERSION,
|
|
75
|
+
BinaryFrameOpcode,
|
|
76
|
+
BleProxyCommand,
|
|
77
|
+
BleProxyErrorCode,
|
|
78
|
+
BleProxyEvent,
|
|
79
|
+
decodeBinaryFrame,
|
|
80
|
+
encodeBinaryFrame
|
|
81
|
+
};
|
|
82
|
+
//# sourceMappingURL=BleProxyProtocol.js.map
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/BleProxyProtocol.ts"],
|
|
4
|
+
"mappings": "AAAA;AAAA;AAAA;AAAA;AAAA;AAaO,MAAM,6BAA6B;AAoBnC,MAAM,kBAAkB;AAAA,EAC3B,WAAW;AAAA,EACX,UAAU;AAAA,EACV,SAAS;AAAA,EACT,YAAY;AAAA,EACZ,kBAAkB;AAAA,EAClB,yBAAyB;AAAA,EACzB,oBAAoB;AAAA,EACpB,qBAAqB;AAAA,EACrB,yBAAyB;AAAA,EACzB,2BAA2B;AAAA,EAC3B,YAAY;AAChB;AAMO,MAAM,gBAAgB;AAAA,EACzB,kBAAkB;AAAA,EAClB,cAAc;AAAA,EACd,aAAa;AAAA,EACb,4BAA4B;AAChC;AA+JO,MAAM,oBAAoB;AAAA,EAC7B,sBAAsB;AAAA,EACtB,iBAAiB;AAAA,EACjB,aAAa;AAAA,EACb,gBAAgB;AAAA,EAChB,kBAAkB;AAAA,EAClB,kBAAkB;AAAA,EAClB,cAAc;AAAA,EACd,SAAS;AAAA,EACT,iBAAiB;AAAA,EACjB,wBAAwB;AAAA,EACxB,YAAY;AAAA,EACZ,aAAa;AAAA,EACb,iBAAiB;AAAA,EACjB,eAAe;AAAA,EACf,oBAAoB;AAAA,EACpB,kBAAkB;AAAA,EAClB,iBAAiB;AAAA,EACjB,eAAe;AACnB;AAMO,MAAM,oBAAoB;AAAA;AAAA,EAE7B,WAAW;AAAA;AAAA,EAEX,cAAc;AAAA;AAAA,EAEd,cAAc;AAClB;AAaA,MAAM,2BAA2B;AAQ1B,SAAS,kBAAkB,QAAgB,kBAA0B,SAAiC;AACzG,QAAM,QAAQ,IAAI,WAAW,2BAA2B,QAAQ,MAAM;AACtE,QAAM,CAAC,IAAI,SAAS;AACpB,QAAM,CAAC,IAAK,oBAAoB,IAAK;AACrC,QAAM,CAAC,IAAI,mBAAmB;AAC9B,QAAM,IAAI,SAAS,wBAAwB;AAC3C,SAAO;AACX;AAEO,SAAS,kBAAkB,MAA+B;AAC7D,MAAI,KAAK,SAAS,0BAA0B;AACxC,UAAM,IAAI,MAAM,2BAA2B,KAAK,MAAM,mBAAmB,wBAAwB,EAAE;AAAA,EACvG;AACA,SAAO;AAAA,IACH,QAAQ,KAAK,CAAC;AAAA,IACd,kBAAmB,KAAK,CAAC,KAAK,IAAK,KAAK,CAAC;AAAA,IACzC,SAAS,KAAK,SAAS,wBAAwB;AAAA,EACnD;AACJ;",
|
|
5
|
+
"names": []
|
|
6
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2025-2026 Open Home Foundation
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
import { type Environment, type Transport } from "@matter/main";
|
|
7
|
+
import { Ble, type BlePeripheralInterface, type Scanner } from "@matter/main/protocol";
|
|
8
|
+
import type { BleProxyHandler } from "./BleProxyHandler.js";
|
|
9
|
+
/**
|
|
10
|
+
* BLE implementation that proxies all operations over a WebSocket connection.
|
|
11
|
+
* Replaces NodeJsBle for environments where BLE hardware is accessed through
|
|
12
|
+
* a remote proxy client (e.g. Home Assistant with ESPHome BLE proxies).
|
|
13
|
+
*
|
|
14
|
+
* Only central (client) mode is supported. Peripheral mode throws.
|
|
15
|
+
*/
|
|
16
|
+
export declare class ProxyBle extends Ble {
|
|
17
|
+
#private;
|
|
18
|
+
constructor(handler: BleProxyHandler, environment?: Environment);
|
|
19
|
+
get peripheralInterface(): BlePeripheralInterface;
|
|
20
|
+
get centralInterface(): Transport;
|
|
21
|
+
get scanner(): Scanner;
|
|
22
|
+
close(): Promise<void>;
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=ProxyBle.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ProxyBle.d.ts","sourceRoot":"","sources":["../../src/ProxyBle.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,KAAK,WAAW,EAAuB,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AACrF,OAAO,EAAE,GAAG,EAAE,KAAK,sBAAsB,EAAE,KAAK,OAAO,EAAE,MAAM,uBAAuB,CAAC;AACvF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAK5D;;;;;;GAMG;AACH,qBAAa,QAAS,SAAQ,GAAG;;IAO7B,YAAY,OAAO,EAAE,eAAe,EAAE,WAAW,CAAC,EAAE,WAAW,EAM9D;IAED,IAAI,mBAAmB,IAAI,sBAAsB,CAEhD;IAED,IAAI,gBAAgB,IAAI,SAAS,CAKhC;IAED,IAAI,OAAO,IAAI,OAAO,CAQrB;IAEK,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAM3B;CACJ"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2025-2026 Open Home Foundation
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
import { ImplementationError } from "@matter/main";
|
|
7
|
+
import { Ble } from "@matter/main/protocol";
|
|
8
|
+
import { ProxyBleCentralInterface } from "./ProxyBleChannel.js";
|
|
9
|
+
import { ProxyBleClient } from "./ProxyBleClient.js";
|
|
10
|
+
import { ProxyBleScanner } from "./ProxyBleScanner.js";
|
|
11
|
+
class ProxyBle extends Ble {
|
|
12
|
+
#handler;
|
|
13
|
+
#proxyBleClient;
|
|
14
|
+
#bleScanner;
|
|
15
|
+
#bleCentralInterface;
|
|
16
|
+
#closed = false;
|
|
17
|
+
constructor(handler, environment) {
|
|
18
|
+
super();
|
|
19
|
+
this.#handler = handler;
|
|
20
|
+
environment?.runtime.add(this);
|
|
21
|
+
}
|
|
22
|
+
get peripheralInterface() {
|
|
23
|
+
throw new ImplementationError("BLE Proxy only supports central mode, not peripheral");
|
|
24
|
+
}
|
|
25
|
+
get centralInterface() {
|
|
26
|
+
if (!this.#bleCentralInterface) {
|
|
27
|
+
this.#bleCentralInterface = new ProxyBleCentralInterface(this.scanner, this.#handler);
|
|
28
|
+
}
|
|
29
|
+
return this.#bleCentralInterface;
|
|
30
|
+
}
|
|
31
|
+
get scanner() {
|
|
32
|
+
if (!this.#bleScanner) {
|
|
33
|
+
if (!this.#proxyBleClient) {
|
|
34
|
+
this.#proxyBleClient = new ProxyBleClient(this.#handler);
|
|
35
|
+
}
|
|
36
|
+
this.#bleScanner = new ProxyBleScanner(this.#proxyBleClient);
|
|
37
|
+
}
|
|
38
|
+
return this.#bleScanner;
|
|
39
|
+
}
|
|
40
|
+
async close() {
|
|
41
|
+
if (this.#closed) return;
|
|
42
|
+
this.#closed = true;
|
|
43
|
+
await this.#bleCentralInterface?.close();
|
|
44
|
+
await this.#bleScanner?.close();
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
export {
|
|
48
|
+
ProxyBle
|
|
49
|
+
};
|
|
50
|
+
//# sourceMappingURL=ProxyBle.js.map
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/ProxyBle.ts"],
|
|
4
|
+
"mappings": "AAAA;AAAA;AAAA;AAAA;AAAA;AAMA,SAA2B,2BAA2C;AACtE,SAAS,WAAsD;AAE/D,SAAS,gCAAgC;AACzC,SAAS,sBAAsB;AAC/B,SAAS,uBAAuB;AASzB,MAAM,iBAAiB,IAAI;AAAA,EACrB;AAAA,EACT;AAAA,EACA;AAAA,EACA;AAAA,EACA,UAAU;AAAA,EAEV,YAAY,SAA0B,aAA2B;AAC7D,UAAM;AACN,SAAK,WAAW;AAGhB,iBAAa,QAAQ,IAAI,IAAI;AAAA,EACjC;AAAA,EAEA,IAAI,sBAA8C;AAC9C,UAAM,IAAI,oBAAoB,sDAAsD;AAAA,EACxF;AAAA,EAEA,IAAI,mBAA8B;AAC9B,QAAI,CAAC,KAAK,sBAAsB;AAC5B,WAAK,uBAAuB,IAAI,yBAAyB,KAAK,SAA4B,KAAK,QAAQ;AAAA,IAC3G;AACA,WAAO,KAAK;AAAA,EAChB;AAAA,EAEA,IAAI,UAAmB;AACnB,QAAI,CAAC,KAAK,aAAa;AACnB,UAAI,CAAC,KAAK,iBAAiB;AACvB,aAAK,kBAAkB,IAAI,eAAe,KAAK,QAAQ;AAAA,MAC3D;AACA,WAAK,cAAc,IAAI,gBAAgB,KAAK,eAAe;AAAA,IAC/D;AACA,WAAO,KAAK;AAAA,EAChB;AAAA,EAEA,MAAM,QAAuB;AACzB,QAAI,KAAK,QAAS;AAClB,SAAK,UAAU;AACf,UAAM,KAAK,sBAAsB,MAAM;AAEvC,UAAM,KAAK,aAAa,MAAM;AAAA,EAClC;AACJ;",
|
|
5
|
+
"names": []
|
|
6
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2025-2026 Open Home Foundation
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
import { type Bytes, type Channel, ChannelType, ServerAddress, type Transport } from "@matter/main";
|
|
7
|
+
import { BleChannel, BtpSessionHandler } from "@matter/main/protocol";
|
|
8
|
+
import type { BleProxyHandler } from "./BleProxyHandler.js";
|
|
9
|
+
import type { ProxyBleScanner } from "./ProxyBleScanner.js";
|
|
10
|
+
/**
|
|
11
|
+
* ConnectionlessTransport implementation that opens BLE channels through the proxy WebSocket.
|
|
12
|
+
* Replaces NobleBleCentralInterface from @matter/nodejs-ble.
|
|
13
|
+
*/
|
|
14
|
+
export declare class ProxyBleCentralInterface implements Transport {
|
|
15
|
+
#private;
|
|
16
|
+
constructor(bleScanner: ProxyBleScanner, handler: BleProxyHandler);
|
|
17
|
+
openChannel(address: ServerAddress): Promise<Channel<Bytes>>;
|
|
18
|
+
onData(listener: (socket: Channel<Bytes>, data: Bytes) => void): Transport.Listener;
|
|
19
|
+
close(): Promise<void>;
|
|
20
|
+
supports(type: ChannelType, _address?: string): type is ChannelType.BLE;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* BLE channel that communicates through the proxy WebSocket.
|
|
24
|
+
* Replaces NobleBleChannel from @matter/nodejs-ble.
|
|
25
|
+
*/
|
|
26
|
+
export declare class ProxyBleChannel extends BleChannel<Bytes> {
|
|
27
|
+
#private;
|
|
28
|
+
constructor(peripheralAddress: string, btpSession: BtpSessionHandler, cleanupObservers: () => void);
|
|
29
|
+
get connected(): boolean;
|
|
30
|
+
markDisconnected(): void;
|
|
31
|
+
pushMessage(data: Bytes): void;
|
|
32
|
+
onClose(listener: () => void): Transport.Listener;
|
|
33
|
+
[Symbol.asyncIterator](): AsyncIterator<Bytes>;
|
|
34
|
+
send(data: Bytes): Promise<void>;
|
|
35
|
+
get name(): string;
|
|
36
|
+
close(): Promise<void>;
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=ProxyBleChannel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ProxyBleChannel.d.ts","sourceRoot":"","sources":["../../src/ProxyBleChannel.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACH,KAAK,KAAK,EACV,KAAK,OAAO,EACZ,WAAW,EAKX,aAAa,EAEb,KAAK,SAAS,EACjB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,UAAU,EAAoC,iBAAiB,EAAa,MAAM,uBAAuB,CAAC;AACnH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAE5D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAgC5D;;;GAGG;AACH,qBAAa,wBAAyB,YAAW,SAAS;;IAMtD,YAAY,UAAU,EAAE,eAAe,EAAE,OAAO,EAAE,eAAe,EAGhE;IAEK,WAAW,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CA2NjE;IAED,MAAM,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,KAAK,KAAK,IAAI,GAAG,SAAS,CAAC,QAAQ,CAKlF;IAEK,KAAK,kBAEV;IAED,QAAQ,CAAC,IAAI,EAAE,WAAW,EAAE,QAAQ,CAAC,EAAE,MAAM,2BAE5C;CACJ;AAED;;;GAGG;AACH,qBAAa,eAAgB,SAAQ,UAAU,CAAC,KAAK,CAAC;;IAWlD,YAAY,iBAAiB,EAAE,MAAM,EAAE,UAAU,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,IAAI,EAOjG;IAED,IAAI,SAAS,YAEZ;IAED,gBAAgB,SAEf;IAED,WAAW,CAAC,IAAI,EAAE,KAAK,GAAG,IAAI,CAQ7B;IAED,OAAO,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,SAAS,CAAC,QAAQ,CAOhD;IAED,CAAC,MAAM,CAAC,aAAa,CAAC,IAAI,aAAa,CAAC,KAAK,CAAC,CAc7C;IAUK,IAAI,CAAC,IAAI,EAAE,KAAK,iBASrB;IAED,IAAI,IAAI,WAEP;IAEK,KAAK,kBAUV;CACJ"}
|
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2025-2026 Open Home Foundation
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
import {
|
|
7
|
+
ChannelType,
|
|
8
|
+
createPromise,
|
|
9
|
+
InternalError,
|
|
10
|
+
Logger,
|
|
11
|
+
NetworkError,
|
|
12
|
+
ServerAddress,
|
|
13
|
+
Time
|
|
14
|
+
} from "@matter/main";
|
|
15
|
+
import { BleChannel, BleError, BtpCodec, BtpFlowError, BtpSessionHandler, MatterBle } from "@matter/main/protocol";
|
|
16
|
+
import { BinaryFrameOpcode, BleProxyCommand, BleProxyEvent } from "./BleProxyProtocol.js";
|
|
17
|
+
const logger = Logger.get("ProxyBleChannel");
|
|
18
|
+
const BTP_HANDSHAKE_RESPONSE_OPCODE_1 = 101;
|
|
19
|
+
const BTP_HANDSHAKE_RESPONSE_OPCODE_2 = 108;
|
|
20
|
+
const BTP_HANDSHAKE_RESPONSE_LENGTH = 6;
|
|
21
|
+
function toCanonicalUuid(uuid) {
|
|
22
|
+
const upper = uuid.toUpperCase();
|
|
23
|
+
if (upper.length === 32) {
|
|
24
|
+
return [
|
|
25
|
+
upper.substring(0, 8),
|
|
26
|
+
upper.substring(8, 12),
|
|
27
|
+
upper.substring(12, 16),
|
|
28
|
+
upper.substring(16, 20),
|
|
29
|
+
upper.substring(20, 32)
|
|
30
|
+
].join("-");
|
|
31
|
+
}
|
|
32
|
+
return upper;
|
|
33
|
+
}
|
|
34
|
+
class ProxyBleCentralInterface {
|
|
35
|
+
#bleScanner;
|
|
36
|
+
#handler;
|
|
37
|
+
#onMatterMessageListener;
|
|
38
|
+
#closed = false;
|
|
39
|
+
constructor(bleScanner, handler) {
|
|
40
|
+
this.#bleScanner = bleScanner;
|
|
41
|
+
this.#handler = handler;
|
|
42
|
+
}
|
|
43
|
+
async openChannel(address) {
|
|
44
|
+
if (this.#closed) {
|
|
45
|
+
throw new NetworkError("Network interface is closed");
|
|
46
|
+
}
|
|
47
|
+
if (!ServerAddress.isBle(address)) {
|
|
48
|
+
throw new InternalError(`Unsupported address type for BLE channel.`);
|
|
49
|
+
}
|
|
50
|
+
if (this.#onMatterMessageListener === void 0) {
|
|
51
|
+
throw new InternalError("Network Interface was not added to the system yet.");
|
|
52
|
+
}
|
|
53
|
+
const { peripheralAddress } = address;
|
|
54
|
+
const { hasAdditionalAdvertisementData } = this.#bleScanner.getDiscoveredDevice(peripheralAddress);
|
|
55
|
+
if (!this.#handler.connected) {
|
|
56
|
+
throw new BleError("BLE proxy client not connected");
|
|
57
|
+
}
|
|
58
|
+
logger.debug(`Connecting to peripheral ${peripheralAddress} via proxy`);
|
|
59
|
+
const { connection_handle, mtu: peripheralMtu } = await this.#handler.sendCommand(BleProxyCommand.Connect, {
|
|
60
|
+
address: peripheralAddress
|
|
61
|
+
});
|
|
62
|
+
let mtu = peripheralMtu ?? 0;
|
|
63
|
+
if (mtu > MatterBle.MAXIMUM_BTP_MTU) {
|
|
64
|
+
mtu = MatterBle.MAXIMUM_BTP_MTU;
|
|
65
|
+
}
|
|
66
|
+
logger.debug(`Connected to ${peripheralAddress}, handle=${connection_handle}, mtu=${mtu}`);
|
|
67
|
+
try {
|
|
68
|
+
const { services } = await this.#handler.sendCommand(BleProxyCommand.DiscoverServices, {
|
|
69
|
+
connection_handle
|
|
70
|
+
});
|
|
71
|
+
const matterService = services.find((s) => MatterBle.isServiceUuid(s.uuid));
|
|
72
|
+
if (!matterService) {
|
|
73
|
+
throw new BleError(`Peripheral ${peripheralAddress} does not have Matter BLE service`);
|
|
74
|
+
}
|
|
75
|
+
const { characteristics } = await this.#handler.sendCommand(BleProxyCommand.DiscoverCharacteristics, {
|
|
76
|
+
connection_handle,
|
|
77
|
+
service_uuid: matterService.uuid
|
|
78
|
+
});
|
|
79
|
+
let c1Uuid;
|
|
80
|
+
let c2Uuid;
|
|
81
|
+
let c3Uuid;
|
|
82
|
+
for (const char of characteristics) {
|
|
83
|
+
const canonical = toCanonicalUuid(char.uuid);
|
|
84
|
+
if (canonical === MatterBle.C1_CHARACTERISTIC_UUID) {
|
|
85
|
+
c1Uuid = char.uuid;
|
|
86
|
+
} else if (canonical === MatterBle.C2_CHARACTERISTIC_UUID) {
|
|
87
|
+
c2Uuid = char.uuid;
|
|
88
|
+
} else if (canonical === MatterBle.C3_CHARACTERISTIC_UUID) {
|
|
89
|
+
c3Uuid = char.uuid;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
if (!c1Uuid || !c2Uuid) {
|
|
93
|
+
throw new BleError(`Peripheral ${peripheralAddress} missing required Matter characteristics (C1/C2)`);
|
|
94
|
+
}
|
|
95
|
+
if (c3Uuid && hasAdditionalAdvertisementData) {
|
|
96
|
+
logger.debug(`Reading additional commissioning data from C3`);
|
|
97
|
+
await this.#handler.sendCommand(BleProxyCommand.ReadCharacteristic, {
|
|
98
|
+
connection_handle,
|
|
99
|
+
characteristic_uuid: c3Uuid
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
const btpHandshakeRequest = BtpCodec.encodeBtpHandshakeRequest({
|
|
103
|
+
versions: MatterBle.BTP_SUPPORTED_VERSIONS,
|
|
104
|
+
attMtu: mtu,
|
|
105
|
+
clientWindowSize: MatterBle.BTP_MAXIMUM_WINDOW_SIZE
|
|
106
|
+
});
|
|
107
|
+
logger.debug(`Sending BTP handshake request on C1`);
|
|
108
|
+
await this.#handler.sendCommand(BleProxyCommand.WriteCharacteristic, {
|
|
109
|
+
connection_handle,
|
|
110
|
+
characteristic_uuid: c1Uuid,
|
|
111
|
+
value: Buffer.from(btpHandshakeRequest).toString("base64"),
|
|
112
|
+
response: true
|
|
113
|
+
});
|
|
114
|
+
await this.#handler.sendCommand(BleProxyCommand.SubscribeCharacteristic, {
|
|
115
|
+
connection_handle,
|
|
116
|
+
characteristic_uuid: c2Uuid
|
|
117
|
+
});
|
|
118
|
+
const {
|
|
119
|
+
promise: handshakePromise,
|
|
120
|
+
resolver: handshakeResolver,
|
|
121
|
+
rejecter: handshakeRejecter
|
|
122
|
+
} = createPromise();
|
|
123
|
+
const btpHandshakeTimeout = Time.getTimer(
|
|
124
|
+
"BLE proxy handshake timeout",
|
|
125
|
+
MatterBle.BTP_CONN_RSP_TIMEOUT,
|
|
126
|
+
() => {
|
|
127
|
+
handshakeRejecter(new BleError(`BTP handshake response not received from ${peripheralAddress}`));
|
|
128
|
+
}
|
|
129
|
+
).start();
|
|
130
|
+
const handshakeObserver = (frame) => {
|
|
131
|
+
if (frame.connectionHandle === connection_handle && frame.opcode === BinaryFrameOpcode.Notification) {
|
|
132
|
+
const data = new Uint8Array(frame.payload);
|
|
133
|
+
if (data[0] === BTP_HANDSHAKE_RESPONSE_OPCODE_1 && data[1] === BTP_HANDSHAKE_RESPONSE_OPCODE_2 && data.length === BTP_HANDSHAKE_RESPONSE_LENGTH) {
|
|
134
|
+
btpHandshakeTimeout.stop();
|
|
135
|
+
handshakeResolver(data);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
this.#handler.binaryFrameReceived.on(handshakeObserver);
|
|
140
|
+
let handshakeResponse;
|
|
141
|
+
try {
|
|
142
|
+
handshakeResponse = await handshakePromise;
|
|
143
|
+
} finally {
|
|
144
|
+
this.#handler.binaryFrameReceived.off(handshakeObserver);
|
|
145
|
+
btpHandshakeTimeout.stop();
|
|
146
|
+
}
|
|
147
|
+
const onMatterMessageListener = this.#onMatterMessageListener;
|
|
148
|
+
const channelRef = {};
|
|
149
|
+
const btpSession = await BtpSessionHandler.createAsCentral(
|
|
150
|
+
handshakeResponse,
|
|
151
|
+
// Write callback: send binary frame to proxy client
|
|
152
|
+
async (data) => {
|
|
153
|
+
const bytes = data instanceof Uint8Array ? data : new Uint8Array(data);
|
|
154
|
+
this.#handler.sendBinaryFrame(BinaryFrameOpcode.WriteData, connection_handle, bytes);
|
|
155
|
+
},
|
|
156
|
+
// Disconnect callback
|
|
157
|
+
async () => {
|
|
158
|
+
if (!channelRef.channel?.connected) return;
|
|
159
|
+
logger.debug(`Disconnecting from ${peripheralAddress} via proxy`);
|
|
160
|
+
try {
|
|
161
|
+
await this.#handler.sendCommand(BleProxyCommand.Disconnect, { connection_handle });
|
|
162
|
+
} catch (error) {
|
|
163
|
+
logger.debug(
|
|
164
|
+
`Peripheral ${peripheralAddress}: Error sending Disconnect to proxy client`,
|
|
165
|
+
error
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
},
|
|
169
|
+
// Matter message callback
|
|
170
|
+
async (data) => {
|
|
171
|
+
if (channelRef.channel) {
|
|
172
|
+
channelRef.channel.pushMessage(data);
|
|
173
|
+
onMatterMessageListener(channelRef.channel, data);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
);
|
|
177
|
+
const binaryObserver = (frame) => {
|
|
178
|
+
if (frame.connectionHandle === connection_handle && frame.opcode === BinaryFrameOpcode.Notification) {
|
|
179
|
+
btpSession.handleIncomingBleData(new Uint8Array(frame.payload)).catch(
|
|
180
|
+
(error) => logger.warn(`Peripheral ${peripheralAddress}: Error handling incoming BLE data`, error)
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
};
|
|
184
|
+
this.#handler.binaryFrameReceived.on(binaryObserver);
|
|
185
|
+
const eventObserver = (event, data) => {
|
|
186
|
+
if (event === BleProxyEvent.Disconnected && typeof data.connection_handle === "number" && data.connection_handle === connection_handle) {
|
|
187
|
+
logger.info(`Peripheral ${peripheralAddress} disconnected unexpectedly`);
|
|
188
|
+
channelRef.channel?.markDisconnected();
|
|
189
|
+
channelRef.channel?.close().catch((error) => logger.debug(`Peripheral ${peripheralAddress}: Error closing channel`, error));
|
|
190
|
+
}
|
|
191
|
+
};
|
|
192
|
+
this.#handler.eventReceived.on(eventObserver);
|
|
193
|
+
const cleanupObservers = () => {
|
|
194
|
+
this.#handler.binaryFrameReceived.off(binaryObserver);
|
|
195
|
+
this.#handler.eventReceived.off(eventObserver);
|
|
196
|
+
};
|
|
197
|
+
const proxyChannel = new ProxyBleChannel(peripheralAddress, btpSession, cleanupObservers);
|
|
198
|
+
channelRef.channel = proxyChannel;
|
|
199
|
+
return proxyChannel;
|
|
200
|
+
} catch (error) {
|
|
201
|
+
try {
|
|
202
|
+
await this.#handler.sendCommand(BleProxyCommand.Disconnect, { connection_handle });
|
|
203
|
+
} catch (cleanupError) {
|
|
204
|
+
logger.debug(`Peripheral ${peripheralAddress}: Error during connect-failure cleanup`, cleanupError);
|
|
205
|
+
}
|
|
206
|
+
throw error;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
onData(listener) {
|
|
210
|
+
this.#onMatterMessageListener = listener;
|
|
211
|
+
return {
|
|
212
|
+
close: async () => await this.close()
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
async close() {
|
|
216
|
+
this.#closed = true;
|
|
217
|
+
}
|
|
218
|
+
supports(type, _address) {
|
|
219
|
+
return type === ChannelType.BLE;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
class ProxyBleChannel extends BleChannel {
|
|
223
|
+
#connected = true;
|
|
224
|
+
#peripheralAddress;
|
|
225
|
+
#btpSession;
|
|
226
|
+
#cleanupObservers;
|
|
227
|
+
#onBtpSessionClosed;
|
|
228
|
+
#closeListeners = /* @__PURE__ */ new Set();
|
|
229
|
+
#iteratorQueue = new Array();
|
|
230
|
+
#iteratorWaiter;
|
|
231
|
+
#iteratorDone = false;
|
|
232
|
+
constructor(peripheralAddress, btpSession, cleanupObservers) {
|
|
233
|
+
super();
|
|
234
|
+
this.#peripheralAddress = peripheralAddress;
|
|
235
|
+
this.#btpSession = btpSession;
|
|
236
|
+
this.#cleanupObservers = cleanupObservers;
|
|
237
|
+
this.#onBtpSessionClosed = () => this.emitClosed();
|
|
238
|
+
btpSession.closed.on(this.#onBtpSessionClosed);
|
|
239
|
+
}
|
|
240
|
+
get connected() {
|
|
241
|
+
return this.#connected;
|
|
242
|
+
}
|
|
243
|
+
markDisconnected() {
|
|
244
|
+
this.#connected = false;
|
|
245
|
+
}
|
|
246
|
+
pushMessage(data) {
|
|
247
|
+
if (this.#iteratorWaiter) {
|
|
248
|
+
const resolve = this.#iteratorWaiter;
|
|
249
|
+
this.#iteratorWaiter = void 0;
|
|
250
|
+
resolve({ value: data, done: false });
|
|
251
|
+
} else if (!this.#iteratorDone) {
|
|
252
|
+
this.#iteratorQueue.push(data);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
onClose(listener) {
|
|
256
|
+
this.#closeListeners.add(listener);
|
|
257
|
+
return {
|
|
258
|
+
close: async () => {
|
|
259
|
+
this.#closeListeners.delete(listener);
|
|
260
|
+
}
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
[Symbol.asyncIterator]() {
|
|
264
|
+
return {
|
|
265
|
+
next: () => {
|
|
266
|
+
if (this.#iteratorQueue.length > 0) {
|
|
267
|
+
return Promise.resolve({ value: this.#iteratorQueue.shift(), done: false });
|
|
268
|
+
}
|
|
269
|
+
if (this.#iteratorDone || !this.#connected) {
|
|
270
|
+
return Promise.resolve({ value: void 0, done: true });
|
|
271
|
+
}
|
|
272
|
+
return new Promise((resolve) => {
|
|
273
|
+
this.#iteratorWaiter = resolve;
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
#terminateIterator() {
|
|
279
|
+
if (!this.#iteratorDone) {
|
|
280
|
+
this.#iteratorDone = true;
|
|
281
|
+
this.#iteratorWaiter?.({ value: void 0, done: true });
|
|
282
|
+
this.#iteratorWaiter = void 0;
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
async send(data) {
|
|
286
|
+
if (!this.#connected) {
|
|
287
|
+
logger.debug(`Cannot send data - not connected to ${this.#peripheralAddress}`);
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
if (this.#btpSession === void 0) {
|
|
291
|
+
throw new BtpFlowError(`Cannot send data, no BTP session initialized`);
|
|
292
|
+
}
|
|
293
|
+
await this.#btpSession.sendMatterMessage(data);
|
|
294
|
+
}
|
|
295
|
+
get name() {
|
|
296
|
+
return `ble-proxy://${this.#peripheralAddress}`;
|
|
297
|
+
}
|
|
298
|
+
async close() {
|
|
299
|
+
this.#connected = false;
|
|
300
|
+
this.#cleanupObservers();
|
|
301
|
+
this.#terminateIterator();
|
|
302
|
+
for (const listener of this.#closeListeners) {
|
|
303
|
+
listener();
|
|
304
|
+
}
|
|
305
|
+
this.#btpSession.closed.off(this.#onBtpSessionClosed);
|
|
306
|
+
await this.#btpSession.close();
|
|
307
|
+
this.emitClosed();
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
export {
|
|
311
|
+
ProxyBleCentralInterface,
|
|
312
|
+
ProxyBleChannel
|
|
313
|
+
};
|
|
314
|
+
//# sourceMappingURL=ProxyBleChannel.js.map
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/ProxyBleChannel.ts"],
|
|
4
|
+
"mappings": "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",
|
|
5
|
+
"names": []
|
|
6
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2025-2026 Open Home Foundation
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
import type { BleProxyHandler } from "./BleProxyHandler.js";
|
|
7
|
+
/**
|
|
8
|
+
* Represents a BLE peripheral discovered through the proxy.
|
|
9
|
+
* Replaces Noble's Peripheral type - stores the data received from the proxy client.
|
|
10
|
+
*/
|
|
11
|
+
export interface ProxyPeripheral {
|
|
12
|
+
address: string;
|
|
13
|
+
name?: string;
|
|
14
|
+
rssi?: number;
|
|
15
|
+
connectable: boolean;
|
|
16
|
+
serviceData: Map<string, Uint8Array>;
|
|
17
|
+
mtu?: number;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* BLE client that communicates over the BLE proxy WebSocket protocol.
|
|
21
|
+
* Replaces NobleBleClient - instead of using Noble directly, sends scan commands
|
|
22
|
+
* to the proxy client and receives device_discovered events.
|
|
23
|
+
*/
|
|
24
|
+
export declare class ProxyBleClient {
|
|
25
|
+
#private;
|
|
26
|
+
constructor(handler: BleProxyHandler);
|
|
27
|
+
setDiscoveryCallback(callback: (peripheral: ProxyPeripheral, matterServiceData: Uint8Array) => void): void;
|
|
28
|
+
startScanning(): Promise<void>;
|
|
29
|
+
stopScanning(): Promise<void>;
|
|
30
|
+
close(): void;
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=ProxyBleClient.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ProxyBleClient.d.ts","sourceRoot":"","sources":["../../src/ProxyBleClient.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAK5D;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,OAAO,CAAC;IACrB,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IACrC,GAAG,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;GAIG;AACH,qBAAa,cAAc;;IAevB,YAAY,OAAO,EAAE,eAAe,EAGnC;IAED,oBAAoB,CAAC,QAAQ,EAAE,CAAC,UAAU,EAAE,eAAe,EAAE,iBAAiB,EAAE,UAAU,KAAK,IAAI,GAAG,IAAI,CAKzG;IAEK,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAgBnC;IAEK,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC,CAalC;IAED,KAAK,IAAI,IAAI,CAGZ;CAyCJ"}
|