Search code examples
javaandroidbluetooth-lowenergybluetooth-gattcharacteristics

Writing characteristic property check is always false Android BluetoothGatt class


I want to create an android application in order to connect and retrieve data from an ESP32 board as well as the ability to send values to the board using Bluetooth Low Energy communication.

I have an ESP32 board with BLE server inside.I've implemented a custom Service with the following characteristic.

/* define the characteristic and it's propeties */
BLECharacteristic dataCharacteristic(
    BLEUUID((uint16_t)0x1A00),
    BLECharacteristic::PROPERTY_READ |
    BLECharacteristic::PROPERTY_WRITE |    
    BLECharacteristic::PROPERTY_NOTIFY);

I successfully implemented all the scanning, reading and notifying functions inside the android application but when it comes to writing BluetoothGatt.writeCharacteristic always returns false in the first Condition:

  if ((characteristic.getProperties() & BluetoothGattCharacteristic.PROPERTY_WRITE) == 0
                && (characteristic.getProperties()
                & BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE) == 0) {
            return false;
        }

While Debugging the android application the characteristic.getProperties() is always 18.

 public boolean writeCharacteristic(BluetoothGattCharacteristic characteristic) {
        if ((characteristic.getProperties() & BluetoothGattCharacteristic.PROPERTY_WRITE) == 0
                && (characteristic.getProperties()
                & BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE) == 0) {
            return false;
        }

        if (VDBG) Log.d(TAG, "writeCharacteristic() - uuid: " + characteristic.getUuid());
        if (mService == null || mClientIf == 0 || characteristic.getValue() == null) return false;

        BluetoothGattService service = characteristic.getService();
        if (service == null) return false;

        BluetoothDevice device = service.getDevice();
        if (device == null) return false;

        synchronized (mDeviceBusy) {
            if (mDeviceBusy) return false;
            mDeviceBusy = true;
        }

        try {
            mService.writeCharacteristic(mClientIf, device.getAddress(),
                    characteristic.getInstanceId(), characteristic.getWriteType(),
                    AUTHENTICATION_NONE, characteristic.getValue());
        } catch (RemoteException e) {
            Log.e(TAG, "", e);
            mDeviceBusy = false;
            return false;
        }

        return true;
    }

Here is the write characteristic code that uses the above function:

            //Get BLE Service
            BluetoothGattService service = gatt.getService(SERVICE_UUID);

            //Get the characteristic
            BluetoothGattCharacteristic dataCharacteristic = 
            service.getCharacteristic(DATA_CHARACTERISTIC_UUID);

            //Pass value
            dataCharacteristic.setValue(value);

            //Write characteristic
            boolean success = gatt.writeCharacteristic(dataCharacteristic);

            if(success){
                Log.d(TAG, "Write characteristic successful");
            }
            else{
                Log.e(TAG, "Write characteristic failed");
            }

I have already tried executing write operation without the read or notify, to prevent multiple requests, but the result is the same.

I also tried using external BLE applications with read write notify functionality and they all worked perfectly with my ESP32 setup.


Solution

  • After a lot of searching and experimenting with various ways of implementing the above communication of an android application and an ESP32 board with BLE server inside, I was able to find the solution.

    In all my tests I used UUIDs in the following way:

    Declaring characteristic uuid inside ESP32

    Characteristic_UUID = BLEUUID((uint16_t) 0x1A00))
    

    And Searching this uuid from android using

    Characteristic _UUID = convertFromInteger (0x1A00)
    

    convertFromInteger function:

        public UUID convertFromInteger (int i) 
        {
            final long MSB = 0x0000000000001000L;
            final long LSB = 0x800000805f9b34fbL;
            long value = i & 0xFFFFFFFF;
            return new UUID (MSB | (value << 32), LSB);
        }
    

    The solution was found when I followed a tutorial in which I noticed the uuids and the differences with the ones I used.When I replaced my old uuids with randomly generated uuid such as "cff6dbb0-996f-427b-9618-9e131a1d6d3f", the whole writeCharacteristic process for BLE server was done without any problem.