Search code examples
javascriptweb-bluetooth

"GATT Error: Not paired." with web-bluetooth when device shows as connected


I'm trying to connect to a Microchip "RN4678" dual mode bluetooth device from my Windows 10 machine using BLE with the web bluetooth api. I can find the device -> the service -> the characteristic I need but I keep getting a "GATT Error: Not paired." when trying to start notifications on the characteristic.

My JavaScript experience is minimal, so I thought that I may have been chaining my promises wrong, however printing out the device info directly before trying to add the characteristic shows the value for "connected" as true.

I have also verified that the device, service, and characteristic work as intended with the "nRF Connect" app on my android device.

Here is my code:

let targetService = '49535343-fe7d-4ae5-8fa9-9fafd205e455';
let txCharacteristicId = '49535343-1e4d-4bd9-ba61-23c647249616';
let rxCharacteristicId = '49535343-8841-43f4-a8d4-ecbe34729bb3';

function onButtonClick(event) {

  // Find bluetooth device
  console.log('Requesting Bluetooth Device...');
  navigator.bluetooth.requestDevice({
    acceptAllDevices: true,
    optionalServices: [targetService]
  })
  // Connect to device
  .then(device => device.gatt.connect())
  // Get the server we want
  .then(server => {
    console.log('Getting UART transparent service...');
    return server.getPrimaryService(targetService);
  })
  // Handle the characteristics we need
  .then(service => {
    return service.getCharacteristic(txCharacteristicId)
  })
  .then(characteristic => {
    console.dir(characteristic.service.device);
    return characteristic.startNotifications();
  })
  .then(characteristic => {
    characteristic.addEventListener('characteristicvaluechanged',
                                    handleTx);
  })
  .catch(error => { 
    console.log(error);
    console.log(error.code);
    console.log(error.message); 
    console.log(error.name); 
  });

}

function handleTx(event) {
  console.log(event.target.value);
}

And here are the console messages I get:

index.html:18 Requesting Bluetooth Device...
index.html:27 Getting UART transparent service...
index.html:35 BluetoothDevice
                gatt: BluetoothRemoteGATTServer
                  connected: true
                  device: BluetoothDevice {id: "p+lJYscejR+Xl4eX+VbNkA==", name: "Dual-SPP", gatt: BluetoothRemoteGATTServer, ongattserverdisconnected: null}
                  __proto__: BluetoothRemoteGATTServer
                id: "p+lJYscejR+Xl4eX+VbNkA=="
                name: "Dual-SPP"
                ongattserverdisconnected: null
                __proto__: BluetoothDevice
index.html:44 DOMException
index.html:45 19
index.html:46 GATT Error: Not paired.
index.html:47 NetworkError

Here is the documentation for the web bluetooth startNotifications() function (https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattcharacteristic-startnotifications):

The startNotifications() method, when invoked, MUST return a new promise promise and run the following steps in parallel. See §5.6.4 Responding to Notifications and Indications for details of receiving notifications.

  1. If this.uuid is blocklisted for reads, reject promise with a SecurityError and abort these steps.
  2. If this.service.device.gatt.connected is false, reject promise with a NetworkError and abort these steps.
  3. Let characteristic be this.[[representedCharacteristic]].
  4. If characteristic is null, return a promise rejected with an InvalidStateError and abort these steps.
  5. If neither of the Notify or Indicate bits are set in characteristic’s properties, reject promise with a NotSupportedError and abort these steps.
  6. If characteristic’s active notification context set contains navigator.bluetooth, resolve promise with this and abort these steps.
  7. If the UA is currently using the Bluetooth system, it MAY reject promise with a NetworkError and abort these steps. ISSUE 9: Implementations may be able to avoid this NetworkError, but for now sites need to serialize their use of this API and/or give the user a way to retry failed operations. https://github.com/WebBluetoothCG/web-bluetooth/issues/188

  8. If the characteristic has a Client Characteristic Configuration descriptor, use any of the Characteristic Descriptors procedures to ensure that one of the Notification or Indication bits in characteristic’s Client Characteristic Configuration descriptor is set, matching the constraints in characteristic’s properties. The UA SHOULD avoid setting both bits, and MUST deduplicate value-change events if both bits are set. Handle errors as described in §5.7 Error handling. Note: Some devices have characteristics whose properties include the Notify or Indicate bit but that don’t have a Client Characteristic Configuration descriptor. These non-standard-compliant characteristics tend to send notifications or indications unconditionally, so this specification allows applications to simply subscribe to their messages.

  9. If the previous step returned an error, reject promise with that error and abort these steps.

  10. Add navigator.bluetooth to characteristic’s active notification context set.
  11. Resolve promise with this. After notifications are enabled, the resulting value-change events won’t be delivered until after the current microtask checkpoint. This allows a developer to set up handlers in the .then handler of the result promise.

Edit: I'm using Chrome version 74, Windows 10.0.17134


Solution

  • I found the solution for my device, I hope it works for you as well. As it turns out, the device must be paired with Windows OS prior to establishing a connection via Web Bluetooth. So even though Web Bluetooth would "connect" and display all GATT properties - the device was actually disconnecting when it receives the startNotifications() command (since it is not paired through the OS). Additionally, (in my case, but this is probably device specific) my "default passcode" was 000000 (needed to be exactly 6 zeros). Be sure to double check that when pairing with Windows OS.

    Edit: This behavior (having to pair the device with the OS, prior to establishing a Web Bluetooth connection) is a bug that has been discovered on macOS in addition to Windows. See this chrome-bug for more information.