webbluetooth
Advanced tools
Comparing version 0.0.4 to 0.0.5
@@ -26,3 +26,3 @@ /* | ||
var bluetooth = require('../index'); | ||
var bluetooth = require('../').bluetooth; | ||
var gattServer; | ||
@@ -66,2 +66,5 @@ var heartChar; | ||
}).then(value => { | ||
if (!value.buffer.byteLength) { | ||
return log('No value'); | ||
} | ||
log('Value: ' + value.getUint16(0)); | ||
@@ -68,0 +71,0 @@ }); |
@@ -27,2 +27,3 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const events_1 = require("events"); | ||
const helpers_1 = require("./helpers"); | ||
@@ -33,4 +34,5 @@ const noble = require("noble"); | ||
*/ | ||
class NobleAdapter { | ||
class NobleAdapter extends events_1.EventEmitter { | ||
constructor() { | ||
super(); | ||
this.deviceHandles = {}; | ||
@@ -43,3 +45,14 @@ this.serviceHandles = {}; | ||
this.initialised = false; | ||
this.enabled = false; | ||
this.enabled = this.state; | ||
noble.on("stateChange", () => { | ||
if (this.enabled !== this.state) { | ||
this.enabled = this.state; | ||
this.emit(NobleAdapter.EVENT_ENABLED, this.enabled); | ||
} | ||
}); | ||
} | ||
get state() { | ||
return (noble.state === "poweredOn"); | ||
} | ||
init(completeFn) { | ||
@@ -90,3 +103,3 @@ if (this.initialised) | ||
const buffer = deviceInfo.advertisement.manufacturerData.slice(2); | ||
manufacturerData[company] = this.bufferToDataView(buffer); | ||
manufacturerData.set(company, this.bufferToDataView(buffer)); | ||
} | ||
@@ -96,19 +109,28 @@ const serviceData = new Map(); | ||
deviceInfo.advertisement.serviceData.forEach(serviceAdvert => { | ||
serviceData[helpers_1.getCanonicalUUID(serviceAdvert.uuid)] = this.bufferToDataView(serviceAdvert.data); | ||
serviceData.set(helpers_1.getCanonicalUUID(serviceAdvert.uuid), this.bufferToDataView(serviceAdvert.data)); | ||
}); | ||
} | ||
this.foundFn({ | ||
_handle: deviceID, | ||
id: deviceID, | ||
name: deviceInfo.advertisement.localName, | ||
uuids: serviceUUIDs | ||
// adData: { | ||
// manufacturerData: manufacturerData, | ||
// serviceData: serviceData, | ||
// txPower: deviceInfo.advertisement.txPowerLevel, | ||
// rssi: deviceInfo.rssi | ||
// } | ||
_serviceUUIDs: serviceUUIDs, | ||
adData: { | ||
rssi: deviceInfo.rssi, | ||
txPower: deviceInfo.advertisement.txPowerLevel, | ||
serviceData: serviceData, | ||
manufacturerData: manufacturerData | ||
} | ||
}); | ||
} | ||
} | ||
getEnabled(completeFn) { | ||
function stateCB() { | ||
completeFn(this.state); | ||
} | ||
// tslint:disable-next-line:no-string-literal | ||
if (noble.state === "unknown") | ||
noble["once"]("stateChange", stateCB.bind(this)); | ||
else | ||
stateCB.call(this); | ||
} | ||
startScan(serviceUUIDs, foundFn, completeFn, errorFn) { | ||
@@ -121,3 +143,3 @@ if (serviceUUIDs.length === 0) { | ||
serviceUUIDs.forEach(serviceUUID => { | ||
if (device.uuids.indexOf(serviceUUID) >= 0) { | ||
if (device._serviceUUIDs.indexOf(serviceUUID) >= 0) { | ||
foundFn(device); | ||
@@ -131,4 +153,4 @@ return; | ||
this.deviceHandles = {}; | ||
function stateCB(state) { | ||
if (state === "poweredOn") { | ||
function stateCB() { | ||
if (this.state === true) { | ||
noble.startScanning([], false, this.checkForError(errorFn, completeFn)); | ||
@@ -144,3 +166,3 @@ } | ||
else | ||
stateCB.call(this, noble.state); | ||
stateCB.call(this); | ||
}); | ||
@@ -177,3 +199,2 @@ } | ||
discovered.push({ | ||
_handle: serviceUUID, | ||
uuid: serviceUUID, | ||
@@ -197,3 +218,2 @@ primary: true | ||
discovered.push({ | ||
_handle: serviceUUID, | ||
uuid: serviceUUID, | ||
@@ -217,3 +237,2 @@ primary: false | ||
discovered.push({ | ||
_handle: charUUID, | ||
uuid: charUUID, | ||
@@ -254,3 +273,2 @@ properties: { | ||
discovered.push({ | ||
_handle: descHandle, | ||
uuid: descUUID | ||
@@ -310,2 +328,3 @@ }); | ||
} | ||
NobleAdapter.EVENT_ENABLED = "enabledchanged"; | ||
exports.NobleAdapter = NobleAdapter; | ||
@@ -312,0 +331,0 @@ /** |
@@ -27,136 +27,152 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const dispatcher_1 = require("./dispatcher"); | ||
const device_1 = require("./device"); | ||
const helpers_1 = require("./helpers"); | ||
const adapter_1 = require("./adapter"); | ||
/** | ||
* @hidden | ||
*/ | ||
const defaultScanTime = 10.24 * 1000; | ||
/** | ||
* @hidden | ||
*/ | ||
let scanner = null; | ||
/** | ||
* @hidden | ||
*/ | ||
function filterDevice(options, deviceInfo, validServices) { | ||
let valid = false; | ||
options.filters.forEach(filter => { | ||
// Name | ||
if (filter.name && filter.name !== deviceInfo.name) | ||
return; | ||
// NamePrefix | ||
if (filter.namePrefix) { | ||
if (filter.namePrefix.length > deviceInfo.name.length) | ||
class Bluetooth extends dispatcher_1.EventDispatcher { | ||
constructor(referringDevice) { | ||
super(); | ||
this.referringDevice = referringDevice; | ||
this.defaultScanTime = 10.24 * 1000; | ||
this.scanner = null; | ||
adapter_1.adapter.on(adapter_1.NobleAdapter.EVENT_ENABLED, value => { | ||
this.dispatchEvent(Bluetooth.EVENT_AVAILABILITY, value); | ||
}); | ||
} | ||
filterDevice(options, deviceInfo, validServices) { | ||
let valid = false; | ||
options.filters.forEach(filter => { | ||
// Name | ||
if (filter.name && filter.name !== deviceInfo.name) | ||
return; | ||
if (filter.namePrefix !== deviceInfo.name.substr(0, filter.namePrefix.length)) | ||
return; | ||
} | ||
// Services | ||
if (filter.services) { | ||
const serviceUUIDs = filter.services.map(helpers_1.getServiceUUID); | ||
const servicesValid = serviceUUIDs.every(serviceUUID => { | ||
return (deviceInfo.uuids.indexOf(serviceUUID) > -1); | ||
}); | ||
if (!servicesValid) | ||
return; | ||
validServices = validServices.concat(serviceUUIDs); | ||
} | ||
valid = true; | ||
}); | ||
if (!valid) | ||
return false; | ||
return deviceInfo; | ||
} | ||
function requestDevice(options) { | ||
return new Promise((resolve, reject) => { | ||
if (scanner !== null) | ||
return reject("requestDevice error: request in progress"); | ||
if (!options.acceptAllDevices && !options.deviceFound) { | ||
// Must have a filter | ||
if (!options.filters || options.filters.length === 0) { | ||
return reject(new TypeError("requestDevice error: no filters specified")); | ||
// NamePrefix | ||
if (filter.namePrefix) { | ||
if (filter.namePrefix.length > deviceInfo.name.length) | ||
return; | ||
if (filter.namePrefix !== deviceInfo.name.substr(0, filter.namePrefix.length)) | ||
return; | ||
} | ||
// Don't allow empty filters | ||
const emptyFilter = options.filters.some(filter => { | ||
return (Object.keys(filter).length === 0); | ||
}); | ||
if (emptyFilter) { | ||
return reject(new TypeError("requestDevice error: empty filter specified")); | ||
// Services | ||
if (filter.services) { | ||
const serviceUUIDs = filter.services.map(helpers_1.getServiceUUID); | ||
const servicesValid = serviceUUIDs.every(serviceUUID => { | ||
return (deviceInfo._serviceUUIDs.indexOf(serviceUUID) > -1); | ||
}); | ||
if (!servicesValid) | ||
return; | ||
validServices = validServices.concat(serviceUUIDs); | ||
} | ||
// Don't allow empty namePrefix | ||
const emptyPrefix = options.filters.some(filter => { | ||
return (typeof filter.namePrefix !== "undefined" && filter.namePrefix === ""); | ||
valid = true; | ||
}); | ||
if (!valid) | ||
return false; | ||
return deviceInfo; | ||
} | ||
getAvailability() { | ||
return new Promise((resolve, _reject) => { | ||
adapter_1.adapter.getEnabled(enabled => { | ||
resolve(enabled); | ||
}); | ||
if (emptyPrefix) { | ||
return reject(new TypeError("requestDevice error: empty namePrefix specified")); | ||
} | ||
} | ||
let searchUUIDs = []; | ||
if (options.filters) { | ||
options.filters.forEach(filter => { | ||
if (filter.services) | ||
searchUUIDs = searchUUIDs.concat(filter.services.map(helpers_1.getServiceUUID)); | ||
}); | ||
} | ||
// Unique-ify | ||
searchUUIDs = searchUUIDs.filter((item, index, array) => { | ||
return array.indexOf(item) === index; | ||
}); | ||
let found = false; | ||
adapter_1.adapter.startScan(searchUUIDs, deviceInfo => { | ||
let validServices = []; | ||
function complete(bluetoothDevice) { | ||
cancelRequest() | ||
.then(() => { | ||
resolve(bluetoothDevice); | ||
} | ||
requestDevice(options) { | ||
return new Promise((resolve, reject) => { | ||
if (this.scanner !== null) | ||
return reject("requestDevice error: request in progress"); | ||
if (!options.acceptAllDevices && !options.deviceFound) { | ||
// Must have a filter | ||
if (!options.filters || options.filters.length === 0) { | ||
return reject(new TypeError("requestDevice error: no filters specified")); | ||
} | ||
// Don't allow empty filters | ||
const emptyFilter = options.filters.some(filter => { | ||
return (Object.keys(filter).length === 0); | ||
}); | ||
if (emptyFilter) { | ||
return reject(new TypeError("requestDevice error: empty filter specified")); | ||
} | ||
// Don't allow empty namePrefix | ||
const emptyPrefix = options.filters.some(filter => { | ||
return (typeof filter.namePrefix !== "undefined" && filter.namePrefix === ""); | ||
}); | ||
if (emptyPrefix) { | ||
return reject(new TypeError("requestDevice error: empty namePrefix specified")); | ||
} | ||
} | ||
// filter devices if filters specified | ||
let searchUUIDs = []; | ||
if (options.filters) { | ||
deviceInfo = filterDevice(options, deviceInfo, validServices); | ||
options.filters.forEach(filter => { | ||
if (filter.services) | ||
searchUUIDs = searchUUIDs.concat(filter.services.map(helpers_1.getServiceUUID)); | ||
}); | ||
} | ||
if (deviceInfo) { | ||
found = true; | ||
// Add additional services | ||
if (options.optionalServices) { | ||
validServices = validServices.concat(options.optionalServices.map(helpers_1.getServiceUUID)); | ||
// Unique-ify | ||
searchUUIDs = searchUUIDs.filter((item, index, array) => { | ||
return array.indexOf(item) === index; | ||
}); | ||
let found = false; | ||
adapter_1.adapter.startScan(searchUUIDs, deviceInfo => { | ||
let validServices = []; | ||
function complete(bluetoothDevice) { | ||
this.cancelRequest() | ||
.then(() => { | ||
resolve(bluetoothDevice); | ||
}); | ||
} | ||
// Set unique list of allowed services | ||
deviceInfo._allowedServices = validServices.filter((item, index, array) => { | ||
return array.indexOf(item) === index; | ||
}); | ||
const bluetoothDevice = new device_1.BluetoothDevice(deviceInfo); | ||
function selectFn() { | ||
complete(bluetoothDevice); | ||
// filter devices if filters specified | ||
if (options.filters) { | ||
deviceInfo = this.filterDevice(options, deviceInfo, validServices); | ||
} | ||
if (!options.deviceFound || options.deviceFound(bluetoothDevice, selectFn)) { | ||
// If no deviceFound function, or deviceFound returns true, resolve with this device immediately | ||
complete(bluetoothDevice); | ||
if (deviceInfo) { | ||
found = true; | ||
// Add additional services | ||
if (options.optionalServices) { | ||
validServices = validServices.concat(options.optionalServices.map(helpers_1.getServiceUUID)); | ||
} | ||
// Set unique list of allowed services | ||
const allowedServices = validServices.filter((item, index, array) => { | ||
return array.indexOf(item) === index; | ||
}); | ||
Object.assign(deviceInfo, { | ||
_bluetooth: this, | ||
_allowedServices: allowedServices | ||
}); | ||
const bluetoothDevice = new device_1.BluetoothDevice(deviceInfo); | ||
function selectFn() { | ||
complete.call(this, bluetoothDevice); | ||
} | ||
if (!options.deviceFound || options.deviceFound(bluetoothDevice, selectFn.bind(this)) === true) { | ||
// If no deviceFound function, or deviceFound returns true, resolve with this device immediately | ||
complete.call(this, bluetoothDevice); | ||
} | ||
} | ||
}, () => { | ||
this.scanner = setTimeout(() => { | ||
this.cancelRequest() | ||
.then(() => { | ||
if (!found) | ||
reject("requestDevice error: no devices found"); | ||
}); | ||
}, options.scanTime || this.defaultScanTime); | ||
}, error => reject(`requestDevice error: ${error}`)); | ||
}); | ||
} | ||
cancelRequest() { | ||
return new Promise((resolve, _reject) => { | ||
if (this.scanner) { | ||
clearTimeout(this.scanner); | ||
this.scanner = null; | ||
adapter_1.adapter.stopScan(); | ||
} | ||
}, () => { | ||
scanner = setTimeout(() => { | ||
cancelRequest() | ||
.then(() => { | ||
if (!found) | ||
reject("requestDevice error: no devices found"); | ||
}); | ||
}, options.scanTime || defaultScanTime); | ||
}, error => reject(`requestDevice error: ${error}`)); | ||
}); | ||
resolve(); | ||
}); | ||
} | ||
} | ||
exports.requestDevice = requestDevice; | ||
function cancelRequest() { | ||
return new Promise((resolve, _reject) => { | ||
if (scanner) { | ||
clearTimeout(scanner); | ||
scanner = null; | ||
adapter_1.adapter.stopScan(); | ||
} | ||
resolve(); | ||
}); | ||
} | ||
exports.cancelRequest = cancelRequest; | ||
/** | ||
* Bluetooth Availability Changed event | ||
* @event | ||
*/ | ||
Bluetooth.EVENT_AVAILABILITY = "availabilitychanged"; | ||
exports.Bluetooth = Bluetooth; | ||
//# sourceMappingURL=bluetooth.js.map |
@@ -27,23 +27,11 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const emitter_1 = require("./emitter"); | ||
const dispatcher_1 = require("./dispatcher"); | ||
const descriptor_1 = require("./descriptor"); | ||
const helpers_1 = require("./helpers"); | ||
const adapter_1 = require("./adapter"); | ||
class BluetoothRemoteGATTCharacteristic extends emitter_1.Emitter { | ||
/** | ||
* @hidden | ||
*/ | ||
class BluetoothRemoteGATTCharacteristic extends dispatcher_1.EventDispatcher { | ||
constructor(init) { | ||
super(); | ||
/** | ||
* @hidden | ||
*/ | ||
this._handle = null; | ||
/** | ||
* @hidden | ||
*/ | ||
this._descriptors = null; | ||
this.service = null; | ||
this.uuid = null; | ||
this.value = null; | ||
this.properties = { | ||
@@ -60,6 +48,18 @@ broadcast: false, | ||
}; | ||
for (const key in init) { | ||
if (init.hasOwnProperty(key)) { | ||
this[key] = init[key]; | ||
} | ||
this._value = null; | ||
this.handle = null; | ||
this.descriptors = null; | ||
Object.assign(this, init); | ||
this.handle = this.uuid; | ||
} | ||
get value() { | ||
return this._value; | ||
} | ||
setValue(value, emit) { | ||
this._value = value; | ||
if (emit) { | ||
this.dispatchEvent(BluetoothRemoteGATTCharacteristic.EVENT_CHANGED, value); | ||
this.service.dispatchEvent(BluetoothRemoteGATTCharacteristic.EVENT_CHANGED, value); | ||
this.service.device.dispatchEvent(BluetoothRemoteGATTCharacteristic.EVENT_CHANGED, value); | ||
this.service.device._bluetooth.dispatchEvent(BluetoothRemoteGATTCharacteristic.EVENT_CHANGED, value); | ||
} | ||
@@ -90,4 +90,4 @@ } | ||
if (!descriptorUUID) | ||
return resolve(this._descriptors); | ||
const filtered = this._descriptors.filter(descriptor => { | ||
return resolve(this.descriptors); | ||
const filtered = this.descriptors.filter(descriptor => { | ||
return (descriptor.uuid === helpers_1.getDescriptorUUID(descriptorUUID)); | ||
@@ -99,7 +99,9 @@ }); | ||
} | ||
if (this._descriptors) | ||
if (this.descriptors) | ||
return complete.call(this); | ||
adapter_1.adapter.discoverDescriptors(this._handle, [], descriptors => { | ||
this._descriptors = descriptors.map(descriptorInfo => { | ||
descriptorInfo.characteristic = this; | ||
adapter_1.adapter.discoverDescriptors(this.handle, [], descriptors => { | ||
this.descriptors = descriptors.map(descriptorInfo => { | ||
Object.assign(descriptorInfo, { | ||
characteristic: this | ||
}); | ||
return new descriptor_1.BluetoothRemoteGATTDescriptor(descriptorInfo); | ||
@@ -117,6 +119,5 @@ }); | ||
return reject("readValue error: device not connected"); | ||
adapter_1.adapter.readCharacteristic(this._handle, dataView => { | ||
this.value = dataView; | ||
adapter_1.adapter.readCharacteristic(this.handle, dataView => { | ||
this.setValue(dataView, true); | ||
resolve(dataView); | ||
this.emit(BluetoothRemoteGATTCharacteristic.EVENT_CHANGED); | ||
}, error => { | ||
@@ -136,4 +137,4 @@ reject(`readValue error: ${error}`); | ||
const dataView = new DataView(arrayBuffer); | ||
adapter_1.adapter.writeCharacteristic(this._handle, dataView, () => { | ||
this.value = dataView; | ||
adapter_1.adapter.writeCharacteristic(this.handle, dataView, () => { | ||
this.setValue(dataView); | ||
resolve(); | ||
@@ -149,5 +150,4 @@ }, error => { | ||
return reject("startNotifications error: device not connected"); | ||
adapter_1.adapter.enableNotify(this._handle, dataView => { | ||
this.value = dataView; | ||
this.emit(BluetoothRemoteGATTCharacteristic.EVENT_CHANGED); | ||
adapter_1.adapter.enableNotify(this.handle, dataView => { | ||
this.setValue(dataView, true); | ||
}, () => { | ||
@@ -164,3 +164,3 @@ resolve(this); | ||
return reject("stopNotifications error: device not connected"); | ||
adapter_1.adapter.disableNotify(this._handle, () => { | ||
adapter_1.adapter.disableNotify(this.handle, () => { | ||
resolve(this); | ||
@@ -167,0 +167,0 @@ }, error => { |
@@ -29,19 +29,13 @@ "use strict"; | ||
class BluetoothRemoteGATTDescriptor { | ||
/** | ||
* @hidden | ||
*/ | ||
constructor(init) { | ||
/** | ||
* @hidden | ||
*/ | ||
this._handle = null; | ||
this.characteristic = null; | ||
this.uuid = null; | ||
this.value = null; | ||
for (const key in init) { | ||
if (init.hasOwnProperty(key)) { | ||
this[key] = init[key]; | ||
} | ||
} | ||
this._value = null; | ||
this.handle = null; | ||
Object.assign(this, init); | ||
this.handle = `${this.characteristic.uuid}-${this.uuid}`; | ||
} | ||
get value() { | ||
return this._value; | ||
} | ||
readValue() { | ||
@@ -51,4 +45,4 @@ return new Promise((resolve, reject) => { | ||
return reject("readValue error: device not connected"); | ||
adapter_1.adapter.readDescriptor(this._handle, dataView => { | ||
this.value = dataView; | ||
adapter_1.adapter.readDescriptor(this.handle, dataView => { | ||
this._value = dataView; | ||
resolve(dataView); | ||
@@ -69,4 +63,4 @@ }, error => { | ||
const dataView = new DataView(arrayBuffer); | ||
adapter_1.adapter.writeDescriptor(this._handle, dataView, () => { | ||
this.value = dataView; | ||
adapter_1.adapter.writeDescriptor(this.handle, dataView, () => { | ||
this._value = dataView; | ||
resolve(); | ||
@@ -73,0 +67,0 @@ }, error => { |
@@ -27,14 +27,15 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const emitter_1 = require("./emitter"); | ||
const dispatcher_1 = require("./dispatcher"); | ||
const server_1 = require("./server"); | ||
class BluetoothDevice extends emitter_1.Emitter { | ||
/** | ||
* @hidden | ||
*/ | ||
class BluetoothDevice extends dispatcher_1.EventDispatcher { | ||
constructor(init) { | ||
super(); | ||
this.id = "unknown"; | ||
this.name = null; | ||
this.gatt = null; | ||
this.watchingAdvertisements = false; | ||
/** | ||
* @hidden | ||
*/ | ||
this._handle = null; | ||
this._bluetooth = null; | ||
/** | ||
@@ -44,19 +45,8 @@ * @hidden | ||
this._allowedServices = []; | ||
this.id = "unknown"; | ||
this.name = null; | ||
// public adData: { | ||
// public appearance?: null; | ||
// public txPower?: null; | ||
// rssi?: number; | ||
// manufacturerData = new Map(); | ||
// serviceData = new Map(); | ||
// } | ||
this.gatt = new server_1.BluetoothRemoteGATTServer(); | ||
this.uuids = []; | ||
for (const key in init) { | ||
if (init.hasOwnProperty(key)) { | ||
this[key] = init[key]; | ||
} | ||
} | ||
this.gatt.device = this; | ||
/** | ||
* @hidden | ||
*/ | ||
this._serviceUUIDs = []; | ||
Object.assign(this, init); | ||
this.gatt = new server_1.BluetoothRemoteGATTServer(this); | ||
} | ||
@@ -63,0 +53,0 @@ } |
@@ -30,12 +30,13 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
__export(require("./bluetooth")); | ||
const bluetooth_1 = require("./bluetooth"); | ||
exports.Bluetooth = bluetooth_1.Bluetooth; | ||
/** | ||
* Default bluetooth instance synonymous with `navigator.bluetooth` | ||
*/ | ||
exports.bluetooth = new bluetooth_1.Bluetooth(); | ||
/** | ||
* Helper methods and enums | ||
*/ | ||
__export(require("./helpers")); | ||
/* | ||
import { WebBluetooth } from "./bluetooth"; | ||
import { NobleAdapter } from "./adapter"; | ||
export const bluetooth = new WebBluetooth(new NobleAdapter()); | ||
export * from "./helpers"; | ||
*/ | ||
//# sourceMappingURL=index.js.map |
@@ -32,9 +32,8 @@ "use strict"; | ||
class BluetoothRemoteGATTServer { | ||
constructor() { | ||
/** | ||
* @hidden | ||
*/ | ||
this._services = null; | ||
this.device = null; | ||
constructor(device) { | ||
this.device = device; | ||
this.connected = false; | ||
this.handle = null; | ||
this.services = null; | ||
this.handle = this.device.id; | ||
} | ||
@@ -45,9 +44,10 @@ connect() { | ||
return reject("connect error: device already connected"); | ||
adapter_1.adapter.connect(this.device._handle, () => { | ||
adapter_1.adapter.connect(this.handle, () => { | ||
this.connected = true; | ||
resolve(this); | ||
}, () => { | ||
this._services = null; | ||
this.services = null; | ||
this.connected = false; | ||
this.device.emit(device_1.BluetoothDevice.EVENT_DISCONNECTED); | ||
this.device.dispatchEvent(device_1.BluetoothDevice.EVENT_DISCONNECTED); | ||
this.device._bluetooth.dispatchEvent(device_1.BluetoothDevice.EVENT_DISCONNECTED); | ||
}, error => { | ||
@@ -59,3 +59,3 @@ reject(`connect Error: ${error}`); | ||
disconnect() { | ||
adapter_1.adapter.disconnect(this.device._handle); | ||
adapter_1.adapter.disconnect(this.handle); | ||
this.connected = false; | ||
@@ -86,4 +86,4 @@ } | ||
if (!serviceUUID) | ||
return resolve(this._services); | ||
const filtered = this._services.filter(service => { | ||
return resolve(this.services); | ||
const filtered = this.services.filter(service => { | ||
return (service.uuid === helpers_1.getServiceUUID(serviceUUID)); | ||
@@ -95,7 +95,9 @@ }); | ||
} | ||
if (this._services) | ||
if (this.services) | ||
return complete.call(this); | ||
adapter_1.adapter.discoverServices(this.device._handle, this.device._allowedServices, services => { | ||
this._services = services.map(serviceInfo => { | ||
serviceInfo.device = this.device; | ||
adapter_1.adapter.discoverServices(this.handle, this.device._allowedServices, services => { | ||
this.services = services.map(serviceInfo => { | ||
Object.assign(serviceInfo, { | ||
device: this.device | ||
}); | ||
return new service_1.BluetoothRemoteGATTService(serviceInfo); | ||
@@ -102,0 +104,0 @@ }); |
@@ -27,33 +27,20 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const emitter_1 = require("./emitter"); | ||
const dispatcher_1 = require("./dispatcher"); | ||
const characteristic_1 = require("./characteristic"); | ||
const helpers_1 = require("./helpers"); | ||
const adapter_1 = require("./adapter"); | ||
class BluetoothRemoteGATTService extends emitter_1.Emitter { | ||
/** | ||
* @hidden | ||
*/ | ||
class BluetoothRemoteGATTService extends dispatcher_1.EventDispatcher { | ||
constructor(init) { | ||
super(); | ||
/** | ||
* @hidden | ||
*/ | ||
this._handle = null; | ||
/** | ||
* @hidden | ||
*/ | ||
this._services = null; | ||
/** | ||
* @hidden | ||
*/ | ||
this._characteristics = null; | ||
this.device = null; | ||
this.uuid = null; | ||
this.isPrimary = false; | ||
for (const key in init) { | ||
if (init.hasOwnProperty(key)) { | ||
this[key] = init[key]; | ||
} | ||
} | ||
this.emit(BluetoothRemoteGATTService.EVENT_ADDED); | ||
this.handle = null; | ||
this.services = null; | ||
this.characteristics = null; | ||
Object.assign(this, init); | ||
this.handle = this.uuid; | ||
this.dispatchEvent(BluetoothRemoteGATTService.EVENT_ADDED); | ||
this.device.dispatchEvent(BluetoothRemoteGATTService.EVENT_ADDED); | ||
this.device._bluetooth.dispatchEvent(BluetoothRemoteGATTService.EVENT_ADDED); | ||
} | ||
@@ -83,4 +70,4 @@ getCharacteristic(characteristicUUID) { | ||
if (!characteristicUUID) | ||
return resolve(this._characteristics); | ||
const filtered = this._characteristics.filter(characteristic => { | ||
return resolve(this.characteristics); | ||
const filtered = this.characteristics.filter(characteristic => { | ||
return (characteristic.uuid === helpers_1.getCharacteristicUUID(characteristicUUID)); | ||
@@ -92,7 +79,9 @@ }); | ||
} | ||
if (this._characteristics) | ||
if (this.characteristics) | ||
return complete.call(this); | ||
adapter_1.adapter.discoverCharacteristics(this._handle, [], characteristics => { | ||
this._characteristics = characteristics.map(characteristicInfo => { | ||
characteristicInfo.service = this; | ||
adapter_1.adapter.discoverCharacteristics(this.handle, [], characteristics => { | ||
this.characteristics = characteristics.map(characteristicInfo => { | ||
Object.assign(characteristicInfo, { | ||
service: this | ||
}); | ||
return new characteristic_1.BluetoothRemoteGATTCharacteristic(characteristicInfo); | ||
@@ -129,4 +118,4 @@ }); | ||
if (!serviceUUID) | ||
return resolve(this._services); | ||
const filtered = this._services.filter(service => { | ||
return resolve(this.services); | ||
const filtered = this.services.filter(service => { | ||
return (service.uuid === helpers_1.getServiceUUID(serviceUUID)); | ||
@@ -138,7 +127,9 @@ }); | ||
} | ||
if (this._services) | ||
if (this.services) | ||
return complete.call(this); | ||
adapter_1.adapter.discoverIncludedServices(this._handle, this.device._allowedServices, services => { | ||
this._services = services.map(serviceInfo => { | ||
serviceInfo.device = this.device; | ||
adapter_1.adapter.discoverIncludedServices(this.handle, this.device._allowedServices, services => { | ||
this.services = services.map(serviceInfo => { | ||
Object.assign(serviceInfo, { | ||
device: this.device | ||
}); | ||
return new BluetoothRemoteGATTService(serviceInfo); | ||
@@ -145,0 +136,0 @@ }); |
{ | ||
"name": "webbluetooth", | ||
"version": "0.0.4", | ||
"version": "0.0.5", | ||
"description": "Node.js implementation of the Web Bluetooth Specification", | ||
@@ -5,0 +5,0 @@ "homepage": "https://github.com/thegecko/webbluetooth", |
@@ -18,4 +18,73 @@ # Node Web Bluetooth | ||
See the examples in [examples/](https://github.com/thegecko/webbluetooth/tree/master/examples/) or view the API documentation at: | ||
See the examples in [examples](https://github.com/thegecko/webbluetooth/tree/master/examples/) or view the API documentation at: | ||
https://thegecko.github.io/webbluetooth/ | ||
## Specification | ||
The Web Bluetooth specification can be found here: | ||
https://webbluetoothcg.github.io/web-bluetooth/ | ||
## Implementation Status | ||
### Bluetooth | ||
- [x] referringDevice - specification unstable | ||
- [x] getAvailability() - specification unstable | ||
- [x] requestDevice() | ||
### Bluetooth Device | ||
- [x] BluetoothDevice | ||
- [ ] BluetoothDevice.watchAdvertisements() - specification unstable | ||
- [ ] BluetoothDevice.unwatchAdvertisements() - specification unstable | ||
### Bluetooth Server | ||
- [x] BluetoothRemoteGATTServer | ||
- [x] BluetoothRemoteGATTServer.connect() | ||
- [x] BluetoothRemoteGATTServer.disconnect() | ||
- [x] BluetoothRemoteGATTServer.getPrimaryService() | ||
- [x] BluetoothRemoteGATTServer.getPrimaryServices() | ||
### Bluetooth Services | ||
- [x] BluetoothRemoteGATTService | ||
- [x] BluetoothRemoteGATTService.getCharacteristic() | ||
- [x] BluetoothRemoteGATTService.getCharacteristics() | ||
- [x] BluetoothRemoteGATTService.getIncludedService() | ||
- [x] BluetoothRemoteGATTService.getIncludedServices() | ||
### Bluetooth Characteristics | ||
- [x] BluetoothRemoteGATTCharacteristic | ||
- [x] BluetoothRemoteGATTCharacteristic.getDescriptor() | ||
- [x] BluetoothRemoteGATTCharacteristic.getDescriptors() | ||
- [x] BluetoothRemoteGATTCharacteristic.readValue() | ||
- [x] BluetoothRemoteGATTCharacteristic.writeValue() | ||
- [x] BluetoothRemoteGATTCharacteristic.startNotifications() | ||
- [x] BluetoothRemoteGATTCharacteristic.stopNotifications() | ||
### Bluetooth Descriptors | ||
- [x] BluetoothRemoteGATTDescriptor | ||
- [x] BluetoothRemoteGATTDescriptor.readValue() | ||
- [x] BluetoothRemoteGATTDescriptor.writeValue() | ||
### Bluetooth Events | ||
- [x] availabilitychanged - specification unstable | ||
- [x] gattserverdisconnected | ||
- [x] characteristicvaluechanged | ||
- [x] serviceadded | ||
- [ ] servicechanged - unsupported in noble | ||
- [ ] serviceremoved - unsupported in noble | ||
### Other | ||
- [x] Device selector hook | ||
- [x] Lookups for known services, characteristics and descriptors | ||
- [x] Canonical UUID helper | ||
- [x] Examples | ||
- [ ] API Documentation |
@@ -26,2 +26,3 @@ /* | ||
import { EventEmitter } from "events"; | ||
import { getCanonicalUUID } from "./helpers"; | ||
@@ -37,3 +38,4 @@ import { BluetoothDevice } from "./device"; | ||
*/ | ||
export interface Adapter { | ||
export interface Adapter extends EventEmitter { | ||
getEnabled: (completeFn: (enabled: boolean) => void) => void; | ||
startScan: (serviceUUIDs: Array<string>, foundFn: (device: Partial<BluetoothDevice>) => void, completeFn?: () => void, errorFn?: (errorMsg: string) => void) => void; | ||
@@ -58,4 +60,6 @@ stopScan: (errorFn?: (errorMsg: string) => void) => void; | ||
*/ | ||
export class NobleAdapter implements Adapter { | ||
export class NobleAdapter extends EventEmitter implements Adapter { | ||
public static EVENT_ENABLED: string = "enabledchanged"; | ||
private deviceHandles: {} = {}; | ||
@@ -68,3 +72,19 @@ private serviceHandles: {} = {}; | ||
private initialised: boolean = false; | ||
private enabled: boolean = false; | ||
constructor() { | ||
super(); | ||
this.enabled = this.state; | ||
noble.on("stateChange", () => { | ||
if (this.enabled !== this.state) { | ||
this.enabled = this.state; | ||
this.emit(NobleAdapter.EVENT_ENABLED, this.enabled); | ||
} | ||
}); | ||
} | ||
private get state(): boolean { | ||
return (noble.state === "poweredOn"); | ||
} | ||
private init(completeFn: () => any) { | ||
@@ -118,3 +138,3 @@ if (this.initialised) return completeFn(); | ||
const buffer = deviceInfo.advertisement.manufacturerData.slice(2); | ||
manufacturerData[company] = this.bufferToDataView(buffer); | ||
manufacturerData.set(company, this.bufferToDataView(buffer)); | ||
} | ||
@@ -125,3 +145,3 @@ | ||
deviceInfo.advertisement.serviceData.forEach(serviceAdvert => { | ||
serviceData[getCanonicalUUID(serviceAdvert.uuid)] = this.bufferToDataView(serviceAdvert.data); | ||
serviceData.set(getCanonicalUUID(serviceAdvert.uuid), this.bufferToDataView(serviceAdvert.data)); | ||
}); | ||
@@ -131,12 +151,11 @@ } | ||
this.foundFn({ | ||
_handle: deviceID, | ||
id: deviceID, | ||
name: deviceInfo.advertisement.localName, | ||
uuids: serviceUUIDs | ||
// adData: { | ||
// manufacturerData: manufacturerData, | ||
// serviceData: serviceData, | ||
// txPower: deviceInfo.advertisement.txPowerLevel, | ||
// rssi: deviceInfo.rssi | ||
// } | ||
_serviceUUIDs: serviceUUIDs, | ||
adData: { | ||
rssi: deviceInfo.rssi, | ||
txPower: deviceInfo.advertisement.txPowerLevel, | ||
serviceData: serviceData, | ||
manufacturerData: manufacturerData | ||
} | ||
}); | ||
@@ -146,2 +165,12 @@ } | ||
public getEnabled(completeFn: (enabled: boolean) => void) { | ||
function stateCB() { | ||
completeFn(this.state); | ||
} | ||
// tslint:disable-next-line:no-string-literal | ||
if (noble.state === "unknown") noble["once"]("stateChange", stateCB.bind(this)); | ||
else stateCB.call(this); | ||
} | ||
public startScan(serviceUUIDs: Array<string>, foundFn: (device: Partial<BluetoothDevice>) => void, completeFn?: () => void, errorFn?: (errorMsg: string) => void): void { | ||
@@ -154,3 +183,3 @@ | ||
serviceUUIDs.forEach(serviceUUID => { | ||
if (device.uuids.indexOf(serviceUUID) >= 0) { | ||
if (device._serviceUUIDs.indexOf(serviceUUID) >= 0) { | ||
foundFn(device); | ||
@@ -165,4 +194,4 @@ return; | ||
this.deviceHandles = {}; | ||
function stateCB(state) { | ||
if (state === "poweredOn") { | ||
function stateCB() { | ||
if (this.state === true) { | ||
noble.startScanning([], false, this.checkForError(errorFn, completeFn)); | ||
@@ -175,3 +204,3 @@ } else { | ||
if (noble.state === "unknown") noble["once"]("stateChange", stateCB.bind(this)); | ||
else stateCB.call(this, noble.state); | ||
else stateCB.call(this); | ||
}); | ||
@@ -213,3 +242,2 @@ } | ||
discovered.push({ | ||
_handle: serviceUUID, | ||
uuid: serviceUUID, | ||
@@ -237,3 +265,2 @@ primary: true | ||
discovered.push({ | ||
_handle: serviceUUID, | ||
uuid: serviceUUID, | ||
@@ -261,3 +288,2 @@ primary: false | ||
discovered.push({ | ||
_handle: charUUID, | ||
uuid: charUUID, | ||
@@ -303,3 +329,2 @@ properties: { | ||
discovered.push({ | ||
_handle: descHandle, | ||
uuid: descUUID | ||
@@ -306,0 +331,0 @@ }); |
@@ -26,156 +26,187 @@ /* | ||
import { EventDispatcher } from "./dispatcher"; | ||
import { BluetoothDevice } from "./device"; | ||
import { getServiceUUID } from "./helpers"; | ||
import { adapter } from "./adapter"; | ||
import { adapter, NobleAdapter } from "./adapter"; | ||
export interface BluetoothLEScanFilterInit { | ||
services?: Array<string>; | ||
name?: string; | ||
namePrefix?: string; | ||
// Maps unsigned shorts to BluetoothDataFilters. | ||
// object manufacturerData; | ||
// Maps BluetoothServiceUUIDs to BluetoothDataFilters. | ||
// object serviceData; | ||
} | ||
export interface RequestDeviceOptions { | ||
acceptAllDevices: boolean; | ||
deviceFound: (device: BluetoothDevice, selectFn: any) => void; | ||
filters: Array<any>; | ||
optionalServices: Array<any>; | ||
scanTime: any; | ||
acceptAllDevices?: boolean; | ||
deviceFound?: (device: BluetoothDevice, selectFn: any) => boolean; | ||
filters?: Array<BluetoothLEScanFilterInit>; | ||
optionalServices?: Array<any>; | ||
scanTime?: any; | ||
} | ||
/** | ||
* @hidden | ||
*/ | ||
const defaultScanTime = 10.24 * 1000; | ||
export class Bluetooth extends EventDispatcher { | ||
/** | ||
* @hidden | ||
*/ | ||
let scanner = null; | ||
/** | ||
* Bluetooth Availability Changed event | ||
* @event | ||
*/ | ||
public static EVENT_AVAILABILITY: string = "availabilitychanged"; | ||
/** | ||
* @hidden | ||
*/ | ||
function filterDevice(options: RequestDeviceOptions, deviceInfo, validServices) { | ||
let valid = false; | ||
private defaultScanTime = 10.24 * 1000; | ||
private scanner = null; | ||
options.filters.forEach(filter => { | ||
// Name | ||
if (filter.name && filter.name !== deviceInfo.name) return; | ||
constructor(public readonly referringDevice?: BluetoothDevice) { | ||
super(); | ||
adapter.on(NobleAdapter.EVENT_ENABLED, value => { | ||
this.dispatchEvent(Bluetooth.EVENT_AVAILABILITY, value); | ||
}); | ||
} | ||
// NamePrefix | ||
if (filter.namePrefix) { | ||
if (filter.namePrefix.length > deviceInfo.name.length) return; | ||
if (filter.namePrefix !== deviceInfo.name.substr(0, filter.namePrefix.length)) return; | ||
} | ||
private filterDevice(options: RequestDeviceOptions, deviceInfo, validServices) { | ||
let valid = false; | ||
// Services | ||
if (filter.services) { | ||
const serviceUUIDs = filter.services.map(getServiceUUID); | ||
const servicesValid = serviceUUIDs.every(serviceUUID => { | ||
return (deviceInfo.uuids.indexOf(serviceUUID) > -1); | ||
}); | ||
options.filters.forEach(filter => { | ||
// Name | ||
if (filter.name && filter.name !== deviceInfo.name) return; | ||
if (!servicesValid) return; | ||
validServices = validServices.concat(serviceUUIDs); | ||
} | ||
// NamePrefix | ||
if (filter.namePrefix) { | ||
if (filter.namePrefix.length > deviceInfo.name.length) return; | ||
if (filter.namePrefix !== deviceInfo.name.substr(0, filter.namePrefix.length)) return; | ||
} | ||
valid = true; | ||
}); | ||
// Services | ||
if (filter.services) { | ||
const serviceUUIDs = filter.services.map(getServiceUUID); | ||
const servicesValid = serviceUUIDs.every(serviceUUID => { | ||
return (deviceInfo._serviceUUIDs.indexOf(serviceUUID) > -1); | ||
}); | ||
if (!valid) return false; | ||
return deviceInfo; | ||
} | ||
export function requestDevice(options: RequestDeviceOptions): Promise<BluetoothDevice> { | ||
return new Promise((resolve, reject) => { | ||
if (scanner !== null) return reject("requestDevice error: request in progress"); | ||
if (!options.acceptAllDevices && !options.deviceFound) { | ||
// Must have a filter | ||
if (!options.filters || options.filters.length === 0) { | ||
return reject(new TypeError("requestDevice error: no filters specified")); | ||
if (!servicesValid) return; | ||
validServices = validServices.concat(serviceUUIDs); | ||
} | ||
// Don't allow empty filters | ||
const emptyFilter = options.filters.some(filter => { | ||
return (Object.keys(filter).length === 0); | ||
}); | ||
if (emptyFilter) { | ||
return reject(new TypeError("requestDevice error: empty filter specified")); | ||
} | ||
valid = true; | ||
}); | ||
// Don't allow empty namePrefix | ||
const emptyPrefix = options.filters.some(filter => { | ||
return (typeof filter.namePrefix !== "undefined" && filter.namePrefix === ""); | ||
}); | ||
if (emptyPrefix) { | ||
return reject(new TypeError("requestDevice error: empty namePrefix specified")); | ||
} | ||
} | ||
if (!valid) return false; | ||
return deviceInfo; | ||
} | ||
let searchUUIDs = []; | ||
if (options.filters) { | ||
options.filters.forEach(filter => { | ||
if (filter.services) searchUUIDs = searchUUIDs.concat(filter.services.map(getServiceUUID)); | ||
public getAvailability(): Promise<boolean> { | ||
return new Promise((resolve, _reject) => { | ||
adapter.getEnabled(enabled => { | ||
resolve(enabled); | ||
}); | ||
} | ||
// Unique-ify | ||
searchUUIDs = searchUUIDs.filter((item, index, array) => { | ||
return array.indexOf(item) === index; | ||
}); | ||
} | ||
let found = false; | ||
adapter.startScan(searchUUIDs, deviceInfo => { | ||
let validServices = []; | ||
public requestDevice(options: RequestDeviceOptions): Promise<BluetoothDevice> { | ||
return new Promise((resolve, reject) => { | ||
if (this.scanner !== null) return reject("requestDevice error: request in progress"); | ||
function complete(bluetoothDevice) { | ||
cancelRequest() | ||
.then(() => { | ||
resolve(bluetoothDevice); | ||
if (!options.acceptAllDevices && !options.deviceFound) { | ||
// Must have a filter | ||
if (!options.filters || options.filters.length === 0) { | ||
return reject(new TypeError("requestDevice error: no filters specified")); | ||
} | ||
// Don't allow empty filters | ||
const emptyFilter = options.filters.some(filter => { | ||
return (Object.keys(filter).length === 0); | ||
}); | ||
if (emptyFilter) { | ||
return reject(new TypeError("requestDevice error: empty filter specified")); | ||
} | ||
// Don't allow empty namePrefix | ||
const emptyPrefix = options.filters.some(filter => { | ||
return (typeof filter.namePrefix !== "undefined" && filter.namePrefix === ""); | ||
}); | ||
if (emptyPrefix) { | ||
return reject(new TypeError("requestDevice error: empty namePrefix specified")); | ||
} | ||
} | ||
// filter devices if filters specified | ||
let searchUUIDs = []; | ||
if (options.filters) { | ||
deviceInfo = filterDevice(options, deviceInfo, validServices); | ||
options.filters.forEach(filter => { | ||
if (filter.services) searchUUIDs = searchUUIDs.concat(filter.services.map(getServiceUUID)); | ||
}); | ||
} | ||
if (deviceInfo) { | ||
found = true; | ||
// Unique-ify | ||
searchUUIDs = searchUUIDs.filter((item, index, array) => { | ||
return array.indexOf(item) === index; | ||
}); | ||
// Add additional services | ||
if (options.optionalServices) { | ||
validServices = validServices.concat(options.optionalServices.map(getServiceUUID)); | ||
let found = false; | ||
adapter.startScan(searchUUIDs, deviceInfo => { | ||
let validServices = []; | ||
function complete(bluetoothDevice) { | ||
this.cancelRequest() | ||
.then(() => { | ||
resolve(bluetoothDevice); | ||
}); | ||
} | ||
// Set unique list of allowed services | ||
deviceInfo._allowedServices = validServices.filter((item, index, array) => { | ||
return array.indexOf(item) === index; | ||
}); | ||
// filter devices if filters specified | ||
if (options.filters) { | ||
deviceInfo = this.filterDevice(options, deviceInfo, validServices); | ||
} | ||
const bluetoothDevice = new BluetoothDevice(deviceInfo); | ||
if (deviceInfo) { | ||
found = true; | ||
function selectFn() { | ||
complete(bluetoothDevice); | ||
// Add additional services | ||
if (options.optionalServices) { | ||
validServices = validServices.concat(options.optionalServices.map(getServiceUUID)); | ||
} | ||
// Set unique list of allowed services | ||
const allowedServices = validServices.filter((item, index, array) => { | ||
return array.indexOf(item) === index; | ||
}); | ||
Object.assign(deviceInfo, { | ||
_bluetooth: this, | ||
_allowedServices: allowedServices | ||
}); | ||
const bluetoothDevice = new BluetoothDevice(deviceInfo); | ||
function selectFn() { | ||
complete.call(this, bluetoothDevice); | ||
} | ||
if (!options.deviceFound || options.deviceFound(bluetoothDevice, selectFn.bind(this)) === true) { | ||
// If no deviceFound function, or deviceFound returns true, resolve with this device immediately | ||
complete.call(this, bluetoothDevice); | ||
} | ||
} | ||
}, () => { | ||
this.scanner = setTimeout(() => { | ||
this.cancelRequest() | ||
.then(() => { | ||
if (!found) reject("requestDevice error: no devices found"); | ||
}); | ||
}, options.scanTime || this.defaultScanTime); | ||
}, error => reject(`requestDevice error: ${error}`)); | ||
}); | ||
} | ||
if (!options.deviceFound || options.deviceFound(bluetoothDevice, selectFn)) { | ||
// If no deviceFound function, or deviceFound returns true, resolve with this device immediately | ||
complete(bluetoothDevice); | ||
} | ||
public cancelRequest(): Promise<void> { | ||
return new Promise((resolve, _reject) => { | ||
if (this.scanner) { | ||
clearTimeout(this.scanner); | ||
this.scanner = null; | ||
adapter.stopScan(); | ||
} | ||
}, () => { | ||
scanner = setTimeout(() => { | ||
cancelRequest() | ||
.then(() => { | ||
if (!found) reject("requestDevice error: no devices found"); | ||
}); | ||
}, options.scanTime || defaultScanTime); | ||
}, error => reject(`requestDevice error: ${error}`)); | ||
}); | ||
resolve(); | ||
}); | ||
} | ||
} | ||
export function cancelRequest(): Promise<void> { | ||
return new Promise((resolve, _reject) => { | ||
if (scanner) { | ||
clearTimeout(scanner); | ||
scanner = null; | ||
adapter.stopScan(); | ||
} | ||
resolve(); | ||
}); | ||
} |
@@ -26,3 +26,3 @@ /* | ||
import { Emitter } from "./emitter"; | ||
import { EventDispatcher } from "./dispatcher"; | ||
import { BluetoothRemoteGATTService } from "./service"; | ||
@@ -33,3 +33,3 @@ import { BluetoothRemoteGATTDescriptor } from "./descriptor"; | ||
export class BluetoothRemoteGATTCharacteristic extends Emitter { | ||
export class BluetoothRemoteGATTCharacteristic extends EventDispatcher { | ||
@@ -42,17 +42,5 @@ /** | ||
/** | ||
* @hidden | ||
*/ | ||
public _handle: string = null; | ||
/** | ||
* @hidden | ||
*/ | ||
public _descriptors: Array<BluetoothRemoteGATTDescriptor> = null; | ||
public service: BluetoothRemoteGATTService = null; | ||
public uuid = null; | ||
public value = null; | ||
public properties = { | ||
public readonly service: BluetoothRemoteGATTService = null; | ||
public readonly uuid = null; | ||
public readonly properties = { | ||
broadcast: false, | ||
@@ -69,11 +57,23 @@ read: false, | ||
/** | ||
* @hidden | ||
*/ | ||
private _value: DataView = null; | ||
public get value(): DataView { | ||
return this._value; | ||
} | ||
private handle: string = null; | ||
private descriptors: Array<BluetoothRemoteGATTDescriptor> = null; | ||
constructor(init?: Partial<BluetoothRemoteGATTCharacteristic>) { | ||
super(); | ||
for (const key in init) { | ||
if (init.hasOwnProperty(key)) { | ||
this[key] = init[key]; | ||
} | ||
Object.assign(this, init); | ||
this.handle = this.uuid; | ||
} | ||
private setValue(value?: DataView, emit?: boolean) { | ||
this._value = value; | ||
if (emit) { | ||
this.dispatchEvent(BluetoothRemoteGATTCharacteristic.EVENT_CHANGED, value); | ||
this.service.dispatchEvent(BluetoothRemoteGATTCharacteristic.EVENT_CHANGED, value); | ||
this.service.device.dispatchEvent(BluetoothRemoteGATTCharacteristic.EVENT_CHANGED, value); | ||
this.service.device._bluetooth.dispatchEvent(BluetoothRemoteGATTCharacteristic.EVENT_CHANGED, value); | ||
} | ||
@@ -103,5 +103,5 @@ } | ||
function complete() { | ||
if (!descriptorUUID) return resolve(this._descriptors); | ||
if (!descriptorUUID) return resolve(this.descriptors); | ||
const filtered = this._descriptors.filter(descriptor => { | ||
const filtered = this.descriptors.filter(descriptor => { | ||
return (descriptor.uuid === getDescriptorUUID(descriptorUUID)); | ||
@@ -114,7 +114,9 @@ }); | ||
if (this._descriptors) return complete.call(this); | ||
if (this.descriptors) return complete.call(this); | ||
adapter.discoverDescriptors(this._handle, [], descriptors => { | ||
this._descriptors = descriptors.map(descriptorInfo => { | ||
descriptorInfo.characteristic = this; | ||
adapter.discoverDescriptors(this.handle, [], descriptors => { | ||
this.descriptors = descriptors.map(descriptorInfo => { | ||
Object.assign(descriptorInfo, { | ||
characteristic: this | ||
}); | ||
return new BluetoothRemoteGATTDescriptor(descriptorInfo); | ||
@@ -134,6 +136,5 @@ }); | ||
adapter.readCharacteristic(this._handle, dataView => { | ||
this.value = dataView; | ||
adapter.readCharacteristic(this.handle, dataView => { | ||
this.setValue(dataView, true); | ||
resolve(dataView); | ||
this.emit(BluetoothRemoteGATTCharacteristic.EVENT_CHANGED); | ||
}, error => { | ||
@@ -145,3 +146,3 @@ reject(`readValue error: ${error}`); | ||
public writeValue(bufferSource: ArrayBuffer | ArrayBufferView) { | ||
public writeValue(bufferSource: ArrayBuffer | ArrayBufferView): Promise<void> { | ||
return new Promise((resolve, reject) => { | ||
@@ -157,4 +158,4 @@ if (!this.service.device.gatt.connected) return reject("writeValue error: device not connected"); | ||
adapter.writeCharacteristic(this._handle, dataView, () => { | ||
this.value = dataView; | ||
adapter.writeCharacteristic(this.handle, dataView, () => { | ||
this.setValue (dataView); | ||
resolve(); | ||
@@ -171,5 +172,4 @@ }, error => { | ||
adapter.enableNotify(this._handle, dataView => { | ||
this.value = dataView; | ||
this.emit(BluetoothRemoteGATTCharacteristic.EVENT_CHANGED); | ||
adapter.enableNotify(this.handle, dataView => { | ||
this.setValue(dataView, true); | ||
}, () => { | ||
@@ -187,3 +187,3 @@ resolve(this); | ||
adapter.disableNotify(this._handle, () => { | ||
adapter.disableNotify(this.handle, () => { | ||
resolve(this); | ||
@@ -190,0 +190,0 @@ }, error => { |
@@ -30,20 +30,16 @@ /* | ||
export class BluetoothRemoteGATTDescriptor { | ||
/** | ||
* @hidden | ||
*/ | ||
public _handle: string = null; | ||
public characteristic: BluetoothRemoteGATTCharacteristic = null; | ||
public uuid = null; | ||
public value = null; | ||
public readonly characteristic: BluetoothRemoteGATTCharacteristic = null; | ||
public readonly uuid: string = null; | ||
/** | ||
* @hidden | ||
*/ | ||
private _value: DataView = null; | ||
public get value(): DataView { | ||
return this._value; | ||
} | ||
private handle: string = null; | ||
constructor(init?: Partial<BluetoothRemoteGATTDescriptor>) { | ||
for (const key in init) { | ||
if (init.hasOwnProperty(key)) { | ||
this[key] = init[key]; | ||
} | ||
} | ||
Object.assign(this, init); | ||
this.handle = `${this.characteristic.uuid}-${this.uuid}`; | ||
} | ||
@@ -55,4 +51,4 @@ | ||
adapter.readDescriptor(this._handle, dataView => { | ||
this.value = dataView; | ||
adapter.readDescriptor(this.handle, dataView => { | ||
this._value = dataView; | ||
resolve(dataView); | ||
@@ -65,3 +61,3 @@ }, error => { | ||
public writeValue(bufferSource: ArrayBuffer | ArrayBufferView) { | ||
public writeValue(bufferSource: ArrayBuffer | ArrayBufferView): Promise<void> { | ||
return new Promise((resolve, reject) => { | ||
@@ -77,4 +73,4 @@ if (!this.characteristic.service.device.gatt.connected) return reject("writeValue error: device not connected"); | ||
adapter.writeDescriptor(this._handle, dataView, () => { | ||
this.value = dataView; | ||
adapter.writeDescriptor(this.handle, dataView, () => { | ||
this._value = dataView; | ||
resolve(); | ||
@@ -81,0 +77,0 @@ }, error => { |
@@ -26,6 +26,7 @@ /* | ||
import { Emitter } from "./emitter"; | ||
import { EventDispatcher } from "./dispatcher"; | ||
import { Bluetooth } from "./bluetooth"; | ||
import { BluetoothRemoteGATTServer } from "./server"; | ||
export class BluetoothDevice extends Emitter { | ||
export class BluetoothDevice extends EventDispatcher { | ||
@@ -38,6 +39,16 @@ /** | ||
public readonly id: string = "unknown"; | ||
public readonly name: string = null; | ||
public readonly gatt: BluetoothRemoteGATTServer = null; | ||
public readonly watchingAdvertisements: boolean = false; | ||
/** | ||
* @hidden | ||
*/ | ||
public _handle: string = null; | ||
public readonly adData: { | ||
rssi?: number; | ||
txPower?: null; | ||
serviceData?: Map<string, DataView>; | ||
manufacturerData?: Map<string, DataView>; | ||
}; | ||
@@ -47,30 +58,26 @@ /** | ||
*/ | ||
public _allowedServices: Array<string> = []; | ||
public readonly _bluetooth: Bluetooth = null; | ||
public id: string = "unknown"; | ||
/** | ||
* @hidden | ||
*/ | ||
public readonly _allowedServices: Array<string> = []; | ||
public name: string = null; | ||
// public adData: { | ||
// public appearance?: null; | ||
// public txPower?: null; | ||
// rssi?: number; | ||
// manufacturerData = new Map(); | ||
// serviceData = new Map(); | ||
// } | ||
public gatt: BluetoothRemoteGATTServer = new BluetoothRemoteGATTServer(); | ||
public uuids: Array<string> = []; | ||
/** | ||
* @hidden | ||
*/ | ||
public _serviceUUIDs: Array<string> = []; | ||
constructor(init?: Partial<BluetoothDevice>) { | ||
super(); | ||
for (const key in init) { | ||
if (init.hasOwnProperty(key)) { | ||
this[key] = init[key]; | ||
} | ||
} | ||
Object.assign(this, init); | ||
this.gatt = new BluetoothRemoteGATTServer(this); | ||
} | ||
/* | ||
public watchAdvertisements(): Promise<void> { | ||
} | ||
this.gatt.device = this; | ||
public unwatchAdvertisements() { | ||
} | ||
*/ | ||
} |
@@ -13,1 +13,7 @@ # Node Web Bluetooth | ||
``` | ||
## Specification | ||
The Web Bluetooth specification can be found here: | ||
https://webbluetoothcg.github.io/web-bluetooth/ |
@@ -243,3 +243,3 @@ /* | ||
export function getCanonicalUUID(uuid) { | ||
export function getCanonicalUUID(uuid: string | number): string { | ||
if (typeof uuid === "number") uuid = uuid.toString(16); | ||
@@ -252,3 +252,3 @@ uuid = uuid.toLowerCase(); | ||
export function getServiceUUID(uuid) { | ||
export function getServiceUUID(uuid: string | number): string { | ||
if (bluetoothServices[uuid]) uuid = bluetoothServices[uuid]; | ||
@@ -258,3 +258,3 @@ return getCanonicalUUID(uuid); | ||
export function getCharacteristicUUID(uuid) { | ||
export function getCharacteristicUUID(uuid: string | number): string { | ||
if (bluetoothCharacteristics[uuid]) uuid = bluetoothCharacteristics[uuid]; | ||
@@ -264,5 +264,5 @@ return getCanonicalUUID(uuid); | ||
export function getDescriptorUUID(uuid) { | ||
export function getDescriptorUUID(uuid: string | number): string { | ||
if (bluetoothDescriptors[uuid]) uuid = bluetoothDescriptors[uuid]; | ||
return getCanonicalUUID(uuid); | ||
} |
@@ -26,11 +26,17 @@ /* | ||
export * from "./bluetooth"; | ||
export * from "./helpers"; | ||
import { Bluetooth } from "./bluetooth"; | ||
/* | ||
import { WebBluetooth } from "./bluetooth"; | ||
import { NobleAdapter } from "./adapter"; | ||
/** | ||
* Default bluetooth instance synonymous with `navigator.bluetooth` | ||
*/ | ||
export const bluetooth = new Bluetooth(); | ||
export const bluetooth = new WebBluetooth(new NobleAdapter()); | ||
/** | ||
* Bluetooth class for creating new instances | ||
*/ | ||
export { Bluetooth }; | ||
/** | ||
* Helper methods and enums | ||
*/ | ||
export * from "./helpers"; | ||
*/ |
@@ -32,10 +32,12 @@ /* | ||
export class BluetoothRemoteGATTServer { | ||
/** | ||
* @hidden | ||
*/ | ||
public _services: Array<BluetoothRemoteGATTService> = null; | ||
public device: BluetoothDevice = null; | ||
public connected: boolean = false; | ||
private handle: string = null; | ||
private services: Array<BluetoothRemoteGATTService> = null; | ||
constructor(public device: BluetoothDevice) { | ||
this.handle = this.device.id; | ||
} | ||
public connect(): Promise<BluetoothRemoteGATTServer> { | ||
@@ -45,9 +47,10 @@ return new Promise((resolve, reject) => { | ||
adapter.connect(this.device._handle, () => { | ||
adapter.connect(this.handle, () => { | ||
this.connected = true; | ||
resolve(this); | ||
}, () => { | ||
this._services = null; | ||
this.services = null; | ||
this.connected = false; | ||
this.device.emit(BluetoothDevice.EVENT_DISCONNECTED); | ||
this.device.dispatchEvent(BluetoothDevice.EVENT_DISCONNECTED); | ||
this.device._bluetooth.dispatchEvent(BluetoothDevice.EVENT_DISCONNECTED); | ||
}, error => { | ||
@@ -60,3 +63,3 @@ reject(`connect Error: ${error}`); | ||
public disconnect() { | ||
adapter.disconnect(this.device._handle); | ||
adapter.disconnect(this.handle); | ||
this.connected = false; | ||
@@ -86,5 +89,5 @@ } | ||
function complete() { | ||
if (!serviceUUID) return resolve(this._services); | ||
if (!serviceUUID) return resolve(this.services); | ||
const filtered = this._services.filter(service => { | ||
const filtered = this.services.filter(service => { | ||
return (service.uuid === getServiceUUID(serviceUUID)); | ||
@@ -97,7 +100,9 @@ }); | ||
if (this._services) return complete.call(this); | ||
if (this.services) return complete.call(this); | ||
adapter.discoverServices(this.device._handle, this.device._allowedServices, services => { | ||
this._services = services.map(serviceInfo => { | ||
serviceInfo.device = this.device; | ||
adapter.discoverServices(this.handle, this.device._allowedServices, services => { | ||
this.services = services.map(serviceInfo => { | ||
Object.assign(serviceInfo, { | ||
device: this.device | ||
}); | ||
return new BluetoothRemoteGATTService(serviceInfo); | ||
@@ -104,0 +109,0 @@ }); |
@@ -26,3 +26,3 @@ /* | ||
import { Emitter } from "./emitter"; | ||
import { EventDispatcher } from "./dispatcher"; | ||
import { BluetoothDevice } from "./device"; | ||
@@ -33,3 +33,3 @@ import { BluetoothRemoteGATTCharacteristic } from "./characteristic"; | ||
export class BluetoothRemoteGATTService extends Emitter { | ||
export class BluetoothRemoteGATTService extends EventDispatcher { | ||
@@ -54,32 +54,17 @@ /** | ||
/** | ||
* @hidden | ||
*/ | ||
public _handle: string = null; | ||
public readonly device: BluetoothDevice = null; | ||
public readonly uuid: string = null; | ||
public readonly isPrimary: boolean = false; | ||
/** | ||
* @hidden | ||
*/ | ||
public _services: Array<BluetoothRemoteGATTService> = null; | ||
private handle: string = null; | ||
private services: Array<BluetoothRemoteGATTService> = null; | ||
private characteristics: Array<BluetoothRemoteGATTCharacteristic> = null; | ||
/** | ||
* @hidden | ||
*/ | ||
public _characteristics: Array<BluetoothRemoteGATTCharacteristic> = null; | ||
public device: BluetoothDevice = null; | ||
public uuid = null; | ||
public isPrimary = false; | ||
/** | ||
* @hidden | ||
*/ | ||
constructor(init?: Partial<BluetoothRemoteGATTService>) { | ||
super(); | ||
for (const key in init) { | ||
if (init.hasOwnProperty(key)) { | ||
this[key] = init[key]; | ||
} | ||
} | ||
this.emit(BluetoothRemoteGATTService.EVENT_ADDED); | ||
Object.assign(this, init); | ||
this.handle = this.uuid; | ||
this.dispatchEvent(BluetoothRemoteGATTService.EVENT_ADDED); | ||
this.device.dispatchEvent(BluetoothRemoteGATTService.EVENT_ADDED); | ||
this.device._bluetooth.dispatchEvent(BluetoothRemoteGATTService.EVENT_ADDED); | ||
} | ||
@@ -108,5 +93,5 @@ | ||
function complete() { | ||
if (!characteristicUUID) return resolve(this._characteristics); | ||
if (!characteristicUUID) return resolve(this.characteristics); | ||
const filtered = this._characteristics.filter(characteristic => { | ||
const filtered = this.characteristics.filter(characteristic => { | ||
return (characteristic.uuid === getCharacteristicUUID(characteristicUUID)); | ||
@@ -119,7 +104,9 @@ }); | ||
if (this._characteristics) return complete.call(this); | ||
if (this.characteristics) return complete.call(this); | ||
adapter.discoverCharacteristics(this._handle, [], characteristics => { | ||
this._characteristics = characteristics.map(characteristicInfo => { | ||
characteristicInfo.service = this; | ||
adapter.discoverCharacteristics(this.handle, [], characteristics => { | ||
this.characteristics = characteristics.map(characteristicInfo => { | ||
Object.assign(characteristicInfo, { | ||
service: this | ||
}); | ||
return new BluetoothRemoteGATTCharacteristic(characteristicInfo); | ||
@@ -156,5 +143,5 @@ }); | ||
function complete() { | ||
if (!serviceUUID) return resolve(this._services); | ||
if (!serviceUUID) return resolve(this.services); | ||
const filtered = this._services.filter(service => { | ||
const filtered = this.services.filter(service => { | ||
return (service.uuid === getServiceUUID(serviceUUID)); | ||
@@ -167,7 +154,9 @@ }); | ||
if (this._services) return complete.call(this); | ||
if (this.services) return complete.call(this); | ||
adapter.discoverIncludedServices(this._handle, this.device._allowedServices, services => { | ||
this._services = services.map(serviceInfo => { | ||
serviceInfo.device = this.device; | ||
adapter.discoverIncludedServices(this.handle, this.device._allowedServices, services => { | ||
this.services = services.map(serviceInfo => { | ||
Object.assign(serviceInfo, { | ||
device: this.device | ||
}); | ||
return new BluetoothRemoteGATTService(serviceInfo); | ||
@@ -174,0 +163,0 @@ }); |
@@ -0,1 +1,3 @@ | ||
/// <reference types="node" /> | ||
import { EventEmitter } from "events"; | ||
import { BluetoothDevice } from "./device"; | ||
@@ -8,3 +10,4 @@ import { BluetoothRemoteGATTService } from "./service"; | ||
*/ | ||
export interface Adapter { | ||
export interface Adapter extends EventEmitter { | ||
getEnabled: (completeFn: (enabled: boolean) => void) => void; | ||
startScan: (serviceUUIDs: Array<string>, foundFn: (device: Partial<BluetoothDevice>) => void, completeFn?: () => void, errorFn?: (errorMsg: string) => void) => void; | ||
@@ -28,3 +31,4 @@ stopScan: (errorFn?: (errorMsg: string) => void) => void; | ||
*/ | ||
export declare class NobleAdapter implements Adapter { | ||
export declare class NobleAdapter extends EventEmitter implements Adapter { | ||
static EVENT_ENABLED: string; | ||
private deviceHandles; | ||
@@ -37,2 +41,5 @@ private serviceHandles; | ||
private initialised; | ||
private enabled; | ||
constructor(); | ||
private readonly state; | ||
private init(completeFn); | ||
@@ -43,2 +50,3 @@ private checkForError(errorFn, continueFn?); | ||
private discover(deviceInfo); | ||
getEnabled(completeFn: (enabled: boolean) => void): void; | ||
startScan(serviceUUIDs: Array<string>, foundFn: (device: Partial<BluetoothDevice>) => void, completeFn?: () => void, errorFn?: (errorMsg: string) => void): void; | ||
@@ -45,0 +53,0 @@ stopScan(_errorFn?: (errorMsg: string) => void): void; |
@@ -0,10 +1,29 @@ | ||
import { EventDispatcher } from "./dispatcher"; | ||
import { BluetoothDevice } from "./device"; | ||
export interface BluetoothLEScanFilterInit { | ||
services?: Array<string>; | ||
name?: string; | ||
namePrefix?: string; | ||
} | ||
export interface RequestDeviceOptions { | ||
acceptAllDevices: boolean; | ||
deviceFound: (device: BluetoothDevice, selectFn: any) => void; | ||
filters: Array<any>; | ||
optionalServices: Array<any>; | ||
scanTime: any; | ||
acceptAllDevices?: boolean; | ||
deviceFound?: (device: BluetoothDevice, selectFn: any) => boolean; | ||
filters?: Array<BluetoothLEScanFilterInit>; | ||
optionalServices?: Array<any>; | ||
scanTime?: any; | ||
} | ||
export declare function requestDevice(options: RequestDeviceOptions): Promise<BluetoothDevice>; | ||
export declare function cancelRequest(): Promise<void>; | ||
export declare class Bluetooth extends EventDispatcher { | ||
readonly referringDevice: BluetoothDevice; | ||
/** | ||
* Bluetooth Availability Changed event | ||
* @event | ||
*/ | ||
static EVENT_AVAILABILITY: string; | ||
private defaultScanTime; | ||
private scanner; | ||
constructor(referringDevice?: BluetoothDevice); | ||
private filterDevice(options, deviceInfo, validServices); | ||
getAvailability(): Promise<boolean>; | ||
requestDevice(options: RequestDeviceOptions): Promise<BluetoothDevice>; | ||
cancelRequest(): Promise<void>; | ||
} |
@@ -1,5 +0,5 @@ | ||
import { Emitter } from "./emitter"; | ||
import { EventDispatcher } from "./dispatcher"; | ||
import { BluetoothRemoteGATTService } from "./service"; | ||
import { BluetoothRemoteGATTDescriptor } from "./descriptor"; | ||
export declare class BluetoothRemoteGATTCharacteristic extends Emitter { | ||
export declare class BluetoothRemoteGATTCharacteristic extends EventDispatcher { | ||
/** | ||
@@ -10,14 +10,5 @@ * Characteristic Value Changed event | ||
static EVENT_CHANGED: string; | ||
/** | ||
* @hidden | ||
*/ | ||
_handle: string; | ||
/** | ||
* @hidden | ||
*/ | ||
_descriptors: Array<BluetoothRemoteGATTDescriptor>; | ||
service: BluetoothRemoteGATTService; | ||
uuid: any; | ||
value: any; | ||
properties: { | ||
readonly service: BluetoothRemoteGATTService; | ||
readonly uuid: any; | ||
readonly properties: { | ||
broadcast: boolean; | ||
@@ -33,12 +24,14 @@ read: boolean; | ||
}; | ||
/** | ||
* @hidden | ||
*/ | ||
private _value; | ||
readonly value: DataView; | ||
private handle; | ||
private descriptors; | ||
constructor(init?: Partial<BluetoothRemoteGATTCharacteristic>); | ||
private setValue(value?, emit?); | ||
getDescriptor(descriptorUUID: any): Promise<BluetoothRemoteGATTDescriptor>; | ||
getDescriptors(descriptorUUID: any): Promise<Array<BluetoothRemoteGATTDescriptor>>; | ||
readValue(): Promise<DataView>; | ||
writeValue(bufferSource: ArrayBuffer | ArrayBufferView): Promise<{}>; | ||
writeValue(bufferSource: ArrayBuffer | ArrayBufferView): Promise<void>; | ||
startNotifications(): Promise<BluetoothRemoteGATTCharacteristic>; | ||
stopNotifications(): Promise<BluetoothRemoteGATTCharacteristic>; | ||
} |
import { BluetoothRemoteGATTCharacteristic } from "./characteristic"; | ||
export declare class BluetoothRemoteGATTDescriptor { | ||
/** | ||
* @hidden | ||
*/ | ||
_handle: string; | ||
characteristic: BluetoothRemoteGATTCharacteristic; | ||
uuid: any; | ||
value: any; | ||
/** | ||
* @hidden | ||
*/ | ||
readonly characteristic: BluetoothRemoteGATTCharacteristic; | ||
readonly uuid: string; | ||
private _value; | ||
readonly value: DataView; | ||
private handle; | ||
constructor(init?: Partial<BluetoothRemoteGATTDescriptor>); | ||
readValue(): Promise<DataView>; | ||
writeValue(bufferSource: ArrayBuffer | ArrayBufferView): Promise<{}>; | ||
writeValue(bufferSource: ArrayBuffer | ArrayBufferView): Promise<void>; | ||
} |
@@ -1,4 +0,5 @@ | ||
import { Emitter } from "./emitter"; | ||
import { EventDispatcher } from "./dispatcher"; | ||
import { Bluetooth } from "./bluetooth"; | ||
import { BluetoothRemoteGATTServer } from "./server"; | ||
export declare class BluetoothDevice extends Emitter { | ||
export declare class BluetoothDevice extends EventDispatcher { | ||
/** | ||
@@ -9,18 +10,28 @@ * Server Disconnected event | ||
static EVENT_DISCONNECTED: string; | ||
readonly id: string; | ||
readonly name: string; | ||
readonly gatt: BluetoothRemoteGATTServer; | ||
readonly watchingAdvertisements: boolean; | ||
/** | ||
* @hidden | ||
*/ | ||
_handle: string; | ||
readonly adData: { | ||
rssi?: number; | ||
txPower?: null; | ||
serviceData?: Map<string, DataView>; | ||
manufacturerData?: Map<string, DataView>; | ||
}; | ||
/** | ||
* @hidden | ||
*/ | ||
_allowedServices: Array<string>; | ||
id: string; | ||
name: string; | ||
gatt: BluetoothRemoteGATTServer; | ||
uuids: Array<string>; | ||
readonly _bluetooth: Bluetooth; | ||
/** | ||
* @hidden | ||
*/ | ||
readonly _allowedServices: Array<string>; | ||
/** | ||
* @hidden | ||
*/ | ||
_serviceUUIDs: Array<string>; | ||
constructor(init?: Partial<BluetoothDevice>); | ||
} |
@@ -215,5 +215,5 @@ export declare enum bluetoothServices { | ||
} | ||
export declare function getCanonicalUUID(uuid: any): any; | ||
export declare function getServiceUUID(uuid: any): any; | ||
export declare function getCharacteristicUUID(uuid: any): any; | ||
export declare function getDescriptorUUID(uuid: any): any; | ||
export declare function getCanonicalUUID(uuid: string | number): string; | ||
export declare function getServiceUUID(uuid: string | number): string; | ||
export declare function getCharacteristicUUID(uuid: string | number): string; | ||
export declare function getDescriptorUUID(uuid: string | number): string; |
@@ -1,2 +0,13 @@ | ||
export * from "./bluetooth"; | ||
import { Bluetooth } from "./bluetooth"; | ||
/** | ||
* Default bluetooth instance synonymous with `navigator.bluetooth` | ||
*/ | ||
export declare const bluetooth: Bluetooth; | ||
/** | ||
* Bluetooth class for creating new instances | ||
*/ | ||
export { Bluetooth }; | ||
/** | ||
* Helper methods and enums | ||
*/ | ||
export * from "./helpers"; |
import { BluetoothDevice } from "./device"; | ||
import { BluetoothRemoteGATTService } from "./service"; | ||
export declare class BluetoothRemoteGATTServer { | ||
/** | ||
* @hidden | ||
*/ | ||
_services: Array<BluetoothRemoteGATTService>; | ||
device: BluetoothDevice; | ||
connected: boolean; | ||
private handle; | ||
private services; | ||
constructor(device: BluetoothDevice); | ||
connect(): Promise<BluetoothRemoteGATTServer>; | ||
@@ -11,0 +10,0 @@ disconnect(): void; |
@@ -1,5 +0,5 @@ | ||
import { Emitter } from "./emitter"; | ||
import { EventDispatcher } from "./dispatcher"; | ||
import { BluetoothDevice } from "./device"; | ||
import { BluetoothRemoteGATTCharacteristic } from "./characteristic"; | ||
export declare class BluetoothRemoteGATTService extends Emitter { | ||
export declare class BluetoothRemoteGATTService extends EventDispatcher { | ||
/** | ||
@@ -20,20 +20,8 @@ * Service Added event | ||
static EVENT_REMOVED: string; | ||
/** | ||
* @hidden | ||
*/ | ||
_handle: string; | ||
/** | ||
* @hidden | ||
*/ | ||
_services: Array<BluetoothRemoteGATTService>; | ||
/** | ||
* @hidden | ||
*/ | ||
_characteristics: Array<BluetoothRemoteGATTCharacteristic>; | ||
device: BluetoothDevice; | ||
uuid: any; | ||
isPrimary: boolean; | ||
/** | ||
* @hidden | ||
*/ | ||
readonly device: BluetoothDevice; | ||
readonly uuid: string; | ||
readonly isPrimary: boolean; | ||
private handle; | ||
private services; | ||
private characteristics; | ||
constructor(init?: Partial<BluetoothRemoteGATTService>); | ||
@@ -40,0 +28,0 @@ getCharacteristic(characteristicUUID: any): Promise<BluetoothRemoteGATTCharacteristic>; |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
1442230
114
5356
90