4

If we call setCharacteristicNotification on a character, not giving Remote Notification on value Change? How to enable the remote Notification on a Central Device in Bluetooth LE ?

Code-Apprentice
  • 81,660
  • 23
  • 145
  • 268
sreekumar
  • 2,439
  • 1
  • 21
  • 27

3 Answers3

19

TO enable Remote Notification on Android,

setCharacteristicNotification(characteristic, enable) is not enough.

Need to write the descriptor for the characteristic. Peripheral has to enable characteristic notification while creating the characteristic.

Once the Notify is enabled , it will have a descriptor with handle 0x2902 . so we need to write BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE to the descriptor. First Convert 0x2902 to 128 bit UUID, it will be like this 00002902-0000-1000-8000-00805f9b34fb (Base Bluetooth UUID is 0000xxxx-0000-1000-8000-00805f9b34fb).

Code below

 protected static final UUID CHARACTERISTIC_UPDATE_NOTIFICATION_DESCRIPTOR_UUID = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb");


 * Enable Notification for characteristic
 *
 * @param bluetoothGatt
 * @param characteristic
 * @param enable
 * @return
 */
public boolean setCharacteristicNotification(BluetoothGatt bluetoothGatt, BluetoothGattCharacteristic characteristic,boolean enable) {
    Logger.d("setCharacteristicNotification");
    bluetoothGatt.setCharacteristicNotification(characteristic, enable);
    BluetoothGattDescriptor descriptor = characteristic.getDescriptor(CHARACTERISTIC_UPDATE_NOTIFICATION_DESCRIPTOR_UUID);
    descriptor.setValue(enable ? BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE : new byte[]{0x00, 0x00});
    return bluetoothGatt.writeDescriptor(descriptor); //descriptor write operation successfully started?

}
sreekumar
  • 2,439
  • 1
  • 21
  • 27
  • 2
    What if characteristic.getDescriptor(CHARACTERISTIC_UPDATE_NOTIFICATION_DESCRIPTOR_UUID) returns null? – swooby Jan 27 '16 at 00:47
  • 2
    Your answer is partially wrong: 0x2902 does not become available it is always there independent of enabled or not. Its value signalises whether indication, notification or none are enabled. 0x2902 is mandatory and should be present always. However some characteristics might be off spec and skip it, especially when they dont have indication / notification properties – paulgavrikov Feb 03 '16 at 16:26
  • Correcting myself: Characteristic is present if notify / indicate property set, otherwise not. – paulgavrikov Feb 03 '16 at 23:36
4

i also receive null value when call descrpitor.setValue, so i just turn it on when discovering service and finally it works very well:

to notify master device that some characteristic is change, call this function on your pheripheral:

private BluetoothGattServer server;
//init....

//on BluetoothGattServerCallback...

//call this after change the characteristic
server.notifyCharacteristicChanged(device, characteristic, false);

in your master device: enable setCharacteristicNotification after discover the service:

@Override
    public void onServicesDiscovered(BluetoothGatt gatt, int status) {
        super.onServicesDiscovered(gatt, status);
        services = mGatt.getServices();
        for(BluetoothGattService service : services){
            if( service.getUuid().equals(SERVICE_UUID)) {
                characteristicData = service.getCharacteristic(CHAR_UUID);
                for (BluetoothGattDescriptor descriptor : characteristicData.getDescriptors()) {
                    descriptor.setValue( BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);
                    mGatt.writeDescriptor(descriptor);
                }
                gatt.setCharacteristicNotification(characteristicData, true);
            }
        }
        if (dialog.isShowing()){
            mHandler.post(new Runnable() {
                @Override
                public void run() {
                    dialog.hide();
                }
            });
        }
   }

now you can check your characteristic value is change, for example onCharacteristicRead function :

@Override
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
        Log.i("onCharacteristicRead", characteristic.toString());
        byte[] value=characteristic.getValue();
        String v = new String(value);
        Log.i("onCharacteristicRead", "Value: " + v);
}
Doni
  • 576
  • 6
  • 9
2

To enable notification you should do as following.

mBluetoothLeService.setCharacteristicNotification(mSampleCharacteristic, true);

of which definition is as following.

if (enabled) {
            BluetoothGattDescriptor bluetoothGattDescriptor = characteristic.getDescriptor(UUID.fromString(SampleGattAttributes.CLIENT_CHARACTERISTIC_CONFIG));
            bluetoothGattDescriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE); 
            mBluetoothGatt.writeDescriptor(bluetoothGattDescriptor);
        } else {
            BluetoothGattDescriptor bluetoothGattDescriptor = characteristic.getDescriptor(UUID.fromString(SampleGattAttributes.CLIENT_CHARACTERISTIC_CONFIG));
            bluetoothGattDescriptor.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE); 
            mBluetoothGatt.writeDescriptor(bluetoothGattDescriptor);
        }

Still if remote notification does not work, try to read characteristics only after enabling notifications for the same.

Reading characteristics is as

mBluetoothLeService.readCharacteristic(eachChara);