4
votes

I have an Android app that is trying to receive BLE notifications. The notifications make it to the iPhone so it appears to be a setup problem, not a GATT server issue.

In the Android app I am doing the following, which in my past experience, is all that was ever required.

1) Set the notification characteristic write-type to 2 (Write type default).

2) Set the notification characteristic to true

3) Set the descriptor to true

4) And this shouldn't be needed, but I have read it sometimes is, I read the characteristic

Here is a sample output from my logs:

GattCallback: BLE-Setting up notifications if possible

GattCallback: BLE-Attempting to find matching characteristics for notification setup
com.android.myapp I/BLEUtilsKt: BLE-Matching service found for service: 4880c12c-fdcb-4077-8920-a450d7f9b907

GattCallback: BLE-State set to: READ_CHARACTERISTIC

GattCallback: BLE-Notify changed. State is now set to: READ_CHARACTERISTIC

GattCallback: BLE-Setting write type on notification characteristic: FEC26EC4-6D71-4442-9F81-55BC21D658D6. Write type is: 2 (WRITE_TYPE_DEFAULT)

GattCallback: BLE-Attempting to set notification characteristic fec26ec4-6d71-4442-9f81-55bc21d658d6 to true

GattCallback: BLE-Characteristic notification set successfully for FEC26EC4-6D71-4442-9F81-55BC21D658D6

GattCallback: BLE-Now setting its descriptor: FEC26EC4-6D71-4442-9F81-55BC21D658D6

GattCallback: BLE-Enabling Client Characteristic Configuration Descriptor for characteristic: fec26ec4-6d71-4442-9f81-55bc21d658d6

GattCallback: BLE-Characteristic Configuration Descriptor write initiated on: 00002902-0000-1000-8000-00805f9b34fb

BleHandler: BLE-Read characteristic being set to: android.bluetooth.BluetoothGattCharacteristic@48fd37c

GattCallback: BLE-Descriptor 00002902-0000-1000-8000-00805F9B34FB written successfully as value [1, 0]

BleHandler: BLE-Priming the pump on GATT: android.bluetooth.BluetoothGatt@d54f120 on read characteristic: android.bluetooth.BluetoothGattCharacteristic@48fd37c

GattCallback: BLE-onCharacteristic Read hit

GattCallback: BLE-Characteristic read successfully. Entering decipherCharacteristicValue

I must be missing something but what I am doing here has worked in the past. Can anyone see what I'm doing wrong please?

Here is the raw code if it will help

private fun setUpNotifications() {

    Timber.i("BLE-Setting up notifications if possible")

    if(mBluetoothGatt == null) {
        Timber.w("BLE-Set up notifications attempted but gatt is still null")
        return
    }

    Timber.i("BLE-Attempting to find matching characteristics for notification setup")
    val matchingCharacteristics = findCharacteristics(mBluetoothGatt!!)

    mState = BleHandler.ConnectionState.READ_CHARACTERISTIC

    Timber.i("BLE-State set to: $mState")

    notifyChanged()

    if(matchingCharacteristics.isEmpty()) {
        Timber.w("BLE-NO MATCHING CHARACTERISTICS FOUND")
        return
    }

    for (characteristic in matchingCharacteristics) {
        characteristic.writeType = BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT
        Timber.i("BLE-Setting write type on notification characteristic: ${characteristic.uuid.toString().toUpperCase(Locale.getDefault())}. Write type is: ${characteristic.writeType} (WRITE_TYPE_DEFAULT)")
        enableCharacteristicNotification(mBluetoothGatt!!, characteristic)

        Timber.i("BLE-Now setting its descriptor: ${characteristic.uuid.toString().toUpperCase(Locale.getDefault())}")
        enableCharacteristicConfigurationDescriptor(mBluetoothGatt!!, characteristic)
        mClientActionListener.setReadCharacteristic(characteristic)
    }
}

    private fun enableCharacteristicNotification(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic) {
    Timber.i("BLE-Attempting to set notification characteristic ${characteristic.uuid.toString()} to true")
    val characteristicWriteSuccess = gatt.setCharacteristicNotification(characteristic, true)

    if (characteristicWriteSuccess) {
        Timber.i("BLE-Characteristic notification set successfully for " + characteristic.uuid.toString().toUpperCase(Locale.getDefault()))
    }
    else {
        Timber.e("BLE-Characteristic notification set failure for " + characteristic.uuid.toString().toUpperCase(Locale.getDefault()))
    }
}

private fun enableCharacteristicConfigurationDescriptor(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic) {
    Timber.i("BLE-Enabling Client Characteristic Configuration Descriptor for characteristic: ${characteristic.uuid}")

    val descriptorList = characteristic.descriptors
    val descriptor = findClientConfigurationDescriptor(descriptorList)

    if (descriptor == null) {
        Timber.e("BLE-Unable to find Characteristic Configuration Descriptor")
        return
    }

    descriptor.value = BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE
    val descriptorWriteInitiated = gatt.writeDescriptor(descriptor)

    if (descriptorWriteInitiated) {
        Timber.i("BLE-Characteristic Configuration Descriptor write initiated on: " + descriptor.uuid.toString())
    }
    else {
        Timber.e("BLE-Characteristic Configuration Descriptor write failed to initiate: " + descriptor.uuid.toString())
    }
}

override fun onCharacteristicChanged(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic) {
    super.onCharacteristicChanged(gatt, characteristic)
    Timber.i("BLE-Characteristic change detected, " + characteristic.uuid.toString())
    decipherCharacteristicValue(characteristic)
} 

fun findClientConfigurationDescriptor(descriptorList: List<BluetoothGattDescriptor>): BluetoothGattDescriptor? {
for (descriptor in descriptorList) {
    if (isClientConfigurationDescriptor(descriptor)) {
        return descriptor
    }
}

return null

}

private fun isClientConfigurationDescriptor(descriptor: BluetoothGattDescriptor?): Boolean {
if (descriptor == null) {
    return false
}
val uuid = descriptor.uuid

if(uuid == CLIENT_CONFIGURATION_DESCRIPTOR) {
    return true
}

return false

val CLIENT_CONFIGURATION_DESCRIPTOR: UUID = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb")
1
Maybe you could post the code?Emil
Code posted as requested.user443654
You need to override onCharacteristicChanged in the BluetoothGattCallback. That's where the notifications will be delivered.Emil
It is. I updated the code to show it. That's the whole point though...I thought setting the characteristic, and descriptor then overriding onCharacteristicChange is all that I ever needed to do before. Doesn't seem to work for this device though.user443654
I assume you want to enable the notification for this UUID-FEC26EC4-6D71-4442-9F81-55BC21D658D6.In that case you should also set the descriptor.Then the oncharacteristicchanged will be triggered.Oooha

1 Answers

0
votes

It ended up that the BLE server had issues. Nothing wrong with the client code at all.