Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 10 additions & 11 deletions src/adapters/adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,25 +23,24 @@
* SOFTWARE.
*/

import { EventEmitter } from 'events';
import { BluetoothDeviceImpl } from '../device';
import { BluetoothRemoteGATTServiceImpl } from '../service';
import { BluetoothRemoteGATTCharacteristicImpl } from '../characteristic';
import { BluetoothRemoteGATTDescriptorImpl } from '../descriptor';
import { BluetoothDevice } from '../device';
import { BluetoothRemoteGATTService } from '../service';
import { BluetoothRemoteGATTCharacteristic } from '../characteristic';
import { BluetoothRemoteGATTDescriptor } from '../descriptor';

/**
* @hidden
*/
export interface Adapter extends EventEmitter {
export interface Adapter extends EventTarget {
getEnabled: () => Promise<boolean>;
startScan: (serviceUUIDs: Array<string>, foundFn: (device: Partial<BluetoothDeviceImpl>) => void) => Promise<void>;
startScan: (serviceUUIDs: Array<string>, foundFn: (device: Partial<BluetoothDevice>) => void) => Promise<void>;
stopScan: () => void;
connect: (handle: string, disconnectFn?: () => void) => Promise<void>;
disconnect: (handle: string) => Promise<void>;
discoverServices: (handle: string, serviceUUIDs?: Array<string>) => Promise<Array<Partial<BluetoothRemoteGATTServiceImpl>>>;
discoverIncludedServices: (handle: string, serviceUUIDs?: Array<string>) => Promise<Array<Partial<BluetoothRemoteGATTServiceImpl>>>;
discoverCharacteristics: (handle: string, characteristicUUIDs?: Array<string>) => Promise<Array<Partial<BluetoothRemoteGATTCharacteristicImpl>>>;
discoverDescriptors: (handle: string, descriptorUUIDs?: Array<string>) => Promise<Array<Partial<BluetoothRemoteGATTDescriptorImpl>>>;
discoverServices: (handle: string, serviceUUIDs?: Array<string>) => Promise<Array<Partial<BluetoothRemoteGATTService>>>;
discoverIncludedServices: (handle: string, serviceUUIDs?: Array<string>) => Promise<Array<Partial<BluetoothRemoteGATTService>>>;
discoverCharacteristics: (handle: string, characteristicUUIDs?: Array<string>) => Promise<Array<Partial<BluetoothRemoteGATTCharacteristic>>>;
discoverDescriptors: (handle: string, descriptorUUIDs?: Array<string>) => Promise<Array<Partial<BluetoothRemoteGATTDescriptor>>>;
readCharacteristic: (handle: string) => Promise<DataView>;
writeCharacteristic: (handle: string, value: DataView, withoutResponse?: boolean) => Promise<void>;
enableNotify: (handle: string, notifyFn: () => void) => Promise<void>;
Expand Down
23 changes: 11 additions & 12 deletions src/adapters/simpleble-adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,12 @@
* SOFTWARE.
*/

import { EventEmitter } from 'events';
import { Adapter as BluetoothAdapter } from './adapter';
import { BluetoothUUID } from '../uuid';
import { BluetoothDeviceImpl } from '../device';
import { BluetoothRemoteGATTCharacteristicImpl } from '../characteristic';
import { BluetoothRemoteGATTServiceImpl } from '../service';
import { BluetoothRemoteGATTDescriptorImpl } from '../descriptor';
import { BluetoothDevice } from '../device';
import { BluetoothRemoteGATTCharacteristic } from '../characteristic';
import { BluetoothRemoteGATTService } from '../service';
import { BluetoothRemoteGATTDescriptor } from '../descriptor';
import {
isEnabled,
getAdapters,
Expand All @@ -42,7 +41,7 @@ import {
/**
* @hidden
*/
export class SimplebleAdapter extends EventEmitter implements BluetoothAdapter {
export class SimplebleAdapter extends EventTarget implements BluetoothAdapter {
private adapter: Adapter;
private peripherals = new Map<string, Peripheral>();
private servicesByPeripheral = new Map<Peripheral, Service[]>();
Expand All @@ -53,7 +52,7 @@ export class SimplebleAdapter extends EventEmitter implements BluetoothAdapter {
private descriptors = new Map<string, string[]>();
private charEvents = new Map<string, (value: DataView) => void>();

private validDevice(device: Partial<BluetoothDeviceImpl>, serviceUUIDs: Array<string>): boolean {
private validDevice(device: Partial<BluetoothDevice>, serviceUUIDs: Array<string>): boolean {
if (serviceUUIDs.length === 0) {
// Match any device
return true;
Expand All @@ -70,7 +69,7 @@ export class SimplebleAdapter extends EventEmitter implements BluetoothAdapter {
return serviceUUIDs.some(serviceUUID => advertisedUUIDs.indexOf(serviceUUID) >= 0);
}

private buildBluetoothDevice(device: Peripheral): Partial<BluetoothDeviceImpl> {
private buildBluetoothDevice(device: Peripheral): Partial<BluetoothDevice> {
const name = device.identifier;
const address = device.address;
const rssi = device.rssi;
Expand Down Expand Up @@ -215,7 +214,7 @@ export class SimplebleAdapter extends EventEmitter implements BluetoothAdapter {
}
}

public async discoverServices(id: string, serviceUUIDs?: Array<string>): Promise<Array<Partial<BluetoothRemoteGATTServiceImpl>>> {
public async discoverServices(id: string, serviceUUIDs?: Array<string>): Promise<Array<Partial<BluetoothRemoteGATTService>>> {
const peripheral = this.peripherals.get(id);
if (!peripheral) {
throw new Error('Peripheral not found');
Expand All @@ -234,12 +233,12 @@ export class SimplebleAdapter extends EventEmitter implements BluetoothAdapter {
return discovered;
}

public async discoverIncludedServices(_handle: string, _serviceUUIDs?: Array<string>): Promise<Array<Partial<BluetoothRemoteGATTServiceImpl>>> {
public async discoverIncludedServices(_handle: string, _serviceUUIDs?: Array<string>): Promise<Array<Partial<BluetoothRemoteGATTService>>> {
// Currently not implemented
return [];
}

public async discoverCharacteristics(serviceUuid: string, characteristicUUIDs?: Array<string>): Promise<Array<Partial<BluetoothRemoteGATTCharacteristicImpl>>> {
public async discoverCharacteristics(serviceUuid: string, characteristicUUIDs?: Array<string>): Promise<Array<Partial<BluetoothRemoteGATTCharacteristic>>> {
const peripheral = this.peripheralByService.get(serviceUuid);
const characteristics = this.characteristicsByService.get(serviceUuid);
const discovered = [];
Expand Down Expand Up @@ -288,7 +287,7 @@ export class SimplebleAdapter extends EventEmitter implements BluetoothAdapter {
return discovered;
}

public async discoverDescriptors(charUuid: string, descriptorUUIDs?: Array<string>): Promise<Array<Partial<BluetoothRemoteGATTDescriptorImpl>>> {
public async discoverDescriptors(charUuid: string, descriptorUUIDs?: Array<string>): Promise<Array<Partial<BluetoothRemoteGATTDescriptor>>> {
const descriptors = this.descriptors.get(charUuid);
const discovered = [];

Expand Down
56 changes: 41 additions & 15 deletions src/bluetooth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@
*/

import { adapter, EVENT_ENABLED } from './adapters';
import { BluetoothDeviceImpl, BluetoothDeviceEvents } from './device';
import { BluetoothDevice, BluetoothDeviceEvents } from './device';
import { BluetoothUUID } from './uuid';
import { EventDispatcher, DOMEvent } from './events';
import { DOMEvent } from './events';

/**
* Bluetooth Options interface
Expand Down Expand Up @@ -54,19 +54,31 @@ export interface BluetoothOptions {
}

/**
* @hidden
* Events for {@link Bluetooth}.
*/
export interface BluetoothEvents extends BluetoothDeviceEvents {
/**
* Bluetooth Availability Changed event
*/
availabilitychanged: Event;
availabilitychanged: BluetoothAdvertisingEvent;
}

/**
* Bluetooth class
* Bluetooth class.
*
* ### Events
*
* | Name | Event | Description |
* | ---- | ----- | ----------- |
* | `advertisementreceived` | {@link BluetoothAdvertisingEvent} | Advertisement received. |
* | `availabilitychanged` | {@link Event} | Bluetooth availability changed. |
* | `characteristicvaluechanged` | {@link Event} | The value of a BLE Characteristic has changed. |
* | `gattserverdisconnected` | {@link Event} | GATT server has been disconnected. |
* | `serviceadded` | {@link Event} | A new service is available. |
* | `servicechanged` | {@link Event} | An existing service has changed. |
* | `serviceremoved` | {@link Event} | A service is unavailable. |
*/
export class BluetoothImpl extends EventDispatcher<BluetoothEvents> implements Bluetooth {
export class Bluetooth extends EventTarget {
/**
* Referring device for the bluetooth instance
*/
Expand All @@ -77,6 +89,20 @@ export class BluetoothImpl extends EventDispatcher<BluetoothEvents> implements B
private scanner = undefined;
private allowedDevices = new Set<string>();

public addEventListener<K extends keyof BluetoothEvents>(
type: K,
callback: (this: this, event: BluetoothEvents[K]) => void,
options?: boolean | AddEventListenerOptions
): void;
/** @hidden */
public addEventListener(
type: string,
callback: EventListenerOrEventListenerObject | null,
options?: EventListenerOptions | boolean
): void {
super.addEventListener(type, callback, options);
}

/**
* Bluetooth constructor
* @param options Bluetooth initialisation options
Expand All @@ -89,7 +115,7 @@ export class BluetoothImpl extends EventDispatcher<BluetoothEvents> implements B
this.scanTime = options.scanTime * 1000;
}

adapter.on(EVENT_ENABLED, _value => {
adapter.addEventListener(EVENT_ENABLED, _value => {
this.dispatchEvent(new DOMEvent(this, 'availabilitychanged'));
});
}
Expand Down Expand Up @@ -166,8 +192,8 @@ export class BluetoothImpl extends EventDispatcher<BluetoothEvents> implements B
}
}

private _onavailabilitychanged: (ev: Event) => void;
public set onavailabilitychanged(fn: (ev: Event) => void) {
private _onavailabilitychanged: (ev: BluetoothAdvertisingEvent) => void;
public set onavailabilitychanged(fn: (ev: BluetoothAdvertisingEvent) => void) {
if (this._onavailabilitychanged) {
this.removeEventListener('availabilitychanged', this._onavailabilitychanged);
this._onavailabilitychanged = undefined;
Expand All @@ -178,7 +204,7 @@ export class BluetoothImpl extends EventDispatcher<BluetoothEvents> implements B
}
}

private filterDevice(filters: Array<BluetoothLEScanFilter>, deviceInfo: Partial<BluetoothDeviceImpl>, validServices): Partial<BluetoothDevice> | undefined {
private filterDevice(filters: Array<BluetoothLEScanFilter>, deviceInfo: Partial<BluetoothDevice>, validServices): Partial<BluetoothDevice> | undefined {
let valid = false;

filters.forEach(filter => {
Expand Down Expand Up @@ -310,7 +336,7 @@ export class BluetoothImpl extends EventDispatcher<BluetoothEvents> implements B
}
}, this.scanTime);

adapter.startScan(searchUUIDs, deviceInfo => {
adapter.startScan(searchUUIDs, (deviceInfo: BluetoothDevice) => {
let validServices = [];

const complete = (bluetoothDevice: BluetoothDevice) => {
Expand All @@ -321,7 +347,7 @@ export class BluetoothImpl extends EventDispatcher<BluetoothEvents> implements B

// filter devices if filters specified
if (isFiltered(options)) {
deviceInfo = this.filterDevice(options.filters, deviceInfo, validServices);
deviceInfo = this.filterDevice(options.filters, deviceInfo, validServices) as BluetoothDevice;
}

if (deviceInfo) {
Expand All @@ -341,7 +367,7 @@ export class BluetoothImpl extends EventDispatcher<BluetoothEvents> implements B
_allowedServices: allowedServices
});

const bluetoothDevice = new BluetoothDeviceImpl(deviceInfo, () => this.forgetDevice(deviceInfo.id));
const bluetoothDevice = new BluetoothDevice(deviceInfo, () => this.forgetDevice(deviceInfo.id));

const selectFn = () => {
complete.call(this, bluetoothDevice);
Expand Down Expand Up @@ -372,14 +398,14 @@ export class BluetoothImpl extends EventDispatcher<BluetoothEvents> implements B
resolve(devices);
}, this.scanTime);

adapter.startScan([], deviceInfo => {
adapter.startScan([], (deviceInfo: BluetoothDevice) => {
if (this.options?.allowAllDevices || this.allowedDevices.has(deviceInfo.id)) {
Object.assign(deviceInfo, {
_bluetooth: this,
_allowedServices: []
});

const bluetoothDevice = new BluetoothDeviceImpl(deviceInfo, () => this.forgetDevice(deviceInfo.id));
const bluetoothDevice = new BluetoothDevice(deviceInfo, () => this.forgetDevice(deviceInfo.id));
devices.push(bluetoothDevice);
}
});
Expand Down
46 changes: 37 additions & 9 deletions src/characteristic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,15 @@
*/

import { adapter } from './adapters';
import { BluetoothRemoteGATTDescriptorImpl } from './descriptor';
import { BluetoothRemoteGATTDescriptor } from './descriptor';
import { BluetoothUUID } from './uuid';
import { BluetoothRemoteGATTServiceImpl } from './service';
import { EventDispatcher, DOMEvent } from './events';
import { BluetoothRemoteGATTService } from './service';
import { DOMEvent } from './events';

const isView = (source: ArrayBuffer | ArrayBufferView): source is ArrayBufferView => (source as ArrayBufferView).buffer !== undefined;

/**
* @hidden
* Events for {@link BluetoothRemoteGATTCharacteristic}.
*/
export interface CharacteristicEvents {
/**
Expand All @@ -42,14 +42,20 @@ export interface CharacteristicEvents {
}

/**
* Bluetooth Remote GATT Characteristic class
* Bluetooth Remote GATT Characteristic class.
*
* ### Events
*
* | Name | Event | Description |
* | ---- | ----- | ----------- |
* | `characteristicvaluechanged` | {@link Event} | The value of a BLE Characteristic has changed. |
*/
export class BluetoothRemoteGATTCharacteristicImpl extends EventDispatcher<CharacteristicEvents> implements BluetoothRemoteGATTCharacteristic {
export class BluetoothRemoteGATTCharacteristic extends EventTarget {

/**
* The service the characteristic is related to
*/
public readonly service: BluetoothRemoteGATTServiceImpl = undefined;
public readonly service: BluetoothRemoteGATTService = undefined;

/**
* The unique identifier of the characteristic
Expand Down Expand Up @@ -88,7 +94,7 @@ export class BluetoothRemoteGATTCharacteristicImpl extends EventDispatcher<Chara
* Characteristic constructor
* @param init A partial class to initialise values
*/
constructor(init: Partial<BluetoothRemoteGATTCharacteristicImpl>) {
constructor(init: Partial<BluetoothRemoteGATTCharacteristic>) {
super();

this.service = init.service;
Expand All @@ -99,6 +105,28 @@ export class BluetoothRemoteGATTCharacteristicImpl extends EventDispatcher<Chara
this.handle = this.uuid;
}

/**
* Bluetooth events.
*
* | Event | Description |
* | ----- | ----------- |
* | `availabilitychanged` | Bluetooth availability changed. |
* | `advertisementreceived` | Advertisement received. |
*/
public addEventListener<K extends keyof CharacteristicEvents>(
type: K,
callback: (this: this, event: CharacteristicEvents[K]) => void,
options?: boolean | AddEventListenerOptions
): void;
/** @hidden */
public addEventListener(
type: string,
callback: EventListenerOrEventListenerObject | null,
options?: EventListenerOptions | boolean
): void {
super.addEventListener(type, callback, options);
}

private setValue(value?: DataView, emit?: boolean) {
this._value = value;
if (emit) {
Expand Down Expand Up @@ -147,7 +175,7 @@ export class BluetoothRemoteGATTCharacteristicImpl extends EventDispatcher<Chara
Object.assign(descriptorInfo, {
characteristic: this
});
return new BluetoothRemoteGATTDescriptorImpl(descriptorInfo);
return new BluetoothRemoteGATTDescriptor(descriptorInfo);
});
}

Expand Down
3 changes: 2 additions & 1 deletion src/descriptor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import { adapter } from './adapters';
/**
* Bluetooth Remote GATT Descriptor class
*/
export class BluetoothRemoteGATTDescriptorImpl implements BluetoothRemoteGATTDescriptor {
export class BluetoothRemoteGATTDescriptor extends EventTarget {

/**
* The characteristic the descriptor is related to
Expand All @@ -55,6 +55,7 @@ export class BluetoothRemoteGATTDescriptorImpl implements BluetoothRemoteGATTDes
* @param init A partial class to initialise values
*/
constructor(init: Partial<BluetoothRemoteGATTDescriptor>) {
super();
this.characteristic = init.characteristic;
this.uuid = init.uuid;
this._value = init.value;
Expand Down
Loading