2

I want to receive characteristic updates notifications from server to client. Both server and client are my android apps. There are a question and a problem.

  1. I have found a "solution" that I need to add this code to subscribe, but add where? On the server side or on the client side?

     val CCC_DESCRIPTOR_UUID = "00002902-0000-1000-8000-00805f9b34fb"
     deviceGatt.setCharacteristicNotification(characteristic, true)
     val desc = characteristic.getDescriptor(UUID.fromString(CCC_DESCRIPTOR_UUID))
     deviceGatt.writeDescriptor(desc, BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE)
    
  2. The problem is that there are no descriptors at all. When server hosts a characteristic I check and there are 0 descriptors. There should be a CCCD by default but there is no one. The same happens when client discovers a service. There are no descriptors connected to characteristic. Can I add one by myself?

Edited:

I have tried to implement according to advice. Without manual adding CCCD on the server side there are no descriptors visible on the client side. So, on the Server side we have:

gattServer!!.addService(generateGattService())
...
private fun generateGattService(): BluetoothGattService {
    val service = BluetoothGattService(GAME_UUID, BluetoothGattService.SERVICE_TYPE_PRIMARY)
    characteristic = BluetoothGattCharacteristic(
        MESSAGE_UUID,
        BluetoothGattCharacteristic.PROPERTY_WRITE or BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE,
        BluetoothGattCharacteristic.PERMISSION_WRITE
    )

    val CCC_DESCRIPTOR_UUID = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb")
    val cccd = BluetoothGattDescriptor(
        CCC_DESCRIPTOR_UUID,
        BluetoothGattDescriptor.PERMISSION_READ or BluetoothGattDescriptor.PERMISSION_WRITE
    )
    characteristic!!.addDescriptor(cccd)

    service.addCharacteristic(characteristic)

    return service
}

On the Client side we have:

private fun onConnected(discoveredGatt: BluetoothGatt){
    val service = discoveredGatt.getService(GAME_UUID)
    val messageCharacteristic = service.getCharacteristic(MESSAGE_UUID)

    discoveredGatt.setCharacteristicNotification(messageCharacteristic, true)

    val CCC_DESCRIPTOR_UUID = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb")
    val desc = messageCharacteristic.getDescriptor(CCC_DESCRIPTOR_UUID)
    //desc.value = BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE
    //discoveredGatt.writeDescriptor(desc)

    Log.i(TAG_CLIENT, "Connected C -> S")
}

There are 2 commented rows. Using debugger I got that this way there is a descriptor connected to characteristic. I can send messages C -> S but this descritor has null value. If we uncomment those 2 rows, there is a descriptor value but messages don't come from anyone to anyone.

P.S. Code to write C -> S:

characteristic.writeType = BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT
characteristic.value = msg
deviceGatt.writeCharacteristic(characteristic)

Code to write S -> C:

characteristic.writeType = BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT
characteristic.value = msg
gattServer.notifyCharacteristicChanged(deviceToNotify, characteristic, false)
ilya_kas
  • 159
  • 1
  • 6

2 Answers2

1

See below the answers to your two questions:-

  1. The setCharacteristicNotification() method is used to enable or disable notifications for a specific characteristic on a GATT server device. Therefore, this method should be added on the GATT client side, because it is the client that subscribes to notifications for a particular characteristic.

  2. As can be seen from this answer, you need the following to provide a notifiable characteristic on the GATT server side:-

a) Create a Bluetooth characteristic from your UUID:

public static final UUID NEW_SERVICE = UUID.fromString("0000ffff-0000-1000-8000-00805f9b34fb");
public static final UUID NEW_VALUE  = UUID.fromString("0000fffe-0000-1000-8000-00805f9b34fb");
BluetoothGattCharacteristic characteristic = gatt.getService(NEW_SERVICE).getCharacteristic(NEW_VALUE);

b) Enable notifications

gatt.setCharacteristicNotification(characteristic,true); 

c) Finally, set the CCCD to allow server initiated updates:-

public static final UUID CONFIG_DESCRIPTOR = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb");
BluetoothGattDescriptor desc = characteristic.getDescriptor(CONFIG_DESCRIPTOR);
desc.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
gatt.writeDescriptor(desc);

Below are some useful links for both GATT client and GATT server side:-

Youssif Saeed
  • 11,789
  • 4
  • 44
  • 72
  • Thanks for your answer. I got first question's answer but that the problem with second. I do literally the same and characteristic.getDescriptor(CONFIG_DESCRIPTOR) returns null because there are no descriptors at all – ilya_kas Feb 15 '23 at 08:10
  • What if you try the code below: BluetoothGattDescriptor cccd = new BluetoothGattDescriptor(UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"), BluetoothGattDescriptor.PERMISSION_READ | BluetoothGattDescriptor.PERMISSION_WRITE); cccd.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE); characteristic.addDescriptor(cccd); More information in this link: https://www.tabnine.com/code/java/classes/android.bluetooth.BluetoothGattDescriptor – Youssif Saeed Feb 15 '23 at 09:16
  • Should I add this on the server side? Because I have tried it on the client's and now there is a descriptor but notifications still don't appear – ilya_kas Feb 15 '23 at 10:52
  • This should be added on the server side - so replacing point (c) above. – Youssif Saeed Feb 15 '23 at 11:11
  • Still no helping effect. Check "Edited" section please – ilya_kas Feb 16 '23 at 14:15
0

Finally I have found a solution. Posting here for the case if someone face the same.

So there are steps to enable notifications:

  1. Server hosts:

    val service = BluetoothGattService(GAME_UUID, BluetoothGattService.SERVICE_TYPE_PRIMARY)
    characteristic = BluetoothGattCharacteristic(
              MESSAGE_UUID,
              BluetoothGattCharacteristic.PROPERTY_READ or  BluetoothGattCharacteristic.PROPERTY_WRITE or  BluetoothGattCharacteristic.PROPERTY_NOTIFY,
              BluetoothGattCharacteristic.PERMISSION_READ or  BluetoothGattCharacteristic.PERMISSION_WRITE)
    
    val CCC_DESCRIPTOR_UUID = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb")
    val cccd = BluetoothGattDescriptor(
        CCC_DESCRIPTOR_UUID,
        BluetoothGattDescriptor.PERMISSION_READ or BluetoothGattDescriptor.PERMISSION_WRITE)
    characteristic!!.addDescriptor(cccd)
    
    service.addCharacteristic(characteristic)
    
  1. Server GattCallbacck overrides onDescriptorReadRequest and onDescriptorWriteRequest with lines respectively

    server.gattServer!!.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, 0, BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE)
    

    and

    server.gattServer!!.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, 0, null)
    
  2. Client does:

    val CCC_DESCRIPTOR_UUID = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb")
    val desc = messageCharacteristic.getDescriptor(CCC_DESCRIPTOR_UUID)
    discoveredGatt.setCharacteristicNotification(messageCharacteristic, true)
    desc.value = BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE
    discoveredGatt.writeDescriptor(desc)
    
  3. GattCallback overrides DEPRECATED!!! version of onCharacteristicChanged:

    override fun onCharacteristicChanged(gatt: BluetoothGatt?, characteristic: BluetoothGattCharacteristic?)
    

https://github.com/alexanderlavrushko/BLEProof-collection was very helpful but requires few scanning fixes to work.

ilya_kas
  • 159
  • 1
  • 6