react-native-ble-manager icon indicating copy to clipboard operation
react-native-ble-manager copied to clipboard

Stuck on retrieveServices (not connected after connection?)

Open Silvesterrr opened this issue 3 years ago โ€ข 30 comments

Describtion Hi, I've got this annoying bug it appears inconsistently every few times. It's really similar to this Issue [#402] (https://github.com/innoveit/react-native-ble-manager/issues/402) It looks something like this:

  • Connect do device
  • Retrieve services -> and at this point the code hangs up I never found out this bug after first run of my app (first connect). Only at second, etc. connection.

I can't find any mistakes because one time it works like a charm and other time it has a problem. I found out that disabling and enabling Bluetooth on the phone and retrying connecting works (But I can't make my users to disable and enable Bluetooth. Or can I ;) ha-ha).

My code I've tried writing my code in 2 ways both have this bug.

async function internalConnect() {
    await BleManager.connect(item.id);
    console.log('after conn');
    await BleManager.retrieveServices(item.id);
    console.log('after retrive');  // <---if the bug appears I never get to see this log
    await BleManager.write(
      item.id,
      global.GATTS_SECURITY_UUID,
      global.GATTC_ACCESS_CODE_UUID,
      stringToIntArray(code),
    );
    console.log('after write');
    await BleManager.read(
      item.id,
      global.GATTS_SECURITY_UUID,
      global.GATTC_ACCESS_CODE_UUID,
    )
      .then(readData => {
        console.log('access code response: ' + readData);
       //My other stuff here
      })
      .catch(error => {
        // Failure code
        console.log(error);
      });
  }

And this way:

BleManager.connect(item.id)
      .then(() => {
        console.log('connected to device');
        setTimeout(() => {
          BleManager.isPeripheralConnected(item.id, []).then(isConnected => {
            //do not remove
            if (isConnected) {
              console.log('Peripheral is connected!');
            } else {
              console.log('Peripheral is NOT connected!');
              Connect(); //<--- run the same function
              return;
            }
          });
        }, 900);
        setTimeout(() => {
          console.log('timeout');

          BleManager.retrieveServices(item.id)
            .then(PeripheralInfo => {
              console.log(PeripheralInfo);

              BleManager.write(
                item.id,
                global.GATTS_SECURITY_UUID,
                global.GATTC_ACCESS_CODE_UUID,
                stringToIntArray(code),
              )
                .then(() => {
                  console.log('written');
                  BleManager.read(
                    item.id,
                    global.GATTS_SECURITY_UUID,
                    global.GATTC_ACCESS_CODE_UUID,
                  )
                    .then(readData => {
                      console.log('access code response: ' + readData);
                      //My stuff here
                    })
                    .catch(error => {
                      handleConnectionErrors(error);
                      return;
                    });
                })
                .catch(error => {
                  handleConnectionErrors(error);
                  return;
                });
            })
            .catch(error => {
              handleConnectionErrors(error);
              return;
            });
        }, 900);
      })
      .catch(error => {
        handleConnectionErrors(error);
        return;
      });

In this way when the bug appears after running isPeripheralConnected I get Peripheral is NOT connected! So I've tried to resolve this by running this function again, but it just loops in this place and doesn't work.

How to Reproduce Accually I don't know. It appears so random, I can't control it. I only know that it appears at second or next connections.

Smartphone:

  • Device: xiaomi redmi note 7
  • OS: android 10 QKQ1.190910.002
  • react-native-cli: 2.0.1
  • react-native: 0.66.4
  • ble-manager: 8.0.1s

Btw, I really like this library. It's really intuitive :)

Silvesterrr avatar Feb 10 '22 23:02 Silvesterrr

same issue

liuliu66666 avatar Feb 11 '22 02:02 liuliu66666

@Silvesterrr any update on this?

michael-jogo avatar Mar 21 '22 10:03 michael-jogo

@Silvesterrr any update on this?

Nope, am focused on something different... But I'll be back onto it soon. If I figure out anything new I'll post it.

Silvesterrr avatar Mar 21 '22 13:03 Silvesterrr

@Silvesterrr I had the same hanging issue with Android only, iOS works perfectly fine to me. There is a workaround I did that solves the issue. Try to createBond before the connect :

if (Platform.OS === 'android') {
   await BleManager.createBond(item.id);
  // you may want to add some delay after create bond
   await BleManager.connect(item.id);
}

Hope this helps.

manxhong avatar Jun 03 '22 13:06 manxhong

Is there any update on this issue? I'm currently struggling with the same issue.

sarevok89 avatar Sep 29 '22 09:09 sarevok89

Same problem on xiaomi pad 5 ๐Ÿ˜’

I tried so many things like clear bluetooth cache / binding etc.. I wasted few hours on this.

As workaround im wating at least 1 sec and if there is no connection (not getting "retrieveServices") I trigger disconnect and then reconnect again every time. something like this (look at "handleHangOutBug" function):

const connectToDevice = async (id) => {
    try {
      await BleManager.connect(id);
    }
    catch(error) {
      handleError(error);
      return connectToDevice(id);
    }
    Log("Weight", "setDevice", "Connected to:", id);
    clearTimeouts();
    setConnectionStatus(1);
    currentDeviceId.current = id;
    retrieveServices(id);
    handleHangOutBug(id);
  }

  const handleHangOutBug = (id) => {
    hangOutTimeout.current = setTimeout(() => {
      if (connectionStatus.current === 1) {
        hangOutretries.current = hangOutretries.current + 1;
        isConnectingProcess.current = true;
        disconnect().then(() => {
          connectToDevice(id);
        });
      }
    }, (1000 + (hangOutretries.current * 250)));
  }

Please let me know if you have better solutions, thanks ๐Ÿ˜€

sundayhd avatar Nov 19 '22 19:11 sundayhd

Toady I played with "bluetooth MAP version & AVRCP version" inside developer options. When I changed map version to 1.3 its looks like that problem go away, so give it a shot ๐Ÿ˜ƒ

sundayhd avatar Nov 22 '22 17:11 sundayhd

Toady I played with "bluetooth MAP version & AVRCP version" inside developer options. When I changed map version to 1.3 its looks like that problem go away, so give it a shot ๐Ÿ˜ƒ

yea, fun fact but I cannot force user to change that. Anyone tried using "react-native-ble-plx"? Does this library has this issue?

Silvesterrr avatar Dec 14 '22 17:12 Silvesterrr

Toady I played with "bluetooth MAP version & AVRCP version" inside developer options. When I changed map version to 1.3 its looks like that problem go away, so give it a shot ๐Ÿ˜ƒ

yea, fun fact but I cannot force user to change that. Anyone tried using "react-native-ble-plx"? Does this library has this issue?

I already tried ble-plx, same issue ๐Ÿ˜Ÿ

sundayhd avatar Dec 27 '22 23:12 sundayhd

Hi @Silvesterrr, I'm also facing similar kind of issue, In very first time BleManager.connect return this error "Connection error" but if I try again it connected without any issue

Did you found a solution for this issue ?

RuchiraSwarnapriya avatar Jan 03 '23 11:01 RuchiraSwarnapriya

Did you found a solution for this issue ? Sorry I did not. I kinda hacked the way throught by disabling bluetooth and enabling it when the problem occures with other library. But I hope this issue will be resolved because it's so frustrating.

Silvesterrr avatar Jan 11 '23 21:01 Silvesterrr

Mismo problema, alguna soluciรณn?

JoshuaGuzman02 avatar Feb 06 '23 21:02 JoshuaGuzman02

Same issue

sfsnaruto avatar May 28 '23 08:05 sfsnaruto

The same issue

KonstantinKostianytsia avatar May 28 '23 19:05 KonstantinKostianytsia

Same here, any solutions for this?

maeda-kazuya avatar Jul 05 '23 03:07 maeda-kazuya

@maeda-kazuya , @KonstantinKostianytsia try to run the scan method first and then call the connect method.

sfsnaruto avatar Jul 05 '23 04:07 sfsnaruto

Thanks, I just came up with some workaround. I added retry process as follows and it works for now. (Still wondering the root cause of failure..)

    let isConnected = false;

    while (!isConnected) {
      await BleManager.connect(id)
        .then(() => {
          isConnected = true;
        })
    }

maeda-kazuya avatar Jul 06 '23 03:07 maeda-kazuya

Also encountering this issue. It'll stall on retrieveServices until something else interrupts it.

cfradella avatar Sep 06 '23 21:09 cfradella

I don't know if this could be an answer, but let me share my code. Before, you should see two parts of the original code.

// react-native-ble-manager > src > types.ts
export interface PeripheralInfo extends Peripheral {
  serviceUUIDs?: string[];
  characteristics?: Characteristic[];
  services?: Service[];
}
// react-native-ble-manager > src > index.ts
retrieveServices(peripheralId: string, serviceUUIDs: string[] = []) {
    return new Promise<PeripheralInfo>((fulfill, reject) => {
      bleManager.retrieveServices(
        peripheralId,
        serviceUUIDs,
        (error: string | null, peripheral: PeripheralInfo) => {
          if (error) {
            reject(error);
          } else {
            fulfill(peripheral);
          }
        }
      );
    });
  }

When you use retrieveServices, it will return the result 'peripheral', whose elements' types are defined by Interface 'PeripheralInfo'. As you can see, the original code makes PeripheralInfo extend Peripheral, and Interface 'Peripheral' is as below.

export interface Peripheral {
  id: string;
  rssi: number;
  name?: string;
  advertising: AdvertisingData;
}

These say, the result of retrieveServices must have attributes 'id', 'rssi', and 'advertising' while others are optional. BUT, what if the result does NOT have the attributes? You'd better not force it to distribute the information of what it may not have.

So, here is the part of my code.

export interface PeripheralInfo { // -> this is what I fixed
  id: string; // -> this is what I added
  serviceUUIDs?: string[];
  characteristics?: Characteristic[];
  services?: Service[];
}

In my code, PeripheralInfo does not extend Peripheral anymore. Instead, the result still contains 'id', because you will offer it when you call retrieveServices function. You can put other options if you want, like this.

rssi?: number;
name?: string;
advertising?: AdvertisingData;

Don't forget to make them optional by using '?'

froggydisk avatar Sep 14 '23 07:09 froggydisk

sometimes connecting is fast, but retrieveServices takes over 30 seconds. And then disconnecting also takes much long time.

2sem avatar Sep 15 '23 04:09 2sem

react-native-ble-plx is better than react-native-ble-manger. its enables us to retireveServices on both platform Android & IOS and perform any thing you can .

RakeebBaig1 avatar Oct 11 '23 16:10 RakeebBaig1

My current workaround is something like this, where I basically race it against another promise. If the other promise resolves first I consider it a timeout and handle it accordingly.

const tryGetServices = await Promise.race([
	BleManager.retrieveServices(peripheral.id),
	new Promise((resolve, reject) =>
		setTimeout(() => {
			resolve('timeout')
		}, 10000)
	),
])

const peripheralData = tryGetServices as PeripheralInfo | string

if (typeof peripheralData === 'string') {
	// timeout
} else {
	// got services, proceed...
}

pernestrand avatar Oct 23 '23 15:10 pernestrand

Any update? I have same problem after upgrade version 8.x.x to 11.x.x

Loovery avatar Dec 24 '23 12:12 Loovery

What I found out.

  1. The problem does not occur on all devices. 100% of the problem is reproduced with older Wahoo kickr (CyclingPower Service).
  2. The device connects without problems. All data is read. The problem is exactly when retrieveServices is requested. It just hangs without any response.

The function retrieveServices, reaches the code:

if !uuids.isEmpty {
                peripheral.instance.discoverServices(uuids)
            } else {
                peripheral.instance.discoverServices(nil)
            }

Nothing further

service: 1818 characteristic: a026e005-0a7d-4ab3-97fa-f1500f9feb8b

react-native: 0.71.11 react-native-ble-manager: 11.0.7

Loovery avatar Dec 26 '23 16:12 Loovery

Version 11.0.8 fixed my problem

Loovery avatar Dec 27 '23 19:12 Loovery