webbluetooth
Advanced tools
Comparing version 1.0.4 to 1.0.5
@@ -26,3 +26,3 @@ /* | ||
var webbluetooth = require('../'); | ||
var webbluetooth = require("../"); | ||
@@ -29,0 +29,0 @@ var eddystoneUUID = 0xFEAA; |
@@ -26,5 +26,5 @@ /* | ||
var bluetooth = require('../').bluetooth; | ||
var bluetooth = require("../").bluetooth; | ||
console.log('Requesting Bluetooth Devices...'); | ||
console.log("Requesting Bluetooth Devices..."); | ||
bluetooth.requestDevice({ | ||
@@ -34,19 +34,19 @@ filters:[{ services:[ "heart_rate" ] }] | ||
.then(device => { | ||
console.log('Found device: ' + device.name); | ||
console.log("Found device: " + device.name); | ||
return device.gatt.connect(); | ||
}) | ||
.then(server => { | ||
console.log('Gatt server connected: ' + server.connected); | ||
console.log("Gatt server connected: " + server.connected); | ||
return server.getPrimaryService("heart_rate"); | ||
}) | ||
.then(service => { | ||
console.log('Primary service: ' + service.uuid); | ||
console.log("Primary service: " + service.uuid); | ||
return service.getCharacteristic("heart_rate_measurement"); | ||
}) | ||
.then(characteristic => { | ||
console.log('Characteristic: ' + characteristic.uuid); | ||
console.log("Characteristic: " + characteristic.uuid); | ||
return characteristic.startNotifications(); | ||
}) | ||
.then(characteristic => { | ||
console.log('Notifications started'); | ||
console.log("Notifications started"); | ||
@@ -53,0 +53,0 @@ characteristic.addEventListener("characteristicvaluechanged", event => { |
@@ -26,9 +26,9 @@ /* | ||
var Bluetooth = require('../').Bluetooth; | ||
var Bluetooth = require("../").Bluetooth; | ||
var bluetoothDevices = []; | ||
process.stdin.setEncoding('utf8'); | ||
process.stdin.on('readable', () => { | ||
process.stdin.setEncoding("utf8"); | ||
process.stdin.on("readable", () => { | ||
var input = process.stdin.read(); | ||
if (input === '\u0003') { | ||
if (input === "\u0003") { | ||
process.exit(); | ||
@@ -56,3 +56,7 @@ } else { | ||
bluetoothDevices.push({ id: bluetoothDevice.id, select: selectFn }); | ||
console.log(bluetoothDevices.length + ": " + bluetoothDevice.name); | ||
if (bluetoothDevice._serviceUUIDs.length) { | ||
console.log("\tAdvertising: " + bluetoothDevice._serviceUUIDs); | ||
} | ||
} | ||
@@ -59,0 +63,0 @@ |
@@ -42,3 +42,3 @@ "use strict"; | ||
this.charNotifies = {}; | ||
this.foundFn = null; | ||
this.discoverFn = null; | ||
this.initialised = false; | ||
@@ -61,3 +61,6 @@ this.enabled = false; | ||
return completeFn(); | ||
noble.on("discover", this.discover.bind(this)); | ||
noble.on("discover", deviceInfo => { | ||
if (this.discoverFn) | ||
this.discoverFn(deviceInfo); | ||
}); | ||
this.initialised = true; | ||
@@ -89,40 +92,52 @@ completeFn(); | ||
} | ||
discover(deviceInfo) { | ||
if (this.foundFn) { | ||
const deviceID = (deviceInfo.address && deviceInfo.address !== "unknown") ? deviceInfo.address : deviceInfo.id; | ||
if (!this.deviceHandles[deviceID]) | ||
this.deviceHandles[deviceID] = deviceInfo; | ||
const serviceUUIDs = []; | ||
if (deviceInfo.advertisement.serviceUuids) { | ||
deviceInfo.advertisement.serviceUuids.forEach(serviceUUID => { | ||
serviceUUIDs.push(helpers_1.getCanonicalUUID(serviceUUID)); | ||
}); | ||
} | ||
const manufacturerData = new Map(); | ||
if (deviceInfo.advertisement.manufacturerData) { | ||
// First 2 bytes are 16-bit company identifier | ||
let company = deviceInfo.advertisement.manufacturerData.readUInt16LE(0); | ||
company = ("0000" + company.toString(16)).slice(-4); | ||
// Remove company ID | ||
const buffer = deviceInfo.advertisement.manufacturerData.slice(2); | ||
manufacturerData.set(company, this.bufferToDataView(buffer)); | ||
} | ||
const serviceData = new Map(); | ||
if (deviceInfo.advertisement.serviceData) { | ||
deviceInfo.advertisement.serviceData.forEach(serviceAdvert => { | ||
serviceData.set(helpers_1.getCanonicalUUID(serviceAdvert.uuid), this.bufferToDataView(serviceAdvert.data)); | ||
}); | ||
} | ||
this.foundFn({ | ||
id: deviceID, | ||
name: deviceInfo.advertisement.localName, | ||
_serviceUUIDs: serviceUUIDs, | ||
adData: { | ||
rssi: deviceInfo.rssi, | ||
txPower: deviceInfo.advertisement.txPowerLevel, | ||
serviceData: serviceData, | ||
manufacturerData: manufacturerData | ||
} | ||
validDevice(deviceInfo, serviceUUIDs) { | ||
if (serviceUUIDs.length === 0) { | ||
// Match any device | ||
return true; | ||
} | ||
if (!deviceInfo.advertisement.serviceUuids) { | ||
// No advertised services, no match | ||
return false; | ||
} | ||
const advertisedUUIDs = deviceInfo.advertisement.serviceUuids.map(serviceUUID => { | ||
return helpers_1.getCanonicalUUID(serviceUUID); | ||
}); | ||
return serviceUUIDs.some(serviceUUID => { | ||
// An advertised UUID matches our search UUIDs | ||
return (advertisedUUIDs.indexOf(serviceUUID) >= 0); | ||
}); | ||
} | ||
deviceToBluetoothDevice(deviceInfo) { | ||
const deviceID = (deviceInfo.address && deviceInfo.address !== "unknown") ? deviceInfo.address : deviceInfo.id; | ||
const serviceUUIDs = []; | ||
if (deviceInfo.advertisement.serviceUuids) { | ||
deviceInfo.advertisement.serviceUuids.forEach(serviceUUID => { | ||
serviceUUIDs.push(helpers_1.getCanonicalUUID(serviceUUID)); | ||
}); | ||
} | ||
const manufacturerData = new Map(); | ||
if (deviceInfo.advertisement.manufacturerData) { | ||
// First 2 bytes are 16-bit company identifier | ||
const company = deviceInfo.advertisement.manufacturerData.readUInt16LE(0); | ||
// Remove company ID | ||
const buffer = deviceInfo.advertisement.manufacturerData.slice(2); | ||
manufacturerData.set(("0000" + company.toString(16)).slice(-4), this.bufferToDataView(buffer)); | ||
} | ||
const serviceData = new Map(); | ||
if (deviceInfo.advertisement.serviceData) { | ||
deviceInfo.advertisement.serviceData.forEach(serviceAdvert => { | ||
serviceData.set(helpers_1.getCanonicalUUID(serviceAdvert.uuid), this.bufferToDataView(serviceAdvert.data)); | ||
}); | ||
} | ||
return { | ||
id: deviceID, | ||
name: deviceInfo.advertisement.localName, | ||
_serviceUUIDs: serviceUUIDs, | ||
adData: { | ||
rssi: deviceInfo.rssi, | ||
txPower: deviceInfo.advertisement.txPowerLevel, | ||
serviceData: serviceData, | ||
manufacturerData: manufacturerData | ||
} | ||
}; | ||
} | ||
@@ -140,15 +155,12 @@ getEnabled(completeFn) { | ||
startScan(serviceUUIDs, foundFn, completeFn, errorFn) { | ||
if (serviceUUIDs.length === 0) { | ||
this.foundFn = foundFn; | ||
} | ||
else { | ||
this.foundFn = device => { | ||
serviceUUIDs.forEach(serviceUUID => { | ||
if (device._serviceUUIDs.indexOf(serviceUUID) >= 0) { | ||
foundFn(device); | ||
return; | ||
} | ||
}); | ||
}; | ||
} | ||
this.discoverFn = deviceInfo => { | ||
if (this.validDevice(deviceInfo, serviceUUIDs)) { | ||
const device = this.deviceToBluetoothDevice(deviceInfo); | ||
if (!this.deviceHandles[device.id]) { | ||
this.deviceHandles[device.id] = deviceInfo; | ||
// Only call the found function the first time we find a valid device | ||
foundFn(device); | ||
} | ||
} | ||
}; | ||
this.init(() => { | ||
@@ -158,3 +170,5 @@ this.deviceHandles = {}; | ||
if (this.state === true) { | ||
noble.startScanning([], false, this.checkForError(errorFn, completeFn)); | ||
// Noble doesn't correctly match short and canonical UUIDs on Linux, so we need to check ourselves | ||
// Continually scan to pick up all advertised UUIDs | ||
noble.startScanning([], true, this.checkForError(errorFn, completeFn)); | ||
} | ||
@@ -173,3 +187,3 @@ else { | ||
stopScan(_errorFn) { | ||
this.foundFn = null; | ||
this.discoverFn = null; | ||
noble.stopScanning(); | ||
@@ -176,0 +190,0 @@ } |
@@ -98,4 +98,6 @@ "use strict"; | ||
return resolve(this.characteristics); | ||
// Canonical-ize characteristic | ||
characteristic = helpers_1.getCharacteristicUUID(characteristic); | ||
const filtered = this.characteristics.filter(characteristicObject => { | ||
return (characteristicObject.uuid === helpers_1.getCharacteristicUUID(characteristic)); | ||
return (characteristicObject.uuid === characteristic); | ||
}); | ||
@@ -102,0 +104,0 @@ if (filtered.length !== 1) |
{ | ||
"name": "webbluetooth", | ||
"version": "1.0.4", | ||
"version": "1.0.5", | ||
"description": "Node.js implementation of the Web Bluetooth Specification", | ||
@@ -5,0 +5,0 @@ "homepage": "https://github.com/thegecko/webbluetooth", |
@@ -68,3 +68,3 @@ /* | ||
private charNotifies: {} = {}; | ||
private foundFn: (device: Partial<BluetoothDevice>) => void = null; | ||
private discoverFn: (device: noble.Peripheral) => void = null; | ||
private initialised: boolean = false; | ||
@@ -89,5 +89,7 @@ private enabled: boolean = false; | ||
private init(completeFn: () => any) { | ||
private init(completeFn: () => any): void { | ||
if (this.initialised) return completeFn(); | ||
noble.on("discover", this.discover.bind(this)); | ||
noble.on("discover", deviceInfo => { | ||
if (this.discoverFn) this.discoverFn(deviceInfo); | ||
}); | ||
this.initialised = true; | ||
@@ -108,3 +110,3 @@ completeFn(); | ||
private bufferToDataView(buffer) { | ||
private bufferToDataView(buffer: Buffer): DataView { | ||
// Buffer to ArrayBuffer | ||
@@ -115,3 +117,3 @@ const arrayBuffer = new Uint8Array(buffer).buffer; | ||
private dataViewToBuffer(dataView) { | ||
private dataViewToBuffer(dataView: DataView): Buffer { | ||
// DataView to TypedArray | ||
@@ -122,43 +124,61 @@ const typedArray = new Uint8Array(dataView.buffer); | ||
private discover(deviceInfo) { | ||
if (this.foundFn) { | ||
const deviceID = (deviceInfo.address && deviceInfo.address !== "unknown") ? deviceInfo.address : deviceInfo.id; | ||
if (!this.deviceHandles[deviceID]) this.deviceHandles[deviceID] = deviceInfo; | ||
private validDevice(deviceInfo: noble.Peripheral, serviceUUIDs: Array<string>): boolean { | ||
if (serviceUUIDs.length === 0) { | ||
// Match any device | ||
return true; | ||
} | ||
const serviceUUIDs = []; | ||
if (deviceInfo.advertisement.serviceUuids) { | ||
deviceInfo.advertisement.serviceUuids.forEach(serviceUUID => { | ||
serviceUUIDs.push(getCanonicalUUID(serviceUUID)); | ||
}); | ||
} | ||
if (!deviceInfo.advertisement.serviceUuids) { | ||
// No advertised services, no match | ||
return false; | ||
} | ||
const manufacturerData = new Map(); | ||
if (deviceInfo.advertisement.manufacturerData) { | ||
// First 2 bytes are 16-bit company identifier | ||
let company = deviceInfo.advertisement.manufacturerData.readUInt16LE(0); | ||
company = ("0000" + company.toString(16)).slice(-4); | ||
// Remove company ID | ||
const buffer = deviceInfo.advertisement.manufacturerData.slice(2); | ||
manufacturerData.set(company, this.bufferToDataView(buffer)); | ||
} | ||
const advertisedUUIDs = deviceInfo.advertisement.serviceUuids.map(serviceUUID => { | ||
return getCanonicalUUID(serviceUUID); | ||
}); | ||
const serviceData = new Map(); | ||
if (deviceInfo.advertisement.serviceData) { | ||
deviceInfo.advertisement.serviceData.forEach(serviceAdvert => { | ||
serviceData.set(getCanonicalUUID(serviceAdvert.uuid), this.bufferToDataView(serviceAdvert.data)); | ||
}); | ||
} | ||
return serviceUUIDs.some(serviceUUID => { | ||
// An advertised UUID matches our search UUIDs | ||
return (advertisedUUIDs.indexOf(serviceUUID) >= 0); | ||
}); | ||
} | ||
this.foundFn({ | ||
id: deviceID, | ||
name: deviceInfo.advertisement.localName, | ||
_serviceUUIDs: serviceUUIDs, | ||
adData: { | ||
rssi: deviceInfo.rssi, | ||
txPower: deviceInfo.advertisement.txPowerLevel, | ||
serviceData: serviceData, | ||
manufacturerData: manufacturerData | ||
} | ||
private deviceToBluetoothDevice(deviceInfo): Partial<BluetoothDevice> { | ||
const deviceID = (deviceInfo.address && deviceInfo.address !== "unknown") ? deviceInfo.address : deviceInfo.id; | ||
const serviceUUIDs = []; | ||
if (deviceInfo.advertisement.serviceUuids) { | ||
deviceInfo.advertisement.serviceUuids.forEach(serviceUUID => { | ||
serviceUUIDs.push(getCanonicalUUID(serviceUUID)); | ||
}); | ||
} | ||
const manufacturerData = new Map(); | ||
if (deviceInfo.advertisement.manufacturerData) { | ||
// First 2 bytes are 16-bit company identifier | ||
const company = deviceInfo.advertisement.manufacturerData.readUInt16LE(0); | ||
// Remove company ID | ||
const buffer = deviceInfo.advertisement.manufacturerData.slice(2); | ||
manufacturerData.set(("0000" + company.toString(16)).slice(-4), this.bufferToDataView(buffer)); | ||
} | ||
const serviceData = new Map(); | ||
if (deviceInfo.advertisement.serviceData) { | ||
deviceInfo.advertisement.serviceData.forEach(serviceAdvert => { | ||
serviceData.set(getCanonicalUUID(serviceAdvert.uuid), this.bufferToDataView(serviceAdvert.data)); | ||
}); | ||
} | ||
return { | ||
id: deviceID, | ||
name: deviceInfo.advertisement.localName, | ||
_serviceUUIDs: serviceUUIDs, | ||
adData: { | ||
rssi: deviceInfo.rssi, | ||
txPower: deviceInfo.advertisement.txPowerLevel, | ||
serviceData: serviceData, | ||
manufacturerData: manufacturerData | ||
} | ||
}; | ||
} | ||
@@ -178,15 +198,14 @@ | ||
if (serviceUUIDs.length === 0) { | ||
this.foundFn = foundFn; | ||
} else { | ||
this.foundFn = device => { | ||
serviceUUIDs.forEach(serviceUUID => { | ||
if (device._serviceUUIDs.indexOf(serviceUUID) >= 0) { | ||
foundFn(device); | ||
return; | ||
} | ||
}); | ||
}; | ||
} | ||
this.discoverFn = deviceInfo => { | ||
if (this.validDevice(deviceInfo, serviceUUIDs)) { | ||
const device = this.deviceToBluetoothDevice(deviceInfo); | ||
if (!this.deviceHandles[device.id]) { | ||
this.deviceHandles[device.id] = deviceInfo; | ||
// Only call the found function the first time we find a valid device | ||
foundFn(device); | ||
} | ||
} | ||
}; | ||
this.init(() => { | ||
@@ -196,3 +215,5 @@ this.deviceHandles = {}; | ||
if (this.state === true) { | ||
noble.startScanning([], false, this.checkForError(errorFn, completeFn)); | ||
// Noble doesn't correctly match short and canonical UUIDs on Linux, so we need to check ourselves | ||
// Continually scan to pick up all advertised UUIDs | ||
noble.startScanning([], true, this.checkForError(errorFn, completeFn)); | ||
} else { | ||
@@ -209,3 +230,3 @@ errorFn("adapter not enabled"); | ||
public stopScan(_errorFn?: (errorMsg: string) => void): void { | ||
this.foundFn = null; | ||
this.discoverFn = null; | ||
noble.stopScanning(); | ||
@@ -212,0 +233,0 @@ } |
@@ -72,3 +72,3 @@ /* | ||
rssi?: number; | ||
txPower?: null; | ||
txPower?: number; | ||
serviceData?: Map<string, DataView>; | ||
@@ -75,0 +75,0 @@ manufacturerData?: Map<string, DataView>; |
@@ -125,4 +125,7 @@ /* | ||
// Canonical-ize characteristic | ||
characteristic = getCharacteristicUUID(characteristic); | ||
const filtered = this.characteristics.filter(characteristicObject => { | ||
return (characteristicObject.uuid === getCharacteristicUUID(characteristic)); | ||
return (characteristicObject.uuid === characteristic); | ||
}); | ||
@@ -129,0 +132,0 @@ |
@@ -37,3 +37,3 @@ /// <reference types="node" /> | ||
private charNotifies; | ||
private foundFn; | ||
private discoverFn; | ||
private initialised; | ||
@@ -48,3 +48,4 @@ private enabled; | ||
private dataViewToBuffer(dataView); | ||
private discover(deviceInfo); | ||
private validDevice(deviceInfo, serviceUUIDs); | ||
private deviceToBluetoothDevice(deviceInfo); | ||
getEnabled(completeFn: (enabled: boolean) => void): void; | ||
@@ -51,0 +52,0 @@ startScan(serviceUUIDs: Array<string>, foundFn: (device: Partial<BluetoothDevice>) => void, completeFn?: () => void, errorFn?: (errorMsg: string) => void): void; |
@@ -39,3 +39,3 @@ import { EventDispatcher } from "./dispatcher"; | ||
rssi?: number; | ||
txPower?: null; | ||
txPower?: number; | ||
serviceData?: Map<string, DataView>; | ||
@@ -42,0 +42,0 @@ manufacturerData?: Map<string, DataView>; |
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
1276119
5721