After calling bleManager.discoverAllServicesAndCharacteristicsForDevice(), calling .services() on the returned bleDevice should return a non-empty list of services.
Calling .services() returns an empty array. This might be a pairing issue, since if I pair with the device via Android's bluetooth menu, it seems to connect without issue and properly returns a non-empty list of services. Restarting the phone also seems to "fix" the issue for me.
I assume this issue is related to https://github.com/Polidea/react-native-ble-plx/issues/488 and the "known bug". Calling connectToDevice() seems to work fine, and the resulting device has the correct name/id.
bleManager.connectToDevice().discoverAllServicesAndCharacteristicsForDevice() with the device or using bleManager..services() on the device.I think I have a related issue.
I am trying to find my device by serviceUUID and that does not work.
uuids = ["UUID_GOES_HERE"]
bluetoothManager.startDeviceScan(uuids, null, (error, device) => { }
The above code never finds anything.
If I remove the uuids argument to make it find everything, then manually filter on the MAC address to get the reported device object. Getting it's .serviceUUIDs also returns null.
My .name field is also empty on Discovery.
Hi!
Could you both install nRF Connect and check your devices with it? They both sound like implementation choices on its side.
There are devices that won't report any services unless they're paired.
A service doesn't have to be advertised and filtering by service UUID only works on those that are advertised. You can see the advertisement package on nRF Connect.
There are two names a device might use: .name and .localName. Both might not be set.
Hi!
Could you both install nRF Connect and check your devices with it? They both sound like implementation choices on its side.
There are devices that won't report any services unless they're paired.
A service doesn't have to be advertised and filtering by service UUID only works on those that are advertised. You can see the advertisement package on nRF Connect.There are two names a device might use:
.nameand.localName. Both might not be set.
Was just about to get back to this. My issue is resolved, it was a configuration problem on my end!
Could you share what configuration problem it was? It could be helpful for anyone else that would stumble upon this issue.
@justintim3 Could you adhere to the issue template, share the code and show native logs as described in the template?
Could you share what configuration problem it was? It could be helpful for anyone else that would stumble upon this issue.
I actually still don't know. I'm running a Bluez server. And whenever a connection request comes in it gets disconnected by the server. So a server side issue, unrelated to this library.
@justintim3 Could you adhere to the issue template, share the code and show native logs as described in the template?
const bleManager = new BleManager();
const foundDevices: Device[] = [];
const subscription = bleManager.onStateChange(async state => {
if (state === 'PoweredOn') {
setTimeout(async () => {
bleManager && bleManager.stopDeviceScan();
await parseClosestDevice(foundDevices);
subscription.remove();
}, 5000);
bleManager.startDeviceScan(
null,
null,
async (error, discoveredBleDevice) => {
if (error) {
console.log('Ble Manager error during scan: ', error);
} else {
if (
discoveredBleDevice?.serviceUUIDs?.includes(SERVICE_UUID) &&
!foundDevices.find(d => d.id === discoveredBleDevice.id)
) {
foundDevices.push(discoveredBleDevice);
}
}
},
);
subscription.remove();
}
});
const parseClosestDevice = async (devices: Device[]) => {
if (devices.length === 0) {
return;
}
devices.sort((a, b) => b.rssi - a.rssi);
const discoveredBleDevice = devices.find((a, i) => i === 0);
if (discoveredBleDevice) {
try {
if (discoveredBleDevice?.serviceUUIDs?.includes(SERVICE_UUID)) {
const connectedDevice: Device = await bleManager.connectToDevice(
discoveredBleDevice.id,
{timeout: Constant.CONNECTION_VALUES.connectWaitMs},
);
const dev = await bleManager.discoverAllServicesAndCharacteristicsForDevice(
connectedDevice.id,
);
const services = await dev.services();
}
} catch (error) {}
}
};
Additional comments/observations:
Some of our users have reported both an initial connection issue (the issue above) as well as a reconnection issue where after initial connection where everything works fine, after disconnection, they are unable to reconnect. Keep in mind that most of our users experiencing connection issues are using Samsung devices with Android 10 such as Galaxy S10/20 and Note 10. I don鈥檛 believe we鈥檝e had connection issues pre Android 10.
The above logs occurred during initial connection when the device was not paired. I鈥檝e personally experienced connection issues inconsistently. Sometimes it would initially pair and connect properly, while other times i would get the empty services array.
Although I think that the initial connection issue is related to pairing as I mentioned in my original post, I will say that the reconnection issue mentioned above obviously occurs after initial pairing, so it may not be just a pairing issue. I鈥檝e only personally experienced this a few times as it is difficult to reproduce, but I did notice that it also returned an empty services array. From my experiences testing this, restarting the app does not seem to fix either issue.
Try postponing service discovery for ~1600 ms when connecting to a bonded device and tell me if that fixes the issue.
Try postponing service discovery for ~1600 ms when connecting to a bonded device and tell me if that fixes the issue.
This does not seem to resolve the issue. I tested adjusting the timeout up to 10000 ms which still did not resolve the issue.
console.log('isConnected', await dev.isConnected());
await new Promise(resolve => setTimeout(resolve, 1600));
const services = await dev.services();
console.log('services', services);
LOG isConnected true
LOG services []
You do not call discoverAllServicesAndCharacteristicsForDevice() at all in the above snippet.
You do not call
discoverAllServicesAndCharacteristicsForDevice()at all in the above snippet.
The above snippet was implied to be inserted inside the initially shared code, so that the the console logs and new Promise surrounded the services call. Sorry if this was unclear.
...
const connectedDevice: Device = await bleManager.connectToDevice(
discoveredBleDevice.id,
{timeout: Constant.CONNECTION_VALUES.connectWaitMs},
);
const dev = await bleManager.discoverAllServicesAndCharacteristicsForDevice(
connectedDevice.id,
);
console.log('isConnected', await dev.isConnected());
await new Promise(resolve => setTimeout(resolve, 1600));
const services = await dev.services();
console.log('services', services);
...
So you are making no delay between connection and service discovery...
I tested it again today, with the suggested 1600 ms delay, this time between connection and service discovery and I still had an empty services array returned. I tested adjusting the delay as high as 4000 ms and it did not resolve the issue.
...
const connectedDevice: Device = await bleManager.connectToDevice(
discoveredBleDevice.id,
{timeout: Constant.CONNECTION_VALUES.connectWaitMs},
);
const dev = await bleManager.discoverAllServicesAndCharacteristicsForDevice(
connectedDevice.id,
);
...
const connectedDevice: Device = await bleManager.connectToDevice(
discoveredBleDevice.id,
{timeout: Constant.CONNECTION_VALUES.connectWaitMs},
);
await new Promise(resolve => setTimeout(resolve, 1600));
const dev = await bleManager.discoverAllServicesAndCharacteristicsForDevice(
connectedDevice.id,
);
const services = await dev.services();
...
Could you add more information according to the issue template? Especially native logs part.
Could you add more information according to the issue template? Especially native logs part.
This is basically the same as my initially shared code, but with the 1600 ms suggestion as well as extra console logs. I hope that helps.
console.log('+++++create ble manager');
const bleManager = new BleManager();
bleManager.setLogLevel('Verbose');
const foundDevices: Device[] = [];
const subscription = bleManager.onStateChange(async state => {
if (state === 'PoweredOn') {
setTimeout(async () => {
bleManager && bleManager.stopDeviceScan();
await parseClosestDevice(foundDevices);
subscription.remove();
}, 5000);
bleManager.startDeviceScan(
null,
null,
async (error, discoveredBleDevice) => {
if (error) {
console.log('Ble Manager error during scan: ', error);
} else {
if (
discoveredBleDevice?.serviceUUIDs?.includes(SERVICE_UUID) &&
!foundDevices.find(d => d.id === discoveredBleDevice.id)
) {
foundDevices.push(discoveredBleDevice);
}
}
},
);
subscription.remove();
}
});
const parseClosestDevice = async (devices: Device[]) => {
if (devices.length === 0) {
return;
}
devices.sort((a, b) => b.rssi - a.rssi);
const discoveredBleDevice = devices.find((a, i) => i === 0);
if (discoveredBleDevice) {
try {
if (discoveredBleDevice?.serviceUUIDs?.includes(SERVICE_UUID)) {
console.log(
'Trying to connect to device: id: ',
discoveredBleDevice.id,
' name: ',
discoveredBleDevice.name,
' rssi: ',
discoveredBleDevice.rssi,
);
const connectedDevice: Device = await bleManager.connectToDevice(
discoveredBleDevice.id,
{timeout: Constant.CONNECTION_VALUES.connectWaitMs},
);
console.log(
'before await new Promise(resolve => setTimeout(resolve, 1600))',
);
await new Promise(resolve => setTimeout(resolve, 1600));
console.log(
'before await bleManager.discoverAllServicesAndCharacteristicsForDevice()',
);
const dev = await bleManager.discoverAllServicesAndCharacteristicsForDevice(
connectedDevice.id,
);
console.log('before await dev.services()');
const services = await dev.services();
console.log('after await dev.services()', services);
...
}
} catch (error) {}
}
};
I see nothing more that can be done. You need to verify that your peripheral is correctly setup and it does indeed answer with some services during the service discovery process.
You could try switching BT off/on or rebooting your phone to see if the problem will persist.
I see nothing more that can be done. You need to verify that your peripheral is correctly setup and it does indeed answer with some services during the service discovery process.
You could try switching BT off/on or rebooting your phone to see if the problem will persist.
Just toggling BT off/on was not able to resolve the issue. Afterwards, I restarted the phone, and it was still not resolved. Toggling BT off/on again then was able to resolve the issue.
Do you have any thoughts why this combination works or what might be the underlying issue? If there is no issue with the library, is there some issue with Android 10 or Samsung software?
Also, what were your thoughts for the 1600ms delay as a possible solution?
Different Android BLE stack implementations tend to differ on when the BLE stack is being reset. Sometimes it is BT toggle, sometimes it is power cycle, formerly it could be BT + WiFi toggle.
Some implementations have bugs.
Also, what were your thoughts for the 1600ms delay as a possible solution?
Android starts to encrypt the connection after it gives the "connected" callback. If the app would query for services at that time it can get a stalled "cached" version instead of what is currently available on the peripheral. Weird things happens while the connection is reencrypted. Waiting for a bit gives the OS time to finish the procedure.