Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Read Characteristic from rxBleDevice gives exception in Android, in iOS why it works fine using same UUID? #635

Closed
anikdey opened this issue Oct 25, 2019 · 5 comments
Labels
question / library Issue containing question / discussion about library workings

Comments

@anikdey
Copy link

anikdey commented Oct 25, 2019

Currently i am working with an application where it involves reading data from the ble device. I am trying to read data from Andesfit Thermometer, Andesfit Blood Pressure, Andesfit Body Weight Scale.

For that i need to notify using Characteristic UUID. The notification stuff works fine and i am receiving data properly when any of the devices emits data.

Think about a situation where the user has already taken a measurement using the blood pressure machine. Then he picked up his device, got connected. I should be able to retrieve the last record and show it in the device.

In order to show the last record i need to read the characteristic using UUID

In iOS i am can retrieve the last record & notify using the same characteristic UUID and it is working fine.

 characteristic UUID is 2A1C

 peripheral.setNotifyValue(true, for: characteristic)
 peripheral.readValue(for: characteristic)

But in Android if i try to read using the characteristic UUID that used for notify it gives me exception.

rxBleDevice.establishConnection(false, Timeout(12000, TimeUnit.MILLISECONDS))
                .flatMapSingle { rxBleConnection ->

                    rxBleConnection.readCharacteristic(UUID.fromString("00002a1c-0000-1000-8000-00805f9b34fb"))
                        .subscribe({bytes ->

                    },{t: Throwable? ->
                        var mess = t!!.localizedMessage
                        t.printStackTrace()
                    })

Exception message is

GATT exception from MAC address F4:5E:AB:0D:7B:93, with type BleGattOperation{description='CHARACTERISTIC_READ'}

Here is my service discovery operation in Android

In my service discovery i can clearly see that this characteristic UUID is just meant for notify.

V/RxBle#ServiceDiscoveryOperation: Primary Service - Health Thermometer (00001809-0000-1000-8000-00805f9b34fb)
V/RxBle#ServiceDiscoveryOperation: Instance ID: 51
V/RxBle#ServiceDiscoveryOperation: -> Characteristics:
V/RxBle#ServiceDiscoveryOperation:  * Temperature Measurement (00002a1c-0000-1000-8000-00805f9b34fb)
V/RxBle#ServiceDiscoveryOperation:    Properties: [ INDICATE ]
V/RxBle#ServiceDiscoveryOperation:    -> Descriptors: 
V/RxBle#ServiceDiscoveryOperation:      * Client Characteristic Configuration (00002902-0000-1000-8000-00805f9b34fb)
V/RxBle#ServiceDiscoveryOperation:      * Characteristic Presentation Format (00002904-0000-1000-8000-00805f9b34fb)
V/RxBle#ServiceDiscoveryOperation:  * Temperature Type (00002a1d-0000-1000-8000-00805f9b34fb)
V/RxBle#ServiceDiscoveryOperation:    Properties: [ READ ]
V/RxBle#ServiceDiscoveryOperation:  * Intermediate Temperature (00002a1e-0000-1000-8000-00805f9b34fb)
V/RxBle#ServiceDiscoveryOperation:    Properties: [ NOTIFY ]
V/RxBle#ServiceDiscoveryOperation:    -> Descriptors: 
V/RxBle#ServiceDiscoveryOperation:      * Client Characteristic Configuration (00002902-0000-1000-8000-00805f9b34fb)
V/RxBle#ServiceDiscoveryOperation:  * Measurement Interval (00002a21-0000-1000-8000-00805f9b34fb)
V/RxBle#ServiceDiscoveryOperation:    Properties: [ READ WRITE INDICATE ]
V/RxBle#ServiceDiscoveryOperation:    -> Descriptors: 
V/RxBle#ServiceDiscoveryOperation:      * Client Characteristic Configuration (00002902-0000-1000-8000-00805f9b34fb)
V/RxBle#ServiceDiscoveryOperation:      * Valid Range (00002906-0000-1000-8000-00805f9b34fb)
V/RxBle#ServiceDiscoveryOperation: Primary Service - Battery Service (0000180f-0000-1000-8000-00805f9b34fb)
V/RxBle#ServiceDiscoveryOperation: Instance ID: 65
V/RxBle#ServiceDiscoveryOperation: -> Characteristics:
V/RxBle#ServiceDiscoveryOperation:  * Battery Level (00002a19-0000-1000-8000-00805f9b34fb)
V/RxBle#ServiceDiscoveryOperation:    Properties: [ READ NOTIFY ]
V/RxBle#ServiceDiscoveryOperation:    -> Descriptors: 
V/RxBle#ServiceDiscoveryOperation:      * Client Characteristic Configuration (00002902-0000-1000-8000-00805f9b34fb)
V/RxBle#ServiceDiscoveryOperation:      * Report Reference (00002908-0000-1000-8000-00805f9b34fb)
V/RxBle#ServiceDiscoveryOperation: --------------- ====== Finished peripheral content ======
@dariuszseweryn
Copy link
Owner

dariuszseweryn commented Oct 25, 2019

In the logs you should see a warning that says that you want to perform operation that is not supported by this characteristic. Android does not allow it and therefore you get an exception. iOS handles this differently. You could try override properties of the characteristic and report back if it worked.

Link to related SO question

@dariuszseweryn dariuszseweryn added the question / library Issue containing question / discussion about library workings label Oct 25, 2019
@anikdey
Copy link
Author

anikdey commented Oct 28, 2019

You could try override properties of the characteristic and report back if it worked.
I have no idea how to override properties of the characteristic. Can you explain me a little bit. Do i need to override properties of the characteristic on the physical device or from Android source code. How should i approach it? Thanks.

@dariuszseweryn
Copy link
Owner

I could imagine that you could try to override characteristic properties by some reflection hack and / or inheriting from it and overriding getters. No specifics though. I do not have time by myself to tinker with it.

@dariuszseweryn
Copy link
Owner

dariuszseweryn commented Nov 12, 2019

I have tried to override characteristics permissions like this:

connection.discoverServices()
    .flatMap { it.getCharacteristic(UUID.fromString("6E400002-B5A3-F393-E0A9-E50E24DCCA9E")) }
    .flatMap { originalCharacteristic ->
        class MyBluetoothGattCharacteristic : BluetoothGattCharacteristic(
            originalCharacteristic.uuid,
            originalCharacteristic.properties or PROPERTY_WRITE,
            originalCharacteristic.permissions
        ) {
            override fun getWriteType(): Int {
                return originalCharacteristic.writeType
            }

            override fun setValue(value: ByteArray?): Boolean {
                return originalCharacteristic.setValue(value)
            }

            override fun getDescriptors(): MutableList<BluetoothGattDescriptor> {
                return originalCharacteristic.descriptors
            }

            override fun getUuid(): UUID {
                return originalCharacteristic.uuid
            }

            override fun setWriteType(writeType: Int) {
                originalCharacteristic.writeType = writeType
            }

            override fun getPermissions(): Int {
                return originalCharacteristic.permissions or PROPERTY_WRITE
            }

            override fun getProperties(): Int {
                return originalCharacteristic.properties or PROPERTY_WRITE
            }

            override fun getService(): BluetoothGattService {
                return originalCharacteristic.service
            }

            override fun getInstanceId(): Int {
                return originalCharacteristic.instanceId
            }

            override fun getValue(): ByteArray {
                return originalCharacteristic.value
            }
        }
        val bgc = MyBluetoothGattCharacteristic()
        connection.writeCharacteristic(bgc, byteArrayOf(0x01))
    }

This was accepted by bluetoothGatt.writeCharacteristic(BluetoothGattCharacteristic) by returning true but it did not seem to reach the HCI and the BluetoothGattCallback.onCharacteristicWrite() was never called. Tested on Google Pixel / Android 10 / 1.10.4.

TL;DR — only characteristic with properly set permissions may be interacted by Android OS.

I have tried on a wrongly implemented peripheral. The above approach works.

@dariuszseweryn
Copy link
Owner

I have updated my previous comment

@dariuszseweryn dariuszseweryn added enhancement question / library Issue containing question / discussion about library workings and removed question / library Issue containing question / discussion about library workings enhancement labels Nov 13, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question / library Issue containing question / discussion about library workings
Projects
None yet
Development

No branches or pull requests

2 participants