react-native-ble-nitro
Version:
High-performance React Native BLE library built on Nitro Modules - drop-in replacement for react-native-ble-plx
427 lines (359 loc) • 11.7 kB
text/typescript
/**
* Device wrapper for compatibility
*
* Wraps Nitro Device objects to provide the original react-native-ble-plx API
*/
import type { Device as NitroDevice } from '../specs/Device.nitro';
import type {
NativeDevice,
UUID,
Base64,
DeviceId,
TransactionId,
ConnectionPriority,
ConnectionOptions,
ServiceDataEntry,
NativeService,
NativeCharacteristic,
NativeDescriptor,
CharacteristicSubscriptionType,
Subscription
} from '../specs/types';
import { serviceDataArrayToMap } from './serviceData';
import {
normalizeCharacteristicSubscriptionType,
stateToString,
characteristicSubscriptionTypeToString
} from './enums';
/**
* Device wrapper that provides react-native-ble-plx compatibility
* Maps Nitro device properties to the expected API surface
*/
export class DeviceWrapper {
constructor(private nitroDevice: NitroDevice | any) {}
// Device identification
get id(): DeviceId {
return this.nitroDevice.id;
}
// Map deviceName back to name for compatibility
get name(): string | null {
return this.nitroDevice.deviceName || null;
}
get rssi(): number | null {
return this.nitroDevice.rssi || null;
}
get mtu(): number {
return this.nitroDevice.mtu;
}
// Advertisement data
get manufacturerData(): Base64 | null {
return this.nitroDevice.manufacturerData || null;
}
get rawScanRecord(): Base64 {
return this.nitroDevice.rawScanRecord;
}
// Convert ServiceDataEntry[] back to { [uuid: string]: Base64 }
get serviceData(): { [uuid: string]: Base64 } | null {
return serviceDataArrayToMap(this.nitroDevice.serviceData || null);
}
get serviceUUIDs(): UUID[] | null {
return this.nitroDevice.serviceUUIDs || null;
}
get localName(): string | null {
return this.nitroDevice.localName || null;
}
get txPowerLevel(): number | null {
return this.nitroDevice.txPowerLevel || null;
}
get solicitedServiceUUIDs(): UUID[] | null {
return this.nitroDevice.solicitedServiceUUIDs || null;
}
get isConnectable(): boolean | null {
return this.nitroDevice.isConnectable || null;
}
get overflowServiceUUIDs(): UUID[] | null {
return this.nitroDevice.overflowServiceUUIDs || null;
}
// Connection management methods
async requestConnectionPriority(
connectionPriority: ConnectionPriority,
transactionId?: TransactionId
): Promise<DeviceWrapper> {
const result = await this.nitroDevice.requestConnectionPriority(connectionPriority, transactionId);
return new DeviceWrapper(result);
}
async readRSSI(transactionId?: TransactionId): Promise<DeviceWrapper> {
const result = await this.nitroDevice.readRSSI(transactionId);
return new DeviceWrapper(result);
}
async requestMTU(mtu: number, transactionId?: TransactionId): Promise<DeviceWrapper> {
const result = await this.nitroDevice.requestMTU(mtu, transactionId);
return new DeviceWrapper(result);
}
async connect(options?: Partial<ConnectionOptions>): Promise<DeviceWrapper> {
// Provide defaults for required fields in Nitro interface
const connectionOptions: ConnectionOptions = {
autoConnect: options?.autoConnect ?? false,
requestMTU: options?.requestMTU ?? 23,
timeout: options?.timeout ?? 0,
};
const result = await this.nitroDevice.connect(connectionOptions);
return new DeviceWrapper(result);
}
async cancelConnection(): Promise<DeviceWrapper> {
const result = await this.nitroDevice.cancelConnection();
return new DeviceWrapper(result);
}
async isConnected(): Promise<boolean> {
return await this.nitroDevice.isConnected();
}
onDisconnected(listener: (error: any | null, device: DeviceWrapper) => void): Subscription {
return this.nitroDevice.onDisconnected((error: any, device: any) => {
listener(error, new DeviceWrapper(device));
});
}
// Service discovery
async discoverAllServicesAndCharacteristics(transactionId?: TransactionId): Promise<DeviceWrapper> {
const result = await this.nitroDevice.discoverAllServicesAndCharacteristics(transactionId);
return new DeviceWrapper(result);
}
async services(): Promise<ServiceWrapper[]> {
const services = await this.nitroDevice.services();
return services.map((service: any) => new ServiceWrapper(service, this.nitroDevice));
}
// Characteristic operations
async characteristicsForService(serviceUUID: UUID): Promise<CharacteristicWrapper[]> {
const characteristics = await this.nitroDevice.characteristicsForService(serviceUUID);
return characteristics.map((char: any) => new CharacteristicWrapper(char, this.nitroDevice));
}
async readCharacteristicForService(
serviceUUID: UUID,
characteristicUUID: UUID,
transactionId?: TransactionId
): Promise<CharacteristicWrapper> {
const result = await this.nitroDevice.readCharacteristicForService(
serviceUUID,
characteristicUUID,
transactionId
);
return new CharacteristicWrapper(result, this.nitroDevice);
}
async writeCharacteristicWithResponseForService(
serviceUUID: UUID,
characteristicUUID: UUID,
valueBase64: Base64,
transactionId?: TransactionId
): Promise<CharacteristicWrapper> {
const result = await this.nitroDevice.writeCharacteristicWithResponseForService(
serviceUUID,
characteristicUUID,
valueBase64,
transactionId
);
return new CharacteristicWrapper(result, this.nitroDevice);
}
async writeCharacteristicWithoutResponseForService(
serviceUUID: UUID,
characteristicUUID: UUID,
valueBase64: Base64,
transactionId?: TransactionId
): Promise<CharacteristicWrapper> {
const result = await this.nitroDevice.writeCharacteristicWithoutResponseForService(
serviceUUID,
characteristicUUID,
valueBase64,
transactionId
);
return new CharacteristicWrapper(result, this.nitroDevice);
}
monitorCharacteristicForService(
serviceUUID: UUID,
characteristicUUID: UUID,
listener: (error: any | null, characteristic: CharacteristicWrapper | null) => void,
transactionId?: TransactionId,
subscriptionType?: 'notification' | 'indication'
): Subscription {
const nitroSubscriptionType = subscriptionType
? normalizeCharacteristicSubscriptionType(subscriptionType)
: undefined;
return this.nitroDevice.monitorCharacteristicForService(
serviceUUID,
characteristicUUID,
(error: any, characteristic: any) => {
listener(
error,
characteristic ? new CharacteristicWrapper(characteristic, this.nitroDevice) : null
);
},
transactionId,
nitroSubscriptionType
);
}
// Descriptor operations
async descriptorsForService(
serviceUUID: UUID,
characteristicUUID: UUID
): Promise<DescriptorWrapper[]> {
const descriptors = await this.nitroDevice.descriptorsForService(serviceUUID, characteristicUUID);
return descriptors.map((desc: any) => new DescriptorWrapper(desc, this.nitroDevice));
}
async readDescriptorForService(
serviceUUID: UUID,
characteristicUUID: UUID,
descriptorUUID: UUID,
transactionId?: TransactionId
): Promise<DescriptorWrapper> {
const result = await this.nitroDevice.readDescriptorForService(
serviceUUID,
characteristicUUID,
descriptorUUID,
transactionId
);
return new DescriptorWrapper(result, this.nitroDevice);
}
async writeDescriptorForService(
serviceUUID: UUID,
characteristicUUID: UUID,
descriptorUUID: UUID,
valueBase64: Base64,
transactionId?: TransactionId
): Promise<DescriptorWrapper> {
const result = await this.nitroDevice.writeDescriptorForService(
serviceUUID,
characteristicUUID,
descriptorUUID,
valueBase64,
transactionId
);
return new DescriptorWrapper(result, this.nitroDevice);
}
}
/**
* Service wrapper for compatibility
*/
export class ServiceWrapper {
constructor(
private nativeService: NativeService,
private nitroDevice: NitroDevice
) {}
get id(): number {
return this.nativeService.id;
}
get uuid(): UUID {
return this.nativeService.uuid;
}
get deviceID(): DeviceId {
return this.nativeService.deviceID;
}
get isPrimary(): boolean {
return this.nativeService.isPrimary;
}
// Delegate to device methods
async characteristics(): Promise<CharacteristicWrapper[]> {
const device = new DeviceWrapper(this.nitroDevice);
return await device.characteristicsForService(this.uuid);
}
async readCharacteristic(
characteristicUUID: UUID,
transactionId?: TransactionId
): Promise<CharacteristicWrapper> {
const device = new DeviceWrapper(this.nitroDevice);
return await device.readCharacteristicForService(this.uuid, characteristicUUID, transactionId);
}
// ... other service methods would delegate similarly
}
/**
* Characteristic wrapper for compatibility
*/
export class CharacteristicWrapper {
constructor(
private nativeCharacteristic: NativeCharacteristic,
private nitroDevice: NitroDevice
) {}
get id(): number {
return this.nativeCharacteristic.id;
}
get uuid(): UUID {
return this.nativeCharacteristic.uuid;
}
get serviceID(): number {
return this.nativeCharacteristic.serviceID;
}
get serviceUUID(): UUID {
return this.nativeCharacteristic.serviceUUID;
}
get deviceID(): DeviceId {
return this.nativeCharacteristic.deviceID;
}
get isReadable(): boolean {
return this.nativeCharacteristic.isReadable;
}
get isWritableWithResponse(): boolean {
return this.nativeCharacteristic.isWritableWithResponse;
}
get isWritableWithoutResponse(): boolean {
return this.nativeCharacteristic.isWritableWithoutResponse;
}
get isNotifiable(): boolean {
return this.nativeCharacteristic.isNotifiable;
}
get isNotifying(): boolean {
return this.nativeCharacteristic.isNotifying;
}
get isIndicatable(): boolean {
return this.nativeCharacteristic.isIndicatable;
}
get value(): Base64 | null {
return this.nativeCharacteristic.value;
}
// Delegate to device methods
async read(transactionId?: TransactionId): Promise<CharacteristicWrapper> {
const device = new DeviceWrapper(this.nitroDevice);
return await device.readCharacteristicForService(this.serviceUUID, this.uuid, transactionId);
}
// ... other characteristic methods would delegate similarly
}
/**
* Descriptor wrapper for compatibility
*/
export class DescriptorWrapper {
constructor(
private nativeDescriptor: NativeDescriptor,
private nitroDevice: NitroDevice
) {}
get id(): number {
return this.nativeDescriptor.id;
}
get uuid(): UUID {
return this.nativeDescriptor.uuid;
}
get characteristicID(): number {
return this.nativeDescriptor.characteristicID;
}
get characteristicUUID(): UUID {
return this.nativeDescriptor.characteristicUUID;
}
get serviceID(): number {
return this.nativeDescriptor.serviceID;
}
get serviceUUID(): UUID {
return this.nativeDescriptor.serviceUUID;
}
get deviceID(): DeviceId {
return this.nativeDescriptor.deviceID;
}
get value(): Base64 | null {
return this.nativeDescriptor.value;
}
// Delegate to device methods
async read(transactionId?: TransactionId): Promise<DescriptorWrapper> {
const device = new DeviceWrapper(this.nitroDevice);
return await device.readDescriptorForService(
this.serviceUUID,
this.characteristicUUID,
this.uuid,
transactionId
);
}
// ... other descriptor methods would delegate similarly
}