import type { PluginListenerHandle } from '@capacitor/core' ; import { Capacitor } from '@capacitor/core' ; import type { DisplayStrings } from './config' ; import { dataViewToHexString , hexStringToDataView } from './conversion' ; import type { BleDevice , BleService , ConnectOptions , Data , ReadResult , RequestBleDeviceOptions , ScanResult , ScanResultInternal , } from './definitions' ; import { BluetoothLe } from './plugin' ; import { getQueue } from './queue' ; import { validateUUID } from './validators' ; export interface BleClientInterface { /**
     * Initialize Bluetooth Low Energy (BLE). If it fails, BLE might be unavailable on this device.
     * On **Android** it will ask for the location permission. On **iOS** it will ask for the Bluetooth permission.
     * For an example, see [usage](#usage).
     */ initialize ( ) : Promise < void > ; /**
     * Reports whether Bluetooth is enabled on this device.
     * Always returns `true` on **web**.
     */ isEnabled ( ) : Promise < boolean > ; /**
     * Enable Bluetooth.
     * Only available on **Android**.
     */ enable ( ) : Promise < void > ; /**
     * Disable Bluetooth.
     * Only available on **Android**.
     */ disable ( ) : Promise < void > ; param callback startEnabledNotifications ( callback ) : Promise < void > ; /**
     * Stop the enabled notifications registered with `startEnabledNotifications`.
     */ stopEnabledNotifications ( ) : Promise < void > ; /**
     * Reports whether Location Services are enabled on this device.
     * Only available on **Android**.
     */ isLocationEnabled ( ) : Promise < boolean > ; /**
     * Open Location settings.
     * Only available on **Android**.
     */ openLocationSettings ( ) : Promise < void > ; /**
     * Open Bluetooth settings.
     * Only available on **Android**.
     */ openBluetoothSettings ( ) : Promise < void > ; /**
     * Open App settings.
     * Not available on **web**.
     * On **iOS** when a user declines the request to use Bluetooth on the first call of `initialize`, it is not possible
     * to request for Bluetooth again from within the app. In this case Bluetooth has to be enabled in the app settings
     * for the app to be able use it.
     */ openAppSettings ( ) : Promise < void > ; param displayStrings setDisplayStrings ( displayStrings ) : Promise < void > ; param options requestDevice ( options ? ) : Promise < BleDevice > ; param options param callback requestLEScan ( options , callback ) : Promise < void > ; /**
     * Stop scanning for BLE devices. For an example, see [usage](#usage).
     */ stopLEScan ( ) : Promise < void > ; param deviceIds getDevices ( deviceIds ) : Promise < BleDevice [ ] > ; param services getConnectedDevices ( services ) : Promise < BleDevice [ ] > ; param deviceId param onDisconnect param options connect ( deviceId , onDisconnect ? , options ? ) : Promise < void > ; param deviceId createBond ( deviceId ) : Promise < void > ; param deviceId isBonded ( deviceId ) : Promise < boolean > ; param deviceId disconnect ( deviceId ) : Promise < void > ; param deviceId getServices ( deviceId ) : Promise < BleService [ ] > ; param deviceId readRssi ( deviceId ) : Promise < number > ; param deviceId param service param characteristic read ( deviceId , service , characteristic ) : Promise < DataView > ; param deviceId param service param characteristic param value write ( deviceId , service , characteristic , value ) : Promise < void > ; param deviceId param service param characteristic param value writeWithoutResponse ( deviceId , service , characteristic , value ) : Promise < void > ; param deviceId param service param characteristic param descriptor readDescriptor ( deviceId , service , characteristic , descriptor ) : Promise < DataView > ; param deviceId param service param characteristic param descriptor param value writeDescriptor ( deviceId , service , characteristic , descriptor , value ) : Promise < void > ; param deviceId param service param characteristic param callback startNotifications ( deviceId , service , characteristic , callback ) : Promise < void > ; param deviceId param service param characteristic stopNotifications ( deviceId , service , characteristic ) : Promise < void > ; } class BleClientClass implements BleClientInterface { private scanListener : PluginListenerHandle | null = null ; private eventListeners = new Map < string , PluginListenerHandle > ( ) ; private queue = getQueue ( true ) ; enableQueue ( ) { this . queue = getQueue ( true ) ; } disableQueue ( ) { this . queue = getQueue ( false ) ; } async initialize ( ) { await this . queue ( async ( ) => { await BluetoothLe . initialize ( ) ; } ) ; } deprecated async getEnabled ( ) { return this . isEnabled ( ) ; } async isEnabled ( ) { const enabled = await this . queue ( async ( ) => { const result = await BluetoothLe . isEnabled ( ) ; return result . value ; } ) ; return enabled ; } async enable ( ) { await this . queue ( async ( ) => { await BluetoothLe . enable ( ) ; } ) ; } async disable ( ) { await this . queue ( async ( ) => { await BluetoothLe . disable ( ) ; } ) ; } async startEnabledNotifications ( callback ) { await this . queue ( async ( ) => { const key = `onEnabledChanged` ; await this . eventListeners . get ( key ) ?. remove ( ) ; const listener = await BluetoothLe . addListener ( key , ( result ) => { callback ( result . value ) ; } ) ; this . eventListeners . set ( key , listener ) ; await BluetoothLe . startEnabledNotifications ( ) ; } ) ; } async stopEnabledNotifications ( ) { await this . queue ( async ( ) => { const key = `onEnabledChanged` ; await this . eventListeners . get ( key ) ?. remove ( ) ; this . eventListeners . delete ( key ) ; await BluetoothLe . stopEnabledNotifications ( ) ; } ) ; } async isLocationEnabled ( ) { const enabled = await this . queue ( async ( ) => { const result = await BluetoothLe . isLocationEnabled ( ) ; return result . value ; } ) ; return enabled ; } async openLocationSettings ( ) { await this . queue ( async ( ) => { await BluetoothLe . openLocationSettings ( ) ; } ) ; } async openBluetoothSettings ( ) { await this . queue ( async ( ) => { await BluetoothLe . openBluetoothSettings ( ) ; } ) ; } async openAppSettings ( ) { await this . queue ( async ( ) => { await BluetoothLe . openAppSettings ( ) ; } ) ; } async setDisplayStrings ( displayStrings ) { await this . queue ( async ( ) => { await BluetoothLe . setDisplayStrings ( displayStrings ) ; } ) ; } async requestDevice ( options ? ) { const result = await this . queue ( async ( ) => { const device = await BluetoothLe . requestDevice ( options ) ; return device ; } ) ; return result ; } async requestLEScan ( options , callback ) { await this . queue ( async ( ) => { await this . scanListener ?. remove ( ) ; this . scanListener = await BluetoothLe . addListener ( 'onScanResult' , ( resultInternal ) => { const result = { ... resultInternal , manufacturerData : this . convertObject ( resultInternal . manufacturerData ) , serviceData : this . convertObject ( resultInternal . serviceData ) , rawAdvertisement : resultInternal . rawAdvertisement ? this . convertValue ( resultInternal . rawAdvertisement ) : undefined , } ; callback ( result ) ; } ) ; await BluetoothLe . requestLEScan ( options ) ; } ) ; } async stopLEScan ( ) { await this . queue ( async ( ) => { await this . scanListener ?. remove ( ) ; this . scanListener = null ; await BluetoothLe . stopLEScan ( ) ; } ) ; } async getDevices ( deviceIds ) { return this . queue ( async ( ) => { const result = await BluetoothLe . getDevices ( { deviceIds } ) ; return result . devices ; } ) ; } async getConnectedDevices ( services ) { return this . queue ( async ( ) => { const result = await BluetoothLe . getConnectedDevices ( { services } ) ; return result . devices ; } ) ; } async connect ( deviceId , onDisconnect ? , options ? ) { await this . queue ( async ( ) => { if ( onDisconnect ) { const key = `disconnected|${ deviceId }` ; await this . eventListeners . get ( key ) ?. remove ( ) ; const listener = await BluetoothLe . addListener ( key , ( ) => { onDisconnect ( deviceId ) ; } ) ; this . eventListeners . set ( key , listener ) ; } await BluetoothLe . connect ( { deviceId , ... options } ) ; } ) ; } async createBond ( deviceId ) { await this . queue ( async ( ) => { await BluetoothLe . createBond ( { deviceId } ) ; } ) ; } async isBonded ( deviceId ) { const isBonded = await this . queue ( async ( ) => { const result = await BluetoothLe . isBonded ( { deviceId } ) ; return result . value ; } ) ; return isBonded ; } async disconnect ( deviceId ) { await this . queue ( async ( ) => { await BluetoothLe . disconnect ( { deviceId } ) ; } ) ; } async getServices ( deviceId ) { const services = await this . queue ( async ( ) => { const result = await BluetoothLe . getServices ( { deviceId } ) ; return result . services ; } ) ; return services ; } async readRssi ( deviceId ) { const value = await this . queue ( async ( ) => { const result = await BluetoothLe . readRssi ( { deviceId } ) ; return parseFloat ( result . value ) ; } ) ; return value ; } async read ( deviceId , service , characteristic ) { service = validateUUID ( service ) ; characteristic = validateUUID ( characteristic ) ; const value = await this . queue ( async ( ) => { const result = await BluetoothLe . read ( { deviceId , service , characteristic , } ) ; return this . convertValue ( result . value ) ; } ) ; return value ; } async write ( deviceId , service , characteristic , value ) { service = validateUUID ( service ) ; characteristic = validateUUID ( characteristic ) ; return this . queue ( async ( ) => { if ( ! value ?. buffer ) { throw new Error ( 'Invalid data.' ) ; } let writeValue = value ; if ( Capacitor . getPlatform ( ) !== 'web' ) { writeValue = dataViewToHexString ( value ) ; } await BluetoothLe . write ( { deviceId , service , characteristic , value : writeValue , } ) ; } ) ; } async writeWithoutResponse ( deviceId , service , characteristic , value ) { service = validateUUID ( service ) ; characteristic = validateUUID ( characteristic ) ; await this . queue ( async ( ) => { if ( ! value ?. buffer ) { throw new Error ( 'Invalid data.' ) ; } let writeValue = value ; if ( Capacitor . getPlatform ( ) !== 'web' ) { writeValue = dataViewToHexString ( value ) ; } await BluetoothLe . writeWithoutResponse ( { deviceId , service , characteristic , value : writeValue , } ) ; } ) ; } async readDescriptor ( deviceId , service , characteristic , descriptor ) { service = validateUUID ( service ) ; characteristic = validateUUID ( characteristic ) ; descriptor = validateUUID ( descriptor ) ; const value = await this . queue ( async ( ) => { const result = await BluetoothLe . readDescriptor ( { deviceId , service , characteristic , descriptor , } ) ; return this . convertValue ( result . value ) ; } ) ; return value ; } async writeDescriptor ( deviceId , service , characteristic , descriptor , value ) { service = validateUUID ( service ) ; characteristic = validateUUID ( characteristic ) ; descriptor = validateUUID ( descriptor ) ; return this . queue ( async ( ) => { if ( ! value ?. buffer ) { throw new Error ( 'Invalid data.' ) ; } let writeValue = value ; if ( Capacitor . getPlatform ( ) !== 'web' ) { writeValue = dataViewToHexString ( value ) ; } await BluetoothLe . writeDescriptor ( { deviceId , service , characteristic , descriptor , value : writeValue , } ) ; } ) ; } async startNotifications ( deviceId , service , characteristic , callback ) { service = validateUUID ( service ) ; characteristic = validateUUID ( characteristic ) ; await this . queue ( async ( ) => { const key = `notification|${ deviceId }|${ service }|${ characteristic }` ; await this . eventListeners . get ( key ) ?. remove ( ) ; const listener = await BluetoothLe . addListener ( key , ( event ) => { callback ( this . convertValue ( event ?. value ) ) ; } ) ; this . eventListeners . set ( key , listener ) ; await BluetoothLe . startNotifications ( { deviceId , service , characteristic , } ) ; } ) ; } async stopNotifications ( deviceId , service , characteristic ) { service = validateUUID ( service ) ; characteristic = validateUUID ( characteristic ) ; await this . queue ( async ( ) => { const key = `notification|${ deviceId }|${ service }|${ characteristic }` ; await this . eventListeners . get ( key ) ?. remove ( ) ; this . eventListeners . delete ( key ) ; await BluetoothLe . stopNotifications ( { deviceId , service , characteristic , } ) ; } ) ; } private convertValue ( value ? ) { if ( typeof value === 'string' ) { return hexStringToDataView ( value ) ; } else if ( value === undefined ) { return new DataView ( new ArrayBuffer ( 0 ) ) ; } return value ; } private convertObject ( obj ? ) { if ( obj === undefined ) { return undefined ; } const result = { } ; for ( const key of Object . keys ( obj ) ) { result [ key ] = this . convertValue ( obj [ key ] ) ; } return result ; } } export const BleClient = new BleClientClass ( ) ;