Search code examples
google-chromebluetooth-lowenergyweb-bluetooth

Web Bluetooth discovering by Service uuid


I'm trying to write a web app to interact with a Eddystone beacon. The beacon advertise a URL for the app and exposes a service and 2 characteristics.

My device has the following services and characteristics as shown by gatttool on linux

$ gatttool -I 
[00:1A:7D:DA:71:15][LE]> connect 00:1A:7D:DA:71:15 
Attempting to connect to 00:1A:7D:DA:71:15 
Connection successful 
[00:1A:7D:DA:71:15][LE]> primary 
attr handle: 0x0001, end grp handle: 0x0005 uuid: 00001800-0000-1000-8000-00805f9b34fb 
attr handle: 0x0006, end grp handle: 0x0009 uuid: 00001801-0000-1000-8000-00805f9b34fb 
attr handle: 0x000a, end grp handle: 0x0012 uuid: ba42561b-b1d2-440a-8d04-0cefb43faece 
[00:1A:7D:DA:71:15][LE]> characteristics 
handle: 0x0002, char properties: 0x02, char value handle: 0x0003, uuid: 00002a00-0000-1000-8000-00805f9b34fb 
handle: 0x0004, char properties: 0x02, char value handle: 0x0005, uuid: 00002a01-0000-1000-8000-00805f9b34fb 
handle: 0x0007, char properties: 0x20, char value handle: 0x0008, uuid: 00002a05-0000-1000-8000-00805f9b34fb 
handle: 0x000b, char properties: 0x1a, char value handle: 0x000c, uuid: 6bcb06e2-7475-42a9-a62a-54a1f3ce11e6 
handle: 0x000f, char properties: 0x1a, char value handle: 0x0010, uuid: 6bcb06e2-7475-42a9-a62a-54a1f3ce11e5 
[00:1A:7D:DA:71:15][LE]

I'm working from the example here

if (navigator.bluetooth) {
  console.log("bluetooth found");
  navigator.bluetooth.requestDevice({
    filters: [{
      services: ['ba42561b-b1d2-440a-8d04-0cefb43faece']
    }]
  })
  .then(device => {
    bluetoothDevice = device;
    console.log(device.name);
    console.log(device.uuids);
    device.connectGATT();
  })
  .then(server => {
    return server.getPrimaryService('ba42561b-b1d2-440a-8d04-0cefb43faece');
  })
  .then(service => {
    return service.getCharacteristic('6bcb06e2-7475-42a9-a62a-54a1f3ce11e6');
  })
  .then( characteristic => {
    var toggleOn = new Uint8Array([1]);
    return characteristic.writeValue(toggleOn);
  })
  .catch(error => { 
    console.log("error:- " + error); 
  });
}

This code never finds the device. If I change the filter to use the namePrefix it finds the device but only lists one of the services and not the one I'm interested in.

Anybody know what I'm doing wrong with the discovery and finding the right services?


Solution

  • The filters argument filters devices primarily based on the advertising packets they send, rather than the services actually exposed by the devices' gatt servers. So, if the beacon just advertises a url and its name, you're unlikely to find it by filtering for particular service UUIDs.

    I say "unlikely" instead of "you won't" because if you've already connected to the device once, your system might cache the set of services the device actually exposes and then use those to match the filter.

    If you switch to the namePrefix argument, you'll need to remember to list all the services you want to use in optionalServices:

    navigator.bluetooth.requestDevice({
      filters: [{
        namePrefix: 'something',
      }],
      optionalServices: ['ba42561b-b1d2-440a-8d04-0cefb43faece']
    });