bluetooth low energy notification - android

i am trying to read temperature value from health profile.health thermometer service. according to official google ble devlopment page when i try to notify a health thermometer characteristic to read temperature i try to write descriptor value (Client Characteristic Configuration) using writeDescriptor a callback method of writeDescriptor return status 5 according to google it's GATT_INSUFFICIENT_AUTHENTICATION.
so i comment the code of writedescriptor and try to call the method mBluetoothGatt.setCharacteristicNotification(characteristic, enabled); but onCharacteristicChanged method never called. when i talk to my ios devloper team. they said that they never write a descriptor value they just set the notification to true and they get temperature value from the same chip.
to write a descriptor value is necessary for android developer to get notification ???
so at last i try to run the official bluetooth app from the bluetooth.com site for test purpose they just disable all three buttons notify read and write???
thank you and sorry for my English
[UPDATE]
find out some log which may cause some bonding issues please help me if you have any solution for that.
Short-Term Key generated still log as error
11-08 11:26:44.392: E/bt-smp(1014): STK Generated
after that bond state change dramatically may this cause insufficient authentication
11-08 11:26:49.437: I/BluetoothBondStateMachine(1014): bondStateChangeCallback: Status: 0 Address: 00:16:A4:C0:FF:EE newState: 2
11-08 11:26:49.437: D/BtGatt.btif(1014): btif_gattc_upstreams_evt: Event 9
11-08 11:26:49.437: E/BluetoothBondStateMachine(1014): In stable state, received invalid newState: 12
[UPDATE]
after upgrading kitkat 4.4 on nexus 7 . add two method
device.createBond();
device.setPairingConfirmation(true);
works for me now i can read the encrypted characteristic. but still unstable. but some success i got.

Yes, in Android for enabling BLE notification, you must both call mBluetoothGatt.setCharacteristicNotification(characteristic, enabled) and write suitable value to descriptor 0x2902 of that characteristic.
I am not sure why you get GATT_INSUFFICIENT_AUTHENTICATION, this may be caused by the implementation of the thermometer.
EDIT :
From the new information in the comment and also the screen captured provided, there are a few things you may want to check :
The characteristic is a indication characteristic, but not a notification characteristic. The value you write to the descriptor should be BluetoothGattDescriptor.ENABLE_INDICATION_VALUE, but not BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE. Notice that you still need to turn on the indication by setCharacteristicNotification(). (Confusing terminology here, but it is necessary as per the docs)
For the unstable Bluetooth stack on Android, try to restart the Bluetooth, and turn of WiFi. This will increase the stability. (Although not 100% solving the problem)

In my case the problem was that BluetoothGatt object can accept only one pending operation. Solution was to do read/write operations in sequence, waiting for the completion callback of first before requesting second read/write operation.

Related

Ble device is not pairing consistently to phone

I have a ble device that I need to regularly extract data from securely and constantly. So on startup I want to make sure to bond the device if it is not already. I have the Mac address of the device in this case.
public void startApp(){
remoteDevice = bluetoothManager.getAdapter().getRemoteDevice(MAC_AD);
if(remoteDevice.getBondState()!=12){
remoteDevice.createBond();
}
}
What ends up happening is that the bond state will alternate between unbonded and currently_bonding but not fully bond.
The strange thing is that sometimes it will work, but usually not, particularly on my google pixel. Bonding through the settings is also very inconsistent.
Is there any way to retry this or some kind of Bluetooth reset that should be done so that I can bond consistently?
I've tried calling createBond() in intervals;
I've often found that calling createBond() directly can have hit-and-miss results depending on the platform (both ends). Logically it should use the same mechanism internally, but I've tended to get better results by calling read on a simple characteristic which has bonded requirements.
It either successes - meaning your connection is bonded - and you can continue. Or it fails, which internally triggers the bonding, and then you can try again after a short delay, at which point it should now be bonded.

Bluetooth LE: Send "Handle Value Notification" to device

I'm trying to reproduce an ATT packet being sent to a Bluetooth LE device already connected to a phone.
Is this even possible?
I've figured out how the packet should look like, I'm just not able to wrap my head around GATT and how it translates to ATT in this specific case.
The wireshark dump looks like this:
localhost () remote () ATT 26 Sent Handle Value Notification, Handle: 0x0035 (Unknown)
Bluetooth Attribute Protocol
Opcode: Handle Value Notification (0x1b)
0... .... = Authentication Signature: False
.0.. .... = Command: False
..01 1011 = Method: Handle Value Notification (0x1b)
Handle: 0x0035 (Unknown)
Value: 0a0b313233343536373839303132
I've already figured out that the actual application payload here starts after the handle 0x0035, with 0x0a 0x0b being some custom control characters and everything afterwards a number (123456789012), exactly as I expected it to be.
How do I translate the "handle" to the GATT protocol? Is this done in Android GATT via UUIDs? If I loop over all services on that device a get a bunch of services, loads of characteristics, descriptors and I'm lost.
Oh, what I forgot to mention: None of the services and characteristics I get seem to be related to the handle 0x0035.
Is "getInstanceId" supposed to return the handle that will be used? Writing to writable characteristics on that device lead to Wireshark showing the handle value corresponding to the getInstanceId.
first thing you have to know is that in Android you can't use the Handles direktly as a developer. You have to deal with the UUIDs. in Wireshark when you have a look at the ATT Protocoll you should be able to see the UUID of the service and the characteristic when opening the Handle drop down. With this Information you should be able to detect the UUids you need.
https://developer.android.com/guide/topics/connectivity/bluetooth-le shows you how to send a value to a notification. In general you can use Constants for example to ebanle notifications. I guess if your server requires specific bytes you should be able to send them the same way.
Well, after inspecting logs and docs a little more I came to the conclusion that the remote device (which should provide serivces) here is actually using a server on the local host and this is a value notification sent from the host to the remote.

Not able to get a callback on onCharacteristicChanged in Android BLE

I am facing quite a peculiar problem.
I am programming on Android to get a reading from a BLE Blood pressure monitor(A&D UA 651). I am able to get the reading from the device on certain devices(galaxy S6, Note 2, Droid Turbo), but on other devices(like the Oneplus One, HTC Desire 810) etc, I am able to connect to the BP monitor, but cannot get a reading from it.
I followed the tutorial posted by Android here.
Write now, I am using setCharacteristicNotification() to alert me of any changes in characteristics. I am also writing the correct descriptor using:
descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);
mBluetoothGatt.writeDescriptor(descriptor);`
Here's the kicker. I've noticed that on the devices where I am not alerted of a change in the characteristic value, if I put a breakpoint inside the callback
onDescriptorWrite(), I am able to get the reading.
The status value in the callback is always 0 (irrespective of whether I can read the value on the characteristic or not.)
This lead me to thinking that I should induce a delay in this callback, but this seldom works.
If anyone has faced this issue before, please let me know. I've been stuck on this issue for quite some time now.
Thanks!

Why does setCharacteristicNotification() not actually enable notifications?

The BluetoothLeGatt Android BLE example contains the following code:
public void setCharacteristicNotification(BluetoothGattCharacteristic characteristic,
boolean enabled) {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
return;
}
mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);
// This is specific to Heart Rate Measurement.
if (UUID_HEART_RATE_MEASUREMENT.equals(characteristic.getUuid())) {
BluetoothGattDescriptor descriptor = characteristic.getDescriptor(
UUID.fromString(SampleGattAttributes.CLIENT_CHARACTERISTIC_CONFIG));
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
mBluetoothGatt.writeDescriptor(descriptor);
}
}
My question is basically, why is the marked code specific to Heart Rate Measurement? It seems like having a Client Characteristic Config Descriptor (CCCD) characteristic is the standard way to control characteristic notification, so why doesn't setCharacteristicNotification() take care of writing to it? And since it doesn't do that, what does setCharacteristicNotification() actually do?
I'm pretty new to BLE and there aren't any explanations of it on the internet that don't assume that you already understand it all! So don't assume I know what a CCCD or whatever is! It was difficult enough finding out what CCCD even stands for!
Edit: See also this answer which supports my understanding of CCCDs (and makes me continue to wonder why you have to write to them manually in Android when there is a function that looks like it should do that for you): https://devzone.nordicsemi.com/index.php/what-does-cccd-mean
I think is a litte bit late for give an answer but today I had the same doubt and I found a clear answer.
Using setCharacteristicNotification() you enable notification localy (on android device) and setting CCC descriptor to ENABLE_NOTIFICATION_VALUE you enable notification on ble peripheral. In fact for enabling CCC notification you have to use setValue() and writeDescriptor() that are methods used for writing characteristics (in this case characteristics descriptors) to remote device.
I found this on: http://processors.wiki.ti.com/index.php/SensorTag_User_Guide
Here is an excerpt from the O'Reilly book "Getting Started With Bluetooth Low Energy":
To enable notifications on Android, you normally have to locally
enable the notification for the particular characteristic you are
interested in.
Once that’s done, you also have to enable notifications on the peer
device by writing to the device’s client characteristic configuration
descriptor (CCCD)
I believe this answers your question.
So
mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);
refers to the first part
and
mBluetoothGatt.writeDescriptor(descriptor);
refers to the 2nd.
For future peoples coming across this, here's the best answer I could find:
By writing to the Client Characteristic Config descriptor, you, the client, are telling the BLE server to switch configurations. (This made no sense to me either initially, but in english:)
This tells the BLE device to switch modes (configurations) to actively gather and report changes to this characteristic instead of changing and only reporting when requested.
It's poorly named, but digging through the docs it appears this is also going to be used for other possible characteristic changes that the client might request: hence the confusing name.
https://developer.bluetooth.org/gatt/descriptors/Pages/DescriptorViewer.aspx?u=org.bluetooth.descriptor.gatt.client_characteristic_configuration.xml
This begs the question, why call BluetoothGatt.setCharacteristicNotification() if we're only going to duplicate our efforts by modifying the descriptor?! Digging through the BluetoothGatt source shows us that setCharacteristicNotification only prepares the local service to receive notifications, not to enable persistent updates.
I know it looks silly, but setting CCCD value is the only way you can tell the API whether you are going to turn on notification or indication.
Currently there is no setCharacteristicIndication. To enable indication, you have to call setCharacteristicNotification (confusing) and then write BluetoothGattDescriptor.ENABLE_INDICATION_VALUE to CCCD, similar to what you did to enable Notification.
All the other answers do not really answer the question.
My guess would be that the Android BLE team took the assumption an application could have more than one BluetoothGattCallback().
By splitting the notification enabling (and disabling) in two steps it would allow the BluetoothGattCallback observers to listen for GATT notification (only invoke setCharacteristicNotification()) - and leave only one BluetoothGattCallback implemention doing the write operations to the GATT server aka the BLE peripheral.
"The Client Characteristic Configuration descriptor defines how the characteristic may be configured by a specific client."

Android BLE 4.3 onDescriptorWrite returns status 128 on enabling characteristics notification

A question on enabling characteristics using the new android BLE 4.3:
I am not getting any notification from the BLE device though I enable notification on characteristics one by one asynchronously using a queue.
I also write the descriptor with UUID "00002902-0000-1000-8000-00805f9b34fb" with ENABLE_NOTIFICATION_VALUE.
I have followed the recommendation from Google sdk doc and as well suggestions from various forums.
By the way I get status = 128 on "onDescriptorWrite". Any idea as what this status means?
I went thru google code and did not see any info on this. Even the source code does not throw any light as how this status is being set.
Let me know if any of you have experienced this when you enabled notifications for the body media device. Also at times I get status 133 on descriptor write. I use latest Nexus 7 for my tests.
I had the same problem, and solved it by disabling and reenabling the bluetooth interface.
The Android BLE stack seems to be still immature and suffers from instability problems.
This error could be related to max threshold imposed by Android OS.
#define BTA_GATTC_NOTIF_REG_MAX 15
- for 4.3 max number of notification/indication is 4
- for 4.4 max number of notification/indication is 7
- for 5.0 max number of notification/indication is 15
https://groups.google.com/forum/#!topic/android-platform/FNHO5KB4sKI
https://android.googlesource.com/platform/external/bluetooth/bluedroid/+/android-5.0.2_r1/bta/gatt/bta_gattc_int.h
A very late answer, but this might prove valuable to anyone encountering status 128 (GATT_NO_RESOURCES) on a gatt.writedescriptor() call.
In my case status 128 showed up when trying to write a descriptor with a value of ENABLE_NOTIFICATION_VALUE for a characteristic that required a subscription for an indication via ENABLE_INDICATION_VALUE instead.
So instead of
BluetoothGattDescriptor descriptor = bluetoothGattCharacteristic.getDescriptor(DESCRIPTOR_UUID);
descriptor.setValue(ENABLE_NOTIFICATION_VALUE);
mGatt.writeDescriptor(descriptor);
going for
BluetoothGattDescriptor descriptor = bluetoothGattCharacteristic.getDescriptor(DESCRIPTOR_UUID);
descriptor.setValue(ENABLE_INDICATION_VALUE);
mGatt.writeDescriptor(descriptor);
Fixed the problem. I assume the other way around will produce the same error status 128.
I received this error when performing writeCharacteristic with the WriteNoResponse property. When I specify the WriteWithoutResponse argument for writeCharacteristic, the problem disappears.

Categories

Resources