Skip to content

Commit

Permalink
Typings for Web bluetooth (DefinitelyTyped#11459)
Browse files Browse the repository at this point in the history
* Typings for Web Bluetooth

* Rename web-bluetooth.d.ts to index.d.ts
  • Loading branch information
urish authored and mhegazy committed Oct 3, 2016
1 parent 6447184 commit 719081a
Show file tree
Hide file tree
Showing 2 changed files with 208 additions and 0 deletions.
123 changes: 123 additions & 0 deletions web-bluetooth/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
// Type definitions for Web Bluetooth
// Project: https://webbluetoothcg.github.io/web-bluetooth/
// Definitions by: Uri Shaked <https://github.com/urish/>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped

type BluetoothServiceUUID = number | string;
type BluetoothCharacteristicUUID = number | string;
type BluetoothDescriptorUUID = number | string;

interface BluetoothRequestDeviceFilter {
services?: BluetoothServiceUUID[];
name?: string;
namePrefix?: string;
manufacturerId?: number;
serviceDataUUID?: BluetoothServiceUUID;
}

interface RequestDeviceOptions {
filters: BluetoothRequestDeviceFilter[];
optionalServices?: number[];
acceptAllDevices?: boolean;
}

interface BluetoothRemoteGATTDescriptor {
readonly characteristic: BluetoothRemoteGATTCharacteristic;
readonly uuid: string;
readonly value?: DataView;
readValue(): Promise<DataView>;
writeValue(value: BufferSource): Promise<void>;
}

interface BluetoothCharacteristicProperties {
readonly broadcast: boolean;
readonly read: boolean;
readonly writeWithoutResponse: boolean;
readonly write: boolean;
readonly notify: boolean;
readonly indicate: boolean;
readonly authenticatedSignedWrites: boolean;
readonly reliableWrite: boolean;
readonly writableAuxiliaries: boolean;
}

interface CharacteristicEventHandlers {
oncharacteristicvaluechanged: (this: this, ev: Event) => any;
}

interface BluetoothRemoteGATTCharacteristic extends EventTarget, CharacteristicEventHandlers {
readonly service?: BluetoothRemoteGATTService;
readonly uuid: string;
readonly properties: BluetoothCharacteristicProperties;
readonly value?: DataView;
getDescriptor(descriptor: BluetoothDescriptorUUID): Promise<BluetoothRemoteGATTDescriptor>;
getDescriptors(descriptor?: BluetoothDescriptorUUID): Promise<BluetoothRemoteGATTDescriptor[]>;
readValue(): Promise<DataView>;
writeValue(value: BufferSource): Promise<void>;
startNotifications(): Promise<BluetoothRemoteGATTCharacteristic>;
stopNotifications(): Promise<BluetoothRemoteGATTCharacteristic>;
addEventListener(type: "characteristicvaluechanged", listener: (this: this, ev: Event) => any, useCapture?: boolean): void;
addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void;
}

interface ServiceEventHandlers {
onserviceadded: (this: this, ev: Event) => any;
onservicechanged: (this: this, ev: Event) => any;
onserviceremoved: (this: this, ev: Event) => any;
}

interface BluetoothRemoteGATTService extends EventTarget, CharacteristicEventHandlers, ServiceEventHandlers {
readonly device: BluetoothDevice;
readonly uuid: string;
readonly isPrimary: boolean;
getCharacteristic(characteristic: BluetoothCharacteristicUUID): Promise<BluetoothRemoteGATTCharacteristic>;
getCharacteristics(characteristic?: BluetoothCharacteristicUUID): Promise<BluetoothRemoteGATTCharacteristic[]>;
getIncludedService(service: BluetoothServiceUUID): Promise<BluetoothRemoteGATTService>;
getIncludedServices(service?: BluetoothServiceUUID): Promise<BluetoothRemoteGATTService[]>;
addEventListener(type: "serviceadded", listener: (this: this, ev: Event) => any, useCapture?: boolean): void;
addEventListener(type: "servicechanged", listener: (this: this, ev: Event) => any, useCapture?: boolean): void;
addEventListener(type: "serviceremoved", listener: (this: this, ev: Event) => any, useCapture?: boolean): void;
addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void;
}

interface BluetoothRemoteGATTServer extends EventTarget {
readonly device: BluetoothDevice;
readonly connected: boolean;
connect(): Promise<BluetoothRemoteGATTServer>;
disconnect(): void;
getPrimaryService(service: BluetoothServiceUUID): Promise<BluetoothRemoteGATTService>;
getPrimaryServices(service?: BluetoothServiceUUID): Promise<BluetoothRemoteGATTService[]>;
}

interface BluetoothDeviceEventHandlers {
ongattserverdisconnected: (this: this, ev: Event) => any;
}

interface BluetoothDevice extends EventTarget, BluetoothDeviceEventHandlers, CharacteristicEventHandlers, ServiceEventHandlers {
readonly id: string;
readonly name?: string;
readonly gatt?: BluetoothRemoteGATTServer;
readonly uuids?: string[];

watchAdvertisements(): Promise<void>;
unwatchAdvertisements(): void;
readonly watchingAdvertisements: boolean;

addEventListener(type: "gattserverdisconnected", listener: (this: this, ev: Event) => any, useCapture?: boolean): void;
addEventListener(type: "advertisementreceived", listener: (this: this, ev: Event) => any, useCapture?: boolean): void;
addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void;
}

interface Bluetooth extends EventTarget, BluetoothDeviceEventHandlers, CharacteristicEventHandlers, ServiceEventHandlers {
getAvailability(): Promise<boolean>;
onavailabilitychanged: (this: this, ev: Event) => any;
readonly referringDevice?: BluetoothDevice;
requestDevice(options?: RequestDeviceOptions): Promise<BluetoothDevice>;

addEventListener(type: "availabilitychanged", listener: (this: this, ev: Event) => any, useCapture?: boolean): void;
addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void;
}

interface Navigator {
bluetooth: Bluetooth;
}
85 changes: 85 additions & 0 deletions web-bluetooth/web-bluetooth-tests.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
// Example 1 (from the spec):
let chosenHeartRateService: BluetoothRemoteGATTService = null;

navigator.bluetooth.requestDevice({
filters: [{
services: ['heart_rate'],
}]
}).then((device: BluetoothDevice) => device.gatt.connect())
.then((server: BluetoothRemoteGATTServer) => server.getPrimaryService('heart_rate'))
.then((service: BluetoothRemoteGATTService) => {
chosenHeartRateService = service;
return Promise.all([
service.getCharacteristic('body_sensor_location')
.then(handleBodySensorLocationCharacteristic),
service.getCharacteristic('heart_rate_measurement')
.then(handleHeartRateMeasurementCharacteristic),
]);
});

function handleBodySensorLocationCharacteristic(characteristic: BluetoothRemoteGATTCharacteristic) {
if (characteristic === null) {
console.log("Unknown sensor location.");
return Promise.resolve();
}
return characteristic.readValue()
.then(sensorLocationData => {
let sensorLocation = sensorLocationData.getUint8(0);
switch (sensorLocation) {
case 0: return 'Other';
case 1: return 'Chest';
case 2: return 'Wrist';
case 3: return 'Finger';
case 4: return 'Hand';
case 5: return 'Ear Lobe';
case 6: return 'Foot';
default: return 'Unknown';
}
}).then(location => console.log(location));
}

function handleHeartRateMeasurementCharacteristic(characteristic: BluetoothRemoteGATTCharacteristic) {
return characteristic.startNotifications()
.then(char => {
characteristic.addEventListener('characteristicvaluechanged',
onHeartRateChanged);
});
}

function onHeartRateChanged(event: Event) {
let characteristic = event.target as BluetoothRemoteGATTCharacteristic;
console.log(parseHeartRate(characteristic.value));
}

function parseHeartRate(data: DataView) {
let flags = data.getUint8(0);
let rate16Bits = flags & 0x1;
let result: any = {};
let index = 1;
if (rate16Bits) {
result.heartRate = data.getUint16(index, /*littleEndian=*/true);
index += 2;
} else {
result.heartRate = data.getUint8(index);
index += 1;
}
let contactDetected = flags & 0x2;
let contactSensorPresent = flags & 0x4;
if (contactSensorPresent) {
result.contactDetected = !!contactDetected;
}
let energyPresent = flags & 0x8;
if (energyPresent) {
result.energyExpended = data.getUint16(index, /*littleEndian=*/true);
index += 2;
}
let rrIntervalPresent = flags & 0x10;
if (rrIntervalPresent) {
let rrIntervals: number[] = [];
for (; index + 1 < data.byteLength; index += 2) {
rrIntervals.push(data.getUint16(index, /*littleEndian=*/true));
}
result.rrIntervals = rrIntervals;
}
return result;
}

0 comments on commit 719081a

Please sign in to comment.