From adb5af874159a11869816b3059670feb60630509 Mon Sep 17 00:00:00 2001 From: Peter Wimmer Date: Wed, 2 Dec 2020 23:28:00 +0100 Subject: [PATCH] Re-connection to already known hubs --- examples/web_bluetooth.css | 9 ---- examples/web_bluetooth.html | 28 +++++++++-- src/poweredup-browser.ts | 95 +++++++++++++++++++++++++++++++++++-- 3 files changed, 114 insertions(+), 18 deletions(-) diff --git a/examples/web_bluetooth.css b/examples/web_bluetooth.css index 72440983..634693c4 100644 --- a/examples/web_bluetooth.css +++ b/examples/web_bluetooth.css @@ -7,19 +7,10 @@ div { margin-bottom: 10px; } -div#current_color { - position: absolute; - top: 61px; - left: 120px; -} - div#color { border: 1px solid #666666; width: 20px; height: 20px; - position: absolute; - top: -4px; - left: 92px; } table td { diff --git a/examples/web_bluetooth.html b/examples/web_bluetooth.html index ce68b232..329c3ad7 100644 --- a/examples/web_bluetooth.html +++ b/examples/web_bluetooth.html @@ -57,8 +57,8 @@ const hubs = poweredUP.getHubs(); // Get an array of all connected hubs document.getElementById("color").style.backgroundColor = PoweredUP.Consts.ColorNames[color]; hubs.forEach(async (hub) => { - const led = await hub.waitForDeviceByType(PoweredUP.Consts.DeviceType.HUB_LED); - led.setColor(color); // Set the color + const led = await hub.waitForDeviceByType(PoweredUP.Consts.DeviceType.HUB_LED); + led.setColor(color); // Set the color }) color++; if (color > 10) { @@ -82,7 +82,23 @@ const scan = function () { if (PoweredUP.isWebBluetooth) { - poweredUP.scan(); // Start scanning for hubs + poweredUP.scan(); // Start scanning for known hubs + } else { + alert("Your browser does not support the Web Bluetooth specification."); + } +} + +const stop = function () { + if (PoweredUP.isWebBluetooth) { + poweredUP.stop(); // Stop scanning for known hubs + } else { + alert("Your browser does not support the Web Bluetooth specification."); + } +} + +const requestDevice = function () { + if (PoweredUP.isWebBluetooth) { + poweredUP.requestDevice(); // Start scanning for new hubs } else { alert("Your browser does not support the Web Bluetooth specification."); } @@ -99,9 +115,11 @@

Web Bluetooth node-poweredup Example

-Add new Hub +Scan for known hubs +Stop scan +Add new hub
-
+
Current Color:
 
diff --git a/src/poweredup-browser.ts b/src/poweredup-browser.ts index 779f7acc..24e42afc 100644 --- a/src/poweredup-browser.ts +++ b/src/poweredup-browser.ts @@ -25,6 +25,8 @@ export class PoweredUP extends EventEmitter { private _connectedHubs: {[uuid: string]: BaseHub} = {}; + private _scan: boolean = false; + private _pendingDevices: BluetoothDevice[] = []; constructor () { @@ -35,9 +37,9 @@ export class PoweredUP extends EventEmitter { /** * Begin scanning for Powered UP Hub devices. - * @method PoweredUP#scan + * @method PoweredUP#requestDevice */ - public async scan () { + public async requestDevice () { try { @@ -61,6 +63,10 @@ export class PoweredUP extends EventEmitter { ] }); + if (this._scan) { + this._watchAdvertisements(device); + } + // @ts-ignore const server = await device.gatt.connect(); this._discoveryEventHandler.call(this, server); @@ -73,6 +79,48 @@ export class PoweredUP extends EventEmitter { } + /** + * Begin scanning for Powered UP Hub devices that were connected before. + * @method PoweredUP#scan + */ + public async scan () { + try { + if (this._scan) { + return true; + } + + this._scan = true; + const devices = await navigator.bluetooth.getDevices(); + + debug("Start watching advertisements"); + + for (const device of devices) { + this._watchAdvertisements(device); + } + + return true; + + } catch (err) { + debug(err); + return false; + } + } + + + /** + * Stop scanning for Powered UP Hub devices. + * @method PoweredUP#stop + */ + public async stop () { + if (!this.scan) { + return true; + } + + debug("Stop watching advertisements"); + this._scan = false; + return true; + } + /** * Retrieve a list of Powered UP Hubs. * @method PoweredUP#getHubs @@ -127,6 +175,45 @@ export class PoweredUP extends EventEmitter { } + private _watchAdvertisements (device: BluetoothDevice) { + if (device.watchingAdvertisements) { + return; + } + + device.addEventListener('advertisementreceived', async (event) => { + // Chrome 87 does not support unwatchAdvertisements yet. + if (!this._scan) { + return; + } + + // If the connection to the hub was lost, it is not possible + // to re-connect as long as 'connected' is still true. + if (device.gatt === undefined || device.gatt.connected || this._pendingDevices.includes(device)) { + debug('Ignored advertisement from ' + device.id); + return; + } + + // Ignore further reconnects for one second. + this._pendingDevices.push(device); + + try { + const server = await device.gatt.connect(); + debug(device.id + ' connected'); + this._discoveryEventHandler.call(this, server); + } catch (err) { + debug(err); + } finally { + setTimeout(() => this._pendingDevices.splice(this._pendingDevices.indexOf(device), 1), 1000); + } + }); + + device.addEventListener('gattserverdisconnected', async (event) => debug(device.id + ' disconnected')); + device.watchAdvertisements(); + + debug('Watching advertisements of ' + device.id); + } + + private _determineLPF2HubType (device: IBLEAbstraction): Promise { return new Promise((resolve, reject) => { let buf: Buffer = Buffer.alloc(0); @@ -177,14 +264,14 @@ export class PoweredUP extends EventEmitter { try { await device.discoverCharacteristicsForService(Consts.BLEService.WEDO2_SMART_HUB); hubType = Consts.HubType.WEDO2_SMART_HUB; - // tslint:disable-next-line + // tslint:disable-next-line } catch (error) {} try { if (hubType !== Consts.HubType.WEDO2_SMART_HUB) { await device.discoverCharacteristicsForService(Consts.BLEService.LPF2_HUB); isLPF2Hub = true; } - // tslint:disable-next-line + // tslint:disable-next-line } catch (error) {} if (isLPF2Hub) {