Logo

dev-resources.site

for different kinds of informations.

Using Web Bluetooth in an Electron App in 2022

Published at
6/12/2022
Categories
javascript
electron
bluetooth
webdev
Author
maneetgoyal
Author
11 person written this
maneetgoyal
open
Using Web Bluetooth in an Electron App in 2022

The Web Bluetooth API is quite a thoughtful browser feature that allows you to interact with your BLE peripherals. If you have such a device handy at the moment, consider testing its capabilities via this link. Say, you could conveniently find out the device information "characteristics" of your peripheral which include details like manufacturer's name, firmware, hardware, and software details, model number, etc. via Bluetooth. I wouldn't dive deeper into the capabilities of the API and shall be assuming that you know how it works.

One thing to note is that this API is currently experimental and isn't too widely supported. Fortunately, Chromium and hence, Chrome and Edge support it to a decent extent which is good enough for a lot of common use cases.

Its availability in Chromium indicates that Electron Apps can utilize it as well. However, the developer experience in doing so isn't too ideal. At the time of this writing, when we "request" a connection to a BLE peripheral, the Electron app doesn't show you any popup window to allow you to select the device you want to connect with. Instead, it silently connects with the first available device which doesn't sound so great. This article is dedicated to getting past this issue.


Chrome and Edge don't have this issue. You get a popup containing a list of devices to choose from.


Okay, so let's quickly reiterate the problem: we don't have access to any popup window or UI to select the preferred BLE device from an Electron App.

Now, what could be the solution? Any frontend developers caught any hint? πŸ‘©β€πŸ’»πŸ€”

Well, if there is no popup, then let's simply create a popup. πŸ˜…


Yes, the solution is that straightforward only if we know what Inter-Process Communication in Electron means. The Electron team has already published a great primer on it. IMO, it should be enough to learn all what we need regarding IPC.


Electron App developers would know that it runs on 2 processes: main and renderer. The main process handles the NodeJS side of things and is responsible for spawning the renderer process which in turn is responsible for rendering the web page.

Now what happens is that once we fire a Bluetooth connection request (requestDevice) in the renderer process, it interestingly triggers a "select-bluetooth-device" event in the main process. The payload of this event contains an array of all the available BLE devices. Upon receiving that list, we need to send it to the renderer process to create the required popup UI. This is where IPC is used: to help the main and the renderer processes communicate with each other.

Now, let's zoom in and look at the code:

  • Renderer: I need to connected to a BLE so I have triggered requestDevice.
const device = await navigator.bluetooth.requestDevice({...});
Enter fullscreen mode Exit fullscreen mode
  • Main: Since I was listening to "select-bluetooth-device", I have received the device list. Sending it to you via the xyz channel.
  win.webContents.on("select-bluetooth-device", (event, devices, callback) => {
    event.preventDefault();
    win.webContents.send("xyz", devices);
    console.log("Bluetooth device list dispatched.");
  });
Enter fullscreen mode Exit fullscreen mode
  • Renderer: Since I was already listening to the xyz channel, I have received the device list. I'll use it to create my popup.
// preload.ts
handleBluetoothDevices: (callback: (evt: IpcRendererEvent, value: ElectronBluetoothDevice[]) => void) => {
    // Fire the callback when we receive something on the "xyz" channel
    ipcRenderer.on("xyz", callback);
},
Enter fullscreen mode Exit fullscreen mode
// renderer.ts
window.electronAPI?.handleBluetoothDevices((_evt: IpcRendererEvent, value: ElectronBluetoothDevice[]) => { 
  // Use the devices array to create the popup
 });
Enter fullscreen mode Exit fullscreen mode
  • Renderer: I created my popup and the user has selected a device. I am sending the device ID to you (via the abc channel) because you have the "means" to connect to a BLE.
// renderer.ts
window.electronAPI?.selectBluetoothDevice(deviceID);
Enter fullscreen mode Exit fullscreen mode
// preload.ts
selectBluetoothDevice: (value: string) => {
    // Send the device ID to "main"
    ipcRenderer.send("abc", value);
},
Enter fullscreen mode Exit fullscreen mode
  • Main: I was listening to the abc channel and have received the device ID. Connecting to the device now.
  ipcMain.on("abc", (_evt: IpcMainEvent, value: string) => {
    ...
    console.log(`Bluetooth device '(${value})' selected.`);
  });
Enter fullscreen mode Exit fullscreen mode

Now, how does main connects to a BLE?

Recall the following:

win.webContents.on("select-bluetooth-device", (event, devices, callback) => {
Enter fullscreen mode Exit fullscreen mode

Here, apart from getting the device list, we also get a "one-time" callback. When this callback is fired with "", the BLE connection terminates and when it is fired with a device ID, a connection to the corresponding BLE peripheral gets established. Finally, you can start interacting with your device. πŸš€


Parting Notes:

  • Since Web Bluetooth API is supported in Chromium, we may be naively thinking of it as a straightforward process. The intent behind this article was to uncover some intricate details which a first time implementer may not know.

  • This SO entry ❀️ can be quite helpful in explaining the workflow in more depth. Recommend anyone in the process of utilizing the Web Bluetooth API in an Electron App to go through it.

  • macOS users remember to allow Chromium and your IDE (say, VS Code) access to Bluetooth via System Preferences if you don't want to waste a few hours scratching your head. Speaking from experience.

bluetooth Article's
30 articles in total
Favicon
Building a BLE Real-Time macOS Menu Bar App
Favicon
"Why is it, when something happens, it is always you TWO?"- troubleshooting Bluetooth and Wi-Fi devices on Debian 12
Favicon
πŸŽ‰ The Fun Beginner’s Guide to Bluetooth on Void Linux πŸŽ‰
Favicon
Automated Session Control with Bluetooth: An Insight into ble-lock-session
Favicon
Capturing the perfect (radio) wave
Favicon
How the Web Bluetooth API Enhances Passkeys
Favicon
High-Power Bluetooth LE Modules and Their Applications
Favicon
Broadcast Audio URI
Favicon
What's the Difference of BLE Connection Roles: Central vs. Peripheral?
Favicon
Embedded Rust Bluetooth on ESP: BLE Scanner
Favicon
RF-star Introduces CC2642R-Q1 Automotive Grade BLE Module for PEPS, PaaK, and BMS
Favicon
How To Use The Web Bluetooth API
Favicon
Unraveling the Wonders of Bluetooth: Connecting the World Wirelessly
Favicon
Bluetooth Bring-Up in AOSP
Favicon
How to disable the Lock key on a non-Mac Bluetooth Keyboard
Favicon
Passkeys Bluetooth: Cross-Platform Authentication
Favicon
a2dp-sink profile Protocol not available
Favicon
Handling Bluetooth Programmatically on Windows
Favicon
Developing a Bluetooth Low energy-based application
Favicon
Interacting with Shimmer3 using Node SerialPort
Favicon
TOP 5 ALL-IN-ONE BEST PRINTERS & SCANNERS FOR 2023
Favicon
From PulseAudio to PipeWire
Favicon
Struggling to fix: Bluetooth connection failed: protocol not available?
Favicon
Bluetooth LE cihazlarla çalışma
Favicon
Demystifying machine learning via Bluetooth with Arduino
Favicon
Interacting with Polar Verity Sense using Web Bluetooth
Favicon
Hacking Nespresso Expert Machine To Brew Coffee Using Custom Applications Via Bluetooth
Favicon
A Rundown of IoT Communication Protocols β€” and Expert Tips for Choosing One for Your Project
Favicon
How to choose in your smart home,is Bluetooth, ZigBee, or WiFi
Favicon
Using Web Bluetooth in an Electron App in 2022

Featured ones: