@matter/nodejs-ble 0.11.0-alpha.0-20241005-e3e4e4a7a

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.
Files changed (84) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +55 -0
  3. package/dist/cjs/BleBroadcaster.d.ts +20 -0
  4. package/dist/cjs/BleBroadcaster.d.ts.map +1 -0
  5. package/dist/cjs/BleBroadcaster.js +121 -0
  6. package/dist/cjs/BleBroadcaster.js.map +6 -0
  7. package/dist/cjs/BlePeripheralInterface.d.ts +15 -0
  8. package/dist/cjs/BlePeripheralInterface.d.ts.map +1 -0
  9. package/dist/cjs/BlePeripheralInterface.js +54 -0
  10. package/dist/cjs/BlePeripheralInterface.js.map +6 -0
  11. package/dist/cjs/BleScanner.d.ts +52 -0
  12. package/dist/cjs/BleScanner.d.ts.map +1 -0
  13. package/dist/cjs/BleScanner.js +240 -0
  14. package/dist/cjs/BleScanner.js.map +6 -0
  15. package/dist/cjs/BlenoBleServer.d.ts +70 -0
  16. package/dist/cjs/BlenoBleServer.d.ts.map +1 -0
  17. package/dist/cjs/BlenoBleServer.js +337 -0
  18. package/dist/cjs/BlenoBleServer.js.map +6 -0
  19. package/dist/cjs/NobleBleChannel.d.ts +32 -0
  20. package/dist/cjs/NobleBleChannel.d.ts.map +1 -0
  21. package/dist/cjs/NobleBleChannel.js +266 -0
  22. package/dist/cjs/NobleBleChannel.js.map +6 -0
  23. package/dist/cjs/NobleBleClient.d.ts +20 -0
  24. package/dist/cjs/NobleBleClient.d.ts.map +1 -0
  25. package/dist/cjs/NobleBleClient.js +108 -0
  26. package/dist/cjs/NobleBleClient.js.map +6 -0
  27. package/dist/cjs/NodeJsBle.d.ts +22 -0
  28. package/dist/cjs/NodeJsBle.d.ts.map +1 -0
  29. package/dist/cjs/NodeJsBle.js +68 -0
  30. package/dist/cjs/NodeJsBle.js.map +6 -0
  31. package/dist/cjs/index.d.ts +9 -0
  32. package/dist/cjs/index.d.ts.map +1 -0
  33. package/dist/cjs/index.js +26 -0
  34. package/dist/cjs/index.js.map +6 -0
  35. package/dist/cjs/package.json +3 -0
  36. package/dist/cjs/tsconfig.tsbuildinfo +1 -0
  37. package/dist/esm/BleBroadcaster.d.ts +20 -0
  38. package/dist/esm/BleBroadcaster.d.ts.map +1 -0
  39. package/dist/esm/BleBroadcaster.js +101 -0
  40. package/dist/esm/BleBroadcaster.js.map +6 -0
  41. package/dist/esm/BlePeripheralInterface.d.ts +15 -0
  42. package/dist/esm/BlePeripheralInterface.d.ts.map +1 -0
  43. package/dist/esm/BlePeripheralInterface.js +34 -0
  44. package/dist/esm/BlePeripheralInterface.js.map +6 -0
  45. package/dist/esm/BleScanner.d.ts +52 -0
  46. package/dist/esm/BleScanner.d.ts.map +1 -0
  47. package/dist/esm/BleScanner.js +220 -0
  48. package/dist/esm/BleScanner.js.map +6 -0
  49. package/dist/esm/BlenoBleServer.d.ts +70 -0
  50. package/dist/esm/BlenoBleServer.d.ts.map +1 -0
  51. package/dist/esm/BlenoBleServer.js +327 -0
  52. package/dist/esm/BlenoBleServer.js.map +6 -0
  53. package/dist/esm/NobleBleChannel.d.ts +32 -0
  54. package/dist/esm/NobleBleChannel.d.ts.map +1 -0
  55. package/dist/esm/NobleBleChannel.js +266 -0
  56. package/dist/esm/NobleBleChannel.js.map +6 -0
  57. package/dist/esm/NobleBleClient.d.ts +20 -0
  58. package/dist/esm/NobleBleClient.d.ts.map +1 -0
  59. package/dist/esm/NobleBleClient.js +88 -0
  60. package/dist/esm/NobleBleClient.js.map +6 -0
  61. package/dist/esm/NodeJsBle.d.ts +22 -0
  62. package/dist/esm/NodeJsBle.d.ts.map +1 -0
  63. package/dist/esm/NodeJsBle.js +48 -0
  64. package/dist/esm/NodeJsBle.js.map +6 -0
  65. package/dist/esm/index.d.ts +9 -0
  66. package/dist/esm/index.d.ts.map +1 -0
  67. package/dist/esm/index.js +9 -0
  68. package/dist/esm/index.js.map +6 -0
  69. package/dist/esm/package.json +3 -0
  70. package/dist/esm/tsconfig.tsbuildinfo +1 -0
  71. package/package.json +83 -0
  72. package/require/package.json +4 -0
  73. package/require/require.cjs +1 -0
  74. package/require/require.d.ts +1 -0
  75. package/require/require.mjs +3 -0
  76. package/src/BleBroadcaster.ts +126 -0
  77. package/src/BlePeripheralInterface.ts +36 -0
  78. package/src/BleScanner.ts +279 -0
  79. package/src/BlenoBleServer.ts +403 -0
  80. package/src/NobleBleChannel.ts +337 -0
  81. package/src/NobleBleClient.ts +117 -0
  82. package/src/NodeJsBle.ts +56 -0
  83. package/src/index.ts +9 -0
  84. package/src/tsconfig.json +16 -0
@@ -0,0 +1,327 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2022-2024 Matter.js Authors
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import { InternalError, Logger, Time, createPromise } from "@matter/general";
7
+ import { require as require2 } from "@matter/nodejs-ble/require";
8
+ import {
9
+ BLE_MATTER_C1_CHARACTERISTIC_UUID,
10
+ BLE_MATTER_C2_CHARACTERISTIC_UUID,
11
+ BLE_MATTER_C3_CHARACTERISTIC_UUID,
12
+ BLE_MATTER_SERVICE_UUID,
13
+ BTP_CONN_RSP_TIMEOUT_MS,
14
+ BleChannel,
15
+ BleError,
16
+ BtpFlowError,
17
+ BtpSessionHandler
18
+ } from "@project-chip/matter.js/ble";
19
+ import { ChannelNotConnectedError } from "@project-chip/matter.js/protocol";
20
+ const logger = Logger.get("BlenoBleServer");
21
+ let Bleno;
22
+ function initializeBleno(server, hciId) {
23
+ if (hciId !== void 0) {
24
+ process.env.BLENO_HCI_DEVICE_ID = hciId.toString();
25
+ }
26
+ Bleno = require2("@stoprocent/bleno");
27
+ class BtpWriteCharacteristicC1 extends Bleno.Characteristic {
28
+ constructor() {
29
+ super({
30
+ uuid: BLE_MATTER_C1_CHARACTERISTIC_UUID,
31
+ properties: ["write"]
32
+ });
33
+ }
34
+ onWriteRequest(data, offset, withoutResponse, callback) {
35
+ logger.debug(`C1 write request: ${data.toString("hex")} ${offset} ${withoutResponse}`);
36
+ try {
37
+ server.handleC1WriteRequest(data, offset, withoutResponse);
38
+ callback(this.RESULT_SUCCESS);
39
+ } catch (e) {
40
+ logger.error(`C1 write request failed: ${e}`);
41
+ callback(this.RESULT_UNLIKELY_ERROR);
42
+ }
43
+ }
44
+ }
45
+ class BtpIndicateCharacteristicC2 extends Bleno.Characteristic {
46
+ constructor() {
47
+ super({
48
+ uuid: BLE_MATTER_C2_CHARACTERISTIC_UUID,
49
+ properties: ["indicate"]
50
+ });
51
+ }
52
+ async onSubscribe(maxValueSize, updateValueCallback) {
53
+ logger.debug(`C2 subscribe ${maxValueSize}`);
54
+ await server.handleC2SubscribeRequest(maxValueSize, updateValueCallback);
55
+ }
56
+ async onUnsubscribe() {
57
+ logger.debug("C2 unsubscribe");
58
+ await server.close();
59
+ }
60
+ onIndicate() {
61
+ logger.debug("C2 indicate");
62
+ server.handleC2Indicate();
63
+ }
64
+ }
65
+ class BtpReadCharacteristicC3 extends Bleno.Characteristic {
66
+ constructor() {
67
+ super({
68
+ uuid: BLE_MATTER_C3_CHARACTERISTIC_UUID,
69
+ properties: ["read"]
70
+ });
71
+ }
72
+ onReadRequest(offset, callback) {
73
+ try {
74
+ const data = server.handleC3ReadRequest(offset);
75
+ logger.debug(`C3 read request: ${data.toString("hex")} ${offset}`);
76
+ callback(this.RESULT_SUCCESS, data);
77
+ } catch (e) {
78
+ logger.debug(`C3 read request failed : ${e} ${offset}`);
79
+ callback(this.RESULT_INVALID_OFFSET);
80
+ }
81
+ }
82
+ }
83
+ class BtpService extends Bleno.PrimaryService {
84
+ constructor() {
85
+ super({
86
+ uuid: BLE_MATTER_SERVICE_UUID,
87
+ characteristics: [
88
+ new BtpWriteCharacteristicC1(),
89
+ new BtpIndicateCharacteristicC2(),
90
+ new BtpReadCharacteristicC3()
91
+ ]
92
+ });
93
+ }
94
+ }
95
+ return new BtpService();
96
+ }
97
+ class BlenoBleServer extends BleChannel {
98
+ state = "unknown";
99
+ isAdvertising = false;
100
+ additionalAdvertisingData = Buffer.alloc(0);
101
+ advertisingData;
102
+ latestHandshakePayload;
103
+ btpSession;
104
+ onMatterMessageListener;
105
+ writeConformationResolver;
106
+ clientAddress;
107
+ btpHandshakeTimeout = Time.getTimer(
108
+ "BTP handshake timeout",
109
+ BTP_CONN_RSP_TIMEOUT_MS,
110
+ () => this.btpHandshakeTimeoutTriggered()
111
+ );
112
+ matterBleService;
113
+ constructor(options) {
114
+ super();
115
+ this.matterBleService = initializeBleno(this, options?.hciId);
116
+ Bleno.on("stateChange", (state) => {
117
+ if (state === this.state) return;
118
+ this.state = state;
119
+ logger.debug(`stateChange: ${state}, address = ${Bleno.address}`);
120
+ if (state !== "poweredOn") {
121
+ Bleno.stopAdvertising();
122
+ } else if (this.advertisingData) {
123
+ Bleno.startAdvertisingWithEIRData(this.advertisingData);
124
+ this.isAdvertising = true;
125
+ }
126
+ });
127
+ Bleno.on("accept", (clientAddress) => {
128
+ logger.debug(`accept new connection, client: ${clientAddress}`);
129
+ this.clientAddress = clientAddress;
130
+ Bleno.updateRssi();
131
+ });
132
+ Bleno.on("disconnect", (clientAddress) => {
133
+ logger.debug(`disconnect, client: ${clientAddress}`);
134
+ if (this.btpSession !== void 0) {
135
+ this.btpSession.close().then(() => {
136
+ this.btpSession = void 0;
137
+ }).catch(() => {
138
+ this.btpSession = void 0;
139
+ });
140
+ }
141
+ });
142
+ Bleno.on("rssiUpdate", (rssi) => {
143
+ logger.debug(`rssiUpdate: ${rssi}`);
144
+ });
145
+ Bleno.on("mtuChange", (mtu) => {
146
+ logger.debug(`mtuChange: ${mtu}`);
147
+ });
148
+ Bleno.on("advertisingStart", (error) => {
149
+ logger.debug(`advertisingStart: ${error ? `error ${error}` : "success"}`);
150
+ if (!error) {
151
+ Bleno.setServices([this.matterBleService]);
152
+ }
153
+ });
154
+ Bleno.on("advertisingStop", () => {
155
+ logger.debug("advertisingStop");
156
+ });
157
+ Bleno.on("servicesSet", (error) => {
158
+ logger.debug(`servicesSet: ${error ? `error ${error}` : "success"}`);
159
+ });
160
+ }
161
+ /**
162
+ * Process a Write request on characteristic C1 from the Matter service.
163
+ * The data are checked if it might be a handshake request and stored until the subscribe request comes in.
164
+ * Otherwise, the data are forwarded to the BTP session handler to be decoded and processed.
165
+ *
166
+ * @param data
167
+ * @param offset
168
+ * @param withoutResponse
169
+ */
170
+ handleC1WriteRequest(data, offset, withoutResponse) {
171
+ if (offset !== 0 || withoutResponse) {
172
+ throw new BleError(`Offset ${offset} or withoutResponse ${withoutResponse} not supported`);
173
+ }
174
+ if (data[0] === 101 && data[1] === 108 && data.length === 9) {
175
+ this.btpHandshakeTimeout.start();
176
+ logger.info(
177
+ `Received Matter handshake request: ${data.toString("hex")}, store until subscribe request comes in.`
178
+ );
179
+ this.latestHandshakePayload = data;
180
+ } else {
181
+ if (this.btpSession !== void 0) {
182
+ logger.debug(`Received Matter data for BTP Session: ${data.toString("hex")}`);
183
+ void this.btpSession.handleIncomingBleData(new Uint8Array(data));
184
+ } else {
185
+ throw new BtpFlowError(
186
+ `Received Matter data but no BTP session was initialized: ${data.toString("hex")}`
187
+ );
188
+ }
189
+ }
190
+ }
191
+ /**
192
+ * Process a Subscribe request on characteristic C2 from the Matter service.
193
+ * This is expected directly after a handshake request and initializes the BTP session handler with the stored
194
+ * handshake payload.
195
+ * The BtpSessionHandler instance is wired with the bleno instance for sending data and disconnecting.
196
+ *
197
+ * @param maxValueSize
198
+ * @param updateValueCallback
199
+ */
200
+ async handleC2SubscribeRequest(maxValueSize, updateValueCallback) {
201
+ if (this.latestHandshakePayload === void 0) {
202
+ throw new BtpFlowError(`Subscription request received before handshake Request`);
203
+ }
204
+ if (this.btpSession !== void 0) {
205
+ throw new BtpFlowError(
206
+ `Subscription request received but BTP session already initialized. Cannot handle two sessions!`
207
+ );
208
+ }
209
+ this.btpHandshakeTimeout.stop();
210
+ this.btpSession = await BtpSessionHandler.createFromHandshakeRequest(
211
+ Math.min(Bleno.mtu - 3, maxValueSize),
212
+ new Uint8Array(this.latestHandshakePayload),
213
+ // callback to write data to characteristic C2
214
+ async (data) => {
215
+ updateValueCallback(Buffer.from(data.buffer));
216
+ const { promise, resolver } = createPromise();
217
+ this.writeConformationResolver = resolver;
218
+ return promise;
219
+ },
220
+ // callback to disconnect the BLE connection
221
+ async () => this.close(),
222
+ // callback to forward decoded and de-assembled Matter messages to ExchangeManager
223
+ async (data) => {
224
+ if (this.onMatterMessageListener === void 0) {
225
+ throw new InternalError(`No listener registered for Matter messages`);
226
+ }
227
+ this.onMatterMessageListener(this, data);
228
+ }
229
+ );
230
+ this.latestHandshakePayload = void 0;
231
+ }
232
+ handleC2Indicate() {
233
+ if (this.writeConformationResolver !== void 0) {
234
+ this.writeConformationResolver();
235
+ this.writeConformationResolver = void 0;
236
+ } else {
237
+ logger.warn(`Received C2 indication but no former write expected a confirmation`);
238
+ }
239
+ }
240
+ /**
241
+ * Process a Read request on characteristic C3 from the Matter service.
242
+ * The relevant data needs optionally to be set before advertising, else empty data are used.
243
+ *
244
+ * @param offset
245
+ */
246
+ handleC3ReadRequest(offset) {
247
+ if (offset > this.additionalAdvertisingData.length) {
248
+ throw new BleError(`Offset ${offset} is larger than data ${this.additionalAdvertisingData.length}`);
249
+ } else {
250
+ return this.additionalAdvertisingData.subarray(offset);
251
+ }
252
+ }
253
+ async advertise(advertiseData, additionalAdvertisementData) {
254
+ this.advertisingData = Buffer.from(advertiseData.buffer);
255
+ if (additionalAdvertisementData) {
256
+ this.additionalAdvertisingData = Buffer.from(additionalAdvertisementData.buffer);
257
+ } else {
258
+ this.additionalAdvertisingData = Buffer.alloc(0);
259
+ }
260
+ if (this.isAdvertising) {
261
+ await this.stopAdvertising();
262
+ this.isAdvertising = false;
263
+ }
264
+ if (this.state === "poweredOn") {
265
+ Bleno.startAdvertisingWithEIRData(this.advertisingData);
266
+ this.isAdvertising = true;
267
+ } else {
268
+ logger.debug(`State is ${this.state}, advertise when powered on`);
269
+ }
270
+ return new Promise((resolve) => {
271
+ Bleno.once("advertisingStart", () => resolve());
272
+ });
273
+ }
274
+ async stopAdvertising() {
275
+ if (this.isAdvertising) {
276
+ return new Promise((resolve) => {
277
+ Bleno.stopAdvertising();
278
+ Bleno.once("advertisingStop", () => {
279
+ this.isAdvertising = false;
280
+ resolve();
281
+ });
282
+ });
283
+ }
284
+ }
285
+ setMatterMessageListener(listener) {
286
+ if (this.onMatterMessageListener !== void 0) {
287
+ throw new InternalError(`onData listener already set`);
288
+ }
289
+ this.onMatterMessageListener = listener;
290
+ }
291
+ async btpHandshakeTimeoutTriggered() {
292
+ await this.disconnect();
293
+ logger.error("Timeout for handshake subscribe request on C2 reached, disconnecting.");
294
+ }
295
+ async close() {
296
+ this.btpHandshakeTimeout.stop();
297
+ await this.disconnect();
298
+ if (this.btpSession !== void 0) {
299
+ await this.btpSession.close();
300
+ this.btpSession = void 0;
301
+ }
302
+ this.onMatterMessageListener = void 0;
303
+ }
304
+ async disconnect() {
305
+ Bleno.disconnect();
306
+ }
307
+ // Channel<Uint8Array>
308
+ /**
309
+ * Send a Matter message to the connected device - need to do BTP assembly first.
310
+ *
311
+ * @param data
312
+ */
313
+ async send(data) {
314
+ if (this.btpSession === void 0) {
315
+ throw new ChannelNotConnectedError(`Cannot send data, no BTP session initialized`);
316
+ }
317
+ await this.btpSession.sendMatterMessage(data);
318
+ }
319
+ // Channel<Uint8Array>
320
+ get name() {
321
+ return `${this.type}://${this.clientAddress}`;
322
+ }
323
+ }
324
+ export {
325
+ BlenoBleServer
326
+ };
327
+ //# sourceMappingURL=BlenoBleServer.js.map
@@ -0,0 +1,6 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/BlenoBleServer.ts"],
4
+ "mappings": "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",
5
+ "names": ["require"]
6
+ }
@@ -0,0 +1,32 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2022-2024 Matter.js Authors
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import { Channel, ChannelType, NetInterface, ServerAddress, TransportInterface } from "@matter/general";
7
+ import { BleChannel, BtpSessionHandler } from "@project-chip/matter.js/ble";
8
+ import type { Characteristic, Peripheral } from "@stoprocent/noble";
9
+ export declare class NobleBleCentralInterface implements NetInterface {
10
+ private openChannels;
11
+ private onMatterMessageListener;
12
+ openChannel(address: ServerAddress, tryCount?: number): Promise<Channel<Uint8Array>>;
13
+ onData(listener: (socket: Channel<Uint8Array>, data: Uint8Array) => void): TransportInterface.Listener;
14
+ close(): Promise<void>;
15
+ supports(type: ChannelType, _address?: string): boolean;
16
+ }
17
+ export declare class NobleBleChannel extends BleChannel<Uint8Array> {
18
+ private readonly peripheral;
19
+ private readonly btpSession;
20
+ static create(peripheral: Peripheral, characteristicC1ForWrite: Characteristic, characteristicC2ForSubscribe: Characteristic, onMatterMessageListener: (socket: Channel<Uint8Array>, data: Uint8Array) => void, _additionalCommissioningRelatedData?: Uint8Array): Promise<NobleBleChannel>;
21
+ private connected;
22
+ constructor(peripheral: Peripheral, btpSession: BtpSessionHandler);
23
+ /**
24
+ * Send a Matter message to the connected device - need to do BTP assembly first.
25
+ *
26
+ * @param data
27
+ */
28
+ send(data: Uint8Array): Promise<void>;
29
+ get name(): string;
30
+ close(): Promise<void>;
31
+ }
32
+ //# sourceMappingURL=NobleBleChannel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NobleBleChannel.d.ts","sourceRoot":"","sources":["../../src/NobleBleChannel.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACH,OAAO,EACP,WAAW,EAGX,YAAY,EACZ,aAAa,EAEb,kBAAkB,EAErB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAUH,UAAU,EAGV,iBAAiB,EACpB,MAAM,6BAA6B,CAAC;AAErC,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AA6BpE,qBAAa,wBAAyB,YAAW,YAAY;IACzD,OAAO,CAAC,YAAY,CAA6C;IACjE,OAAO,CAAC,uBAAuB,CAAwE;IAEvG,WAAW,CAAC,OAAO,EAAE,aAAa,EAAE,QAAQ,SAAI,GAAG,OAAO,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IAwI/E,MAAM,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC,UAAU,CAAC,EAAE,IAAI,EAAE,UAAU,KAAK,IAAI,GAAG,kBAAkB,CAAC,QAAQ;IAOhG,KAAK;IAMX,QAAQ,CAAC,IAAI,EAAE,WAAW,EAAE,QAAQ,CAAC,EAAE,MAAM;CAMhD;AAED,qBAAa,eAAgB,SAAQ,UAAU,CAAC,UAAU,CAAC;IA6EnD,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,UAAU;WA7ElB,MAAM,CACf,UAAU,EAAE,UAAU,EACtB,wBAAwB,EAAE,cAAc,EACxC,4BAA4B,EAAE,cAAc,EAC5C,uBAAuB,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC,UAAU,CAAC,EAAE,IAAI,EAAE,UAAU,KAAK,IAAI,EAChF,mCAAmC,CAAC,EAAE,UAAU,GACjD,OAAO,CAAC,eAAe,CAAC;IAmE3B,OAAO,CAAC,SAAS,CAAQ;gBAGJ,UAAU,EAAE,UAAU,EACtB,UAAU,EAAE,iBAAiB;IAUlD;;;;OAIG;IACG,IAAI,CAAC,IAAI,EAAE,UAAU;IAY3B,IAAI,IAAI,WAEP;IAEK,KAAK;CAId"}
@@ -0,0 +1,266 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2022-2024 Matter.js Authors
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import {
7
+ ChannelType,
8
+ InternalError,
9
+ Logger,
10
+ Time,
11
+ createPromise
12
+ } from "@matter/general";
13
+ import {
14
+ BLE_MATTER_C1_CHARACTERISTIC_UUID,
15
+ BLE_MATTER_C2_CHARACTERISTIC_UUID,
16
+ BLE_MATTER_C3_CHARACTERISTIC_UUID,
17
+ BLE_MATTER_SERVICE_UUID,
18
+ BLE_MAXIMUM_BTP_MTU,
19
+ BTP_CONN_RSP_TIMEOUT_MS,
20
+ BTP_MAXIMUM_WINDOW_SIZE,
21
+ BTP_SUPPORTED_VERSIONS,
22
+ Ble,
23
+ BleChannel,
24
+ BleError,
25
+ BtpFlowError,
26
+ BtpSessionHandler
27
+ } from "@project-chip/matter.js/ble";
28
+ import { BtpCodec } from "@project-chip/matter.js/codec";
29
+ const logger = Logger.get("BleChannel");
30
+ function nobleUuidToUuid(uuid) {
31
+ uuid = uuid.toUpperCase();
32
+ if (uuid.length !== 32) {
33
+ return uuid;
34
+ }
35
+ const parts = [
36
+ uuid.substring(0, 8),
37
+ uuid.substring(8, 12),
38
+ uuid.substring(12, 16),
39
+ uuid.substring(16, 20),
40
+ uuid.substring(20, 32)
41
+ ];
42
+ return parts.join("-");
43
+ }
44
+ class NobleBleCentralInterface {
45
+ openChannels = /* @__PURE__ */ new Map();
46
+ onMatterMessageListener;
47
+ openChannel(address, tryCount = 1) {
48
+ return new Promise((resolve, reject) => {
49
+ if (this.onMatterMessageListener === void 0) {
50
+ reject(new InternalError(`Network Interface was not added to the system yet.`));
51
+ return;
52
+ }
53
+ if (address.type !== "ble") {
54
+ reject(new InternalError(`Unsupported address type ${address.type}.`));
55
+ return;
56
+ }
57
+ const { peripheral, hasAdditionalAdvertisementData } = Ble.get().getBleScanner().getDiscoveredDevice(address.peripheralAddress);
58
+ if (tryCount > 3) {
59
+ reject(new BleError(`Failed to connect to peripheral ${peripheral.address}`));
60
+ return;
61
+ }
62
+ logger.debug("BLE peripheral state", peripheral.state);
63
+ if (peripheral.state === "connected" || peripheral.state === "connecting") {
64
+ reject(
65
+ new BleError(
66
+ `Peripheral ${address.peripheralAddress} is already connected or connecting. Only one connection supported right now.`
67
+ )
68
+ );
69
+ return;
70
+ }
71
+ if (this.openChannels.has(address)) {
72
+ reject(
73
+ new BleError(
74
+ `Peripheral ${address.peripheralAddress} is already connected. Only one connection supported right now.`
75
+ )
76
+ );
77
+ return;
78
+ }
79
+ if (peripheral.state !== "disconnected") {
80
+ peripheral.disconnectAsync().then(() => this.openChannel(address, tryCount), reject);
81
+ return;
82
+ }
83
+ peripheral.once("connect", async () => {
84
+ if (this.onMatterMessageListener === void 0) {
85
+ reject(new InternalError(`Network Interface was not added to the system yet.`));
86
+ return;
87
+ }
88
+ const services = await peripheral.discoverServicesAsync([BLE_MATTER_SERVICE_UUID]);
89
+ logger.debug(`Found services: ${services.map((s) => s.uuid).join(", ")}`);
90
+ for (const service of services) {
91
+ logger.debug(`found service: ${service.uuid}`);
92
+ if (service.uuid !== BLE_MATTER_SERVICE_UUID) continue;
93
+ const characteristics = await service.discoverCharacteristicsAsync();
94
+ let characteristicC1ForWrite;
95
+ let characteristicC2ForSubscribe;
96
+ let additionalCommissioningRelatedData;
97
+ for (const characteristic of characteristics) {
98
+ logger.debug("found characteristic:", characteristic.uuid, characteristic.properties);
99
+ switch (nobleUuidToUuid(characteristic.uuid)) {
100
+ case BLE_MATTER_C1_CHARACTERISTIC_UUID:
101
+ logger.debug("found C1 characteristic");
102
+ characteristicC1ForWrite = characteristic;
103
+ break;
104
+ case BLE_MATTER_C2_CHARACTERISTIC_UUID:
105
+ logger.debug("found C2 characteristic");
106
+ characteristicC2ForSubscribe = characteristic;
107
+ break;
108
+ case BLE_MATTER_C3_CHARACTERISTIC_UUID:
109
+ logger.debug("found C3 characteristic");
110
+ if (hasAdditionalAdvertisementData) {
111
+ logger.debug("reading additional commissioning related data");
112
+ const data = await characteristic.readAsync();
113
+ additionalCommissioningRelatedData = new Uint8Array(data);
114
+ logger.debug("additional data", data);
115
+ }
116
+ }
117
+ }
118
+ if (!characteristicC1ForWrite || !characteristicC2ForSubscribe) {
119
+ logger.debug("missing characteristics");
120
+ continue;
121
+ }
122
+ peripheral.removeAllListeners("disconnect");
123
+ this.openChannels.set(address, peripheral);
124
+ resolve(
125
+ await NobleBleChannel.create(
126
+ peripheral,
127
+ characteristicC1ForWrite,
128
+ characteristicC2ForSubscribe,
129
+ this.onMatterMessageListener,
130
+ additionalCommissioningRelatedData
131
+ )
132
+ );
133
+ return;
134
+ }
135
+ peripheral.removeAllListeners("disconnect");
136
+ reject(new BleError(`Peripheral ${peripheral.address} does not have the required characteristics`));
137
+ });
138
+ const reTryHandler = async (error) => {
139
+ if (error) {
140
+ logger.error(
141
+ `Peripheral ${peripheral.address} disconnected while trying to connect, try again`,
142
+ error
143
+ );
144
+ } else {
145
+ logger.info(`Peripheral ${peripheral.address} disconnected while trying to connect, try gain`);
146
+ }
147
+ peripheral.removeAllListeners("disconnect");
148
+ peripheral.removeAllListeners("connect");
149
+ this.openChannel(address, tryCount + 1).then(resolve).catch(reject);
150
+ };
151
+ peripheral.once("disconnect", reTryHandler);
152
+ logger.debug(`Connect to Peripheral now (try ${tryCount})`);
153
+ peripheral.connectAsync().catch(reTryHandler);
154
+ });
155
+ }
156
+ onData(listener) {
157
+ this.onMatterMessageListener = listener;
158
+ return {
159
+ close: async () => await this.close()
160
+ };
161
+ }
162
+ async close() {
163
+ for (const peripheral of this.openChannels.values()) {
164
+ await peripheral.disconnectAsync();
165
+ }
166
+ }
167
+ supports(type, _address) {
168
+ if (type !== ChannelType.BLE) {
169
+ return false;
170
+ }
171
+ return true;
172
+ }
173
+ }
174
+ class NobleBleChannel extends BleChannel {
175
+ constructor(peripheral, btpSession) {
176
+ super();
177
+ this.peripheral = peripheral;
178
+ this.btpSession = btpSession;
179
+ peripheral.once("disconnect", () => {
180
+ logger.debug(`Disconnected from peripheral ${peripheral.address}`);
181
+ this.connected = false;
182
+ void this.btpSession.close();
183
+ });
184
+ }
185
+ static async create(peripheral, characteristicC1ForWrite, characteristicC2ForSubscribe, onMatterMessageListener, _additionalCommissioningRelatedData) {
186
+ let mtu = peripheral.mtu ?? 0;
187
+ if (mtu > BLE_MAXIMUM_BTP_MTU) {
188
+ mtu = BLE_MAXIMUM_BTP_MTU;
189
+ }
190
+ logger.debug(`Using MTU=${mtu} (Peripheral MTU=${peripheral.mtu})`);
191
+ const btpHandshakeRequest = BtpCodec.encodeBtpHandshakeRequest({
192
+ versions: BTP_SUPPORTED_VERSIONS,
193
+ attMtu: mtu,
194
+ clientWindowSize: BTP_MAXIMUM_WINDOW_SIZE
195
+ });
196
+ logger.debug(`sending BTP handshake request: ${Logger.toJSON(btpHandshakeRequest)}`);
197
+ await characteristicC1ForWrite.writeAsync(Buffer.from(btpHandshakeRequest.buffer), false);
198
+ const btpHandshakeTimeout = Time.getTimer("BLE handshake timeout", BTP_CONN_RSP_TIMEOUT_MS, async () => {
199
+ await peripheral.disconnectAsync();
200
+ logger.debug("Handshake Response not received. Disconnected from peripheral");
201
+ }).start();
202
+ logger.debug("subscribing to C2 characteristic");
203
+ await characteristicC2ForSubscribe.subscribeAsync();
204
+ const { promise: handshakeResponseReceivedPromise, resolver } = createPromise();
205
+ characteristicC2ForSubscribe.once("data", (data, isNotification) => {
206
+ logger.debug(`received first data on C2: ${data.toString("hex")} (isNotification: ${isNotification})`);
207
+ if (data[0] === 101 && data[1] === 108 && data.length === 6) {
208
+ logger.info(`Received Matter handshake response: ${data.toString("hex")}.`);
209
+ btpHandshakeTimeout.stop();
210
+ resolver(data);
211
+ }
212
+ });
213
+ const handshakeResponse = await handshakeResponseReceivedPromise;
214
+ const btpSession = await BtpSessionHandler.createAsCentral(
215
+ new Uint8Array(handshakeResponse),
216
+ // callback to write data to characteristic C1
217
+ async (data) => {
218
+ return await characteristicC1ForWrite.writeAsync(Buffer.from(data.buffer), false);
219
+ },
220
+ // callback to disconnect the BLE connection
221
+ async () => void characteristicC2ForSubscribe.unsubscribeAsync().then(() => peripheral.disconnectAsync().then(() => logger.debug("disconnected from peripheral"))),
222
+ // callback to forward decoded and de-assembled Matter messages to ExchangeManager
223
+ async (data) => {
224
+ if (onMatterMessageListener === void 0) {
225
+ throw new InternalError(`No listener registered for Matter messages`);
226
+ }
227
+ onMatterMessageListener(nobleChannel, data);
228
+ }
229
+ );
230
+ characteristicC2ForSubscribe.on("data", (data, isNotification) => {
231
+ logger.debug(`received data on C2: ${data.toString("hex")} (isNotification: ${isNotification})`);
232
+ void btpSession.handleIncomingBleData(new Uint8Array(data));
233
+ });
234
+ const nobleChannel = new NobleBleChannel(peripheral, btpSession);
235
+ return nobleChannel;
236
+ }
237
+ connected = true;
238
+ /**
239
+ * Send a Matter message to the connected device - need to do BTP assembly first.
240
+ *
241
+ * @param data
242
+ */
243
+ async send(data) {
244
+ if (!this.connected) {
245
+ logger.debug("Cannot send data because not connected to peripheral.");
246
+ return;
247
+ }
248
+ if (this.btpSession === void 0) {
249
+ throw new BtpFlowError(`Cannot send data, no BTP session initialized`);
250
+ }
251
+ await this.btpSession.sendMatterMessage(data);
252
+ }
253
+ // Channel<Uint8Array>
254
+ get name() {
255
+ return `${this.type}://${this.peripheral.address}`;
256
+ }
257
+ async close() {
258
+ await this.btpSession.close();
259
+ await this.peripheral.disconnectAsync();
260
+ }
261
+ }
262
+ export {
263
+ NobleBleCentralInterface,
264
+ NobleBleChannel
265
+ };
266
+ //# sourceMappingURL=NobleBleChannel.js.map
@@ -0,0 +1,6 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/NobleBleChannel.ts"],
4
+ "mappings": "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",
5
+ "names": []
6
+ }
@@ -0,0 +1,20 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2022-2024 Matter.js Authors
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import type { Peripheral } from "@stoprocent/noble";
7
+ import { BleOptions } from "./NodeJsBle.js";
8
+ export declare class NobleBleClient {
9
+ private readonly discoveredPeripherals;
10
+ private shouldScan;
11
+ private isScanning;
12
+ private nobleState;
13
+ private deviceDiscoveredCallback;
14
+ constructor(options?: BleOptions);
15
+ setDiscoveryCallback(callback: (peripheral: Peripheral, manufacturerData: Uint8Array) => void): void;
16
+ startScanning(): Promise<void>;
17
+ stopScanning(): Promise<void>;
18
+ private handleDiscoveredDevice;
19
+ }
20
+ //# sourceMappingURL=NobleBleClient.d.ts.map