@matter/react-native 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.
- package/LICENSE +201 -0
- package/README.md +56 -0
- package/dist/cjs/ble/BleReactNative.d.ts +17 -0
- package/dist/cjs/ble/BleReactNative.d.ts.map +1 -0
- package/dist/cjs/ble/BleReactNative.js +61 -0
- package/dist/cjs/ble/BleReactNative.js.map +6 -0
- package/dist/cjs/ble/BleScanner.d.ts +52 -0
- package/dist/cjs/ble/BleScanner.d.ts.map +1 -0
- package/dist/cjs/ble/BleScanner.js +239 -0
- package/dist/cjs/ble/BleScanner.js.map +6 -0
- package/dist/cjs/ble/ReactNativeBleChannel.d.ts +33 -0
- package/dist/cjs/ble/ReactNativeBleChannel.d.ts.map +1 -0
- package/dist/cjs/ble/ReactNativeBleChannel.js +252 -0
- package/dist/cjs/ble/ReactNativeBleChannel.js.map +6 -0
- package/dist/cjs/ble/ReactNativeBleClient.d.ts +25 -0
- package/dist/cjs/ble/ReactNativeBleClient.d.ts.map +1 -0
- package/dist/cjs/ble/ReactNativeBleClient.js +143 -0
- package/dist/cjs/ble/ReactNativeBleClient.js.map +6 -0
- package/dist/cjs/ble/export.d.ts +8 -0
- package/dist/cjs/ble/export.d.ts.map +1 -0
- package/dist/cjs/ble/export.js +25 -0
- package/dist/cjs/ble/export.js.map +6 -0
- package/dist/cjs/crypto/ReactNativeCrypto.d.ts +12 -0
- package/dist/cjs/crypto/ReactNativeCrypto.d.ts.map +1 -0
- package/dist/cjs/crypto/ReactNativeCrypto.js +95 -0
- package/dist/cjs/crypto/ReactNativeCrypto.js.map +6 -0
- package/dist/cjs/crypto/export.d.ts +7 -0
- package/dist/cjs/crypto/export.d.ts.map +1 -0
- package/dist/cjs/crypto/export.js +24 -0
- package/dist/cjs/crypto/export.js.map +6 -0
- package/dist/cjs/crypto/register.d.ts +7 -0
- package/dist/cjs/crypto/register.d.ts.map +1 -0
- package/dist/cjs/crypto/register.js +15 -0
- package/dist/cjs/crypto/register.js.map +6 -0
- package/dist/cjs/environment/ReactNativeEnvironment.d.ts +16 -0
- package/dist/cjs/environment/ReactNativeEnvironment.d.ts.map +1 -0
- package/dist/cjs/environment/ReactNativeEnvironment.js +60 -0
- package/dist/cjs/environment/ReactNativeEnvironment.js.map +6 -0
- package/dist/cjs/environment/export.d.ts +7 -0
- package/dist/cjs/environment/export.d.ts.map +1 -0
- package/dist/cjs/environment/export.js +24 -0
- package/dist/cjs/environment/export.js.map +6 -0
- package/dist/cjs/environment/register.d.ts +7 -0
- package/dist/cjs/environment/register.d.ts.map +1 -0
- package/dist/cjs/environment/register.js +12 -0
- package/dist/cjs/environment/register.js.map +6 -0
- package/dist/cjs/export.d.ts +9 -0
- package/dist/cjs/export.d.ts.map +1 -0
- package/dist/cjs/export.js +10 -0
- package/dist/cjs/export.js.map +6 -0
- package/dist/cjs/net/NetworkReactNative.d.ts +20 -0
- package/dist/cjs/net/NetworkReactNative.d.ts.map +1 -0
- package/dist/cjs/net/NetworkReactNative.js +173 -0
- package/dist/cjs/net/NetworkReactNative.js.map +6 -0
- package/dist/cjs/net/UdpChannelReactNative.d.ts +39 -0
- package/dist/cjs/net/UdpChannelReactNative.d.ts.map +1 -0
- package/dist/cjs/net/UdpChannelReactNative.js +184 -0
- package/dist/cjs/net/UdpChannelReactNative.js.map +6 -0
- package/dist/cjs/net/export.d.ts +8 -0
- package/dist/cjs/net/export.d.ts.map +1 -0
- package/dist/cjs/net/export.js +35 -0
- package/dist/cjs/net/export.js.map +6 -0
- package/dist/cjs/net/register.d.ts +7 -0
- package/dist/cjs/net/register.d.ts.map +1 -0
- package/dist/cjs/net/register.js +15 -0
- package/dist/cjs/net/register.js.map +6 -0
- package/dist/cjs/package.json +10 -0
- package/dist/cjs/storage/StorageBackendAsyncStorage.d.ts +31 -0
- package/dist/cjs/storage/StorageBackendAsyncStorage.d.ts.map +1 -0
- package/dist/cjs/storage/StorageBackendAsyncStorage.js +142 -0
- package/dist/cjs/storage/StorageBackendAsyncStorage.js.map +6 -0
- package/dist/cjs/tsconfig.tsbuildinfo +1 -0
- package/dist/esm/ble/BleReactNative.d.ts +17 -0
- package/dist/esm/ble/BleReactNative.d.ts.map +1 -0
- package/dist/esm/ble/BleReactNative.js +41 -0
- package/dist/esm/ble/BleReactNative.js.map +6 -0
- package/dist/esm/ble/BleScanner.d.ts +52 -0
- package/dist/esm/ble/BleScanner.d.ts.map +1 -0
- package/dist/esm/ble/BleScanner.js +219 -0
- package/dist/esm/ble/BleScanner.js.map +6 -0
- package/dist/esm/ble/ReactNativeBleChannel.d.ts +33 -0
- package/dist/esm/ble/ReactNativeBleChannel.d.ts.map +1 -0
- package/dist/esm/ble/ReactNativeBleChannel.js +257 -0
- package/dist/esm/ble/ReactNativeBleChannel.js.map +6 -0
- package/dist/esm/ble/ReactNativeBleClient.d.ts +25 -0
- package/dist/esm/ble/ReactNativeBleClient.d.ts.map +1 -0
- package/dist/esm/ble/ReactNativeBleClient.js +123 -0
- package/dist/esm/ble/ReactNativeBleClient.js.map +6 -0
- package/dist/esm/ble/export.d.ts +8 -0
- package/dist/esm/ble/export.d.ts.map +1 -0
- package/dist/esm/ble/export.js +8 -0
- package/dist/esm/ble/export.js.map +6 -0
- package/dist/esm/crypto/ReactNativeCrypto.d.ts +12 -0
- package/dist/esm/crypto/ReactNativeCrypto.d.ts.map +1 -0
- package/dist/esm/crypto/ReactNativeCrypto.js +65 -0
- package/dist/esm/crypto/ReactNativeCrypto.js.map +6 -0
- package/dist/esm/crypto/export.d.ts +7 -0
- package/dist/esm/crypto/export.d.ts.map +1 -0
- package/dist/esm/crypto/export.js +7 -0
- package/dist/esm/crypto/export.js.map +6 -0
- package/dist/esm/crypto/register.d.ts +7 -0
- package/dist/esm/crypto/register.d.ts.map +1 -0
- package/dist/esm/crypto/register.js +14 -0
- package/dist/esm/crypto/register.js.map +6 -0
- package/dist/esm/environment/ReactNativeEnvironment.d.ts +16 -0
- package/dist/esm/environment/ReactNativeEnvironment.d.ts.map +1 -0
- package/dist/esm/environment/ReactNativeEnvironment.js +40 -0
- package/dist/esm/environment/ReactNativeEnvironment.js.map +6 -0
- package/dist/esm/environment/export.d.ts +7 -0
- package/dist/esm/environment/export.d.ts.map +1 -0
- package/dist/esm/environment/export.js +7 -0
- package/dist/esm/environment/export.js.map +6 -0
- package/dist/esm/environment/register.d.ts +7 -0
- package/dist/esm/environment/register.d.ts.map +1 -0
- package/dist/esm/environment/register.js +11 -0
- package/dist/esm/environment/register.js.map +6 -0
- package/dist/esm/export.d.ts +9 -0
- package/dist/esm/export.d.ts.map +1 -0
- package/dist/esm/export.js +9 -0
- package/dist/esm/export.js.map +6 -0
- package/dist/esm/net/NetworkReactNative.d.ts +20 -0
- package/dist/esm/net/NetworkReactNative.d.ts.map +1 -0
- package/dist/esm/net/NetworkReactNative.js +151 -0
- package/dist/esm/net/NetworkReactNative.js.map +6 -0
- package/dist/esm/net/UdpChannelReactNative.d.ts +39 -0
- package/dist/esm/net/UdpChannelReactNative.d.ts.map +1 -0
- package/dist/esm/net/UdpChannelReactNative.js +162 -0
- package/dist/esm/net/UdpChannelReactNative.js.map +6 -0
- package/dist/esm/net/export.d.ts +8 -0
- package/dist/esm/net/export.d.ts.map +1 -0
- package/dist/esm/net/export.js +14 -0
- package/dist/esm/net/export.js.map +6 -0
- package/dist/esm/net/register.d.ts +7 -0
- package/dist/esm/net/register.d.ts.map +1 -0
- package/dist/esm/net/register.js +14 -0
- package/dist/esm/net/register.js.map +6 -0
- package/dist/esm/package.json +10 -0
- package/dist/esm/storage/StorageBackendAsyncStorage.d.ts +31 -0
- package/dist/esm/storage/StorageBackendAsyncStorage.d.ts.map +1 -0
- package/dist/esm/storage/StorageBackendAsyncStorage.js +112 -0
- package/dist/esm/storage/StorageBackendAsyncStorage.js.map +6 -0
- package/dist/esm/tsconfig.tsbuildinfo +1 -0
- package/package.json +105 -0
- package/src/ble/BleReactNative.ts +45 -0
- package/src/ble/BleScanner.ts +277 -0
- package/src/ble/ReactNativeBleChannel.ts +313 -0
- package/src/ble/ReactNativeBleClient.ts +132 -0
- package/src/ble/export.ts +8 -0
- package/src/crypto/ReactNativeCrypto.ts +108 -0
- package/src/crypto/export.ts +7 -0
- package/src/crypto/register.ts +16 -0
- package/src/environment/ReactNativeEnvironment.ts +53 -0
- package/src/environment/export.ts +7 -0
- package/src/environment/register.ts +16 -0
- package/src/export.ts +11 -0
- package/src/net/NetworkReactNative.ts +190 -0
- package/src/net/UdpChannelReactNative.ts +219 -0
- package/src/net/export.ts +13 -0
- package/src/net/register.ts +17 -0
- package/src/storage/StorageBackendAsyncStorage.ts +145 -0
- package/src/tsconfig.json +17 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2022-2024 Matter.js Authors
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
import { ChannelType, NetInterface, TransportInterface } from "#general";
|
|
7
|
+
import { Ble, InstanceBroadcaster, Scanner } from "#protocol";
|
|
8
|
+
export declare class BleReactNative extends Ble {
|
|
9
|
+
private bleCentral;
|
|
10
|
+
constructor();
|
|
11
|
+
getBleCentralInterface(): NetInterface;
|
|
12
|
+
getBleScanner(): Scanner;
|
|
13
|
+
getBlePeripheralInterface(): TransportInterface;
|
|
14
|
+
getBleBroadcaster(): InstanceBroadcaster;
|
|
15
|
+
supports(type: ChannelType): type is ChannelType.BLE;
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=BleReactNative.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BleReactNative.d.ts","sourceRoot":"","sources":["../../../src/ble/BleReactNative.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,WAAW,EAAuB,YAAY,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAC9F,OAAO,EAAE,GAAG,EAAE,mBAAmB,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAK9D,qBAAa,cAAe,SAAQ,GAAG;IACnC,OAAO,CAAC,UAAU,CAAmC;;IAMrD,sBAAsB,IAAI,YAAY;IAOtC,aAAa,IAAI,OAAO;IAOxB,yBAAyB,IAAI,kBAAkB;IAI/C,iBAAiB,IAAI,mBAAmB;IAIxC,QAAQ,CAAC,IAAI,EAAE,WAAW;CAG7B"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2022-2024 Matter.js Authors
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
import { ChannelType, ImplementationError } from "#general";
|
|
7
|
+
import { Ble } from "#protocol";
|
|
8
|
+
import { BleScanner } from "./BleScanner.js";
|
|
9
|
+
import { ReactNativeBleCentralInterface } from "./ReactNativeBleChannel.js";
|
|
10
|
+
import { ReactNativeBleClient } from "./ReactNativeBleClient.js";
|
|
11
|
+
class BleReactNative extends Ble {
|
|
12
|
+
bleCentral;
|
|
13
|
+
constructor() {
|
|
14
|
+
super();
|
|
15
|
+
}
|
|
16
|
+
getBleCentralInterface() {
|
|
17
|
+
if (this.bleCentral === void 0) {
|
|
18
|
+
this.bleCentral = new ReactNativeBleClient();
|
|
19
|
+
}
|
|
20
|
+
return new ReactNativeBleCentralInterface();
|
|
21
|
+
}
|
|
22
|
+
getBleScanner() {
|
|
23
|
+
if (this.bleCentral === void 0) {
|
|
24
|
+
this.bleCentral = new ReactNativeBleClient();
|
|
25
|
+
}
|
|
26
|
+
return new BleScanner(this.bleCentral);
|
|
27
|
+
}
|
|
28
|
+
getBlePeripheralInterface() {
|
|
29
|
+
throw new ImplementationError("React Native can only act as a central device, not a peripheral.");
|
|
30
|
+
}
|
|
31
|
+
getBleBroadcaster() {
|
|
32
|
+
throw new ImplementationError("React Native can only act as a central device, not a broadcaster.");
|
|
33
|
+
}
|
|
34
|
+
supports(type) {
|
|
35
|
+
return type === ChannelType.BLE;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
export {
|
|
39
|
+
BleReactNative
|
|
40
|
+
};
|
|
41
|
+
//# sourceMappingURL=BleReactNative.js.map
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/ble/BleReactNative.ts"],
|
|
4
|
+
"mappings": "AAAA;AAAA;AAAA;AAAA;AAAA;AAMA,SAAS,aAAa,2BAA6D;AACnF,SAAS,WAAyC;AAClD,SAAS,kBAAkB;AAC3B,SAAS,sCAAsC;AAC/C,SAAS,4BAA4B;AAE9B,MAAM,uBAAuB,IAAI;AAAA,EAC5B;AAAA,EAER,cAAc;AACV,UAAM;AAAA,EACV;AAAA,EAEA,yBAAuC;AACnC,QAAI,KAAK,eAAe,QAAW;AAC/B,WAAK,aAAa,IAAI,qBAAqB;AAAA,IAC/C;AACA,WAAO,IAAI,+BAA+B;AAAA,EAC9C;AAAA,EAEA,gBAAyB;AACrB,QAAI,KAAK,eAAe,QAAW;AAC/B,WAAK,aAAa,IAAI,qBAAqB;AAAA,IAC/C;AACA,WAAO,IAAI,WAAW,KAAK,UAAU;AAAA,EACzC;AAAA,EAEA,4BAAgD;AAC5C,UAAM,IAAI,oBAAoB,kEAAkE;AAAA,EACpG;AAAA,EAEA,oBAAyC;AACrC,UAAM,IAAI,oBAAoB,mEAAmE;AAAA,EACrG;AAAA,EAEA,SAAS,MAAmB;AACxB,WAAO,SAAS,YAAY;AAAA,EAChC;AACJ;",
|
|
5
|
+
"names": []
|
|
6
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2022-2024 Matter.js Authors
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
import { ChannelType } from "#general";
|
|
7
|
+
import { CommissionableDevice, CommissionableDeviceIdentifiers, Scanner } from "#protocol";
|
|
8
|
+
import { Device } from "react-native-ble-plx";
|
|
9
|
+
import { ReactNativeBleClient } from "./ReactNativeBleClient.js";
|
|
10
|
+
export type DiscoveredBleDevice = {
|
|
11
|
+
deviceData: CommissionableDeviceData;
|
|
12
|
+
peripheral: Device;
|
|
13
|
+
hasAdditionalAdvertisementData: boolean;
|
|
14
|
+
};
|
|
15
|
+
type CommissionableDeviceData = CommissionableDevice & {
|
|
16
|
+
SD: number;
|
|
17
|
+
};
|
|
18
|
+
export declare class BleScanner implements Scanner {
|
|
19
|
+
private readonly bleClient;
|
|
20
|
+
get type(): ChannelType;
|
|
21
|
+
private readonly recordWaiters;
|
|
22
|
+
private readonly discoveredMatterDevices;
|
|
23
|
+
constructor(bleClient: ReactNativeBleClient);
|
|
24
|
+
getDiscoveredDevice(address: string): DiscoveredBleDevice;
|
|
25
|
+
/**
|
|
26
|
+
* Registers a deferred promise for a specific queryId together with a timeout and return the promise.
|
|
27
|
+
* The promise will be resolved when the timer runs out latest.
|
|
28
|
+
*/
|
|
29
|
+
private registerWaiterPromise;
|
|
30
|
+
/**
|
|
31
|
+
* Remove a waiter promise for a specific queryId and stop the connected timer. If required also resolve the
|
|
32
|
+
* promise.
|
|
33
|
+
*/
|
|
34
|
+
private finishWaiter;
|
|
35
|
+
cancelCommissionableDeviceDiscovery(identifier: CommissionableDeviceIdentifiers): void;
|
|
36
|
+
private handleDiscoveredDevice;
|
|
37
|
+
private findCommissionableQueryIdentifier;
|
|
38
|
+
/**
|
|
39
|
+
* Builds an identifier string for commissionable queries based on the given identifier object.
|
|
40
|
+
* Some identifiers are identical to the official DNS-SD identifiers, others are custom.
|
|
41
|
+
*/
|
|
42
|
+
private buildCommissionableQueryIdentifier;
|
|
43
|
+
private getCommissionableDevices;
|
|
44
|
+
findOperationalDevice(): Promise<undefined>;
|
|
45
|
+
getDiscoveredOperationalDevice(): undefined;
|
|
46
|
+
findCommissionableDevices(identifier: CommissionableDeviceIdentifiers, timeoutSeconds?: number): Promise<CommissionableDevice[]>;
|
|
47
|
+
findCommissionableDevicesContinuously(identifier: CommissionableDeviceIdentifiers, callback: (device: CommissionableDevice) => void, timeoutSeconds?: number): Promise<CommissionableDevice[]>;
|
|
48
|
+
getDiscoveredCommissionableDevices(identifier: CommissionableDeviceIdentifiers): CommissionableDevice[];
|
|
49
|
+
close(): void;
|
|
50
|
+
}
|
|
51
|
+
export {};
|
|
52
|
+
//# sourceMappingURL=BleScanner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BleScanner.d.ts","sourceRoot":"","sources":["../../../src/ble/BleScanner.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAS,WAAW,EAAsC,MAAM,UAAU,CAAC;AAClF,OAAO,EAAsB,oBAAoB,EAAE,+BAA+B,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAE/G,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AAIjE,MAAM,MAAM,mBAAmB,GAAG;IAC9B,UAAU,EAAE,wBAAwB,CAAC;IACrC,UAAU,EAAE,MAAM,CAAC;IACnB,8BAA8B,EAAE,OAAO,CAAC;CAC3C,CAAC;AAEF,KAAK,wBAAwB,GAAG,oBAAoB,GAAG;IACnD,EAAE,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,qBAAa,UAAW,YAAW,OAAO;IAe1B,OAAO,CAAC,QAAQ,CAAC,SAAS;IAdtC,IAAI,IAAI,gBAEP;IAED,OAAO,CAAC,QAAQ,CAAC,aAAa,CAO1B;IACJ,OAAO,CAAC,QAAQ,CAAC,uBAAuB,CAA0C;gBAErD,SAAS,EAAE,oBAAoB;IAMrD,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,mBAAmB;IAQhE;;;OAGG;YACW,qBAAqB;IAcnC;;;OAGG;IACH,OAAO,CAAC,YAAY;IAapB,mCAAmC,CAAC,UAAU,EAAE,+BAA+B;IAK/E,OAAO,CAAC,sBAAsB;IAoC9B,OAAO,CAAC,iCAAiC;IAmCzC;;;OAGG;IACH,OAAO,CAAC,kCAAkC;IAa1C,OAAO,CAAC,wBAAwB;IA4B1B,qBAAqB,IAAI,OAAO,CAAC,SAAS,CAAC;IAKjD,8BAA8B,IAAI,SAAS;IAKrC,yBAAyB,CAC3B,UAAU,EAAE,+BAA+B,EAC3C,cAAc,SAAK,GACpB,OAAO,CAAC,oBAAoB,EAAE,CAAC;IAc5B,qCAAqC,CACvC,UAAU,EAAE,+BAA+B,EAC3C,QAAQ,EAAE,CAAC,MAAM,EAAE,oBAAoB,KAAK,IAAI,EAChD,cAAc,SAAK,GACpB,OAAO,CAAC,oBAAoB,EAAE,CAAC;IA0BlC,kCAAkC,CAAC,UAAU,EAAE,+BAA+B,GAAG,oBAAoB,EAAE;IAIvG,KAAK,IAAI,IAAI;CAMhB"}
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2022-2024 Matter.js Authors
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
import { Bytes, ChannelType, createPromise, Logger, Time } from "#general";
|
|
7
|
+
import { BleError, BtpCodec } from "#protocol";
|
|
8
|
+
import { VendorId } from "#types";
|
|
9
|
+
const logger = Logger.get("BleScanner");
|
|
10
|
+
class BleScanner {
|
|
11
|
+
constructor(bleClient) {
|
|
12
|
+
this.bleClient = bleClient;
|
|
13
|
+
this.bleClient.setDiscoveryCallback(
|
|
14
|
+
(address, manufacturerData) => this.handleDiscoveredDevice(address, manufacturerData)
|
|
15
|
+
);
|
|
16
|
+
}
|
|
17
|
+
get type() {
|
|
18
|
+
return ChannelType.BLE;
|
|
19
|
+
}
|
|
20
|
+
recordWaiters = /* @__PURE__ */ new Map();
|
|
21
|
+
discoveredMatterDevices = /* @__PURE__ */ new Map();
|
|
22
|
+
getDiscoveredDevice(address) {
|
|
23
|
+
const device = this.discoveredMatterDevices.get(address);
|
|
24
|
+
if (device === void 0) {
|
|
25
|
+
throw new BleError(`No device found for address ${address}`);
|
|
26
|
+
}
|
|
27
|
+
return device;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Registers a deferred promise for a specific queryId together with a timeout and return the promise.
|
|
31
|
+
* The promise will be resolved when the timer runs out latest.
|
|
32
|
+
*/
|
|
33
|
+
async registerWaiterPromise(queryId, timeoutSeconds, resolveOnUpdatedRecords = true) {
|
|
34
|
+
const { promise, resolver } = createPromise();
|
|
35
|
+
const timer = Time.getTimer(
|
|
36
|
+
"BLE query timeout",
|
|
37
|
+
timeoutSeconds * 1e3,
|
|
38
|
+
() => this.finishWaiter(queryId, true)
|
|
39
|
+
).start();
|
|
40
|
+
this.recordWaiters.set(queryId, { resolver, timer, resolveOnUpdatedRecords });
|
|
41
|
+
logger.debug(
|
|
42
|
+
`Registered waiter for query ${queryId} with timeout ${timeoutSeconds} seconds${resolveOnUpdatedRecords ? "" : " (not resolving on updated records)"}`
|
|
43
|
+
);
|
|
44
|
+
await promise;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Remove a waiter promise for a specific queryId and stop the connected timer. If required also resolve the
|
|
48
|
+
* promise.
|
|
49
|
+
*/
|
|
50
|
+
finishWaiter(queryId, resolvePromise, isUpdatedRecord = false) {
|
|
51
|
+
const waiter = this.recordWaiters.get(queryId);
|
|
52
|
+
if (waiter === void 0) return;
|
|
53
|
+
const { timer, resolver, resolveOnUpdatedRecords } = waiter;
|
|
54
|
+
if (isUpdatedRecord && !resolveOnUpdatedRecords) return;
|
|
55
|
+
logger.debug(`Finishing waiter for query ${queryId}, resolving: ${resolvePromise}`);
|
|
56
|
+
timer.stop();
|
|
57
|
+
if (resolvePromise) {
|
|
58
|
+
resolver();
|
|
59
|
+
}
|
|
60
|
+
this.recordWaiters.delete(queryId);
|
|
61
|
+
}
|
|
62
|
+
cancelCommissionableDeviceDiscovery(identifier) {
|
|
63
|
+
const queryKey = this.buildCommissionableQueryIdentifier(identifier);
|
|
64
|
+
this.finishWaiter(queryKey, true);
|
|
65
|
+
}
|
|
66
|
+
handleDiscoveredDevice(peripheral, manufacturerServiceData) {
|
|
67
|
+
logger.debug(
|
|
68
|
+
`Discovered device ${peripheral.id} "${peripheral.localName}" ${manufacturerServiceData === void 0 ? void 0 : Bytes.toHex(manufacturerServiceData)}`
|
|
69
|
+
);
|
|
70
|
+
try {
|
|
71
|
+
const { discriminator, vendorId, productId, hasAdditionalAdvertisementData } = BtpCodec.decodeBleAdvertisementServiceData(manufacturerServiceData);
|
|
72
|
+
const commissionableDevice = {
|
|
73
|
+
deviceIdentifier: peripheral.id,
|
|
74
|
+
D: discriminator,
|
|
75
|
+
SD: discriminator >> 8 & 15,
|
|
76
|
+
VP: `${vendorId}+${productId}`,
|
|
77
|
+
CM: 1,
|
|
78
|
+
// Can be no other mode,
|
|
79
|
+
addresses: [{ type: "ble", peripheralAddress: peripheral.id }]
|
|
80
|
+
};
|
|
81
|
+
logger.debug(`Discovered device ${peripheral.id} data: ${JSON.stringify(commissionableDevice)}`);
|
|
82
|
+
const deviceExisting = this.discoveredMatterDevices.has(peripheral.id);
|
|
83
|
+
this.discoveredMatterDevices.set(peripheral.id, {
|
|
84
|
+
deviceData: commissionableDevice,
|
|
85
|
+
peripheral,
|
|
86
|
+
hasAdditionalAdvertisementData
|
|
87
|
+
});
|
|
88
|
+
const queryKey = this.findCommissionableQueryIdentifier(commissionableDevice);
|
|
89
|
+
if (queryKey !== void 0) {
|
|
90
|
+
this.finishWaiter(queryKey, true, deviceExisting);
|
|
91
|
+
}
|
|
92
|
+
} catch (error) {
|
|
93
|
+
logger.debug(`Seems not to be a valid Matter device: Failed to decode device data: ${error}`);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
findCommissionableQueryIdentifier(record) {
|
|
97
|
+
const longDiscriminatorQueryId = this.buildCommissionableQueryIdentifier({ longDiscriminator: record.D });
|
|
98
|
+
if (this.recordWaiters.has(longDiscriminatorQueryId)) {
|
|
99
|
+
return longDiscriminatorQueryId;
|
|
100
|
+
}
|
|
101
|
+
const shortDiscriminatorQueryId = this.buildCommissionableQueryIdentifier({ shortDiscriminator: record.SD });
|
|
102
|
+
if (this.recordWaiters.has(shortDiscriminatorQueryId)) {
|
|
103
|
+
return shortDiscriminatorQueryId;
|
|
104
|
+
}
|
|
105
|
+
if (record.VP !== void 0) {
|
|
106
|
+
const vendorIdQueryId = this.buildCommissionableQueryIdentifier({
|
|
107
|
+
vendorId: VendorId(parseInt(record.VP.split("+")[0]))
|
|
108
|
+
});
|
|
109
|
+
if (this.recordWaiters.has(vendorIdQueryId)) {
|
|
110
|
+
return vendorIdQueryId;
|
|
111
|
+
}
|
|
112
|
+
if (record.VP.includes("+")) {
|
|
113
|
+
const productIdQueryId = this.buildCommissionableQueryIdentifier({
|
|
114
|
+
vendorId: VendorId(parseInt(record.VP.split("+")[1]))
|
|
115
|
+
});
|
|
116
|
+
if (this.recordWaiters.has(productIdQueryId)) {
|
|
117
|
+
return productIdQueryId;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
if (this.recordWaiters.has("*")) {
|
|
122
|
+
return "*";
|
|
123
|
+
}
|
|
124
|
+
return void 0;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Builds an identifier string for commissionable queries based on the given identifier object.
|
|
128
|
+
* Some identifiers are identical to the official DNS-SD identifiers, others are custom.
|
|
129
|
+
*/
|
|
130
|
+
buildCommissionableQueryIdentifier(identifier) {
|
|
131
|
+
if ("longDiscriminator" in identifier) {
|
|
132
|
+
return `D:${identifier.longDiscriminator}`;
|
|
133
|
+
} else if ("shortDiscriminator" in identifier) {
|
|
134
|
+
return `SD:${identifier.shortDiscriminator}`;
|
|
135
|
+
} else if ("vendorId" in identifier) {
|
|
136
|
+
return `V:${identifier.vendorId}`;
|
|
137
|
+
} else if ("productId" in identifier) {
|
|
138
|
+
return `P:${identifier.productId}`;
|
|
139
|
+
} else return "*";
|
|
140
|
+
}
|
|
141
|
+
getCommissionableDevices(identifier) {
|
|
142
|
+
const storedRecords = Array.from(this.discoveredMatterDevices.values());
|
|
143
|
+
const foundRecords = new Array();
|
|
144
|
+
if ("longDiscriminator" in identifier) {
|
|
145
|
+
foundRecords.push(...storedRecords.filter(({ deviceData: { D } }) => D === identifier.longDiscriminator));
|
|
146
|
+
} else if ("shortDiscriminator" in identifier) {
|
|
147
|
+
foundRecords.push(
|
|
148
|
+
...storedRecords.filter(({ deviceData: { SD } }) => SD === identifier.shortDiscriminator)
|
|
149
|
+
);
|
|
150
|
+
} else if ("vendorId" in identifier) {
|
|
151
|
+
foundRecords.push(
|
|
152
|
+
...storedRecords.filter(
|
|
153
|
+
({ deviceData: { VP } }) => VP === `${identifier.vendorId}` || VP?.startsWith(`${identifier.vendorId}+`)
|
|
154
|
+
)
|
|
155
|
+
);
|
|
156
|
+
} else if ("productId" in identifier) {
|
|
157
|
+
foundRecords.push(
|
|
158
|
+
...storedRecords.filter(({ deviceData: { VP } }) => VP?.endsWith(`+${identifier.productId}`))
|
|
159
|
+
);
|
|
160
|
+
} else {
|
|
161
|
+
foundRecords.push(...storedRecords.filter(({ deviceData: { CM } }) => CM === 1 || CM === 2));
|
|
162
|
+
}
|
|
163
|
+
return foundRecords;
|
|
164
|
+
}
|
|
165
|
+
async findOperationalDevice() {
|
|
166
|
+
logger.info(`skip BLE scan because scanning for operational devices is not supported`);
|
|
167
|
+
return void 0;
|
|
168
|
+
}
|
|
169
|
+
getDiscoveredOperationalDevice() {
|
|
170
|
+
logger.info(`skip BLE scan because scanning for operational devices is not supported`);
|
|
171
|
+
return void 0;
|
|
172
|
+
}
|
|
173
|
+
async findCommissionableDevices(identifier, timeoutSeconds = 10) {
|
|
174
|
+
let storedRecords = this.getCommissionableDevices(identifier);
|
|
175
|
+
if (storedRecords.length === 0) {
|
|
176
|
+
const queryKey = this.buildCommissionableQueryIdentifier(identifier);
|
|
177
|
+
await this.bleClient.startScanning();
|
|
178
|
+
await this.registerWaiterPromise(queryKey, timeoutSeconds);
|
|
179
|
+
storedRecords = this.getCommissionableDevices(identifier);
|
|
180
|
+
await this.bleClient.stopScanning();
|
|
181
|
+
}
|
|
182
|
+
return storedRecords.map(({ deviceData }) => deviceData);
|
|
183
|
+
}
|
|
184
|
+
async findCommissionableDevicesContinuously(identifier, callback, timeoutSeconds = 60) {
|
|
185
|
+
const discoveredDevices = /* @__PURE__ */ new Set();
|
|
186
|
+
const discoveryEndTime = Time.nowMs() + timeoutSeconds * 1e3;
|
|
187
|
+
const queryKey = this.buildCommissionableQueryIdentifier(identifier);
|
|
188
|
+
await this.bleClient.startScanning();
|
|
189
|
+
while (true) {
|
|
190
|
+
this.getCommissionableDevices(identifier).forEach(({ deviceData }) => {
|
|
191
|
+
const { deviceIdentifier } = deviceData;
|
|
192
|
+
if (!discoveredDevices.has(deviceIdentifier)) {
|
|
193
|
+
discoveredDevices.add(deviceIdentifier);
|
|
194
|
+
callback(deviceData);
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
const remainingTime = Math.ceil((discoveryEndTime - Time.nowMs()) / 1e3);
|
|
198
|
+
if (remainingTime <= 0) {
|
|
199
|
+
break;
|
|
200
|
+
}
|
|
201
|
+
await this.registerWaiterPromise(queryKey, remainingTime, false);
|
|
202
|
+
}
|
|
203
|
+
await this.bleClient.stopScanning();
|
|
204
|
+
return this.getCommissionableDevices(identifier).map(({ deviceData }) => deviceData);
|
|
205
|
+
}
|
|
206
|
+
getDiscoveredCommissionableDevices(identifier) {
|
|
207
|
+
return this.getCommissionableDevices(identifier).map(({ deviceData }) => deviceData);
|
|
208
|
+
}
|
|
209
|
+
close() {
|
|
210
|
+
void this.bleClient.stopScanning();
|
|
211
|
+
[...this.recordWaiters.keys()].forEach(
|
|
212
|
+
(queryId) => this.finishWaiter(queryId, !!this.recordWaiters.get(queryId)?.timer)
|
|
213
|
+
);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
export {
|
|
217
|
+
BleScanner
|
|
218
|
+
};
|
|
219
|
+
//# sourceMappingURL=BleScanner.js.map
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/ble/BleScanner.ts"],
|
|
4
|
+
"mappings": "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",
|
|
5
|
+
"names": []
|
|
6
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
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 "#general";
|
|
7
|
+
import { BleChannel, BtpSessionHandler } from "#protocol";
|
|
8
|
+
import { Characteristic, Device } from "react-native-ble-plx";
|
|
9
|
+
export declare class ReactNativeBleCentralInterface implements NetInterface {
|
|
10
|
+
private openChannels;
|
|
11
|
+
private onMatterMessageListener;
|
|
12
|
+
openChannel(address: ServerAddress): Promise<Channel<Uint8Array>>;
|
|
13
|
+
onData(listener: (socket: Channel<Uint8Array>, data: Uint8Array) => void): TransportInterface.Listener;
|
|
14
|
+
close(): Promise<void>;
|
|
15
|
+
supports(type: ChannelType): type is ChannelType.BLE;
|
|
16
|
+
}
|
|
17
|
+
export declare class ReactNativeBleChannel extends BleChannel<Uint8Array> {
|
|
18
|
+
private readonly peripheral;
|
|
19
|
+
private readonly btpSession;
|
|
20
|
+
static create(peripheral: Device, characteristicC1ForWrite: Characteristic, characteristicC2ForSubscribe: Characteristic, onMatterMessageListener: (socket: Channel<Uint8Array>, data: Uint8Array) => void, _additionalCommissioningRelatedData?: Uint8Array): Promise<ReactNativeBleChannel>;
|
|
21
|
+
private connected;
|
|
22
|
+
private disconnectSubscription;
|
|
23
|
+
constructor(peripheral: Device, btpSession: BtpSessionHandler);
|
|
24
|
+
/**
|
|
25
|
+
* Send a Matter message to the connected device - need to do BTP assembly first.
|
|
26
|
+
*
|
|
27
|
+
* @param data
|
|
28
|
+
*/
|
|
29
|
+
send(data: Uint8Array): Promise<void>;
|
|
30
|
+
get name(): string;
|
|
31
|
+
close(): Promise<void>;
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=ReactNativeBleChannel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ReactNativeBleChannel.d.ts","sourceRoot":"","sources":["../../../src/ble/ReactNativeBleChannel.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAEH,OAAO,EACP,WAAW,EAGX,YAAY,EACZ,aAAa,EAEb,kBAAkB,EAErB,MAAM,UAAU,CAAC;AAClB,OAAO,EAUH,UAAU,EAIV,iBAAiB,EACpB,MAAM,WAAW,CAAC;AACnB,OAAO,EAEH,cAAc,EACd,MAAM,EAGT,MAAM,sBAAsB,CAAC;AAK9B,qBAAa,8BAA+B,YAAW,YAAY;IAC/D,OAAO,CAAC,YAAY,CAAyC;IAC7D,OAAO,CAAC,uBAAuB,CAAwE;IAEjG,WAAW,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IA6FvE,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;CAG7B;AAED,qBAAa,qBAAsB,SAAQ,UAAU,CAAC,UAAU,CAAC;IAkHzD,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,UAAU;WAlHlB,MAAM,CACf,UAAU,EAAE,MAAM,EAClB,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,qBAAqB,CAAC;IAuGjC,OAAO,CAAC,SAAS,CAAQ;IACzB,OAAO,CAAC,sBAAsB,CAAe;gBAGxB,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,iBAAiB;IAWlD;;;;OAIG;IACG,IAAI,CAAC,IAAI,EAAE,UAAU;IAY3B,IAAI,IAAI,WAEP;IAEK,KAAK;CAKd"}
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2022-2024 Matter.js Authors
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
import {
|
|
7
|
+
Bytes,
|
|
8
|
+
ChannelType,
|
|
9
|
+
InternalError,
|
|
10
|
+
Logger,
|
|
11
|
+
Time,
|
|
12
|
+
createPromise
|
|
13
|
+
} from "#general";
|
|
14
|
+
import {
|
|
15
|
+
BLE_MATTER_C1_CHARACTERISTIC_UUID,
|
|
16
|
+
BLE_MATTER_C2_CHARACTERISTIC_UUID,
|
|
17
|
+
BLE_MATTER_C3_CHARACTERISTIC_UUID,
|
|
18
|
+
BLE_MATTER_SERVICE_UUID,
|
|
19
|
+
BLE_MAXIMUM_BTP_MTU,
|
|
20
|
+
BTP_CONN_RSP_TIMEOUT_MS,
|
|
21
|
+
BTP_MAXIMUM_WINDOW_SIZE,
|
|
22
|
+
BTP_SUPPORTED_VERSIONS,
|
|
23
|
+
Ble,
|
|
24
|
+
BleChannel,
|
|
25
|
+
BleError,
|
|
26
|
+
BtpCodec,
|
|
27
|
+
BtpFlowError,
|
|
28
|
+
BtpSessionHandler
|
|
29
|
+
} from "#protocol";
|
|
30
|
+
import {
|
|
31
|
+
BleErrorCode,
|
|
32
|
+
BleError as ReactNativeBleError
|
|
33
|
+
} from "react-native-ble-plx";
|
|
34
|
+
const logger = Logger.get("BleChannel");
|
|
35
|
+
class ReactNativeBleCentralInterface {
|
|
36
|
+
openChannels = /* @__PURE__ */ new Map();
|
|
37
|
+
onMatterMessageListener;
|
|
38
|
+
async openChannel(address) {
|
|
39
|
+
if (address.type !== "ble") {
|
|
40
|
+
throw new InternalError(`Unsupported address type ${address.type}.`);
|
|
41
|
+
}
|
|
42
|
+
if (this.onMatterMessageListener === void 0) {
|
|
43
|
+
throw new InternalError(`Network Interface was not added to the system yet.`);
|
|
44
|
+
}
|
|
45
|
+
const { peripheral, hasAdditionalAdvertisementData } = Ble.get().getBleScanner().getDiscoveredDevice(address.peripheralAddress);
|
|
46
|
+
if (this.openChannels.has(address)) {
|
|
47
|
+
throw new BleError(
|
|
48
|
+
`Peripheral ${address.peripheralAddress} is already connected. Only one connection supported right now.`
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
logger.debug(`Connect to Peripheral now`);
|
|
52
|
+
let device;
|
|
53
|
+
try {
|
|
54
|
+
device = await peripheral.connect();
|
|
55
|
+
} catch (error) {
|
|
56
|
+
if (error instanceof ReactNativeBleError && error.errorCode === BleErrorCode.DeviceAlreadyConnected) {
|
|
57
|
+
device = peripheral;
|
|
58
|
+
} else {
|
|
59
|
+
throw new BleError(`Error connecting to peripheral: ${error.message}`);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
logger.debug(`Peripheral connected successfully, MTU = ${device.mtu}`);
|
|
63
|
+
device = await device.discoverAllServicesAndCharacteristics();
|
|
64
|
+
const services = await device.services();
|
|
65
|
+
for (const service of services) {
|
|
66
|
+
logger.debug(`found service: ${service.uuid}`);
|
|
67
|
+
if (service.uuid !== BLE_MATTER_SERVICE_UUID) continue;
|
|
68
|
+
const characteristics = await device.characteristicsForService(service.uuid);
|
|
69
|
+
let characteristicC1ForWrite;
|
|
70
|
+
let characteristicC2ForSubscribe;
|
|
71
|
+
let additionalCommissioningRelatedData;
|
|
72
|
+
for (const characteristic of characteristics) {
|
|
73
|
+
logger.debug("found characteristic:", characteristic.uuid);
|
|
74
|
+
switch (characteristic.uuid) {
|
|
75
|
+
case BLE_MATTER_C1_CHARACTERISTIC_UUID:
|
|
76
|
+
logger.debug("found C1 characteristic");
|
|
77
|
+
characteristicC1ForWrite = characteristic;
|
|
78
|
+
break;
|
|
79
|
+
case BLE_MATTER_C2_CHARACTERISTIC_UUID:
|
|
80
|
+
logger.debug("found C2 characteristic");
|
|
81
|
+
characteristicC2ForSubscribe = characteristic;
|
|
82
|
+
break;
|
|
83
|
+
case BLE_MATTER_C3_CHARACTERISTIC_UUID:
|
|
84
|
+
logger.debug("found C3 characteristic");
|
|
85
|
+
if (hasAdditionalAdvertisementData) {
|
|
86
|
+
logger.debug("reading additional commissioning related data");
|
|
87
|
+
const characteristicWithValue = await service.readCharacteristic(characteristic.uuid);
|
|
88
|
+
if (characteristicWithValue.value !== null) {
|
|
89
|
+
additionalCommissioningRelatedData = Bytes.fromBase64(characteristicWithValue.value);
|
|
90
|
+
} else {
|
|
91
|
+
logger.debug("no value in characteristic C3");
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
if (!characteristicC1ForWrite || !characteristicC2ForSubscribe) {
|
|
97
|
+
logger.debug("missing characteristics");
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
this.openChannels.set(address, peripheral);
|
|
101
|
+
return await ReactNativeBleChannel.create(
|
|
102
|
+
peripheral,
|
|
103
|
+
characteristicC1ForWrite,
|
|
104
|
+
characteristicC2ForSubscribe,
|
|
105
|
+
this.onMatterMessageListener,
|
|
106
|
+
additionalCommissioningRelatedData
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
throw new BleError(`No Matter service found on peripheral ${peripheral.id}`);
|
|
110
|
+
}
|
|
111
|
+
onData(listener) {
|
|
112
|
+
this.onMatterMessageListener = listener;
|
|
113
|
+
return {
|
|
114
|
+
close: async () => await this.close()
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
async close() {
|
|
118
|
+
for (const peripheral of this.openChannels.values()) {
|
|
119
|
+
await peripheral.cancelConnection();
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
supports(type) {
|
|
123
|
+
return type === ChannelType.BLE;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
class ReactNativeBleChannel extends BleChannel {
|
|
127
|
+
constructor(peripheral, btpSession) {
|
|
128
|
+
super();
|
|
129
|
+
this.peripheral = peripheral;
|
|
130
|
+
this.btpSession = btpSession;
|
|
131
|
+
this.disconnectSubscription = peripheral.onDisconnected((error) => {
|
|
132
|
+
logger.debug(`Disconnected from peripheral ${peripheral.id}: ${error}`);
|
|
133
|
+
this.connected = false;
|
|
134
|
+
this.disconnectSubscription.remove();
|
|
135
|
+
void this.btpSession.close();
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
static async create(peripheral, characteristicC1ForWrite, characteristicC2ForSubscribe, onMatterMessageListener, _additionalCommissioningRelatedData) {
|
|
139
|
+
let mtu = peripheral.mtu ?? 0;
|
|
140
|
+
if (mtu > BLE_MAXIMUM_BTP_MTU) {
|
|
141
|
+
mtu = BLE_MAXIMUM_BTP_MTU;
|
|
142
|
+
}
|
|
143
|
+
logger.debug(`Using MTU=${mtu} (Peripheral MTU=${peripheral.mtu})`);
|
|
144
|
+
const btpHandshakeRequest = BtpCodec.encodeBtpHandshakeRequest({
|
|
145
|
+
versions: BTP_SUPPORTED_VERSIONS,
|
|
146
|
+
attMtu: mtu,
|
|
147
|
+
clientWindowSize: BTP_MAXIMUM_WINDOW_SIZE
|
|
148
|
+
});
|
|
149
|
+
logger.debug(`sending BTP handshake request: ${Logger.toJSON(btpHandshakeRequest)}`);
|
|
150
|
+
characteristicC1ForWrite = await characteristicC1ForWrite.writeWithResponse(
|
|
151
|
+
Bytes.toBase64(btpHandshakeRequest)
|
|
152
|
+
);
|
|
153
|
+
const btpHandshakeTimeout = Time.getTimer("BLE handshake timeout", BTP_CONN_RSP_TIMEOUT_MS, async () => {
|
|
154
|
+
await peripheral.cancelConnection();
|
|
155
|
+
logger.debug("Handshake Response not received. Disconnected from peripheral");
|
|
156
|
+
}).start();
|
|
157
|
+
logger.debug("subscribing to C2 characteristic");
|
|
158
|
+
const { promise: handshakeResponseReceivedPromise, resolver } = createPromise();
|
|
159
|
+
let handshakeReceived = false;
|
|
160
|
+
const handshakeSubscription = characteristicC2ForSubscribe.monitor((error, characteristic) => {
|
|
161
|
+
if (error !== null || characteristic === null) {
|
|
162
|
+
if (error instanceof ReactNativeBleError && error.errorCode === 2 && handshakeReceived) {
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
logger.debug("Error while monitoring C2 characteristic", error);
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
const characteristicData = characteristic.value;
|
|
169
|
+
if (characteristicData === null) {
|
|
170
|
+
logger.debug("C2 characteristic value is null");
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
const data = Bytes.fromBase64(characteristicData);
|
|
174
|
+
logger.debug(`received first data on C2: ${Bytes.toHex(data)}`);
|
|
175
|
+
if (data[0] === 101 && data[1] === 108 && data.length === 6) {
|
|
176
|
+
logger.info(`Received Matter handshake response: ${Bytes.toHex(data)}.`);
|
|
177
|
+
btpHandshakeTimeout.stop();
|
|
178
|
+
resolver(data);
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
const handshakeResponse = await handshakeResponseReceivedPromise;
|
|
182
|
+
handshakeReceived = true;
|
|
183
|
+
handshakeSubscription.remove();
|
|
184
|
+
let connectionCloseExpected = false;
|
|
185
|
+
const btpSession = await BtpSessionHandler.createAsCentral(
|
|
186
|
+
new Uint8Array(handshakeResponse),
|
|
187
|
+
// callback to write data to characteristic C1
|
|
188
|
+
async (data) => {
|
|
189
|
+
characteristicC1ForWrite = await characteristicC1ForWrite.writeWithResponse(Bytes.toBase64(data));
|
|
190
|
+
},
|
|
191
|
+
// callback to disconnect the BLE connection
|
|
192
|
+
async () => {
|
|
193
|
+
connectionCloseExpected = true;
|
|
194
|
+
dataSubscription.remove();
|
|
195
|
+
await peripheral.cancelConnection();
|
|
196
|
+
logger.debug("disconnected from peripheral");
|
|
197
|
+
},
|
|
198
|
+
// callback to forward decoded and de-assembled Matter messages to ExchangeManager
|
|
199
|
+
async (data) => {
|
|
200
|
+
if (onMatterMessageListener === void 0) {
|
|
201
|
+
throw new InternalError(`No listener registered for Matter messages`);
|
|
202
|
+
}
|
|
203
|
+
onMatterMessageListener(bleChannel, data);
|
|
204
|
+
}
|
|
205
|
+
);
|
|
206
|
+
const dataSubscription = characteristicC2ForSubscribe.monitor((error, characteristic) => {
|
|
207
|
+
if (error !== null || characteristic === null) {
|
|
208
|
+
if (error instanceof ReactNativeBleError && error.errorCode === 2 && connectionCloseExpected) {
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
logger.debug("Error while monitoring C2 characteristic", error);
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
const characteristicData = characteristic.value;
|
|
215
|
+
if (characteristicData === null) {
|
|
216
|
+
logger.debug("C2 characteristic value is null");
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
const data = Bytes.fromBase64(characteristicData);
|
|
220
|
+
logger.debug(`received data on C2: ${Bytes.toHex(data)}`);
|
|
221
|
+
void btpSession.handleIncomingBleData(new Uint8Array(data));
|
|
222
|
+
});
|
|
223
|
+
const bleChannel = new ReactNativeBleChannel(peripheral, btpSession);
|
|
224
|
+
return bleChannel;
|
|
225
|
+
}
|
|
226
|
+
connected = true;
|
|
227
|
+
disconnectSubscription;
|
|
228
|
+
/**
|
|
229
|
+
* Send a Matter message to the connected device - need to do BTP assembly first.
|
|
230
|
+
*
|
|
231
|
+
* @param data
|
|
232
|
+
*/
|
|
233
|
+
async send(data) {
|
|
234
|
+
if (!this.connected) {
|
|
235
|
+
logger.debug("Cannot send data because not connected to peripheral.");
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
if (this.btpSession === void 0) {
|
|
239
|
+
throw new BtpFlowError(`Cannot send data, no BTP session initialized`);
|
|
240
|
+
}
|
|
241
|
+
await this.btpSession.sendMatterMessage(data);
|
|
242
|
+
}
|
|
243
|
+
// Channel<Uint8Array>
|
|
244
|
+
get name() {
|
|
245
|
+
return `ble://${this.peripheral.id}`;
|
|
246
|
+
}
|
|
247
|
+
async close() {
|
|
248
|
+
await this.btpSession.close();
|
|
249
|
+
this.disconnectSubscription.remove();
|
|
250
|
+
await this.peripheral.cancelConnection();
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
export {
|
|
254
|
+
ReactNativeBleCentralInterface,
|
|
255
|
+
ReactNativeBleChannel
|
|
256
|
+
};
|
|
257
|
+
//# sourceMappingURL=ReactNativeBleChannel.js.map
|