diff --git a/examples/list-adapters.js b/examples/list-adapters.js new file mode 100644 index 00000000..3357a166 --- /dev/null +++ b/examples/list-adapters.js @@ -0,0 +1,28 @@ +/* +* Node Web Bluetooth +* Copyright (c) 2022 Rob Moran +* +* The MIT License (MIT) +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +const webbluetooth = require("../"); + +console.log(webbluetooth.getSimpleBleHardwareAdapters()); diff --git a/src/adapters/adapter.ts b/src/adapters/adapter.ts index cb43550b..a173bc1b 100644 --- a/src/adapters/adapter.ts +++ b/src/adapters/adapter.ts @@ -48,4 +48,13 @@ export interface Adapter extends EventEmitter { disableNotify: (handle: string) => Promise; readDescriptor: (handle: string) => Promise; writeDescriptor: (handle: string, value: DataView) => Promise; + useHardwareAdapter: (adapterIndex: number) => void; + getHardwareAdapters: () => Array; +} + +/** Basic Hardware Details for an Hardware adapter. */ +export interface HardwareAdapterDetails { + identifier: string; + address: string; + active: boolean; } diff --git a/src/adapters/simpleble-adapter.ts b/src/adapters/simpleble-adapter.ts index cc34b47c..e3b5490d 100644 --- a/src/adapters/simpleble-adapter.ts +++ b/src/adapters/simpleble-adapter.ts @@ -53,6 +53,24 @@ export class SimplebleAdapter extends EventEmitter implements BluetoothAdapter { private descriptors = new Map(); private charEvents = new Map void>(); + getHardwareAdapters() { + return getAdapters().map( + ({ identifier, address, active }) => + ({ identifier, address, active }) + ); + } + + useHardwareAdapter(adapterIndex: number) { + if (this.adapter !== undefined) { + throw new Error('Can not change adapter after already used.'); + } + const adapter = getAdapters()[adapterIndex]; + if (adapter === undefined) { + throw new Error(`Adapter ${adapterIndex} not found.`); + } + this.adapter = getAdapters()[adapterIndex]; + } + private validDevice(device: Partial, serviceUUIDs: Array): boolean { if (serviceUUIDs.length === 0) { // Match any device diff --git a/src/adapters/simpleble.ts b/src/adapters/simpleble.ts index 0ee81b6b..4beee7d1 100644 --- a/src/adapters/simpleble.ts +++ b/src/adapters/simpleble.ts @@ -23,6 +23,8 @@ * SOFTWARE. */ +import { HardwareAdapterDetails } from './adapter'; + // eslint-disable-next-line @typescript-eslint/no-var-requires const simpleble = require('bindings')('simpleble.node'); module.exports = simpleble; @@ -85,10 +87,7 @@ export interface Peripheral { } /** SimpleBLE Adapter. */ -export interface Adapter { - identifier: string; - address: string; - active: boolean; +export interface Adapter extends HardwareAdapterDetails { peripherals: Peripheral[]; pairedPeripherals: Peripheral[]; scanFor(ms: number): boolean; diff --git a/src/bluetooth.ts b/src/bluetooth.ts index 368241f0..dd1101ef 100644 --- a/src/bluetooth.ts +++ b/src/bluetooth.ts @@ -27,6 +27,7 @@ import { adapter, EVENT_ENABLED } from './adapters'; import { BluetoothDeviceImpl, BluetoothDeviceEvents } from './device'; import { BluetoothUUID } from './uuid'; import { EventDispatcher, DOMEvent } from './events'; +import { HardwareAdapterDetails } from './adapters/adapter'; /** * Bluetooth Options interface @@ -51,6 +52,11 @@ export interface BluetoothOptions { * An optional referring device */ referringDevice?: BluetoothDevice; + + /** + * An optional BLE Hardware Adapter index to use + */ + hardwareAdapterIndex?: number; } /** @@ -88,6 +94,9 @@ export class BluetoothImpl extends EventDispatcher implements B if (options.scanTime) { this.scanTime = options.scanTime * 1000; } + if (typeof options.hardwareAdapterIndex === 'number') { + adapter.useHardwareAdapter(options.hardwareAdapterIndex); + } adapter.on(EVENT_ENABLED, _value => { this.dispatchEvent(new DOMEvent(this, 'availabilitychanged')); @@ -405,3 +414,7 @@ export class BluetoothImpl extends EventDispatcher implements B throw new Error('requestLEScan error: method not implemented.'); } } + +export function getHardwareAdapters(): HardwareAdapterDetails[] { + return adapter.getHardwareAdapters(); +} diff --git a/src/index.ts b/src/index.ts index cbdcf322..b9ad28e6 100644 --- a/src/index.ts +++ b/src/index.ts @@ -23,7 +23,7 @@ * SOFTWARE. */ -import { BluetoothImpl, BluetoothOptions } from './bluetooth'; +import { BluetoothImpl, BluetoothOptions, getHardwareAdapters } from './bluetooth'; /** * Default bluetooth instance synonymous with `navigator.bluetooth` @@ -33,7 +33,7 @@ export const bluetooth = new BluetoothImpl(); /** * Bluetooth class for creating new instances */ -export { BluetoothImpl as Bluetooth, BluetoothOptions }; +export { BluetoothImpl as Bluetooth, BluetoothOptions, getHardwareAdapters as getSimpleBleHardwareAdapters }; /** * Helper methods and enums