@matter/nodejs-ble 0.17.0-alpha.0-20260507-059f7763b → 0.17.0-alpha.0-20260508-29ff5ae9e
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/package.json +4 -4
- package/dist/cjs/BleScanner.d.ts +0 -19
- package/dist/cjs/BleScanner.d.ts.map +0 -1
- package/dist/cjs/BleScanner.js +0 -43
- package/dist/cjs/BleScanner.js.map +0 -6
- package/dist/cjs/BlenoBleServer.d.ts +0 -74
- package/dist/cjs/BlenoBleServer.d.ts.map +0 -1
- package/dist/cjs/BlenoBleServer.js +0 -415
- package/dist/cjs/BlenoBleServer.js.map +0 -6
- package/dist/cjs/BlenoPeripheralInterface.d.ts +0 -19
- package/dist/cjs/BlenoPeripheralInterface.d.ts.map +0 -1
- package/dist/cjs/BlenoPeripheralInterface.js +0 -63
- package/dist/cjs/BlenoPeripheralInterface.js.map +0 -6
- package/dist/cjs/NobleBleChannel.d.ts +0 -38
- package/dist/cjs/NobleBleChannel.d.ts.map +0 -1
- package/dist/cjs/NobleBleChannel.js +0 -601
- package/dist/cjs/NobleBleChannel.js.map +0 -6
- package/dist/cjs/NobleBleClient.d.ts +0 -24
- package/dist/cjs/NobleBleClient.d.ts.map +0 -1
- package/dist/cjs/NobleBleClient.js +0 -153
- package/dist/cjs/NobleBleClient.js.map +0 -6
- package/dist/cjs/NodeJsBle.d.ts +0 -20
- package/dist/cjs/NodeJsBle.d.ts.map +0 -1
- package/dist/cjs/NodeJsBle.js +0 -86
- package/dist/cjs/NodeJsBle.js.map +0 -6
- package/dist/cjs/index.d.ts +0 -9
- package/dist/cjs/index.d.ts.map +0 -1
- package/dist/cjs/index.js +0 -26
- package/dist/cjs/index.js.map +0 -6
- package/dist/cjs/install.d.ts +0 -7
- package/dist/cjs/install.d.ts.map +0 -1
- package/dist/cjs/install.js +0 -29
- package/dist/cjs/install.js.map +0 -6
- package/dist/cjs/package.json +0 -3
- package/dist/esm/BleScanner.js +0 -23
- package/dist/esm/BleScanner.js.map +0 -6
- package/dist/esm/BlenoBleServer.js +0 -403
- package/dist/esm/BlenoBleServer.js.map +0 -6
- package/dist/esm/BlenoPeripheralInterface.js +0 -43
- package/dist/esm/BlenoPeripheralInterface.js.map +0 -6
- package/dist/esm/NobleBleChannel.js +0 -601
- package/dist/esm/NobleBleChannel.js.map +0 -6
- package/dist/esm/NobleBleClient.js +0 -133
- package/dist/esm/NobleBleClient.js.map +0 -6
- package/dist/esm/NodeJsBle.js +0 -66
- package/dist/esm/NodeJsBle.js.map +0 -6
- package/dist/esm/index.js +0 -9
- package/dist/esm/index.js.map +0 -6
- package/dist/esm/install.js +0 -28
- package/dist/esm/install.js.map +0 -6
- package/dist/esm/package.json +0 -3
|
@@ -1,601 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @license
|
|
3
|
-
* Copyright 2022-2026 Matter.js Authors
|
|
4
|
-
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
-
*/
|
|
6
|
-
import {
|
|
7
|
-
Bytes,
|
|
8
|
-
ChannelType,
|
|
9
|
-
Diagnostic,
|
|
10
|
-
InternalError,
|
|
11
|
-
Logger,
|
|
12
|
-
Minutes,
|
|
13
|
-
NetworkError,
|
|
14
|
-
ServerAddress,
|
|
15
|
-
Time,
|
|
16
|
-
asError,
|
|
17
|
-
createPromise
|
|
18
|
-
} from "@matter/general";
|
|
19
|
-
import {
|
|
20
|
-
BleChannel,
|
|
21
|
-
BleDisconnectedError,
|
|
22
|
-
BleError,
|
|
23
|
-
BtpCodec,
|
|
24
|
-
BtpFlowError,
|
|
25
|
-
BtpSessionHandler,
|
|
26
|
-
MatterBle
|
|
27
|
-
} from "@matter/protocol";
|
|
28
|
-
const logger = Logger.get("BleChannel");
|
|
29
|
-
function isNobleDisconnectError(error) {
|
|
30
|
-
if (!(error instanceof Error)) {
|
|
31
|
-
return false;
|
|
32
|
-
}
|
|
33
|
-
if (error.message.startsWith("Disconnected")) {
|
|
34
|
-
return true;
|
|
35
|
-
}
|
|
36
|
-
const match = error.message.match(/^status:\s*(\d+)/);
|
|
37
|
-
return match !== null && Number(match[1]) >= 2;
|
|
38
|
-
}
|
|
39
|
-
function nobleUuidToUuid(uuid) {
|
|
40
|
-
uuid = uuid.toUpperCase();
|
|
41
|
-
if (uuid.length !== 32) {
|
|
42
|
-
return uuid;
|
|
43
|
-
}
|
|
44
|
-
const parts = [
|
|
45
|
-
uuid.substring(0, 8),
|
|
46
|
-
uuid.substring(8, 12),
|
|
47
|
-
uuid.substring(12, 16),
|
|
48
|
-
uuid.substring(16, 20),
|
|
49
|
-
uuid.substring(20, 32)
|
|
50
|
-
];
|
|
51
|
-
return parts.join("-");
|
|
52
|
-
}
|
|
53
|
-
class NobleBleCentralInterface {
|
|
54
|
-
#bleScanner;
|
|
55
|
-
#connectionsInProgress = /* @__PURE__ */ new Set();
|
|
56
|
-
#connectionGuards = /* @__PURE__ */ new Set();
|
|
57
|
-
#openChannels = /* @__PURE__ */ new Map();
|
|
58
|
-
#onMatterMessageListener;
|
|
59
|
-
#closed = false;
|
|
60
|
-
constructor(bleScanner) {
|
|
61
|
-
this.#bleScanner = bleScanner;
|
|
62
|
-
}
|
|
63
|
-
openChannel(address, tryCount = 1) {
|
|
64
|
-
if (this.#closed) {
|
|
65
|
-
throw new NetworkError("Network interface is closed");
|
|
66
|
-
}
|
|
67
|
-
return new Promise((resolve, reject) => {
|
|
68
|
-
let resolvedOrRejected = false;
|
|
69
|
-
function rejectOnce(error) {
|
|
70
|
-
if (!resolvedOrRejected) {
|
|
71
|
-
resolvedOrRejected = true;
|
|
72
|
-
reject(asError(error));
|
|
73
|
-
} else {
|
|
74
|
-
logger.debug(`Already resolved or rejected, ignore error:`, error);
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
function resolveOnce(value) {
|
|
78
|
-
if (!resolvedOrRejected) {
|
|
79
|
-
resolvedOrRejected = true;
|
|
80
|
-
resolve(value);
|
|
81
|
-
} else {
|
|
82
|
-
logger.debug(`Already resolved or rejected, ignore success`);
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
if (this.#onMatterMessageListener === void 0) {
|
|
86
|
-
rejectOnce(
|
|
87
|
-
new InternalError(`Network Interface was not added to the system yet, so can not connect it.`)
|
|
88
|
-
);
|
|
89
|
-
return;
|
|
90
|
-
}
|
|
91
|
-
if (!ServerAddress.isBle(address)) {
|
|
92
|
-
rejectOnce(new InternalError(`Unsupported address type for BLE channel.`));
|
|
93
|
-
return;
|
|
94
|
-
}
|
|
95
|
-
const { peripheralAddress } = address;
|
|
96
|
-
if (tryCount > 3) {
|
|
97
|
-
rejectOnce(new BleError(`Failed to connect to peripheral ${peripheralAddress}`));
|
|
98
|
-
return;
|
|
99
|
-
}
|
|
100
|
-
const { peripheral, hasAdditionalAdvertisementData } = this.#bleScanner.getDiscoveredDevice(peripheralAddress);
|
|
101
|
-
if (this.#openChannels.has(peripheralAddress)) {
|
|
102
|
-
rejectOnce(
|
|
103
|
-
new BleError(
|
|
104
|
-
`Peripheral ${peripheralAddress} is already connected. Only one connection supported right now.`
|
|
105
|
-
)
|
|
106
|
-
);
|
|
107
|
-
return;
|
|
108
|
-
}
|
|
109
|
-
if (this.#connectionsInProgress.has(peripheralAddress)) {
|
|
110
|
-
rejectOnce(new BleError(`Connection to peripheral ${peripheralAddress} is already in progress.`));
|
|
111
|
-
return;
|
|
112
|
-
}
|
|
113
|
-
this.#connectionsInProgress.add(peripheralAddress);
|
|
114
|
-
if (peripheral.state === "error") {
|
|
115
|
-
this.#connectionsInProgress.delete(peripheralAddress);
|
|
116
|
-
rejectOnce(
|
|
117
|
-
new BleError(
|
|
118
|
-
`Can not connect to peripheral "${peripheralAddress}" because unexpected state "${peripheral.state}"`
|
|
119
|
-
)
|
|
120
|
-
);
|
|
121
|
-
return;
|
|
122
|
-
}
|
|
123
|
-
let connectListener;
|
|
124
|
-
const connectionGuard = {
|
|
125
|
-
// Timeout when trying to connect to the device because sometimes connect fails and noble does
|
|
126
|
-
// not emit an event. If device does not connect we do not try any longer and reject the promise
|
|
127
|
-
// because a re-discovery is the best option to get teh device into a good state again
|
|
128
|
-
connectTimeout: Time.getTimer("BLE connect timeout", Minutes(2), () => {
|
|
129
|
-
logger.debug(`Timeout while connecting to peripheral ${peripheralAddress}`);
|
|
130
|
-
peripheral.removeListener("connect", connectListener);
|
|
131
|
-
peripheral.removeListener("disconnect", reTryHandler);
|
|
132
|
-
clearConnectionGuard();
|
|
133
|
-
this.#connectionsInProgress.delete(peripheralAddress);
|
|
134
|
-
rejectOnce(new BleError(`Timeout while connecting to peripheral ${peripheralAddress}`));
|
|
135
|
-
}),
|
|
136
|
-
disconnectTimeout: Time.getTimer("BLE disconnect timeout", Minutes.one, () => {
|
|
137
|
-
logger.debug(`Timeout while disconnecting to peripheral ${peripheralAddress}`);
|
|
138
|
-
peripheral.removeListener("disconnect", reTryHandler);
|
|
139
|
-
clearConnectionGuard();
|
|
140
|
-
this.#connectionsInProgress.delete(peripheralAddress);
|
|
141
|
-
rejectOnce(new BleError(`Timeout while disconnecting to peripheral ${peripheralAddress}`));
|
|
142
|
-
}),
|
|
143
|
-
// Timeout when trying to interview the device because sometimes when no response from device
|
|
144
|
-
// comes noble does not resolve promises
|
|
145
|
-
interviewTimeout: Time.getTimer("BLE interview timeout", Minutes.one, () => {
|
|
146
|
-
logger.debug(`Timeout while interviewing peripheral ${peripheralAddress}`);
|
|
147
|
-
peripheral.removeListener("disconnect", reTryHandler);
|
|
148
|
-
clearConnectionGuard();
|
|
149
|
-
this.#connectionsInProgress.delete(peripheralAddress);
|
|
150
|
-
if (peripheral.state === "connected") {
|
|
151
|
-
peripheral.disconnectAsync().catch((error) => logger.error(`Ignored error while disconnecting`, error));
|
|
152
|
-
}
|
|
153
|
-
rejectOnce(new BleError(`Timeout while interviewing peripheral ${peripheralAddress}`));
|
|
154
|
-
})
|
|
155
|
-
};
|
|
156
|
-
this.#connectionGuards.add(connectionGuard);
|
|
157
|
-
const clearConnectionGuard = () => {
|
|
158
|
-
const { connectTimeout, interviewTimeout, disconnectTimeout } = connectionGuard;
|
|
159
|
-
connectTimeout?.stop();
|
|
160
|
-
interviewTimeout?.stop();
|
|
161
|
-
disconnectTimeout?.stop();
|
|
162
|
-
this.#connectionGuards.delete(connectionGuard);
|
|
163
|
-
};
|
|
164
|
-
const reTryHandler = (error) => {
|
|
165
|
-
clearConnectionGuard();
|
|
166
|
-
this.#connectionsInProgress.delete(peripheralAddress);
|
|
167
|
-
peripheral.removeListener("connect", connectListener);
|
|
168
|
-
peripheral.removeListener("disconnect", reTryHandler);
|
|
169
|
-
if (error) {
|
|
170
|
-
logger.info(
|
|
171
|
-
`Peripheral ${peripheralAddress} disconnected while trying to connect, try again`,
|
|
172
|
-
error
|
|
173
|
-
);
|
|
174
|
-
} else {
|
|
175
|
-
logger.info(`Peripheral ${peripheralAddress} disconnected while trying to connect, try again`);
|
|
176
|
-
}
|
|
177
|
-
this.openChannel(address, tryCount + 1).then(resolveOnce).catch(rejectOnce);
|
|
178
|
-
};
|
|
179
|
-
const connectHandler = async (error) => {
|
|
180
|
-
connectionGuard.connectTimeout.stop();
|
|
181
|
-
if (!this.#connectionGuards.has(connectionGuard)) {
|
|
182
|
-
return;
|
|
183
|
-
}
|
|
184
|
-
if (error) {
|
|
185
|
-
clearConnectionGuard();
|
|
186
|
-
this.#connectionsInProgress.delete(peripheralAddress);
|
|
187
|
-
peripheral.removeListener("disconnect", reTryHandler);
|
|
188
|
-
rejectOnce(
|
|
189
|
-
new BleError(`Error while connecting to peripheral ${peripheralAddress}`, { cause: error })
|
|
190
|
-
);
|
|
191
|
-
return;
|
|
192
|
-
}
|
|
193
|
-
if (this.#onMatterMessageListener === void 0) {
|
|
194
|
-
clearConnectionGuard();
|
|
195
|
-
this.#connectionsInProgress.delete(peripheralAddress);
|
|
196
|
-
peripheral.removeListener("disconnect", reTryHandler);
|
|
197
|
-
rejectOnce(new InternalError(`Network Interface was not added to the system yet or was cleared.`));
|
|
198
|
-
return;
|
|
199
|
-
}
|
|
200
|
-
try {
|
|
201
|
-
connectionGuard.interviewTimeout.start();
|
|
202
|
-
const services = await peripheral.discoverServicesAsync([MatterBle.SERVICE_UUID_SHORT]);
|
|
203
|
-
if (!this.#connectionGuards.has(connectionGuard)) {
|
|
204
|
-
return;
|
|
205
|
-
}
|
|
206
|
-
logger.debug(
|
|
207
|
-
`Peripheral ${peripheralAddress}: Found services: ${services.map((s) => s.uuid).join(", ")}`
|
|
208
|
-
);
|
|
209
|
-
for (const service of services) {
|
|
210
|
-
logger.debug(`Peripheral ${peripheralAddress}: Handle service: ${service.uuid}`);
|
|
211
|
-
if (!MatterBle.isServiceUuid(service.uuid)) continue;
|
|
212
|
-
const characteristics = await service.discoverCharacteristicsAsync();
|
|
213
|
-
if (!this.#connectionGuards.has(connectionGuard)) {
|
|
214
|
-
return;
|
|
215
|
-
}
|
|
216
|
-
let characteristicC1ForWrite;
|
|
217
|
-
let characteristicC2ForSubscribe;
|
|
218
|
-
let additionalCommissioningRelatedData;
|
|
219
|
-
for (const characteristic of characteristics) {
|
|
220
|
-
logger.debug(
|
|
221
|
-
`Peripheral ${peripheralAddress}: Handle characteristic:`,
|
|
222
|
-
characteristic.uuid,
|
|
223
|
-
characteristic.properties
|
|
224
|
-
);
|
|
225
|
-
switch (nobleUuidToUuid(characteristic.uuid)) {
|
|
226
|
-
case MatterBle.C1_CHARACTERISTIC_UUID:
|
|
227
|
-
logger.debug(`Peripheral ${peripheralAddress}: Found C1 characteristic`);
|
|
228
|
-
characteristicC1ForWrite = characteristic;
|
|
229
|
-
break;
|
|
230
|
-
case MatterBle.C2_CHARACTERISTIC_UUID:
|
|
231
|
-
logger.debug(`Peripheral ${peripheralAddress}: Found C2 characteristic`);
|
|
232
|
-
characteristicC2ForSubscribe = characteristic;
|
|
233
|
-
break;
|
|
234
|
-
case MatterBle.C3_CHARACTERISTIC_UUID:
|
|
235
|
-
logger.debug(`Peripheral ${peripheralAddress}: Found C3 characteristic`);
|
|
236
|
-
if (hasAdditionalAdvertisementData) {
|
|
237
|
-
logger.debug(
|
|
238
|
-
`Peripheral ${peripheralAddress}: Reading additional commissioning related data`
|
|
239
|
-
);
|
|
240
|
-
const data = await characteristic.readAsync();
|
|
241
|
-
if (!this.#connectionGuards.has(connectionGuard)) {
|
|
242
|
-
return;
|
|
243
|
-
}
|
|
244
|
-
additionalCommissioningRelatedData = new Uint8Array(data);
|
|
245
|
-
logger.debug(`Peripheral ${peripheralAddress}: Additional data:`, data);
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
if (!characteristicC1ForWrite || !characteristicC2ForSubscribe) {
|
|
250
|
-
logger.debug(
|
|
251
|
-
`Peripheral ${peripheralAddress}: Missing required Matter characteristics. Ignore.`
|
|
252
|
-
);
|
|
253
|
-
continue;
|
|
254
|
-
}
|
|
255
|
-
connectionGuard.interviewTimeout.stop();
|
|
256
|
-
peripheral.removeListener("disconnect", reTryHandler);
|
|
257
|
-
this.#openChannels.set(peripheralAddress, peripheral);
|
|
258
|
-
peripheral.once("disconnect", () => this.#openChannels.delete(peripheralAddress));
|
|
259
|
-
try {
|
|
260
|
-
resolveOnce(
|
|
261
|
-
await NobleBleChannel.create(
|
|
262
|
-
peripheral,
|
|
263
|
-
characteristicC1ForWrite,
|
|
264
|
-
characteristicC2ForSubscribe,
|
|
265
|
-
this.#onMatterMessageListener,
|
|
266
|
-
additionalCommissioningRelatedData
|
|
267
|
-
)
|
|
268
|
-
);
|
|
269
|
-
clearConnectionGuard();
|
|
270
|
-
this.#connectionsInProgress.delete(peripheralAddress);
|
|
271
|
-
return;
|
|
272
|
-
} catch (error2) {
|
|
273
|
-
this.#connectionsInProgress.delete(peripheralAddress);
|
|
274
|
-
this.#openChannels.delete(peripheralAddress);
|
|
275
|
-
if (peripheral.state === "connected") {
|
|
276
|
-
logger.debug(
|
|
277
|
-
`Disconnect because of initialization error of peripheral ${ServerAddress.urlFor(address)}`
|
|
278
|
-
);
|
|
279
|
-
await peripheral.disconnectAsync().catch(
|
|
280
|
-
(error3) => logger.debug(
|
|
281
|
-
`Peripheral ${peripheral.address}: Error while disconnecting`,
|
|
282
|
-
error3
|
|
283
|
-
)
|
|
284
|
-
);
|
|
285
|
-
}
|
|
286
|
-
reTryHandler(error2);
|
|
287
|
-
return;
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
} catch (error2) {
|
|
291
|
-
if (this.#connectionGuards.has(connectionGuard)) {
|
|
292
|
-
reTryHandler(error2);
|
|
293
|
-
}
|
|
294
|
-
return;
|
|
295
|
-
} finally {
|
|
296
|
-
this.#connectionsInProgress.delete(peripheralAddress);
|
|
297
|
-
clearConnectionGuard();
|
|
298
|
-
}
|
|
299
|
-
peripheral.removeListener("disconnect", reTryHandler);
|
|
300
|
-
rejectOnce(
|
|
301
|
-
new BleError(`Peripheral ${peripheralAddress} does not have the required Matter characteristics`)
|
|
302
|
-
);
|
|
303
|
-
};
|
|
304
|
-
connectListener = (error) => {
|
|
305
|
-
connectHandler(error).catch((handlerError) => {
|
|
306
|
-
logger.warn(`Peripheral ${peripheralAddress}: Unexpected error in connect handler`, handlerError);
|
|
307
|
-
clearConnectionGuard();
|
|
308
|
-
this.#connectionsInProgress.delete(peripheralAddress);
|
|
309
|
-
peripheral.removeListener("disconnect", reTryHandler);
|
|
310
|
-
rejectOnce(handlerError);
|
|
311
|
-
});
|
|
312
|
-
};
|
|
313
|
-
if (peripheral.state === "connected") {
|
|
314
|
-
logger.debug(`Peripheral ${peripheralAddress}: Already connected`);
|
|
315
|
-
connectHandler().catch((error) => {
|
|
316
|
-
logger.warn(`Peripheral ${peripheralAddress}: Unexpected error in connect handler`, error);
|
|
317
|
-
clearConnectionGuard();
|
|
318
|
-
this.#connectionsInProgress.delete(peripheralAddress);
|
|
319
|
-
peripheral.removeListener("disconnect", reTryHandler);
|
|
320
|
-
rejectOnce(error);
|
|
321
|
-
});
|
|
322
|
-
} else if (peripheral.state === "disconnecting") {
|
|
323
|
-
logger.debug(`Peripheral ${peripheralAddress}: Disconnect in progress`);
|
|
324
|
-
connectionGuard.disconnectTimeout.start();
|
|
325
|
-
tryCount--;
|
|
326
|
-
peripheral.once("disconnect", reTryHandler);
|
|
327
|
-
} else {
|
|
328
|
-
if (peripheral.state === "connecting") {
|
|
329
|
-
peripheral.cancelConnect();
|
|
330
|
-
}
|
|
331
|
-
connectionGuard.connectTimeout.start();
|
|
332
|
-
peripheral.once("connect", connectListener);
|
|
333
|
-
peripheral.once("disconnect", reTryHandler);
|
|
334
|
-
logger.debug(`Peripheral ${peripheralAddress}: Connect to Peripheral now (try ${tryCount})`);
|
|
335
|
-
peripheral.connectAsync().catch((error) => {
|
|
336
|
-
if (!this.#connectionGuards.has(connectionGuard)) {
|
|
337
|
-
return;
|
|
338
|
-
}
|
|
339
|
-
logger.info(`Peripheral ${peripheralAddress}: Error while connecting to peripheral`, error);
|
|
340
|
-
reTryHandler(error);
|
|
341
|
-
});
|
|
342
|
-
}
|
|
343
|
-
});
|
|
344
|
-
}
|
|
345
|
-
onData(listener) {
|
|
346
|
-
this.#onMatterMessageListener = listener;
|
|
347
|
-
return {
|
|
348
|
-
close: async () => await this.close()
|
|
349
|
-
};
|
|
350
|
-
}
|
|
351
|
-
async close() {
|
|
352
|
-
this.#closed = true;
|
|
353
|
-
for (const peripheral of this.#openChannels.values()) {
|
|
354
|
-
if (peripheral.state === "connected") {
|
|
355
|
-
logger.debug(`Peripheral ${peripheral.address}: Disconnect from peripheral while closing central`);
|
|
356
|
-
peripheral.disconnectAsync().catch((error) => logger.error(`Peripheral ${peripheral.address}: Error while disconnecting`, error));
|
|
357
|
-
}
|
|
358
|
-
}
|
|
359
|
-
this.#openChannels.clear();
|
|
360
|
-
}
|
|
361
|
-
supports(type, _address) {
|
|
362
|
-
if (type !== ChannelType.BLE) {
|
|
363
|
-
return false;
|
|
364
|
-
}
|
|
365
|
-
return true;
|
|
366
|
-
}
|
|
367
|
-
}
|
|
368
|
-
class NobleBleChannel extends BleChannel {
|
|
369
|
-
constructor(peripheral, btpSession, cleanupDataListener) {
|
|
370
|
-
super();
|
|
371
|
-
this.peripheral = peripheral;
|
|
372
|
-
this.btpSession = btpSession;
|
|
373
|
-
this.#cleanupDataListener = cleanupDataListener;
|
|
374
|
-
peripheral.once("disconnect", () => {
|
|
375
|
-
logger.debug(`Disconnected from peripheral ${peripheral.address}. Closing BTP session`);
|
|
376
|
-
this.#connected = false;
|
|
377
|
-
this.#cleanupDataListener();
|
|
378
|
-
this.#terminateIterator();
|
|
379
|
-
for (const listener of this.#closeListeners) {
|
|
380
|
-
listener();
|
|
381
|
-
}
|
|
382
|
-
this.btpSession.close().catch((error) => {
|
|
383
|
-
logger.debug(`Peripheral ${peripheral.address}: Error closing BTP session on disconnect`, error);
|
|
384
|
-
});
|
|
385
|
-
this.emitClosed();
|
|
386
|
-
});
|
|
387
|
-
this.btpSession.closed.on(() => this.emitClosed());
|
|
388
|
-
}
|
|
389
|
-
peripheral;
|
|
390
|
-
btpSession;
|
|
391
|
-
static async create(peripheral, characteristicC1ForWrite, characteristicC2ForSubscribe, onMatterMessageListener, _additionalCommissioningRelatedData) {
|
|
392
|
-
const { address: peripheralAddress } = peripheral;
|
|
393
|
-
let mtu = peripheral.mtu ?? 0;
|
|
394
|
-
if (mtu > MatterBle.MAXIMUM_BTP_MTU) {
|
|
395
|
-
mtu = MatterBle.MAXIMUM_BTP_MTU;
|
|
396
|
-
}
|
|
397
|
-
logger.debug(
|
|
398
|
-
`Peripheral ${peripheralAddress}: Using MTU=${mtu} bytes (Peripheral supports up to ${peripheral.mtu} bytes)`
|
|
399
|
-
);
|
|
400
|
-
const {
|
|
401
|
-
promise: handshakeResponseReceivedPromise,
|
|
402
|
-
resolver: handshakeResolver,
|
|
403
|
-
rejecter: handshakeRejecter
|
|
404
|
-
} = createPromise();
|
|
405
|
-
const handshakeHandler = (data, isNotification) => {
|
|
406
|
-
if (data[0] === 101 && data[1] === 108 && data.length === 6) {
|
|
407
|
-
logger.info(
|
|
408
|
-
`Peripheral ${peripheralAddress}: Received Matter handshake response: ${data.toString("hex")}.`
|
|
409
|
-
);
|
|
410
|
-
btpHandshakeTimeout.stop();
|
|
411
|
-
handshakeResolver(data);
|
|
412
|
-
} else {
|
|
413
|
-
logger.debug(
|
|
414
|
-
`Peripheral ${peripheralAddress}: Received first data on C2: ${data.toString("hex")} (isNotification: ${isNotification}) - No handshake response, ignoring`
|
|
415
|
-
);
|
|
416
|
-
}
|
|
417
|
-
};
|
|
418
|
-
const btpHandshakeTimeout = Time.getTimer("BLE handshake timeout", MatterBle.BTP_CONN_RSP_TIMEOUT, async () => {
|
|
419
|
-
characteristicC2ForSubscribe.removeListener("data", handshakeHandler);
|
|
420
|
-
if (peripheral.state === "connected") {
|
|
421
|
-
await characteristicC2ForSubscribe.unsubscribeAsync().catch((error) => {
|
|
422
|
-
if (!isNobleDisconnectError(error)) {
|
|
423
|
-
logger.error(`Peripheral ${peripheralAddress}: Error while unsubscribing`, error);
|
|
424
|
-
}
|
|
425
|
-
});
|
|
426
|
-
}
|
|
427
|
-
logger.debug(
|
|
428
|
-
`Peripheral ${peripheralAddress}: Handshake Response not received. Disconnect from peripheral`
|
|
429
|
-
);
|
|
430
|
-
handshakeRejecter(new BleError(`Peripheral ${peripheralAddress}: Handshake Response not received`));
|
|
431
|
-
}).start();
|
|
432
|
-
const btpHandshakeRequest = BtpCodec.encodeBtpHandshakeRequest({
|
|
433
|
-
versions: MatterBle.BTP_SUPPORTED_VERSIONS,
|
|
434
|
-
attMtu: mtu,
|
|
435
|
-
clientWindowSize: MatterBle.BTP_MAXIMUM_WINDOW_SIZE
|
|
436
|
-
});
|
|
437
|
-
logger.debug(
|
|
438
|
-
`Peripheral ${peripheralAddress}: Sending BTP handshake request: ${Diagnostic.json(btpHandshakeRequest)}`
|
|
439
|
-
);
|
|
440
|
-
try {
|
|
441
|
-
await characteristicC1ForWrite.writeAsync(Buffer.from(Bytes.of(btpHandshakeRequest)), false);
|
|
442
|
-
characteristicC2ForSubscribe.on("data", handshakeHandler);
|
|
443
|
-
logger.debug(`Peripheral ${peripheralAddress}: Subscribing to C2 characteristic`);
|
|
444
|
-
await characteristicC2ForSubscribe.subscribeAsync();
|
|
445
|
-
} catch (error) {
|
|
446
|
-
btpHandshakeTimeout.stop();
|
|
447
|
-
characteristicC2ForSubscribe.removeListener("data", handshakeHandler);
|
|
448
|
-
if (isNobleDisconnectError(error)) {
|
|
449
|
-
throw new BleDisconnectedError(error.message, { cause: error });
|
|
450
|
-
}
|
|
451
|
-
throw error;
|
|
452
|
-
}
|
|
453
|
-
const handshakeResponse = await handshakeResponseReceivedPromise;
|
|
454
|
-
characteristicC2ForSubscribe.removeListener("data", handshakeHandler);
|
|
455
|
-
const btpSession = await BtpSessionHandler.createAsCentral(
|
|
456
|
-
new Uint8Array(handshakeResponse),
|
|
457
|
-
// callback to write data to characteristic C1; translates noble's disconnect/transport
|
|
458
|
-
// errors into BleDisconnectedError so BtpSessionHandler can handle them specifically
|
|
459
|
-
async (data) => {
|
|
460
|
-
try {
|
|
461
|
-
return await characteristicC1ForWrite.writeAsync(Buffer.from(Bytes.of(data)), false);
|
|
462
|
-
} catch (error) {
|
|
463
|
-
if (isNobleDisconnectError(error)) {
|
|
464
|
-
throw new BleDisconnectedError(error.message, { cause: error });
|
|
465
|
-
}
|
|
466
|
-
throw error;
|
|
467
|
-
}
|
|
468
|
-
},
|
|
469
|
-
// callback to disconnect the BLE connection
|
|
470
|
-
async () => {
|
|
471
|
-
if (peripheral.state !== "connected" || !nobleChannel.connected) return;
|
|
472
|
-
logger.debug(`Peripheral ${peripheralAddress}: Disconnect from peripheral because btp session closed`);
|
|
473
|
-
characteristicC2ForSubscribe.unsubscribeAsync().catch((error) => {
|
|
474
|
-
if (!isNobleDisconnectError(error)) {
|
|
475
|
-
logger.debug(`Peripheral ${peripheralAddress}: Error while unsubscribing from C2`, error);
|
|
476
|
-
}
|
|
477
|
-
}).then(() => {
|
|
478
|
-
if (peripheral.state !== "connected") {
|
|
479
|
-
return;
|
|
480
|
-
}
|
|
481
|
-
return peripheral.disconnectAsync().then(
|
|
482
|
-
() => logger.debug(`Peripheral ${peripheralAddress}: Disconnected from peripheral`),
|
|
483
|
-
(error) => logger.debug(`Peripheral ${peripheralAddress}: Error while disconnecting`, error)
|
|
484
|
-
);
|
|
485
|
-
}).catch(
|
|
486
|
-
(error) => logger.debug(`Peripheral ${peripheralAddress}: Error during disconnect cleanup`, error)
|
|
487
|
-
);
|
|
488
|
-
},
|
|
489
|
-
// callback to forward decoded and de-assembled Matter messages
|
|
490
|
-
async (data) => {
|
|
491
|
-
if (onMatterMessageListener === void 0) {
|
|
492
|
-
throw new InternalError(`No listener registered for Matter messages`);
|
|
493
|
-
}
|
|
494
|
-
nobleChannel.pushMessage(data);
|
|
495
|
-
onMatterMessageListener(nobleChannel, data);
|
|
496
|
-
}
|
|
497
|
-
);
|
|
498
|
-
const c2DataHandler = (data, isNotification) => {
|
|
499
|
-
logger.debug(
|
|
500
|
-
`Peripheral ${peripheralAddress}: received data on C2: ${data.toString("hex")} (isNotification: ${isNotification})`
|
|
501
|
-
);
|
|
502
|
-
btpSession.handleIncomingBleData(new Uint8Array(data)).catch((error) => {
|
|
503
|
-
logger.info(`Peripheral ${peripheralAddress}: Error handling incoming BLE data`, error);
|
|
504
|
-
});
|
|
505
|
-
};
|
|
506
|
-
characteristicC2ForSubscribe.on("data", c2DataHandler);
|
|
507
|
-
const nobleChannel = new NobleBleChannel(peripheral, btpSession, () => {
|
|
508
|
-
characteristicC2ForSubscribe.removeListener("data", c2DataHandler);
|
|
509
|
-
});
|
|
510
|
-
return nobleChannel;
|
|
511
|
-
}
|
|
512
|
-
#connected = true;
|
|
513
|
-
#closeListeners = /* @__PURE__ */ new Set();
|
|
514
|
-
#iteratorQueue = new Array();
|
|
515
|
-
#iteratorWaiter;
|
|
516
|
-
#iteratorDone = false;
|
|
517
|
-
#cleanupDataListener;
|
|
518
|
-
get connected() {
|
|
519
|
-
return this.#connected && this.peripheral.state === "connected";
|
|
520
|
-
}
|
|
521
|
-
/**
|
|
522
|
-
* Send a Matter message to the connected device - need to do BTP assembly first.
|
|
523
|
-
*
|
|
524
|
-
* @param data
|
|
525
|
-
*/
|
|
526
|
-
async send(data) {
|
|
527
|
-
if (!this.connected) {
|
|
528
|
-
throw new BleDisconnectedError(
|
|
529
|
-
`Peripheral ${this.peripheral.address}: Cannot send data because not connected to peripheral.`
|
|
530
|
-
);
|
|
531
|
-
}
|
|
532
|
-
if (this.btpSession === void 0) {
|
|
533
|
-
throw new BtpFlowError(
|
|
534
|
-
`Peripheral ${this.peripheral.address}: Cannot send data, no BTP session initialized`
|
|
535
|
-
);
|
|
536
|
-
}
|
|
537
|
-
await this.btpSession.sendMatterMessage(data);
|
|
538
|
-
}
|
|
539
|
-
// Channel<Bytes>
|
|
540
|
-
get name() {
|
|
541
|
-
return `${this.type}://${this.peripheral.address}`;
|
|
542
|
-
}
|
|
543
|
-
onClose(listener) {
|
|
544
|
-
this.#closeListeners.add(listener);
|
|
545
|
-
return {
|
|
546
|
-
close: async () => {
|
|
547
|
-
this.#closeListeners.delete(listener);
|
|
548
|
-
}
|
|
549
|
-
};
|
|
550
|
-
}
|
|
551
|
-
/** Called by the BTP session when a complete Matter message is assembled. */
|
|
552
|
-
pushMessage(message) {
|
|
553
|
-
if (this.#iteratorWaiter) {
|
|
554
|
-
const resolve = this.#iteratorWaiter;
|
|
555
|
-
this.#iteratorWaiter = void 0;
|
|
556
|
-
resolve({ value: message, done: false });
|
|
557
|
-
} else if (!this.#iteratorDone) {
|
|
558
|
-
this.#iteratorQueue.push(message);
|
|
559
|
-
}
|
|
560
|
-
}
|
|
561
|
-
[Symbol.asyncIterator]() {
|
|
562
|
-
return {
|
|
563
|
-
next: () => {
|
|
564
|
-
if (this.#iteratorQueue.length > 0) {
|
|
565
|
-
return Promise.resolve({ value: this.#iteratorQueue.shift(), done: false });
|
|
566
|
-
}
|
|
567
|
-
if (this.#iteratorDone || !this.#connected) {
|
|
568
|
-
return Promise.resolve({ value: void 0, done: true });
|
|
569
|
-
}
|
|
570
|
-
return new Promise((resolve) => {
|
|
571
|
-
this.#iteratorWaiter = resolve;
|
|
572
|
-
});
|
|
573
|
-
}
|
|
574
|
-
};
|
|
575
|
-
}
|
|
576
|
-
#terminateIterator() {
|
|
577
|
-
if (!this.#iteratorDone) {
|
|
578
|
-
this.#iteratorDone = true;
|
|
579
|
-
this.#iteratorWaiter?.({ value: void 0, done: true });
|
|
580
|
-
this.#iteratorWaiter = void 0;
|
|
581
|
-
}
|
|
582
|
-
}
|
|
583
|
-
async close() {
|
|
584
|
-
this.#cleanupDataListener();
|
|
585
|
-
this.#terminateIterator();
|
|
586
|
-
await this.btpSession.close();
|
|
587
|
-
if (this.connected) {
|
|
588
|
-
this.peripheral.disconnectAsync().catch((error) => {
|
|
589
|
-
if (!isNobleDisconnectError(error)) {
|
|
590
|
-
logger.error(`Peripheral ${this.peripheral.address}: Error while disconnecting`, error);
|
|
591
|
-
}
|
|
592
|
-
});
|
|
593
|
-
}
|
|
594
|
-
this.emitClosed();
|
|
595
|
-
}
|
|
596
|
-
}
|
|
597
|
-
export {
|
|
598
|
-
NobleBleCentralInterface,
|
|
599
|
-
NobleBleChannel
|
|
600
|
-
};
|
|
601
|
-
//# sourceMappingURL=NobleBleChannel.js.map
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../src/NobleBleChannel.ts"],
|
|
4
|
-
"mappings": "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",
|
|
5
|
-
"names": ["error"]
|
|
6
|
-
}
|