bluetooth-le
bluetooth-le copied to clipboard
(Possible) Android 11 issue - Error: Connection timeout 9 out of 10 times
Describe the bug Experiencing failed connection attempts 9 out of 10 times on certain Ble devices when I build on Android 11 but not on Android 10 or any iOS devices.
Connecting to the same BLE device, very short range, data light flashes on the front of the device but connection times out with Android 11. Fine on all other devices. Difficult to reproduce as it only happens on Android 11 devices on a particular Ble device. Publishing here just in case other people experience it.
To Reproduce Steps to reproduce the behavior:
try { await BleClient.initialize();
//needed for iOS, not for Android.
await BleClient.getDevices([deviceId]);
// connect to device, the onDisconnect callback is optional
await BleClient.connect(deviceId, (deviceIdDisco) => this.onDisconnect(deviceIdDisco));
const servicesAvail = await BleClient.getServices(deviceId);
console.log('services Avail:', JSON.stringify(servicesAvail));
await BleClient.write(deviceId, UUID_SERVICE, UUID_CHARACTERISTIC, data)
}catch (error) {
console.error(error);
}
Fails on BleClient.connect with error 'Error: Connection timeout.' 9 out of ten times on Android 11 but works perfect on iOS and Android 10/9. Takes around 4 seconds to timeout with lights flashing on the device im connecting to.
Expected behavior Connects and allows me to write data to the device
Plugin version:
-
@capacitor-community/bluetooth-le: 1.8.0
-
iOS working
-
Android 11 Fail
-
Android 10 & 9 working
Hardware is Techlast 8 inch tablets with Android 9/10/11 Connecting device is a Mobile Printer with no real branding
Additional context Could totally be a hardware / OS clash just making people aware just in case others have Android 11 issues.
Thanks
Having a similar issue with Android 11. Created issue 359 which details what I'm experiencing. BleClient.disconnect disconnects from BLE peripheral, but there's some setting that isn't fully implemented which prevents the first BleClient.connect call thereafter from connecting to the peripheral. Calling BleClient.connect a second time on the same peripheral then allows app to connect to peripheral. I don't think this is a hardware issue, but sounds like an Android 11/BLE library incompatibility issue, but I'm no expert.
Having a similar issue with Android 11. Created issue 359 which details what I'm experiencing. BleClient.disconnect disconnects from BLE peripheral, but allows app to remain bound to peripheral. Calling BleClient.connect on the same peripheral the first time after disconnecting causes app and peripheral to unbind. Calling BleClient.connect a second time on the same peripheral then allows app to connect to peripheral. Would be nice if there were an API that allowed us to manually unbind app from peripheral as a work around. I don't think this is a hardware issue, but sounds like an Android 11/BLE library incompatibility issue, but I'm no expert.
Thats really helpful, thanks Karunt, I'll put a second connect/disconnect at the end of my process and update if that fixes fixes the issue.
If it's helpful, here's how I structured my code (in Angular/Ionic) for connecting to a peripheral. If there's an error (in this case, there is a connection timeout error), then I show an alert with the error. Dismissing the alert causes the app to re-scan available devices (using the BleClient.requestDevice api),, followed by connection to the selected device.
async addBleDevice(){
try{
await this.bleService.connectToDevice();
}
catch(error){
if(error.message){
this.headerText = 'Alert';
this.subHeaderText = 'Connection Unsuccessful';
this.messageText = error.message;
this.buttonArray = [{text: 'OK', role: 'cancel', handler: () => this.addBleDevice()}];
this.showAlert();
}
}
}
bleService.connectToDevice(){
try{
this.connectedDevice = await BleClient.requestDevice();
await BleClient.connect(this.connectedDevice.deviceId);
return this.connectedDevice;
} catch(error){
//Insert your error related code
}
}
Have you tried manually setting the timeout? The default is 10 sec for connect
.
https://github.com/capacitor-community/bluetooth-le#connect
I don't think timeout is the issue. The exact same code worked 2 months ago prior to Android 11 upgrade, and I don't believe the default timeout has changed since.. Even now, BleClient.connect successfully transmits a message to the BLE peripheral, except that the type of message it sends appears to be identical to what BleClient.disconnect sends. A second implementation of BleClient.connect resolves the matter. It's almost as though BleClient.disconnect doesn't complete its job of disconnecting the app from the peripheral, and the first implementation of BleClient.connect thereafter is needed to complete the disconnection. I structured my work around such that BleClient.connect is now called within a while loop which allows for 5 connection attempts (and resulting timeout errors are basically disregarded until after the 5th attempt). Invariably, the app connects to the peripheral on the 2nd try, which is consistent with the problem described in issue 359. Furthermore, when the peripheral is reset to factory standard (ie, no prior disconnect attempt), the very first implementation of BleClient.connect successfully connects the app to the peripheral (with the default timeout), further showing that the default timeout doesn't appear to the be the issue. Here's a really rudimentary code with promises in nested try/catch blocks to show the work around (I am working on accomplishing the same with observables), which is an alternative to the code I posted above (basically avoids user having to select a new peripheral device each time a connection times out, with up to 5 tries to connect):
async connectToDevice(){
let connectionStatus = false;
let n = 0;
try{
this.connectedDevice = await BleClient.requestDevice();
while (connectionStatus === false && n < 5){
try{
n ++;
await BleClient.connect(this.connectedDevice.deviceId);
connectionStatus = true;
return this.connectedDevice;
} catch(error){
if(n === 5){
const device = this.connectedDevice.name ? this.connectedDevice.name : this.connectedDevice.deviceId;
throw new Error('Unable to connect to ' + device + '. Select another Bluetooth device.');
} else if (n < 5){
console.log('Do nothing with error');
} else {
throw new Error('Some other error');
}}
}
}
catch(err){
if (err.message === 'requestDevice cancelled.'){
console.log('Do nothing with requestDevice cancellation request');
}
}
}
It seems that I have the same problems with some devices (in my case Samsung A41 and google pixel3 but he work on pixel5 and 6). I think other devices will soon have the same problem. My app has been downloaded over 100 times, so it's very device specific. (This bug is only on Android 11 too) I will try your code but I don't have these problematic phone in my possession.
Turns out I’m having similar issue with the bleClient write function too. Anyone else experienced timeout error with write?
Hi , i relaunch this subject, I try the code with multiple connect but its not the solution to my side. I use the method requestLEScan().
With over 50 differents android phone is ok but i have 3 phones that not working. I have tell to my client to download BleScanner (on the problematic phone) to see if my product are visible. And with this application is OK, we found my product. Its not working in android 12 equally.
With apple, no problem.
Someone see this problem?
Here's a leaner, observables based, code to connect that is now working for me consistently:
To connect to peripheral with BLE:
connectToDevice(){
const connectToDevice$: Observable<void> =
from(BleClient.requestDevice()).pipe(
mergeMap(resp => from(BleClient.connect(resp.deviceId))),
retry(5),
catchError(error => {
if(error.message !== 'requestDevice cancelled.'){
throw new Error('Unable to connect');
} else{
throw new Error(error.message);
}
})
);
return connectToDevice$;
}
To write to peripheral device using BLE:
write(connectedDeviceId: string, endpoint: string, payload: any){
const characteristicUUID = this.mapCharacteristic(endpoint);
const write$ = of(this.mapCharacteristic(endpoint)).pipe(
concatMap(resp => BleClient.write(connectedDeviceId, this.baseUUID, resp, payload)),
retry(5),
map(resp => 'success')
);
return write$;
}
You can then subscribe to the return values from these functions (they both return observables) wherever they're being called. Each of these functions tries to connect (or write) up to 5 times, and if it still fails, then throws an error. Let us know if you're able to resolve your issue with this construct.
Karunt, i done a code similar to you with retry who increase my reliabilty to the connection, so is a good point.
In my case, the problems comes to the geolocalisation. In fact, even i ask to activate this last one, if directly, in the phone, the geolocalisation are deactivate, the scan dont working (with requestLEScan in my case). So when customers activate natively in our phone the geolocalisation, is OK for me and no problems to connect
Thanks for the code anyway.
Hi all, I'm still facing the above issue on Android 13 (API 33, OnePlus 10T 5G). I'm coding on Ionic-React and building the app with Capacitor to test an android version of that. After successfully scan with BleClient.requestDevice() I get stuck on BleClient.connect() getting a Connection Timeout error. I cannot figure out why in other devices (a Samsung A510F with Android 10, API 29) the connect method perfectly works. Can anyone please help meee? :)
Currently I don't see how this could be fixed in the plugin, as it's an issue with specific Android devices. Therefore I'm closing this issue for now. If anyone has an idea how this could be fixed, let me know and I'm happy to take another look.
You could build in a fail-safe code/check into the plugin that re-attempts a connection in case a device specific issue causes the connection to not proceed the first time around. This way individual programmers don't have to build in their own fail safe code, especially since you know that there are several devices that are experiencing this issue. On Sunday, April 2, 2023 at 11:42:15 AM EDT, Patrick Wespi @.***> wrote:
Currently I don't see how this could be fixed in the plugin, as it's an issue with specific Android devices. Therefore I'm closing this issue for now. If anyone has an idea how this could be fixed, let me know and I'm happy to take another look.
— Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you commented.Message ID: @.***>