06 February 2020 / Last updated: 10 Apr 2020

Control your devices from a web browser using Bluetooth

Execution time: 1hr - 2hr
Difficulty: Medium
Cost: Low
Here’s how to use the Web Bluetooth API and balena to control Bluetooth Low Energy (BLE) devices remotely from a browser. This guide shows you how to build a simple LED setup that you can switch on and off from a web browser. We’ll also dive into how this works and how it can drive other awesome ideas.
Build a simple LED setup that you can switch on and off from a web browser with balena.
In this article, we will demonstrate how to use bleno, a Node.js library, to implement Bluetooth Low Energy (BLE) peripherals on a balenaOS-powered device and use a web app to communicate with it from a browser.
Note: This piece is an optimized version of a previous exploration of balenaBLE published in October 2019. We've improved it for usability and granular steps that our users enjoy and appreciate.


Here's a high-level look at how balenaBLE works and how your device interacts via bluetooth.
For the purpose of our demo, we are going to use Bluetooth to control an LED connected to a Raspberry Pi (our peripheral device) from the balenaBLE web app (on our central device, e.g. your laptop). A physical push button is also attached to the Raspberry Pi and allows toggling the LED on and off. You can see this data collection and notification within the Web Bluetooth application when the physical button is pressed.
The Raspberry Pi will be configured as a peripheral device called balenaBLE with the following services and characteristics:
Here's a high level look at configuring balenaBLE.

Hardware required

Here's some hardware that you'll need for this project.
  1. A balenaOS supported device with BLE e.g Raspberry Pi 3A+/3B/3B+/Zero W/4B
  2. An SD card
  3. Power supply
  4. LED
  5. Resistor (above 50 Ohms, advisable to include for long test sessions)
  6. A computer, laptop, or Android smartphone with BLE running the latest Chrome web browser
  7. A push button
  8. Breadboard to add ease to this test build (optional)

Software required

  1. balenaEtcher to write balenaOS to SD card
  2. A free balenaCloud account to set up and manage the Pi
  3. The balena-web-ble project from Github
  4. Download and install balena CLI tools, which allows you to install the project code on your device


Set up the balena device

With all of your hardware and software prepared, let’s start setting up the device.

Sign up for a free balenaCloud account

If you don’t have one already, sign up for a free balenaCloud account. You can use single sign-on (SSO) via Google and GitHub to get going quickly.

Create a balenaCloud application

Add an application by clicking the ‘Create Application’ button. Select the correct device type for the device you’re using, and then choose ‘Starter’ as the application type. Select ‘Create New Application’ and you’ll now have a new balenaCloud application appear on the dashboard.
Note: The ‘Starter’ application provides you with all of the features of the microservices application, up to ten free devices.
You’ll see the dashboard for your newly created application, where you can move on to the next step and add your device. You’ll want to choose a name you’ll stick with throughout the project as you’ll need this name to identify the device to push code to later.

Add a device and download the balenaOS disk image from the dashboard

Add a device within your new application by clicking the 'add device' button. Make sure to specify your device type, which is important that it matches the device you’re using so you download the proper OS. If you plan on connecting to a wireless network, you can set your WiFI SSID and passphrase during this step, too.
Note: The following GIF walks through these steps and uses a Raspberry Pi 3 as an example. Be sure to choose the actual device you’re using for your project!
Add Wi-Fi access to your balena device with the proper credentials.
This process creates a customized image configured for your application and device type and includes your network settings if you specified them.
For new users, we recommend using a development image, as it permits a number of testing and troubleshooting features to help. Get more details on the differences between development and production images in our documentation.
For more experienced users, go ahead and deploy the production image straight away.

Flash your SD card with the balenaOS disk image and boot the device

Once the OS download completes, you can use balenaEtcher, a free open-source flashing tool, to flash the OS onto the SD card. Once the flashing is complete, insert the SD card to the device and connect its power supply.
A new balena device appears!
After a few seconds, it should connect to the internet and show up on the balenaCloud dashboard.

Troubleshooting your device

Devices typically show up on the dashboard once booted and after a few minutes. If your device still hasn't shown up on your dashboard after a few minutes, something might be wrong. Use this extensive troubleshooting guide in the documentation or come on over to the forums where we’ll be able to help out.

Deploy the project code

Once the device is connected and showing in the dashboard, it is time to deploy the application that will create a BLE peripheral device.

Download the project from GitHub

Get the balenaBLE project from this GitHub repo, either by downloading the .zip or using git clone <url>.
Get the balena project from GitHub

Push the project code to your device with balena-cli

Using the above-mentioned balenaCLI, run the command balena push <appName> where <appName> is the name of the application you created within the balenaCloud dashboard earlier. For this example project, we will use the balena push web-ble command.
If all went well you’ll see the balena unicorn mascot and the code you’ve just pushed will automatically be distributed to the devices in your application.
You should also see the main service running on the dashboard:
Successfully pushing new service to balena device.

Set up the device

Connect the LED and pushbutton as follows:
Here's a Fritzing diagram of your physical setup for balenaBLE.
By default, the project uses GPIO 17 for the LED and GPIO 4 for the pushbutton. If you want to use a different pin, you can configure the LED_PIN and BTN_PIN environment variables in the dashboard. For example, if you want to use GPIO 27 for the LED instead:
Here's where you can configure environment variables in balenaCloud.
Note: After configuring the environment variable, the main service will be restarted.

Load the Web Bluetooth App

The web app to control the Bluetooth peripheral device can be accessed here. We’ve hosted a copy of the application for you to test with, but you can download the code and host it yourself too. Load the web app on your laptop or android device in the Chrome browser.
Here's a successful installation of balenaBLE in a browser.
Turn on Bluetooth on your smartphone or laptop. Click on the “Connect” button which will trigger device scanning. After connecting, you can see the device’s CPU information and will be able to toggle the LED on or off.
Here's a GIF of balenaBLE at work, turning the LED on and off, and sending device data to balenaCloud.
You can also see the device logs in the dashboard as the light is toggled.
Here's the collection of device data via BLE.
You can also use the pushbutton to control the LED. The Web Bluetooth application will be notified and reflect the actual state of the LED on the UI.
Here's the push button function at work.
The Web Bluetooth API is available in secure contexts only in the web browser. For development purposes, the Web Bluetooth is available from the localhost. The web app here has been deployed on Github Pages which provides HTTPS access by default.

How it works

Bluetooth Low Energy (BLE), formerly known as Bluetooth Smart, is a subset of the classic Bluetooth specification designed to provide communication with low power consumption. It is helpful to understand some specific concepts and terminology when developing BLE applications.

Web BLE lets you imagine the possibilities

Developing bluetooth controlled projects traditionally means writing platform specific native applications and deploying it to an app store for distribution (which approval processes can take a while). With Web BLE, you can simply provide a URL to load your web app and it just works from your browser. You could create web-based apps that read data from heart-rate monitors, control a mood lamp, check your device’s battery level, or, maybe even fly a drone (!), all directly from your browser.

Generic Access Profile (GAP)

The GAP defines how BLE devices communicate with other BLE-enabled devices. In the context of a BLE network, a device can be:
  1. A peripheral device: these are typically low power and resource-constrained devices that advertise themselves and wait for a central device to connect to them. The Raspberry Pi acts as a peripheral device in this project.
  2. A central device: these are typically smartphones or powerful devices that initiate a connection with peripheral BLE devices. For our demo, a laptop or an android smartphone with the latest Chrome web browser will act as the central device. The Web Bluetooth application loaded through the browser initiates a connection with the Raspberry Pi.
A peripheral device can connect to only a single central device at a time. Once a connection has been established, peripheral devices stop advertising themselves. A central device, on the other hand, can connect to several peripheral devices and can relay messages among peripheral devices.

Generic Attribute Profile (GATT)

Once BLE devices have established a connection, the Generic Attribute Profile (GATT) dictates how data is exchanged over the connection. Devices can adopt different roles:
  1. GATT Server: These are typically peripheral devices that have attributes that the client can make requests to.
  2. GATT Client: Send requests to the GATT server. They can read or write to attributes on the server.


A GATT server offers one or more services. Some services can be grouped together into profiles. There are several predefined profiles and services by the Bluetooth SIG. For example, the Blood Pressure Profile(https://www.bluetooth.org/docman/handlers/downloaddoc.ashx?doc_id=457086) contains the Blood Pressure Service and the Device Information Service.
Each service is identified by a Universally Unique Identifier (UUID). For officially adopted BLE Services(https://www.bluetooth.com/specifications/gatt/services/), the UUID is 16-bit, while custom services are 128-bit. A service like Online UUID Generator(https://www.uuidgenerator.net/) can be used to generate custom UUIDs.


Services can contain one or more characteristics. They are also identified by either 16-bit or 128-bit UUIDs. A Characteristic has a value, which is an array of bytes and a collection of Descriptors.
Depending on the properties of the Characteristic, a GATT Client can read or write its value, or register to be notified when the value changes. A GATT Descriptor provides further information about a Characteristic’s value.

Going Further

This project uses the bleno library to create a BLE peripheral device. Feel free to explore the API and experiment with other BLE properties and characteristics to make your own custom BLE peripheral device.
You can then customize the web app accordingly to suit your use case. The relevant files are index.html and ble-client.js in the project. For instance, imagine replacing the LED with a relay to manage switching devices on and off. Like we said previously, the possibilities are endless. If you do make something cool, please do let us know.
If you decide to test out this project or build your own, we’d love to hear how it went. Similarly, if you get stuck or have any questions, let us know in our forums, on Twitter @balena_io, on Instagram @balena_io or on Facebook.
by Rahul ThakoorHardware Hacker in Residence