capacitor-community / bluetooth-le

Capacitor plugin for Bluetooth Low Energy
MIT License
285 stars 85 forks source link

Connecting device2 delays writing data to device1 #678

Closed stefanhaebler closed 2 months ago

stefanhaebler commented 3 months ago

Describe the bug My application connects to multiple bluetooth lamps in parallel BleClient.connect(...). These lamps are not part of a common bluetooth network and don't know anything about each other. Then I send flashing instructions every second to some of those lamps BleClient.write(..), same service, same characteristics, same data. All works fine until here.

If now, e.g. triggered by a new lamp bluetooth discovery, a new connection is initiated to this new lamp, the continuous sending of the flashing instructions is interrupted/delayed until this new connection is established.

Following scenario in this flashing interruption log.txt: Connecting to the new lamp takes 3.7 seconds (C5:B0:AA:EC:69:34), and writing the flashing instructions takes therefore 3.2 seconds (F7:93:5B:0C:29:E4 and D0:CF:5E:E1:2C:30). Writing flashing instructions normally takes ~100ms. The time measuring is taken like this:

public connectDevice(deviceId: string, onDisconnect: (deviceId: string) => void): Promise<void> {
  console.time(`removeme ${deviceId} connectDevice`);
  console.timeLog(`removeme ${deviceId} connectDevice`, 'start');
  return BleClient.connect(deviceId, onDisconnect).finally(() => {
    console.timeLog(`removeme ${deviceId} connectDevice`, 'end');
    console.timeEnd(`removeme ${deviceId} connectDevice`);
  });
}

public write(
  deviceId: string,
  serviceId: BluetoothServiceUuid,
  characteristicId: BluetoothCharacteristicUuid,
  requestData: ArrayBuffer
): Promise<void> {
  console.time(`removeme ${deviceId} write`);
  console.timeLog(`removeme ${deviceId} write`, 'start');
  return BleClient.write(deviceId, serviceId, characteristicId, new DataView(requestData)).finally(() => {
    console.timeLog(`removeme ${deviceId} write`, 'end');
    console.timeEnd(`removeme ${deviceId} write`);
  });
}

I wonder if bluetooth-le is somehow blocking itself when running multiple connections? Or can I somehow better address this problem with different connection/writing options...?

Expected behavior I would expect the flashing to continue normally.

Plugin version:

Smartphone (please complete the following information):

stefanhaebler commented 2 months ago

It would be great if someone more knowledgeable in the bluetooth mechanics could assist me with this one...

It seems that while bluetooth-le is BleClient.connect(...)ing to a new device, it is postponing all other interactions, like e.g. BleClient.write(..)s via existing connections to other devices.

Is this a bug, or just "how it's implemented" or does it "need to be like this"? Or am doing something wrong here?

Thanks for any advise!

peitschie commented 2 months ago

@stefanhaebler I've had a quick squizz, but nothing in particular stands out to me about this. As far as I can tell (perhaps @pwespi can confirm with more confidence... I'm still finding my way through the codebase a bit)... there shouldn't be anything here that would stop you writing to one device while connecting to another...

pwespi commented 2 months ago

There is actually a queue for method calls in the JavaScript layer of the plugin. I suspect what you're seeing is caused by it. It was introduced to avoid concurrency issues in the BLE stack, but it might be too restricting for your use case.

There is an undocumented way to disable it with BleClient.disableQueue() that you could use. But be aware that this might have other side effects.

stefanhaebler commented 2 months ago

Thanks very much for the valuable background info! I understood it works as designed.

I'll try to BleClient.disableQueue() and see how it impacts my setup.