Seperated BLEDevice out into NobleDevice and WebBLEDevice usingi nterfaces

This commit is contained in:
Nathan Kellenicki 2019-03-18 11:16:54 -07:00
parent 6f8f5bbaf8
commit f23e5ad679
33 changed files with 364 additions and 288 deletions

View File

@ -5585,7 +5585,7 @@
<span class="jsdoc-message">
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a>
on Thu Feb 7th 2019
on Mon Mar 18th 2019
using the <a href="https://github.com/docstrap/docstrap">DocStrap template</a>.
</span>

View File

@ -4188,7 +4188,7 @@
<span class="jsdoc-message">
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a>
on Thu Feb 7th 2019
on Mon Mar 18th 2019
using the <a href="https://github.com/docstrap/docstrap">DocStrap template</a>.
</span>

View File

@ -2467,7 +2467,7 @@
<span class="jsdoc-message">
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a>
on Thu Feb 7th 2019
on Mon Mar 18th 2019
using the <a href="https://github.com/docstrap/docstrap">DocStrap template</a>.
</span>

View File

@ -4444,7 +4444,7 @@
<span class="jsdoc-message">
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a>
on Thu Feb 7th 2019
on Mon Mar 18th 2019
using the <a href="https://github.com/docstrap/docstrap">DocStrap template</a>.
</span>

View File

@ -5157,7 +5157,7 @@
<span class="jsdoc-message">
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a>
on Thu Feb 7th 2019
on Mon Mar 18th 2019
using the <a href="https://github.com/docstrap/docstrap">DocStrap template</a>.
</span>

View File

@ -3409,7 +3409,7 @@
<span class="jsdoc-message">
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a>
on Thu Feb 7th 2019
on Mon Mar 18th 2019
using the <a href="https://github.com/docstrap/docstrap">DocStrap template</a>.
</span>

View File

@ -1018,7 +1018,7 @@
<span class="jsdoc-message">
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a>
on Thu Feb 7th 2019
on Mon Mar 18th 2019
using the <a href="https://github.com/docstrap/docstrap">DocStrap template</a>.
</span>

View File

@ -5158,7 +5158,7 @@
<span class="jsdoc-message">
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a>
on Thu Feb 7th 2019
on Mon Mar 18th 2019
using the <a href="https://github.com/docstrap/docstrap">DocStrap template</a>.
</span>

View File

@ -351,7 +351,7 @@ exports.BoostMoveHub = BoostMoveHub;
<span class="jsdoc-message">
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a>
on Thu Feb 7th 2019
on Mon Mar 18th 2019
using the <a href="https://github.com/docstrap/docstrap">DocStrap template</a>.
</span>

View File

@ -6681,7 +6681,7 @@
<span class="jsdoc-message">
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a>
on Thu Feb 7th 2019
on Mon Mar 18th 2019
using the <a href="https://github.com/docstrap/docstrap">DocStrap template</a>.
</span>

View File

@ -282,7 +282,7 @@ var BLECharacteristic;
<span class="jsdoc-message">
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a>
on Thu Feb 7th 2019
on Mon Mar 18th 2019
using the <a href="https://github.com/docstrap/docstrap">DocStrap template</a>.
</span>

View File

@ -300,7 +300,7 @@ exports.DuploTrainBase = DuploTrainBase;
<span class="jsdoc-message">
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a>
on Thu Feb 7th 2019
on Mon Mar 18th 2019
using the <a href="https://github.com/docstrap/docstrap">DocStrap template</a>.
</span>

View File

@ -3272,7 +3272,7 @@
<span class="jsdoc-message">
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a>
on Thu Feb 7th 2019
on Mon Mar 18th 2019
using the <a href="https://github.com/docstrap/docstrap">DocStrap template</a>.
</span>

View File

@ -448,7 +448,7 @@ exports.Hub = Hub;
<span class="jsdoc-message">
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a>
on Thu Feb 7th 2019
on Mon Mar 18th 2019
using the <a href="https://github.com/docstrap/docstrap">DocStrap template</a>.
</span>

View File

@ -314,7 +314,7 @@ poweredUP.scan(); // Start scanning for Hubs</code></pre><p>More examples are av
<span class="jsdoc-message">
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a>
on Thu Feb 7th 2019
on Mon Mar 18th 2019
using the <a href="https://github.com/docstrap/docstrap">DocStrap template</a>.
</span>

View File

@ -503,7 +503,7 @@ exports.LPF2Hub = LPF2Hub;
<span class="jsdoc-message">
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a>
on Thu Feb 7th 2019
on Mon Mar 18th 2019
using the <a href="https://github.com/docstrap/docstrap">DocStrap template</a>.
</span>

View File

@ -93,9 +93,9 @@ var __importStar = (this &amp;&amp; this.__importStar) || function (mod) {
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
const bledevice_1 = require("./bledevice");
const boostmovehub_1 = require("./boostmovehub");
const duplotrainbase_1 = require("./duplotrainbase");
const nobledevice_1 = require("./nobledevice");
const puphub_1 = require("./puphub");
const pupremote_1 = require("./pupremote");
const wedo2smarthub_1 = require("./wedo2smarthub");
@ -193,7 +193,7 @@ class PoweredUP extends events_1.EventEmitter {
return Object.keys(this._connectedHubs).map((uuid) => this._connectedHubs[uuid]).filter((hub) => hub.name === name);
}
async _discoveryEventHandler(peripheral) {
const device = new bledevice_1.BLEDevice(peripheral);
const device = new nobledevice_1.NobleDevice(peripheral);
let hub;
if (await wedo2smarthub_1.WeDo2SmartHub.IsWeDo2SmartHub(peripheral)) {
hub = new wedo2smarthub_1.WeDo2SmartHub(device, this.autoSubscribe);
@ -286,7 +286,7 @@ exports.PoweredUP = PoweredUP;
<span class="jsdoc-message">
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a>
on Thu Feb 7th 2019
on Mon Mar 18th 2019
using the <a href="https://github.com/docstrap/docstrap">DocStrap template</a>.
</span>

View File

@ -308,7 +308,7 @@ exports.PUPHub = PUPHub;
<span class="jsdoc-message">
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a>
on Thu Feb 7th 2019
on Mon Mar 18th 2019
using the <a href="https://github.com/docstrap/docstrap">DocStrap template</a>.
</span>

View File

@ -238,7 +238,7 @@ exports.PUPRemote = PUPRemote;
<span class="jsdoc-message">
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a>
on Thu Feb 7th 2019
on Mon Mar 18th 2019
using the <a href="https://github.com/docstrap/docstrap">DocStrap template</a>.
</span>

File diff suppressed because one or more lines are too long

View File

@ -540,7 +540,7 @@ exports.WeDo2SmartHub = WeDo2SmartHub;
<span class="jsdoc-message">
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a>
on Thu Feb 7th 2019
on Mon Mar 18th 2019
using the <a href="https://github.com/docstrap/docstrap">DocStrap template</a>.
</span>

View File

@ -1,237 +0,0 @@
import { Characteristic, Peripheral, Service } from "noble";
import Debug = require("debug");
import { EventEmitter } from "events";
import { write } from "fs";
const debug = Debug("bledevice");
export class BLEDevice extends EventEmitter {
// @ts-ignore
private _noblePeripheral: Peripheral | null;
private _webBLEServer: any;
private _uuid: string;
private _name: string = "";
private _listeners: {[uuid: string]: any} = {};
private _characteristics: {[uuid: string]: Characteristic} = {};
private _queue: Promise<any> = Promise.resolve();
private _mailbox: Buffer[] = [];
private _connected: boolean = false;
private _connecting: boolean = false;
constructor (device: any) {
super();
if (device._noble) {
this._noblePeripheral = device;
this._uuid = device.uuid;
device.on("disconnect", () => {
this._connected = false;
this._connected = false;
this.emit("disconnect");
});
// NK: This hack allows LPF2.0 hubs to send a second advertisement packet consisting of the hub name before we try to read it
setTimeout(() => {
this._name = device.advertisement.localName;
this.emit("discoverComplete");
}, 1000);
} else {
this._webBLEServer = device;
this._uuid = device.device.id;
this._name = device.device.name;
device.device.addEventListener("gattserverdisconnected", () => {
this._connected = false;
this._connected = false;
this.emit("disconnect");
});
setTimeout(() => {
this.emit("discoverComplete");
}, 2000);
}
}
public get uuid () {
return this._uuid;
}
public get name () {
return this._name;
}
public get connecting () {
return this._connecting;
}
public get connected () {
return this._connected;
}
public connect () {
return new Promise((resolve, reject) => {
if (this._noblePeripheral) {
this._connecting = true;
this._noblePeripheral.connect((err: string) => {
this._connecting = false;
this._connected = true;
return resolve();
});
} else {
this._connected = true;
return resolve();
}
});
}
public disconnect () {
return new Promise((resolve, reject) => {
if (this._noblePeripheral) {
this._noblePeripheral.connect((err: string) => {
return resolve();
});
} else {
this._webBLEServer.device.gatt.disconnect();
return resolve();
}
});
}
public discoverCharacteristicsForService (uuid: string) {
return new Promise(async (discoverResolve, discoverReject) => {
if (this._noblePeripheral) {
uuid = this._sanitizeUUID(uuid);
this._noblePeripheral.discoverServices([uuid], (err: string, services: Service[]) => {
if (err) {
return discoverReject(err);
}
debug("Service/characteristic discovery started");
const servicePromises: Array<Promise<null>> = [];
services.forEach((service) => {
servicePromises.push(new Promise((resolve, reject) => {
service.discoverCharacteristics([], (err, characteristics) => {
characteristics.forEach((characteristic) => {
this._characteristics[characteristic.uuid] = characteristic;
});
return resolve();
});
}));
});
Promise.all(servicePromises).then(() => {
debug("Service/characteristic discovery finished");
return discoverResolve();
});
});
} else if (this._webBLEServer) {
debug("Service/characteristic discovery started");
let service;
try {
service = await this._webBLEServer.getPrimaryService(uuid);
} catch (err) {
return discoverReject(err);
}
const characteristics = await service.getCharacteristics();
for (const characteristic of characteristics) {
this._characteristics[characteristic.uuid] = characteristic;
}
debug("Service/characteristic discovery finished");
return discoverResolve();
}
});
}
public subscribeToCharacteristic (uuid: string, callback: (data: Buffer) => void) {
if (this._noblePeripheral) {
uuid = this._sanitizeUUID(uuid);
this._characteristics[uuid].on("data", (data: Buffer) => {
return callback(data);
});
this._characteristics[uuid].subscribe((err) => {
if (err) {
throw new Error(err);
}
});
} else if (this._webBLEServer) {
if (this._listeners[uuid]) {
// @ts-ignore
this._characteristics[uuid].removeEventListener("characteristicvaluechanged", this._listeners[uuid]);
}
// @ts-ignore
this._listeners[uuid] = (event) => {
const buf = Buffer.alloc(event.target.value.buffer.byteLength);
const view = new Uint8Array(event.target.value.buffer);
for (let i = 0; i < buf.length; i++) {
buf[i] = view[i];
}
return callback(buf);
};
// @ts-ignore
this._characteristics[uuid].addEventListener("characteristicvaluechanged", this._listeners[uuid]);
for (const data of this._mailbox) {
callback(data);
}
this._mailbox = [];
// @ts-ignore
this._characteristics[uuid].startNotifications();
}
}
public addToCharacteristicMailbox (uuid: string, data: Buffer) {
this._mailbox.push(data);
}
public readFromCharacteristic (uuid: string, callback: (err: string | null, data: Buffer | null) => void) {
if (this._noblePeripheral) {
uuid = this._sanitizeUUID(uuid);
this._characteristics[uuid].read((err: string, data: Buffer) => {
return callback(err, data);
});
} else if (this._webBLEServer) {
// @ts-ignore
this._characteristics[uuid].readValue().then((data) => {
const buf = Buffer.alloc(data.buffer.byteLength);
const view = new Uint8Array(data.buffer);
for (let i = 0; i < buf.length; i++) {
buf[i] = view[i];
}
callback(null, buf);
});
}
}
public writeToCharacteristic (uuid: string, data: Buffer, callback?: () => void) {
if (this._noblePeripheral) {
uuid = this._sanitizeUUID(uuid);
this._characteristics[uuid].write(data, false, callback);
} else {
// @ts-ignore
this._queue = this._queue.then(() => this._characteristics[uuid].writeValue(data)).then(() => {
if (callback) {
callback();
}
});
}
}
private _sanitizeUUID (uuid: string) {
return uuid.replace(/-/g, "");
}
}

View File

@ -1,12 +1,12 @@
import { Peripheral } from "noble";
import { BLEDevice } from "./bledevice";
import { LPF2Hub } from "./lpf2hub";
import { Port } from "./port";
import * as Consts from "./consts";
import Debug = require("debug");
import { IBLEDevice } from "./interfaces";
const debug = Debug("boostmovehub");
@ -34,7 +34,7 @@ export class BoostMoveHub extends LPF2Hub {
}
constructor (device: BLEDevice, autoSubscribe: boolean = true) {
constructor (device: IBLEDevice, autoSubscribe: boolean = true) {
super(device, autoSubscribe);
this.type = Consts.HubType.BOOST_MOVE_HUB;
this._ports = {

View File

@ -1,12 +1,12 @@
import { Peripheral } from "noble";
import { BLEDevice } from "./bledevice";
import { LPF2Hub } from "./lpf2hub";
import { Port } from "./port";
import * as Consts from "./consts";
import Debug = require("debug");
import { IBLEDevice } from "./interfaces";
const debug = Debug("duplotrainbase");
@ -64,7 +64,7 @@ export class DuploTrainBase extends LPF2Hub {
}
constructor (device: BLEDevice, autoSubscribe: boolean = true) {
constructor (device: IBLEDevice, autoSubscribe: boolean = true) {
super(device, autoSubscribe);
this.type = Consts.HubType.DUPLO_TRAIN_HUB;
this._ports = {

View File

@ -1,6 +1,6 @@
import { EventEmitter } from "events";
import { BLEDevice } from "./bledevice";
import { IBLEDevice, IFirmwareInfo } from "./interfaces";
import { Port } from "./port";
import * as Consts from "./consts";
@ -9,14 +9,6 @@ import Debug = require("debug");
const debug = Debug("hub");
export interface IFirmwareInfo {
major: number;
minor: number;
bugFix: number;
build: number;
}
/**
* @class Hub
* @extends EventEmitter
@ -36,13 +28,13 @@ export class Hub extends EventEmitter {
protected _voltage: number = 0;
protected _current: number = 0;
protected _bleDevice: BLEDevice;
protected _bleDevice: IBLEDevice;
private _rssi: number = -100;
private _isConnecting = false;
private _isConnected = false;
constructor (device: BLEDevice, autoSubscribe: boolean = true) {
constructor (device: IBLEDevice, autoSubscribe: boolean = true) {
super();
this.autoSubscribe = !!autoSubscribe;
this._bleDevice = device;

23
src/interfaces.ts Normal file
View File

@ -0,0 +1,23 @@
import { EventEmitter } from "events";
export interface IFirmwareInfo {
major: number;
minor: number;
bugFix: number;
build: number;
}
export interface IBLEDevice extends EventEmitter {
uuid: string;
name: string;
connecting: boolean;
connected: boolean;
connect: () => Promise<any>;
disconnect: () => Promise<any>;
discoverCharacteristicsForService: (uuid: string) => Promise<any>;
subscribeToCharacteristic: (uuid: string, callback: (data: Buffer) => void) => void;
addToCharacteristicMailbox: (uuid: string, data: Buffer) => void;
readFromCharacteristic: (uuid: string, callback: (err: string | null, data: Buffer | null) => void) => void;
writeToCharacteristic: (uuid: string, data: Buffer, callback?: () => void) => void;
}

150
src/nobledevice.ts Normal file
View File

@ -0,0 +1,150 @@
import { Characteristic, Peripheral, Service } from "noble";
import Debug = require("debug");
import { EventEmitter } from "events";
import { IBLEDevice } from "./interfaces";
const debug = Debug("bledevice");
export class NobleDevice extends EventEmitter implements IBLEDevice {
private _noblePeripheral: Peripheral;
private _uuid: string;
private _name: string = "";
private _listeners: {[uuid: string]: any} = {};
private _characteristics: {[uuid: string]: Characteristic} = {};
private _queue: Promise<any> = Promise.resolve();
private _mailbox: Buffer[] = [];
private _connected: boolean = false;
private _connecting: boolean = false;
constructor (device: any) {
super();
this._noblePeripheral = device;
this._uuid = device.uuid;
device.on("disconnect", () => {
this._connected = false;
this._connected = false;
this.emit("disconnect");
});
// NK: This hack allows LPF2.0 hubs to send a second advertisement packet consisting of the hub name before we try to read it
setTimeout(() => {
this._name = device.advertisement.localName;
this.emit("discoverComplete");
}, 1000);
}
public get uuid () {
return this._uuid;
}
public get name () {
return this._name;
}
public get connecting () {
return this._connecting;
}
public get connected () {
return this._connected;
}
public connect () {
return new Promise((resolve, reject) => {
this._connecting = true;
this._noblePeripheral.connect((err: string) => {
this._connecting = false;
this._connected = true;
return resolve();
});
});
}
public disconnect () {
return new Promise((resolve, reject) => {
this._noblePeripheral.connect((err: string) => {
return resolve();
});
});
}
public discoverCharacteristicsForService (uuid: string) {
return new Promise(async (discoverResolve, discoverReject) => {
uuid = this._sanitizeUUID(uuid);
this._noblePeripheral.discoverServices([uuid], (err: string, services: Service[]) => {
if (err) {
return discoverReject(err);
}
debug("Service/characteristic discovery started");
const servicePromises: Array<Promise<null>> = [];
services.forEach((service) => {
servicePromises.push(new Promise((resolve, reject) => {
service.discoverCharacteristics([], (err, characteristics) => {
characteristics.forEach((characteristic) => {
this._characteristics[characteristic.uuid] = characteristic;
});
return resolve();
});
}));
});
Promise.all(servicePromises).then(() => {
debug("Service/characteristic discovery finished");
return discoverResolve();
});
});
});
}
public subscribeToCharacteristic (uuid: string, callback: (data: Buffer) => void) {
uuid = this._sanitizeUUID(uuid);
this._characteristics[uuid].on("data", (data: Buffer) => {
return callback(data);
});
this._characteristics[uuid].subscribe((err) => {
if (err) {
throw new Error(err);
}
});
}
public addToCharacteristicMailbox (uuid: string, data: Buffer) {
this._mailbox.push(data);
}
public readFromCharacteristic (uuid: string, callback: (err: string | null, data: Buffer | null) => void) {
uuid = this._sanitizeUUID(uuid);
this._characteristics[uuid].read((err: string, data: Buffer) => {
return callback(err, data);
});
}
public writeToCharacteristic (uuid: string, data: Buffer, callback?: () => void) {
uuid = this._sanitizeUUID(uuid);
this._characteristics[uuid].write(data, false, callback);
}
private _sanitizeUUID (uuid: string) {
return uuid.replace(/-/g, "");
}
}

View File

@ -1,9 +1,9 @@
import { BLEDevice } from "./bledevice";
import { BoostMoveHub } from "./boostmovehub";
import { DuploTrainBase } from "./duplotrainbase";
import { Hub } from "./hub";
import { PUPHub } from "./puphub";
import { PUPRemote } from "./pupremote";
import { WebBLEDevice } from "./webbledevice";
import { WeDo2SmartHub } from "./wedo2smarthub";
import * as Consts from "./consts";
@ -11,7 +11,7 @@ import * as Consts from "./consts";
import { EventEmitter } from "events";
import Debug = require("debug");
import { LPF2Hub } from "./lpf2hub";
import { IBLEDevice } from "./interfaces";
const debug = Debug("poweredup");
@ -99,7 +99,7 @@ export class PoweredUP extends EventEmitter {
}
private _determineLPF2HubType (device: BLEDevice) {
private _determineLPF2HubType (device: IBLEDevice): Promise<Consts.HubType> {
return new Promise((resolve, reject) => {
let buf: Buffer = Buffer.alloc(0);
device.subscribeToCharacteristic(Consts.BLECharacteristic.LPF2_ALL, (data: Buffer) => {
@ -137,7 +137,7 @@ export class PoweredUP extends EventEmitter {
private async _discoveryEventHandler (server: BluetoothRemoteGATTServer) {
const device = new BLEDevice(server);
const device = new WebBLEDevice(server);
let hub: Hub;
@ -157,7 +157,6 @@ export class PoweredUP extends EventEmitter {
} catch (error) {}
if (isLPF2Hub) {
// @ts-ignore
hubType = await this._determineLPF2HubType(device);
}

View File

@ -1,9 +1,9 @@
import { Peripheral } from "noble-mac";
import { BLEDevice } from "./bledevice";
import { BoostMoveHub } from "./boostmovehub";
import { DuploTrainBase } from "./duplotrainbase";
import { Hub } from "./hub";
import { NobleDevice } from "./nobledevice";
import { PUPHub } from "./puphub";
import { PUPRemote } from "./pupremote";
import { WeDo2SmartHub } from "./wedo2smarthub";
@ -130,7 +130,7 @@ export class PoweredUP extends EventEmitter {
private async _discoveryEventHandler (peripheral: Peripheral) {
const device = new BLEDevice(peripheral);
const device = new NobleDevice(peripheral);
let hub: Hub;

View File

@ -1,12 +1,12 @@
import { Peripheral } from "noble";
import { BLEDevice } from "./bledevice";
import { LPF2Hub } from "./lpf2hub";
import { Port } from "./port";
import * as Consts from "./consts";
import Debug = require("debug");
import { IBLEDevice } from "./interfaces";
const debug = Debug("puphub");
@ -39,7 +39,7 @@ export class PUPHub extends LPF2Hub {
}
constructor (device: BLEDevice, autoSubscribe: boolean = true) {
constructor (device: IBLEDevice, autoSubscribe: boolean = true) {
super(device, autoSubscribe);
this.type = Consts.HubType.POWERED_UP_HUB;
this._ports = {

View File

@ -1,12 +1,12 @@
import { Peripheral } from "noble";
import { BLEDevice } from "./bledevice";
import { LPF2Hub } from "./lpf2hub";
import { Port } from "./port";
import * as Consts from "./consts";
import Debug = require("debug");
import { IBLEDevice } from "./interfaces";
const debug = Debug("pupremote");
@ -64,7 +64,7 @@ export class PUPRemote extends LPF2Hub {
}
constructor (device: BLEDevice, autoSubscribe: boolean = true) {
constructor (device: IBLEDevice, autoSubscribe: boolean = true) {
super(device, autoSubscribe);
this.type = Consts.HubType.POWERED_UP_REMOTE;
this._ports = {

149
src/webbledevice.ts Normal file
View File

@ -0,0 +1,149 @@
import Debug = require("debug");
import { EventEmitter } from "events";
import { IBLEDevice } from "./interfaces";
const debug = Debug("bledevice");
export class WebBLEDevice extends EventEmitter implements IBLEDevice {
private _webBLEServer: any;
private _uuid: string;
private _name: string = "";
private _listeners: {[uuid: string]: any} = {};
private _characteristics: {[uuid: string]: any} = {};
private _queue: Promise<any> = Promise.resolve();
private _mailbox: Buffer[] = [];
private _connected: boolean = false;
private _connecting: boolean = false;
constructor (device: any) {
super();
this._webBLEServer = device;
this._uuid = device.device.id;
this._name = device.device.name;
device.device.addEventListener("gattserverdisconnected", () => {
this._connected = false;
this._connected = false;
this.emit("disconnect");
});
setTimeout(() => {
this.emit("discoverComplete");
}, 2000);
}
public get uuid () {
return this._uuid;
}
public get name () {
return this._name;
}
public get connecting () {
return this._connecting;
}
public get connected () {
return this._connected;
}
public connect () {
return new Promise((resolve, reject) => {
this._connected = true;
return resolve();
});
}
public disconnect () {
return new Promise((resolve, reject) => {
this._webBLEServer.device.gatt.disconnect();
return resolve();
});
}
public discoverCharacteristicsForService (uuid: string) {
return new Promise(async (discoverResolve, discoverReject) => {
debug("Service/characteristic discovery started");
let service;
try {
service = await this._webBLEServer.getPrimaryService(uuid);
} catch (err) {
return discoverReject(err);
}
const characteristics = await service.getCharacteristics();
for (const characteristic of characteristics) {
this._characteristics[characteristic.uuid] = characteristic;
}
debug("Service/characteristic discovery finished");
return discoverResolve();
});
}
public subscribeToCharacteristic (uuid: string, callback: (data: Buffer) => void) {
if (this._listeners[uuid]) {
this._characteristics[uuid].removeEventListener("characteristicvaluechanged", this._listeners[uuid]);
}
// @ts-ignore
this._listeners[uuid] = (event) => {
const buf = Buffer.alloc(event.target.value.buffer.byteLength);
const view = new Uint8Array(event.target.value.buffer);
for (let i = 0; i < buf.length; i++) {
buf[i] = view[i];
}
return callback(buf);
};
this._characteristics[uuid].addEventListener("characteristicvaluechanged", this._listeners[uuid]);
for (const data of this._mailbox) {
callback(data);
}
this._mailbox = [];
this._characteristics[uuid].startNotifications();
}
public addToCharacteristicMailbox (uuid: string, data: Buffer) {
this._mailbox.push(data);
}
public readFromCharacteristic (uuid: string, callback: (err: string | null, data: Buffer | null) => void) {
// @ts-ignore
this._characteristics[uuid].readValue().then((data) => {
const buf = Buffer.alloc(data.buffer.byteLength);
const view = new Uint8Array(data.buffer);
for (let i = 0; i < buf.length; i++) {
buf[i] = view[i];
}
callback(null, buf);
});
}
public writeToCharacteristic (uuid: string, data: Buffer, callback?: () => void) {
this._queue = this._queue.then(() => this._characteristics[uuid].writeValue(data)).then(() => {
if (callback) {
callback();
}
});
}
private _sanitizeUUID (uuid: string) {
return uuid.replace(/-/g, "");
}
}

View File

@ -1,12 +1,12 @@
import { Peripheral } from "noble";
import { BLEDevice } from "./bledevice";
import { Hub } from "./hub";
import { Port } from "./port";
import * as Consts from "./consts";
import Debug = require("debug");
import { IBLEDevice } from "./interfaces";
import { isBrowserContext } from "./utils";
const debug = Debug("wedo2smarthub");
@ -38,7 +38,7 @@ export class WeDo2SmartHub extends Hub {
private _lastTiltY: number = 0;
constructor (device: BLEDevice, autoSubscribe: boolean = true) {
constructor (device: IBLEDevice, autoSubscribe: boolean = true) {
super(device, autoSubscribe);
this.type = Consts.HubType.WEDO2_SMART_HUB;
this._ports = {