I am working on an android application which reads data from a BLE device. I came across plenty of solutions here on how to read multiple characteristics and most of them suggested Queues.
I did implement the Queue method and everything is working fine in my code as expected. The reason why i started this thread is to find the best possible and most efficient solution and also to clear some of my doubts regarding how certain BLE service characteristics work.
I have taken the below two links as reference which helped me in making my code work.
Source 1:
Android: BLE how to read multiple Characteristics?
Source 2:
Android BLE API: GATT Notification not received
My requirement was to read the heart rate measurement & battery level. Initially i tried adding the heart rate & battery characteristics into a Queue and then call read/set methods for each of the added elements.
MainActivity:
private void displayGattServices(List<BluetoothGattService> gattServices)
{
// get the required service & characteristics
................
................
// add the characteristics via Queue
hRM_characteristicReadQueue.add(characteristics);
// Initiate read/set methods
read_Characteristic();
};
private void read_Characteristic()
{
bluetoothHDPService.read(hRM_characteristicReadQueue.element());
bluetoothHDPService.set(hRM_characteristicReadQueue.element(),true);
hRM_characteristicReadQueue.remove();
};
bluetoothHDPService:
public void read(BluetoothGattCharacteristic characteristic)
{
if (bluetoothAdapter == null || bluetoothGatt == null)
{
Log.w(TAG, "BluetoothAdapter not initialized");
return;
};
bluetoothGatt.readCharacteristic(characteristic);
};
public void set(BluetoothGattCharacteristic characteristic, boolean enabled)
{
if(bluetoothAdapter == null || bluetoothGatt == null)
{
Log.w(TAG, "BluetoothAdapter not initialized");
return;
};
bluetoothGatt.setCharacteristicNotification(characteristic, enabled);
BluetoothGattDescriptor descriptor = characteristic.getDescriptor(CLIENT_UUID);
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
bluetoothGatt.writeDescriptor(descriptor);
};
Back at MainActivity: (Once the read characteristic BLE callback operation is triggered)
I used the Broadcast Receiver to read/set the next Queue element.
private final BroadcastReceiver gattUpdateReceiver = new BroadcastReceiver()
{
@Override
public void onReceive(Context context, Intent intent)
{
// TODO Auto-generated method stub
final String action = intent.getAction();
if (Service_HeartRateX_HDP.ACTION_GATT_CONNECTED.equals(action))
{
// Connection with the BLE device successful
................
................
}
else if (Service_HeartRateX_HDP.ACTION_GATT_DISCONNECTED.equals(action))
{
// BLE device is disconnected
................
................
}
else if (Service_HeartRateX_HDP.ACTION_GATT_SERVICES_DISCOVERED.equals(action))
{
displayGattServices(bluetoothHDPService.getSupportedGattServices());
}
else if (Service_HeartRateX_HDP.ACTION_DATA_AVAILABLE.equals(action))
{
Log.i(TAG, "Collecting data");
// Collecting the incoming data
displayData(intent.getStringExtra(Service_HeartRateX_HDP.HEART_DATA),
intent.getStringExtra(Service_HeartRateX_HDP.BATTERY_DATA));
if(hRM_characteristicReadQueue.size() > 0)
{
read_Characteristic();
};
};
};
};
The above code snippet worked correctly only for one characteristic (heart rate) BLE device continued sending the heart rate measurement data, while for the other characteristic (battery percentage) BLE device sent the battery percentage data only once. Please note that, the order of the Queue element was such that heart rate characteristic was read/set and removed from the Queue first followed by the battery characteristic.
Initially i thought the queue didn't work as expected and tried interchanging the characteristics order in the queue with battery percentage being the first element to be read/set and removed followed by the heart rate characteristic to see if the issue was indeed related to incorrect programming.
But it didn't turn out to be the case, as the BLE device did the same thing as before (continued sending the heart rate measurement data, while the battery percentage was sent only once).
So taking the above scenarios into consideration, i came to the conclusion that battery level percentage characteristic needs to be read/set every once in a while to force the BLE device to send its data. This was further aided by the below post where one developer had to use a timer thread to get the battery percentage updates regularly from the BLE device.
how to update the battery level for every 5seconds in ble in android
I was reluctant to use a timer thread in my code, since this was making my already complex code into complex infinity. I then added the below condition at read_Characteristic() method to overcome this problem.
@ MainActivity
// where hrmBattery_Characteristics is a temporary variable which holds the
// battery characteristics
if(hRM_characteristicReadQueue.element() != hrmBattery_Characteristics)
{
hRM_characteristicReadQueue.remove();
};
By doing so, battery characteristics is never removed from the Queue and read_Characteristic() method will be called every once in a while via the broadcast receiver (synchronous pattern is maintained). This currently works perfectly in my code, but i need the experts advice on whether this is correct.
Is this problem related only to the battery or other characteristics as well. Fortunately as of now i need data for only these two characteristics (heart rate measurement data & battery percentage).
I haven't tried for more than two characteristics since my BLE device has only limited set of features and these are the only two which are currently present in it.
Is this because of the BLE device inability to send large packets of data to the android device at a given stretch? The reason being, even though the above code is working fine there was never one instance where both the data (heart rate & battery percentage) were sent in the same stretch.
If someone can throw some light into this i would be greatly indebted.
Thanks in advance!