Start Building with Web Bluetooth and Progressive Web Apps

A Short Introduction

Web Bluetooth is a a new technology that connects the Web with the Internet of Things. Web Bluetooth is so new, it’s still being built and prototyped! But of course, that doesn’t mean we can’t play with it…

Essentially, Web Bluetooth lets you control any Bluetooth Low Energy device (smart home appliances, health accessories like heart rate or glucose monitors, temperature sensors, etc.) directly from your PC or smart phone, without having to install an app first.

Web Bluetooth will eventually enable developers to build one solution that will work on all platforms, including both mobile and desktop, which means lower development costs, more open source control interfaces for various physical products, and more innovation.

Evenings are best spent with fine wine, fine company, and Web Bluetooth

In this post I will explain the basics of Web Bluetooth by building a demo web app that controls the smart bulb that I reversed engineered in the previous post. In addition, I’ll explore how you can extend this app to become a Progressive Web App, which is an exciting new approach that we’ll go into later in the post.

I will assume for this tutorial you have basic familiarity with Bluetooth Low Energy terms such as Peripherals, Services and Characteristics — if not, check out the previous post to learn about them.

You might be thinking, “But Uri, we can already send commands to the bulb, and anyway doesn’t the bulb already come with an app?” Well, it does come with an app, but does that app include voice control?

(It doesn’t, and I’m going to show you how you can build one that does.)

If you are impatient, you can see the code here or try the online demo (see next section for supported browsers/platforms). If you’d like more information about Web Bluetooth, check out this Google Developers article.

Can I use Web Bluetooth?

As of November 2018, Web Bluetooth works on Chrome for Android 6+, Windows 10, Mac OS X, Linux and Chrome OS. However, things change rapidly, so it might be good to periodically check the implementation status page.

I’ll be using Chrome to build my web app in this demonstration. It should work out of the box in most platforms (Linux may require additional setup).

The Web Bluetooth API

The API is exposed under the navigator.bluetooth JavaScript namespace. Is it based on Promises, so make sure you are familiar with them first.

In order to use Web Bluetooth, your site must be served over a secure connection (HTTPS). A secure website is becoming a requirement for a growing number of new web APIs, and it is fairly easy to set up one. One way (which I use here) is using GitHub hosting, a.k.a gh-pages.

Building a Web Bluetooth App

This is the sequence of actions that will be common that all Web Bluetooth apps. Before seeing the code, let’s look at the sequence first:

  1. Scan for a relevant Device
  2. Connect to it
  3. Get the Service you are interested in
  4. Get the Characteristic you are interested in
  5. ReadWrite or Subscribe to the Characteristic

Now for a code example — Connect to the smart bulb, and then write to it:

// Step 1: Scan for a device with 0xffe5 service
navigator.bluetooth.requestDevice({
  filters: [{ services: [0xffe5] }]
})
  .then(function(device) {
    // Step 2: Connect to it
    return device.gatt.connect();
  })
  .then(function(server) {
    // Step 3: Get the Service
    return server.getPrimaryService(0xffe5);
  })
  .then(function(service) {
    // Step 4: get the Characteristic
    return service.getCharacteristic(0xffe9);
  })
  .then(function(characteristic) {
    // Step 5: Write to the characteristic
    var data = new Uint8Array([0xbb, 0x25, 0x05, 0x44]);
    return characteristic.writeValue(data);
  })
  .catch(function(error) {
     // And of course: error handling!
     console.error('Connection failed!', error);
  });

This code scans for a device with a Service number ffe5, then ask for this service, ask for characteristic number ffe9, and finally write four bytes: bb 25 05 44, which is the command for the bulb to slowly fade between all the rainbow colors and white, as I explained in the previous post.

The dialog asking the user which device he wishes to connect to

Now, how to run it: there are a number of ways to do this, but they’re all a little tricky. You can paste the code above into Chrome’s Console once you have enabled the Web Bluetooth flag, but this only works on supported operating systems (i.e. Mac with Chrome 53, Linux or Chrome OS).

If you have an Android 6 device, you can enable development mode, connect it to the PC with a USB cable, and then in your Chrome on the PC go to the following URL: “chrome://inspect”. This will open a Chrome Console that will be connected to the Android device — which is how I tend to do it on my Windows machine. Here is a page that explains this last method step-by-step.

You can check out the code for the demo app that controls the bulb in this example here. The code above lives in the connect() function.

Troubleshooting

If no devices show up, make sure that:

  1. Both Bluetooth and Location Services are turned on. On Android 6, both Bluetooth and Location access are required in order to scan for BLE devices.
  2. No other app is connected the target device. BLE devices stop advertising their services once some app is connected to them.
  3. If you still don’t see any device, try restarting chrome, turning Bluetooth off and then on again, or restarting your device.

You can find another example inside the Web Bluetooth standard specification document. The example shows how to connect to a heart rate monitor device, read the Service Location Characteristic (which tells you where the sensor is placed — which body part), and subscribe to notifications from the Heart Rate Characteristic, meaning you will get an event whenever the device performs a new measurement. If you want to see a working example, check out this demo on GitHub.

Interacting with the Internet of Things: Changing the Bulb’s Color

We’ve seen some code that connects to the bulb and sends it commands, so let’s now create a function that sets the color given red, green and blue values:

function setColor(red, green, blue) {
  var data = new Uint8Array([
    0x56, red, green, blue, 0x00, 0xf0, 0xaa
  ]);
  return ledCharacteristic.writeValue(data);
}

Note that the function assumes that we saved the reference to the characteristic object that we got in the previous step in a global variable called ledCharacteristic.

We can connect to the device, and now we have a function with which to change its color. As discussed int he last post, color component values are defined as RGB values between 0 and 255. For example, to set the color to purple, we would use:

setColor(255, 0, 255);

Now that we have our underlying function, we can add buttons for various color presets, or create a fully-featured color picker to let the user set any color he desires. Or we can also…

Add Voice Control!

Since we’ve got the basic app functionality in place, let’s make it more interesting by adding voice control. This will use the Web Speech API. I’ll take a shortcut and use a tiny JavaScript library called annyang which provides a simpler interface to the Speech API.

Using the annyang library is as simple as listing all the voice commands that you want to implement, and then calling the start() method:

annyang.addCommands({
  "red":   function() { setColor(255,0,0); },
  "green": function() { setColor(0,255,0); },
  "blue":  function() { setColor(0,0,255); }
});
annyang.start({ continuous: true });

As you can see, adding new commands is pretty straight forward. You can experiment with adding new colors, an “off” command, or even more interesting commands such as “random color”, “crossfade”, or “blink rapidly”.

The Chrome implementation of the Web Speech API uses the Google Cloud services for recognizing the speech, so there is a delay of about 1 second until you get the results.

Calling annyang.start() will request from the user a permission to access their Microphone, so it can listen to their voice. In the actual app, I’ll add a microphone button and call this method only after the user pressed this button. After all, having a web page ask you for permission to use your mic first thing when you load the page is pretty creepy, don’t you think?

Finally, you probably noticed that I passed a continuous:true parameter to the start() method. This makes sure the function continuously listens for user commands, and not just the single time.

Making it a Progressive Web App

So we can control the smart bulb from our browser, but what if we wanted to control it from our phone, and not only from the browser on our phone, but from an app on our phone? Enter the Progressive Web App.

In a nutshell, Progressive Web Apps (PWAs) are websites that look, feel, and — increasingly — function, like native applications. By taking advantage of the awesome new capabilities we now have when developing on the web (like Web Bluetooth!), we can now use things like service workers to mimic native app capabilities like offline functioning, notifications, and all sorts of neat stuff.

So since we already have an app to control the bulb, let’s see if we can turn it into a PWA.

To pick a sample problem: what if I’m offline and want to change the color of the bulb? Luckily, with PWA I can create a Service Worker that will define the behavior of the app when the phone is offline.

(For those of you who’ve been paying attention: you’re right, we won’t have access to the voice control capability because of the Google Cloud Speech API dependency, but that doesn’t mean we can’t still build in some useful behavior!)

To generate the service worker automatically, I will use a tool called “sw-precache”. I won’t dive into the details here, but you can read about it in this great blog post by my friend Wassim Chegam.

Additionally, I’ll add a manifest.json file to set the icon and app title (for when users add our site to their homescreens). This also creates a nice splash screen that is displayed while the app is loading:

“Web Light” added to home screen
Our Progressive Web App Splash Screen

Having both a service worker and an offline manifest file, together with the fact the the site is served over HTTPS, results in a nice bonus — if a user visits our web app frequently, he will get prompted automatically by Chrome to add a shortcut to the app to his device’s home screen:

Chrome will automatically suggest to add your web app to the user’s home screen

This feature is called App Install Banners. You can read more about it and the qualifying criteria in here.

Web Bluetooth and the Physical Web

In a previous post, I discussed all the cool things you can do with the Physical Web. With the Physical Web, you can send a link to your website from a Bluetooth beacon to a user’s device. With PWA, that link can be to your web app that looks, feels, and functions like a native app. Then with Web Bluetooth, you can then speak to the device!

One interesting feature that is currently being developed is the ability to hand off a device from the Physical Web to Web Bluetooth. As per the current specs, if the user opened a link through the Physical Web, a reference to the device where the link originated from will be available to the web page through navigator.bluetooth.referringDevice.

This means that the user won’t have to go through the device selection dialog and pair with the device again — essentially bridging the gap between the Physical Web and Web Bluetooth. All a user needs to do is discover the web link for a nearby device using the Physical Web, then the Physical Web will hand off the device to your web page once they open the link, and you will be able to start communicating with the device directly from that web page.

Pretty cool, right?

Other Notable Web Bluetooth Projects

Security: always something we want to keep in mind. It isn’t too hard to think up some good pranks you might want to pull with Web Bluetooth, but at the same time there’s some more nefarious things the bad guys might want to try with it, too. Luckily, the guys on the Chrome team are pretty smart, and they’ve built security considerations into the platform. Jeffrey Yasskin from the Chrome Team wrote a great post about the Web Bluetooth security model.

Although it’s still a new technology, there are already some community projects that take advantage of Web Bluetooth to control various devices. These are some of my favorites:

You can find a list of other Web Bluetooth projects here. And here are some more resources:

p.s. — if you were worried at all about the security of Web Bluetooth, rest assured: the Chrome team is already on it. Check out Jeffrey Yasskin’s great post about the Web Bluetooth security model to find out more.

Call to Action: Let’s Push Web Bluetooth Forward!

Build your own demos, share the with the community… make awesome stuff.

Another small thing you can do to help push Web Bluetooth forward is to vote for Web Bluetooth on Microsoft Edge. Even if you don’t use it, its inclusion will help push the standard forward, making life easier for everyone. You can vote for it up to three times on UserVoice.

If you happen to find bugs, think of useful features, or have any other feedback, I have it first hand that the Chrome team wants “Feedback feedback feedback 😉” You can do so on their GitHub Issues Page.