react-native-ble-manager
react-native-ble-manager copied to clipboard
Stuck on retrieveServices (not connected after connection?)
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 :)
same issue
@Silvesterrr any update on this?
@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 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.
Is there any update on this issue? I'm currently struggling with the same issue.
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 ๐
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 ๐
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?
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 ๐
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 ?
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.
Mismo problema, alguna soluciรณn?
Same issue
The same issue
Same here, any solutions for this?
@maeda-kazuya , @KonstantinKostianytsia try to run the scan method first and then call the connect method.
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;
})
}
Also encountering this issue. It'll stall on retrieveServices
until something else interrupts it.
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 '?'
sometimes connecting is fast, but retrieveServices takes over 30 seconds. And then disconnecting also takes much long time.
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 .
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...
}
Any update? I have same problem after upgrade version 8.x.x to 11.x.x
What I found out.
- The problem does not occur on all devices. 100% of the problem is reproduced with older Wahoo kickr (CyclingPower Service).
- 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
Version 11.0.8 fixed my problem