Skip to content

Commit c5ca119

Browse files
committed
Improvements to BLE connectivity
1 parent e68ab12 commit c5ca119

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';
@@ -50,23 +50,23 @@ class BLEWorkflow extends Workflow {
5050
btnBond = modal.querySelector('#promptBond');
5151
btnReconnect = modal.querySelector('#bleReconnect');
5252

53-
btnRequestBluetoothDevice.addEventListener('click', async (event) => {
54-
await this.onRequestBluetoothDeviceButtonClick(event);
55-
});
56-
btnBond.addEventListener('click', async (event) => {
57-
await this.onBond(event);
58-
});
59-
btnReconnect.addEventListener('click', async (event) => {
60-
await this.reconnectButtonHandler(event);
61-
});
53+
btnRequestBluetoothDevice.addEventListener('click', this.onRequestBluetoothDeviceButtonClick.bind(this));
54+
//btnBond.addEventListener('click', this.onBond.bind(this));
55+
btnReconnect.addEventListener('click', this.reconnectButtonHandler.bind(this));
6256

57+
// Check if Web Bluetooth is available
6358
if (!(await this.available() instanceof Error)) {
6459
let stepOne;
6560
if (stepOne = modal.querySelector('.step:first-of-type')) {
6661
stepOne.classList.add("hidden");
6762
}
68-
const devices = await navigator.bluetooth.getDevices();
69-
this.connectionStep(devices.length > 0 ? 2 : 1);
63+
try {
64+
const devices = await navigator.bluetooth.getDevices();
65+
console.log(devices);
66+
this.connectionStep(devices.length > 0 ? 2 : 1);
67+
} catch (e) {
68+
console.log("New Permissions backend for Web Bluetooth not enabled. Go to chrome://flags/#enable-web-bluetooth-new-permissions-backend to enable.", e);
69+
}
7070
} else {
7171
modal.querySelectorAll('.step:not(:first-of-type)').forEach((stepItem) => {
7272
stepItem.classList.add("hidden");
@@ -79,7 +79,9 @@ class BLEWorkflow extends Workflow {
7979

8080
async onSerialReceive(e) {;
8181
// TODO: Make use of super.onSerialReceive() so that title can be extracted
82-
this.writeToTerminal(this.decoder.decode(e.target.value.buffer, {stream: true}));
82+
let output = this.decoder.decode(e.target.value.buffer, {stream: true});
83+
console.log(output);
84+
this.writeToTerminal(output);
8385
}
8486

8587
async connectToSerial() {
@@ -89,6 +91,8 @@ class BLEWorkflow extends Workflow {
8991
this.txCharacteristic = await this.serialService.getCharacteristic(bleNusCharTXUUID);
9092
this.rxCharacteristic = await this.serialService.getCharacteristic(bleNusCharRXUUID);
9193

94+
// Remove any existing event listeners to prevent multiple reads
95+
this.txCharacteristic.removeEventListener('characteristicvaluechanged', this.onSerialReceive.bind(this));
9296
this.txCharacteristic.addEventListener('characteristicvaluechanged', this.onSerialReceive.bind(this));
9397
await this.txCharacteristic.startNotifications();
9498
return true;
@@ -105,92 +109,102 @@ class BLEWorkflow extends Workflow {
105109
console.log('Getting existing permitted Bluetooth devices...');
106110
const devices = await navigator.bluetooth.getDevices();
107111

108-
console.log('> Got ' + devices.length + ' Bluetooth devices.');
112+
console.log('> Found ' + devices.length + ' Bluetooth device(s).');
109113
// These devices may not be powered on or in range, so scan for
110114
// advertisement packets from them before connecting.
111115
for (const device of devices) {
112116
await this.connectToBluetoothDevice(device);
113117
}
114118
}
115119
catch (error) {
116-
console.log('Argh! ' + error);
120+
console.error(error);
121+
await this._showMessage(error);
117122
}
118123
}
119124
}
120125

126+
// Bring up a dialog to request a device
127+
async requestDevice() {
128+
return navigator.bluetooth.requestDevice({
129+
filters: [{services: [0xfebb]},], // <- Prefer filters to save energy & show relevant devices.
130+
optionalServices: [0xfebb, bleNusServiceUUID]
131+
});
132+
}
133+
121134
async connectToBluetoothDevice(device) {
122135
const abortController = new AbortController();
123136

124-
device.addEventListener('advertisementreceived', async (event) => {
137+
async function onAdvertisementReceived(event) {
125138
console.log('> Received advertisement from "' + device.name + '"...');
126139
// Stop watching advertisements to conserve battery life.
127140
abortController.abort();
128141
console.log('Connecting to GATT Server from "' + device.name + '"...');
129142
try {
130-
await this.showBusy(device.gatt.connect());
143+
await device.gatt.connect();
144+
} catch (error) {
145+
await this._showMessage("Failed to connect to device. Try forgetting device from OS bluetooth devices and try again.");
146+
}
147+
if (device.gatt.connected) {
131148
console.log('> Bluetooth device "' + device.name + ' connected.');
132149
await this.switchToDevice(device);
150+
} else {
151+
console.log('Unable to connect to bluetooth device "' + device.name + '.');
133152
}
134-
catch (error) {
135-
console.log('Argh! ' + error);
136-
}
137-
}, {once: true});
153+
}
138154

139-
//await this.showBusy(device.gatt.connect());
140-
await navigator.bluetooth.requestDevice({
141-
filters: [{services: [0xfebb]},], // <- Prefer filters to save energy & show relevant devices.
142-
optionalServices: [0xfebb, bleNusServiceUUID]
143-
});
155+
device.removeEventListener('advertisementreceived', onAdvertisementReceived.bind(this));
156+
device.addEventListener('advertisementreceived', onAdvertisementReceived.bind(this));
144157

145158
this.debugLog("connecting to " + device.name);
146159
try {
147160
console.log('Watching advertisements from "' + device.name + '"...');
148161
await device.watchAdvertisements({signal: abortController.signal});
149162
}
150163
catch (error) {
151-
console.log('Argh! ' + error);
164+
console.error(error);
165+
await this._showMessage(error);
152166
}
153167
}
154168

155169
// Request Bluetooth Device
156170
async onRequestBluetoothDeviceButtonClick(e) {
157-
try {
171+
//try {
158172
console.log('Requesting any Bluetooth device...');
159173
this.debugLog("Requesting device. Cancel if empty and try existing");
160-
let device = await navigator.bluetooth.requestDevice({
161-
filters: [{services: [0xfebb]},], // <- Prefer filters to save energy & show relevant devices.
162-
optionalServices: [0xfebb, bleNusServiceUUID]
163-
});
174+
let device = await this.requestDevice();
164175

165-
await this.showBusy(device.gatt.connect());
166176
console.log('> Requested ' + device.name);
177+
await device.gatt.connect();
167178

168179
await this.switchToDevice(device);
169-
}
180+
/*}
170181
catch (error) {
171-
console.log('Argh: ' + error);
182+
console.error(error);
183+
await this._showMessage(error);
172184
this.debugLog('No device selected. Try to connect to existing.');
173-
}
185+
}*/
174186
}
175187

176188
async switchToDevice(device) {
177189
console.log(device);
178190
this.bleDevice = device;
191+
this.bleDevice.removeEventListener("gattserverdisconnected", this.onDisconnected.bind(this));
179192
this.bleDevice.addEventListener("gattserverdisconnected", this.onDisconnected.bind(this));
180193
this.bleServer = this.bleDevice.gatt;
181194
console.log("connected", this.bleServer);
182195
let services;
183196

184-
try {
197+
console.log(device.gatt.connected);
198+
//try {
185199
services = await this.bleServer.getPrimaryServices();
186-
} catch (e) {
200+
/*} catch (e) {
187201
console.log(e, e.stack);
188-
}
202+
}*/
189203
console.log(services);
190204

191205
console.log('Initializing File Transfer Client...');
192206
this.initFileClient(new FileTransferClient(this.bleDevice, 65536));
193-
this.debugLog("connected");
207+
await this.fileHelper.bond();
194208
await this.connectToSerial();
195209

196210
// Enable/Disable UI buttons
@@ -243,15 +257,17 @@ class BLEWorkflow extends Workflow {
243257
if (result = await super.connect() instanceof Error) {
244258
return result;
245259
}
260+
// Is this a new connection?
246261
if (!this.bleDevice) {
247262
let devices = await navigator.bluetooth.getDevices();
248263
for (const device of devices) {
249264
await this.connectToBluetoothDevice(device);
250265
}
251266
}
252267

268+
// Do we have a connection now but still need to connect serial?
253269
if (this.bleDevice && !this.bleServer) {
254-
await await this.showBusy(this.bleDevice.gatt.connect());
270+
await this.showBusy(this.bleDevice.gatt.connect());
255271
this.switchToDevice(this.bleDevice);
256272
}
257273
}

0 commit comments

Comments
 (0)