Skip to content

Commit 8c1fc69

Browse files
authored
Merge pull request #300 from makermelissa/ble-improvements
Improvements to Bluetooth connectivity
2 parents 71b617a + 39373d6 commit 8c1fc69

File tree

5 files changed

+618
-46
lines changed

5 files changed

+618
-46
lines changed

index.html

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,9 @@ <h1>Web Bluetooth not available!</h1>
212212
flag. However be careful as it would be risky to browse the web with this flag turned
213213
on as it enables many other experimental web platform features. Starting with Chromium
214214
version 100, enable the <a href="about://flags/#enable-web-bluetooth">about://flags/#enable-web-bluetooth</a>
215-
safer flag instead.</p>
215+
safer flag instead. You can also enable Web Bluetooth Binding by enabling the
216+
<a href="about://flags/#enable-web-bluetooth-new-permissions-backend">about://flags/#enable-web-bluetooth-new-permissions-backend</a>
217+
flag instead of the experimental features if it is available.</p>
216218
</div>
217219
</section>
218220
<section class="step">

js/workflows/ble.js

Lines changed: 58 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@
33
*/
44

55
import {FileTransferClient} from '../common/ble-file-transfer.js';
6-
import {CONNTYPE, CONNSTATE} from '../constants.js';
6+
import {CONNTYPE} from '../constants.js';
77
import {Workflow} from './workflow.js';
88
import {GenericModal, DeviceInfoModal} from '../common/dialogs.js';
9-
import {sleep, getUrlParam} from '../common/utilities.js';
9+
import {sleep} from '../common/utilities.js';
1010

1111
const bleNusServiceUUID = 'adaf0001-4369-7263-7569-74507974686e';
1212
const bleNusCharRXUUID = 'adaf0002-4369-7263-7569-74507974686e';
@@ -63,23 +63,23 @@ class BLEWorkflow extends Workflow {
6363
bond: btnBond
6464
};
6565

66-
btnRequestBluetoothDevice.addEventListener('click', async (event) => {
67-
await this.onRequestBluetoothDeviceButtonClick(event);
68-
});
69-
btnBond.addEventListener('click', async (event) => {
70-
await this.onBond(event);
71-
});
72-
btnReconnect.addEventListener('click', async (event) => {
73-
await this.reconnectButtonHandler(event);
74-
});
66+
btnRequestBluetoothDevice.addEventListener('click', this.onRequestBluetoothDeviceButtonClick.bind(this));
67+
btnBond.addEventListener('click', this.onBond.bind(this));
68+
btnReconnect.addEventListener('click', this.reconnectButtonHandler.bind(this));
7569

70+
// Check if Web Bluetooth is available
7671
if (!(await this.available() instanceof Error)) {
7772
let stepOne;
7873
if (stepOne = modal.querySelector('.step:first-of-type')) {
7974
stepOne.classList.add("hidden");
8075
}
81-
const devices = await navigator.bluetooth.getDevices();
82-
this.connectionStep(devices.length > 0 ? 2 : 1);
76+
try {
77+
const devices = await navigator.bluetooth.getDevices();
78+
console.log(devices);
79+
this.connectionStep(devices.length > 0 ? 2 : 1);
80+
} catch (e) {
81+
console.log("New Permissions backend for Web Bluetooth not enabled. Go to chrome://flags/#enable-web-bluetooth-new-permissions-backend to enable.", e);
82+
}
8383
} else {
8484
modal.querySelectorAll('.step:not(:first-of-type)').forEach((stepItem) => {
8585
stepItem.classList.add("hidden");
@@ -92,7 +92,9 @@ class BLEWorkflow extends Workflow {
9292

9393
async onSerialReceive(e) {;
9494
// TODO: Make use of super.onSerialReceive() so that title can be extracted
95-
this.writeToTerminal(this.decoder.decode(e.target.value.buffer, {stream: true}));
95+
let output = this.decoder.decode(e.target.value.buffer, {stream: true});
96+
console.log(output);
97+
this.writeToTerminal(output);
9698
}
9799

98100
async connectToSerial() {
@@ -102,6 +104,8 @@ class BLEWorkflow extends Workflow {
102104
this.txCharacteristic = await this.serialService.getCharacteristic(bleNusCharTXUUID);
103105
this.rxCharacteristic = await this.serialService.getCharacteristic(bleNusCharRXUUID);
104106

107+
// Remove any existing event listeners to prevent multiple reads
108+
this.txCharacteristic.removeEventListener('characteristicvaluechanged', this.onSerialReceive.bind(this));
105109
this.txCharacteristic.addEventListener('characteristicvaluechanged', this.onSerialReceive.bind(this));
106110
await this.txCharacteristic.startNotifications();
107111
return true;
@@ -118,92 +122,102 @@ class BLEWorkflow extends Workflow {
118122
console.log('Getting existing permitted Bluetooth devices...');
119123
const devices = await navigator.bluetooth.getDevices();
120124

121-
console.log('> Got ' + devices.length + ' Bluetooth devices.');
125+
console.log('> Found ' + devices.length + ' Bluetooth device(s).');
122126
// These devices may not be powered on or in range, so scan for
123127
// advertisement packets from them before connecting.
124128
for (const device of devices) {
125129
await this.connectToBluetoothDevice(device);
126130
}
127131
}
128132
catch (error) {
129-
console.log('Argh! ' + error);
133+
console.error(error);
134+
await this._showMessage(error);
130135
}
131136
}
132137
}
133138

139+
// Bring up a dialog to request a device
140+
async requestDevice() {
141+
return navigator.bluetooth.requestDevice({
142+
filters: [{services: [0xfebb]},], // <- Prefer filters to save energy & show relevant devices.
143+
optionalServices: [0xfebb, bleNusServiceUUID]
144+
});
145+
}
146+
134147
async connectToBluetoothDevice(device) {
135148
const abortController = new AbortController();
136149

137-
device.addEventListener('advertisementreceived', async (event) => {
150+
async function onAdvertisementReceived(event) {
138151
console.log('> Received advertisement from "' + device.name + '"...');
139152
// Stop watching advertisements to conserve battery life.
140153
abortController.abort();
141154
console.log('Connecting to GATT Server from "' + device.name + '"...');
142155
try {
143-
await this.showBusy(device.gatt.connect());
156+
await device.gatt.connect();
157+
} catch (error) {
158+
await this._showMessage("Failed to connect to device. Try forgetting device from OS bluetooth devices and try again.");
159+
}
160+
if (device.gatt.connected) {
144161
console.log('> Bluetooth device "' + device.name + ' connected.');
145162
await this.switchToDevice(device);
163+
} else {
164+
console.log('Unable to connect to bluetooth device "' + device.name + '.');
146165
}
147-
catch (error) {
148-
console.log('Argh! ' + error);
149-
}
150-
}, {once: true});
166+
}
151167

152-
//await this.showBusy(device.gatt.connect());
153-
await navigator.bluetooth.requestDevice({
154-
filters: [{services: [0xfebb]},], // <- Prefer filters to save energy & show relevant devices.
155-
optionalServices: [0xfebb, bleNusServiceUUID]
156-
});
168+
device.removeEventListener('advertisementreceived', onAdvertisementReceived.bind(this));
169+
device.addEventListener('advertisementreceived', onAdvertisementReceived.bind(this));
157170

158171
this.debugLog("connecting to " + device.name);
159172
try {
160173
console.log('Watching advertisements from "' + device.name + '"...');
161174
await device.watchAdvertisements({signal: abortController.signal});
162175
}
163176
catch (error) {
164-
console.log('Argh! ' + error);
177+
console.error(error);
178+
await this._showMessage(error);
165179
}
166180
}
167181

168182
// Request Bluetooth Device
169183
async onRequestBluetoothDeviceButtonClick(e) {
170-
try {
184+
//try {
171185
console.log('Requesting any Bluetooth device...');
172186
this.debugLog("Requesting device. Cancel if empty and try existing");
173-
let device = await navigator.bluetooth.requestDevice({
174-
filters: [{services: [0xfebb]},], // <- Prefer filters to save energy & show relevant devices.
175-
optionalServices: [0xfebb, bleNusServiceUUID]
176-
});
187+
let device = await this.requestDevice();
177188

178-
await this.showBusy(device.gatt.connect());
179189
console.log('> Requested ' + device.name);
190+
await device.gatt.connect();
180191

181192
await this.switchToDevice(device);
182-
}
193+
/*}
183194
catch (error) {
184-
console.log('Argh: ' + error);
195+
console.error(error);
196+
await this._showMessage(error);
185197
this.debugLog('No device selected. Try to connect to existing.');
186-
}
198+
}*/
187199
}
188200

189201
async switchToDevice(device) {
190202
console.log(device);
191203
this.bleDevice = device;
204+
this.bleDevice.removeEventListener("gattserverdisconnected", this.onDisconnected.bind(this));
192205
this.bleDevice.addEventListener("gattserverdisconnected", this.onDisconnected.bind(this));
193206
this.bleServer = this.bleDevice.gatt;
194207
console.log("connected", this.bleServer);
195208
let services;
196209

197-
try {
210+
console.log(device.gatt.connected);
211+
//try {
198212
services = await this.bleServer.getPrimaryServices();
199-
} catch (e) {
213+
/*} catch (e) {
200214
console.log(e, e.stack);
201-
}
215+
}*/
202216
console.log(services);
203217

204218
console.log('Initializing File Transfer Client...');
205219
this.initFileClient(new FileTransferClient(this.bleDevice, 65536));
206-
this.debugLog("connected");
220+
await this.fileHelper.bond();
207221
await this.connectToSerial();
208222

209223
// Enable/Disable UI buttons
@@ -256,15 +270,17 @@ class BLEWorkflow extends Workflow {
256270
if (result = await super.connect() instanceof Error) {
257271
return result;
258272
}
273+
// Is this a new connection?
259274
if (!this.bleDevice) {
260275
let devices = await navigator.bluetooth.getDevices();
261276
for (const device of devices) {
262277
await this.connectToBluetoothDevice(device);
263278
}
264279
}
265280

281+
// Do we have a connection now but still need to connect serial?
266282
if (this.bleDevice && !this.bleServer) {
267-
await await this.showBusy(this.bleDevice.gatt.connect());
283+
await this.showBusy(this.bleDevice.gatt.connect());
268284
this.switchToDevice(this.bleDevice);
269285
}
270286
}

0 commit comments

Comments
 (0)