dotintent / react-native-ble-plx

React Native BLE library
Apache License 2.0
2.94k stars 492 forks source link

Bluetooth resources saturation after some time #1186

Open davelaffi opened 1 month ago

davelaffi commented 1 month ago

Prerequisites

Question

Hi all! I have a project with a mobile application which receives data from 2 devices which uses esp32 to communicate and put them in two different buffers. Each device sends a single data of 323 bytes every 100ms so a total of 6460 bytes per second.

We work at 521 MTU rate. We don't have visibility on firmware and detailed knowledge of the devices architecture.

To handle data I have created this EventIterator:

const createEventIterator = (direction: Direction, device: Device) => {
  const serviceUuid = SERVICE_UUIDS[direction];
  return new EventIterator<string>(({ push, stop, fail }) => {
    device.monitorCharacteristicForService(
      serviceUuid,
      READ_CHARACTERISTIC_UUID,
      (error, characteristic) => {
        if (!error && characteristic?.value) {
          push(Buffer.from(characteristic.value, "base64").toString());
        } else if (error) {
          if (error.errorCode === BleErrorCode.OperationCancelled) {
            stop();
          } else {
            fail(error);
          }
        }
      }
    );
  });
};

The "Direction" is used to choose which of the two devices. Each one has is own "monitorCharacteristicForService". And then I process data like that:

try {
      for await (const str of createEventIterator(direction, device)) {
        processMessage(direction, data);
      }
    } catch (error: any) {
// Catch error
    }

In this scenario, I have tried with multiple devices and everything seems to work correctly. I receive all data! I've tested with: Iphone 14 Iphone 8 One Plus 6

But with some android device like: Samsung s21 Samsung A34 Samsung A5 Honor 8xa

I have some troubles because lots of data are not received. The connection is established correctly and the first 10 data are correctly received, then only ONE of the two devices (randomly) starts to raise Notification failed status 4, code 6 on a lot of data, which is a saturation of bluetooth resources of the device. From that moment on, the mobile app will receive only some of the data, for example: if 10 data are sent in 1s, only one of the 10 data will have a success status and will be received, the others will throw a Notification failed error.

I have tried to reduce the number of data sent by the device to 160 bytes per data, and now the problem happens after almost 2 minutes of perfect trasmission.

In addition, if I try to write a message to characteristic during this lack of data, the library throws a:

{
    "message": "Characteristic 3b6e9d2b-bca8-45f0-8287-71515b1dddaf write failed for device 7C:9E:BD:92:48:82 and service b8e7ccee-9244-4a17-b274-5288b9079fa9",
    "errorCode": 401,
    "attErrorCode": 17,
    "iosErrorCode": null,
    "androidErrorCode": null,
    "reason": "GATT exception from MAC='XX:XX:XX:XX:XX:XX', status 17 (GATT_INSUF_RESOURCE), type BleGattOperation{description='CHARACTERISTIC_WRITE'}. (Look up status 0x11 here https://cs.android.com/android/platform/superproject/+/master:packages/modules/Bluetooth/system/stack/include/gatt_api.h)",
    "name": "BleError"
}

I really don't know why after some time the device starts to have difficulties to make data reach the mobile device, it seems a saturation after lots of data are received that improves if I reduce data that are sent. I cannot explain why this depends on the mobile device used for the test, maybe performance of the mobile phone?

I even don't know if the problem is caused by a lack of resources of either the mobile device or the device/esp32, or it is something releted to the mobile application implementation.

I hope someone can help me, I know it's not very well detailed, if further clarification are needed, please answer and ask to me!

EmmaZachara commented 1 month ago

Hi @davelaffi, thanks for the question; we'll get back to you soon with answers.

davelaffi commented 1 month ago

Hi, I share with you updates on the issue.

We are talking with the company who made the firmware of the device and changing two parameters improve the connection, decreasing the loss of data.

In particular they increased DLE, but more important, they changed CONNECTION INTERVAL. Sometimes the mobile device negotiates again this value and is restored to the default making the connection unstable and losing some data.

Is there a way to set CONNECTION INTERVAL value from Android and IOS apis?

Thank you

EmmaZachara commented 1 month ago

@davelaffi, I'm glad it helped. We'll verify the connection interval value and let you know as soon as possible.