There are a few gotchas when working with Web Bluetooth:

  • server.getPrimaryServices() will only give you access to services you’ve expressly asked for in filters.services and optionalServices.
  • 16 bit UUIDs have to be a number, example: 0x181A - 128-bit UUIDs can be string
  • 16 bit UUIDs are extendend to: 0000181a-0000-1000-8000-00805f9b34fb
  • Read values are a DataView object, DataView is a handy built-in to work with bytes.

The DataView view provides a low-level interface for reading and writing multiple number types in a binary ArrayBuffer, without having to care about the platform’s endianness.

  • Transfered data uses little-endian byte order, most DataView functions have a parameter to set littleEndian.
  • Devices serial characteristics is blacklisted and can not be read.

Getting all characteristics

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
let allCharacteristics = new Map();

let options = {
  filters: [
    {services: ['ea0669f3-fd44-406f-98e0-5feaeed5cb22']},
  ],
  optionalServices: [LIST_OF_ALL_SERVICES_YOU_WANT_TO_USE]
};
navigator.bluetooth.requestDevice(options)
.then((device) => {
  console.log(device.name);
  // device.addEventListener('gattserverdisconnected', this.onDisconnected); // setting up disconnect callback
  return device.gatt.connect();
})
.then((server) => {
  return server.getPrimaryServices(); // gets all services listed in filters.services and optionalServices
})
.then((services) => {
  console.log('Getting Characteristics...');
  let queue = Promise.resolve();
  services.forEach(service => {
    queue = queue.then(_ => service.getCharacteristics().then(characteristics => {
      console.log('> Service: ' + service.uuid);
      characteristics.forEach(characteristic => {
        console.log('>> Characteristic: ' + characteristic.uuid + ' ' + getSupportedProperties(characteristic));
        allCharacteristics.set(characteristic.uuid, characteristic);
      });
    }));
  });
  return queue;
})
.catch((error) => {
  console.log(error);
});

To read values

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
let char = allCharacteristics.get('3d05109a-7de0-4146-9ee8-9283ac9e4b12');
if (char === undefined) {
  console.log('Temperature characteristics does not exist');
  return;
}
char.readValue().then((value) => {
  // value is a DataView, getInt16's second paramter is littleendian
  this.temperature = (value.getInt16(0, true) / 100) + ' °C';
})
.catch(error => {
  console.log(error);
});


// for strings
let decoder = new TextDecoder('utf-8');
char.readValue().then((value) => {
  let v = decoder.decode(value);
  console.log('acceleroemter', v);
})
.catch(error => {
  console.log(error);
});

To write values

````js // values let arr = Uint8Array.of(true); char.writeValue(arr).then(() => { console.log(‘value has been sent’, arr); }) .catch(error => { console.log(error); });

// strings let s = ‘hello world’; let encoder = new TextEncoder(‘utf-8’); char.writeValue(encoder.encode(s)).then(() => { console.log(‘value has been sent’, s); }) .catch(error => { console.log(error); });

```