Introduction to the Bluetooth API Web

0
340

In the early months of 2017, in version 56 of Chrome, an interesting feature was added: the ability to connect and talk with Bluetooth devices.

Thanks to the Bluetooth Web API, it is possible to create an application that connects to a BLE ( Bluetooth Low Energy ) device, reads information from the device and receives notifications when certain values change.

As often happens with these new features, two requirements must be met:

the application must be served via HTTPS protocol;
connection to the device is only possible as a consequence of a voluntary user action (for example a click or a “tap”).
The use of this new functionality requires a minimum of knowledge of the functioning of the BLE and the GATT ( Generic Attribute Profile ), which we will provide for the course of this lesson.

We will implement, in the following, the code necessary to connect to a Bluetooth device. Let’s analyze the following code:

      navigator.bluetooth.requestDevice ({...})
        .then (device => {console.log (device)})
        .catch (error => {console.log (error);});

Running this code causes Chrome to show the user a window in which to select a BLE device. The user can also decide to cancel the request.

The method requestDeviceprovides a Promise : it waits for a user action and any connection time to the selected device. In case the connection is successful, the code inside the block will be executed then. Otherwise, the one in the block will be executed catch.

The function requestDevicesupports a mandatory argument: it is necessary to provide an object that describes the filters that the browser must apply to the search for devices. The object can have different properties, which allow you to specify different features:

  • it is possible to request the browser to search only the devices that expose a specific service
      / * For standard services I use the service name
        {filters: [{services: ['battery_service']}]}
        / * For non-standard services I use Bluetooth UUID
        {filters: [{ 
            services: [
                0x1234, 
                0x12345678, 
                '99999999-0000-1000-8000-00805f9b34fb'
                ] 
            }] 
        }
  • it is possible to ask the browser to show the devices that expose a particular name:
      {filters: [{
            name: 'Mi Band 2'
            }]
        }
  • finally, you can decide to request any device using the keyword acceptAllDevices. In this case, it is still necessary to specify the services to which we will have to access through the keyword optionalServices:
      {
            acceptAllDevices: true,
            optionalServices: ['battery_service']
        }

In case the connection is successful, Promise returns an object Device. With this object, it is possible to connect to the GATT server and perform read and write operations of the device properties (as long as the device allows this type of operation).

      navigator.bluetooth.requestDevice (
            {filters: ...}
        )
        .then (device => {
            // Obtained the device I connect to the GATT Server
            return device.gatt.connect ();
        })
        .then (server => {/ * ... * /})

Only after establishing the connection to the server can we proceed with the reading of the properties of the device:

      .then (server => {
            // I hook myself into the battery management service
            return server.getPrimaryService ('battery_service');
        })
        .then (service => {
            // Recover the characteristic relating to the battery
            return service.getCharacteristic ('battery_level');
        })
        .then (characteristic => {
            // I read the current battery value
            return characteristic.readValue ();
        })
        .then (value => {
            console.log ('Battery charge:' + value);
        })

It is also possible to decide to exploit an event listener to visualize possible variations of a characteristic of the device: after having recovered the service, we could use a code similar to the following:

      .then (service => ...)
        .then (characteristic => characteristic.startNotifications ())
        .then (characteristic => {
            characteristic.addEventListener ( 'characteristicvaluechanged',
                                            handleCharacteristicValueChanged);
            console.log ('Notifications have been started.');
        })
        .catch(error => { console.log(error); });

        function handleCharacteristicValueChanged(event) {
            const value = event.target.value;
            console.log('Valore ricevuto ' + value);
        }

The function handelCharacteristicValueChangedwill be executed every time the value of the listening characteristic changes (in the case at every change of the battery level).

Another information that we might want to manage is the possible disconnection of the previously connected device . To do this, you need to change the hooking code to the device:

navigator.bluetooth.requestDevice(...)
        .then(device => {
            device.addEventListener('gattserverdisconnected', onDisconnected);

            return device.gatt.connect();
        })

When the device is disconnected, the browser will execute the code contained in the function onDisconnectedallowing to manage the disconnection of the device.

If you do not have a BLE device with which to test this new technology, you can use the BLE simulator made available by the Web Bluetooth Community.

One last tip is to look at the examples provided by the Chrome team: it will be possible to discover all the available features and test the enormous potential of the API.

LEAVE A REPLY

Please enter your comment!
Please enter your name here