Harsimran Sandhu
Harsimran Sandhu

Reputation: 21

Not receiving notifications even when notifications are enabled for ble device

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

Answers (2)

paolo
paolo

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

alexander.cpp
alexander.cpp

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

Related Questions