I am trying to write a Bluetooth LE app that accesses a Zephyr HxM Smart heart monitor. This monitor has several Bluetooth services, but I am interested in the Battery Service, Heart Rate Service, and a Custom Service that has Activity and Peak Acceleration. There is one characteristic for each, Battery Level, (BAT), Heart Rate Measurement (HR), and Custom Measurement (CUS). The HxM updates about once per sec.
I am doing this with a Galaxy S4 with Android 4.4.
It is not working as expected from the documentation.
My initial approach was to do:
Read BAT
Set notification for HR
Set notification for CUS.
Then wait for the callbacks. Setting notification means calling
BluetoothGatt.setCharacteristicNotification(Characteristic char , boolean enabled)
(One could also do notification for BAT, however, the spec does not require this to be supported. The HxM, however, does support it.)
This didn't work. I got BAT and notifications for HR, but not CUS. If I eliminated the second step, I got notifications for CUS. I couldn't get both. (This indicates I am reading the characteristics correctly, so that is [probably] not the problem.)
I found some indications there were problems with the Bluetooth stack for Android being synchronous, but no hard documentation. I then tried the following:
Read BAT.
Wait for the BAT reading, then set notification for HR,
Get HR, then disable notification for HR, and start notification for CUS.
Get CUS, then disable notification for CUS, and start notification for HR.
And continue to loop.
I got BAT and that is all.
By trial and error, I discovered the following works:
Read BAT.
Wait for the BAT reading, then set notification for HR,
Get HR, then start notification for CUS.
Get CUS, then start notification for HR.
And continue to loop.
(Same as above but without disabling notifications.) Typically, I get a HR reading, then the CUS one within 200 ms. One can assume they are from the same update. (There are no timestamps in the data, which have to be kept short to be LE.) In reality the logic is more complicated, as timers are necessary in case expected readings don't come in. This logic is FAR more complicated (and more prone to error) than my first try, which is what the documentation seems to say is what is appropriate.
I have contacted Zephyr, and they say the HxM Smart has been extensively tested on Windows, and will do simultaneous notifications as it should. There are also indications it works as it should on iOS.
There is a further problem that I do not understand. In order to get notifications, you have to enable the Characteristics locally for notification with something like:
BluetoothGattDescriptor descriptor = characteristic
.getDescriptor(UUID_CLIENT_CHARACTERISTIC_CONFIG);
resSet = descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
resWrite = mBluetoothGatt.writeDescriptor(descriptor);
This is a per characteristic setting, and should only need to be done once, when the characteristic is first received. Instead, I find I have to do it every time I set the notifications. It is possible this just causes a sufficient time delay for things to work. I don't know. This trial and error is taking a lot of my time. It would be nice to have a definitive statement of how it works.
I should note that for all calls that return a result, the result is true (success).
I apologize for the long statement. My question is:
I find no documentation that I have to do the things described. All indications are that you set up notifications and wait for the callbacks. Is there documentation, or is this a bug, or just a bad implementation? (Or is it my error?) I would especially like to know where is the documentation for what I have had to do.
Second, there is a further complication. I have tried to debug into the routines to see what the code is actually doing. When I get to BluetoothGatt.class, the source lines don't match what the debug stack says. I thus assume that the S4 is not using standard Android. I don't know where to go from there. It has been frustrating, and while I have something that appears to work, it is kludgy and almost certainly less robust.
Thanks for any help.
I had the same problem with writing multiple values in sequence, putting a Thread.sleep(200) in between them solved the problem (alas i should say). Maybe this helps as well with getting notifications. Tested this on android 4.4.2 on Nexus 5. And no, 4.4 does not solve all problems...
Im probably very late to this but you should implement a queuing architecture for setting up your characteristics to send notifications. I used a similar technique to miznick in the post https://stackoverflow.com/a/18207869/3314615 and ended up just writing wrapper code for the native BLE stack since there are several apps i use BLE for. Ever since then I have had no issues receiving notifications. I agree with you that the Android BLE documentation should have some sort of information or warning about the BLE Stack not being synchronous. Frankly, i believe it should be re-written to handle synchronous write calls and just queue them.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With