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")