Reputation: 21
I use following code to enable notification on android device using kotlin: with this code notifications get enabled, but i am not recieving notification even when data changes on the device. I am not recieving any error, i am so confused as i am developing my first ble app. I don't know what more details i could include
is EnableNotifications -> with(operation) {
gatt.findCharacteristic(characteristicUuid)?.let { characteristic ->
val cccdUuid = UUID.fromString(CCC_DESCRIPTOR_UUID)
val payload = when {
characteristic.isIndicatable() ->
BluetoothGattDescriptor.ENABLE_INDICATION_VALUE
characteristic.isNotifiable() ->
BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE
else ->
error("${characteristic.uuid} doesn't support notifications/indications")
}
characteristic.getDescriptor(cccdUuid)?.let { cccDescriptor ->
if (!gatt.setCharacteristicNotification(characteristic, true)) {
Timber.e("setCharacteristicNotification failed for ${characteristic.uuid}")
signalEndOfOperation()
return
}
cccDescriptor.value = payload
gatt.writeDescriptor(cccDescriptor)
}}
//which is writing descriptor as follows:
override fun onDescriptorWrite(
gatt: BluetoothGatt,
descriptor: BluetoothGattDescriptor,
status: Int
) {
with(descriptor) {
when (status) {
BluetoothGatt.GATT_SUCCESS -> {
Timber.i("Wrote to descriptor $uuid | value: ${value.toHexString()}")
if (isCccd()) {
onCccdWrite(gatt, value, characteristic)
} else {
listeners.forEach {
it.get()?.onDescriptorWrite?.invoke(
gatt.device,
this
)
}
}
}
BluetoothGatt.GATT_WRITE_NOT_PERMITTED -> {
Timber.e("Write not permitted for $uuid!")
}
else -> {
Timber.e("Descriptor write failed for $uuid, error: $status")
}
and then on characteristic changed the following code get used:
override fun onCharacteristicChanged(
gatt: BluetoothGatt,
characteristic: BluetoothGattCharacteristic
) {
with(characteristic) {
super.onCharacteristicChanged(gatt, characteristic)
Timber.i("Characteristic $uuid changed | value: ${value.toHexString()}")
listeners.forEach {
it.get()?.onCharacteristicChanged?.invoke(gatt.device, this)
}
}
}
As above code is written in manager class, I am calling this with following code from activity which need to recieve notification:
val characteristicNotify = BluetoothGattCharacteristic(
char_uuid, BluetoothGattCharacteristic.PROPERTY_NOTIFY ,
1
)
Manager.enableNotifications(device, characteristicNotify)
Upvotes: 2
Views: 2509
Reputation: 420
With API level 33 (Android 13) some new bluetooth apis were added. For example the following method on BluetoothGattCallback:
public void onCharacteristicChanged (BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic,
byte[] value)
If you override this method in your ble callback and run your app on an older device (i.e on android 11) you won't be notified of characteristic changes.
Upvotes: 1
Reputation: 838
The code which subscribes to notifications looks good, because it finds available characteristic from BluetoothGatt, checks if it supports subscription, calls gatt.setCharacteristicNotification
and then gatt.writeDescriptor
.
It's difficult to say from your part of code, but I guess these lines don't do what you expect, because this is how you should create characteristic on Peripheral side, not Central:
// Central should get the existing characteristic from BluetoothGatt
// but this code creates a new characteristic
val characteristicNotify = BluetoothGattCharacteristic(
char_uuid, BluetoothGattCharacteristic.PROPERTY_NOTIFY ,
1
)
Manager.enableNotifications(device, characteristicNotify)
Central should use characteristics provided by the discovered BluetoothGattService (available after BluetoothGattCallback.onServicesDiscovered
), but not create new characteristics.
This example of subscribing to indications may be useful: BLEProof: MainActivity.kt:351 on github
Also I suggest to ensure that the Peripheral you are connecting to is sending notifications properly - using one of these Android apps: LightBlue, BLE Scanner, you can manually scan for your Peripheral, discover services and subscribe to your characteristic, just to be sure that Peripheral works as expected.
Upvotes: 1