Skip to content

Connection issue when a user chooses a device that is not appairable anymore #40

@HaudinFlorence

Description

@HaudinFlorence

Description:
When a user wants to pair a Lego Move Hub, the user experience with the bluetooth-manager is the following one:

Screencast.From.2025-03-26.16-41-49.mp4

To pair a Move Hub device, the user has to press its green button. This opens a pairing time window that lasts about 15 s. In the previous screencast, the green button has been pressed once the Chrome chooser pop up is already opened and we can see that the device name appearing once detected. Note that the Move Hub remains in the list even if it is not appairable anymore. : there is no update for this device related to the scanning searching for bluetooth devices. As a consequence, it may happen that the user clicks on the Pair button a bit too late and thus outside of the pairing window. We are here reporting the behavior observed in that precise situation:

The snippet of code related to connection and getting the services available for this type of device is the following one:

async connectAndGetAllServices(): Promise<
      Array<BluetoothRemoteGATTService> | undefined
    > {
      this.native.addEventListener('gattserverdisconnected', event => {
        this.isConnected = false;
        this.disconnected.emit(true);
      });
      const server = this.native.gatt
      if (server) {
        server.connect();
        if (server.connected === true) {
          this.isConnected = true;
          const services = await server.getPrimaryServices();
          if (!services || services.length === 0) {
            throw new Error('Server exists but no service found on the device.');
          } else { return services; }
        }
        else {
          throw new Error('There is no connection to server. No attempt to get a service.')
        }
      }
      else {
        throw new Error('Server is not defined.');
      }
    }

There is first this error message:

BluetoothManager.ts:215 Uncaught (in promise) Error: There is no connection to server. No attempt to get a service.
    at MoveHub.connectAndGetAllServices (

And then after a bit more than 40 s, there is this other error:

Uncaught (in promise) NetworkError: Connection Error: Connection attempt failed.

After this failed tentative of connection, if the user tries to connnect the same device again, goes back on the Chrome pop up and clicks on the Move Hub to try a reconnection, this one gets automatically connected without having to click on Pair. This may not be what the user wants and we would like to "stop" the possibility of "auto-re-connection without explicitly clicking on Pair". Note that nevertheless the connection is not maintained and this error message is sent:

moveHub.ts:116 The connection state is false

This warning message comes from the initDevice method from the MoveHub class, related to the disconnected signal.

this.disconnected.connect(async (sender, disconnected: boolean) => {
      if (disconnected) {
        this.deviceInfo.connected = false;
        this.isConnected = false;
      }
      console.warn(
        'The connection state is',
        this.isConnected
      );
    });

We have tried to prevent the attempt of connection to last 40 s, by using a timeout with 5 s delay and we have also called the gatt.disconnect method to interrupt any pending connection attempts as mentioned in the specification https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattserver-disconnect. We are sharing the updated version of the connectAndGetAllServices function:

    async connectAndGetAllServices(): Promise<
      Array<BluetoothRemoteGATTService> | undefined
    > {
      this.native.addEventListener('gattserverdisconnected', event => {
        this.isConnected = false;
        this.disconnected.emit(true);
      });
      const server = this.native.gatt
      if (server) {
        const timeout = 5000;
        const connectWithTimeout = new Promise<void>((resolve, reject) => {
        const timeoutId = setTimeout(() => {
            reject(
              new Error('Connection to GATT server timed out'));
            server.disconnect();
            this.dispose();
          }, timeout);

          server.connect().then(async () => {
            clearTimeout(timeoutId);
            resolve();
            this.isConnected = true;
            this.connected.emit(true);
          })
            .catch((error) => {
              server.disconnect();
              reject(error);
            });
        });
        await connectWithTimeout
        if (server.connected === true) {
          const services = await server.getPrimaryServices();
          if (!services || services.length === 0) {
            throw new Error('Server exists but no service found on the device.');
          } else { return services; }
        }
        else {
          throw new Error('There is no connection to server. No attempt to get a service.')
        }
      }
      else {
        throw new Error('Server is not defined.');
      }
    }

If the user tries to connect too late as explained previously, this error messages after 5 s is now displayed:

Uncaught (in promise) Error: Connection to GATT server timed out

When the user tries to reconnect, the behavior is exactly the same as previously: the device is reconnected without having to click on Pair. The server.disconnect does not seem to stop any pending connection attempts. This may be related to the issue reported here on Chromium: https://issues.chromium.org/issues/40502943.

Note that the connection is lost after few seconds with this error message:

hub.ts:686 Error while writing:  - Error InvalidStateError: Failed to execute 'writeValue' on 'BluetoothRemoteGATTCharacteristic': Characteristic with UUID 00001624-1212-efde-1623-785feabcd123 is no longer valid. Remember to retrieve the characteristic again after reconnecting.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions