Can't read Heart Rate in Xiaomi Band 2 - android

I was trying to read Heart Rate values from my Xiaomi Band 2. For this I tried using and adapting BluetoothLeGatt project from https://github.com/android/connectivity-samples/tree/master/BluetoothLeGatt .
So far I was able to survey the BLE devices nearby. After that I selected Xiaomi Band 2 and I could successfully list out all the services this device had, including Heart Rate Service. Inside Heart Rate Service I found the characteristic Heart Rate Measurement that I was looking for.
I tried to print data from this characteristic without success. I was unable to see any data in my log, even though I made some slight changes.
This is my LEScanCallback (with the slight changes done)
// Implements callback methods for GATT events that the app cares about. For example,
// connection change and services discovered.
private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
String intentAction;
if (newState == BluetoothProfile.STATE_CONNECTED) {
intentAction = ACTION_GATT_CONNECTED;
mConnectionState = STATE_CONNECTED;
broadcastUpdate(intentAction);
Log.i(TAG, "Connected to GATT server.");
// Attempts to discover services after successful connection.
Log.i(TAG, "Attempting to start service discovery:" +
mBluetoothGatt.discoverServices());
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
intentAction = ACTION_GATT_DISCONNECTED;
mConnectionState = STATE_DISCONNECTED;
Log.i(TAG, "Disconnected from GATT server.");
broadcastUpdate(intentAction);
}
}
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED);
} else {
Log.w(TAG, "onServicesDiscovered received: " + status);
}
BluetoothGattCharacteristic characteristic =
gatt.getService(HEART_RATE_SERVICE_UUID)
.getCharacteristic(HEART_RATE_MEASUREMENT_CHAR_UUID);
System.out.println("HEART_RATE_MEASUREMENT_CHAR_UUID: "+HEART_RATE_MEASUREMENT_CHAR_UUID);
/*gatt.setCharacteristicNotification(characteristic, true);
BluetoothGattDescriptor descriptor = characteristic.getDescriptor(CLIENT_CHARACTERISTIC_CONFIG_UUID);
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);
gatt.writeDescriptor(descriptor); */
setCharacteristicNotification(characteristic,true);
}
#Override
public void onCharacteristicRead(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic,
int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
}
System.out.println("onCharacteristicRead: " + Arrays.toString(characteristic.getValue()));
}
#Override
public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status){
super.onDescriptorWrite(gatt, descriptor, status);
System.out.println("onDescriptorWrite");
BluetoothGattCharacteristic characteristic = gatt.getService(HEART_RATE_SERVICE_UUID)
.getCharacteristic(HEART_RATE_MEASUREMENT_CHAR_UUID);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
characteristic.setValue(new byte[]{1, 1});
//gatt.writeCharacteristic(characteristic);
boolean success = gatt.readCharacteristic(characteristic);
System.out.println("success? "+success);
System.out.println("status: "+status);
}
#Override
public void onCharacteristicChanged(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic) {
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
System.out.println("onCharacteristicChanged: " + Arrays.toString(characteristic.getValue()));
}
};
I don't get to the point onCharacteristicRead() or onCharacteristicChanged() is called. I believe it's because gatt.readCharacteristic(characteristic) is FALSE and status is 3 (GATT_WRITE_NOT_PERMITTED) in onDescriptorWrite() function.
Can somebody help me figuring out the problem? I'm starting to lose all hope...

Related

onCharacteristicChanged is not called in BluetoothGatt

What i am doing:
Connecting my Android app to the device using gatt.connect().
After connecting, i am discovering all the services.
Then, i am enabling the notification on all the control characteristics. It is a successful write.
After that, i am trying to write some data on one of those control characteristics, which is a success.
The expected behavior is that i should receive a reply on onCharacteristicChanged(), but it is not triggering.
Connecting:
mBluetoothGatt = device.connectGatt(mContext, false, mGattCallback);
mDevice = device;
GATT Callback
private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
Log.i(Constant.BLUETOOTH_GATT_TAG, "Status: " + status);
super.onConnectionStateChange(gatt, status, newState);
switch (newState) {
case STATE_CONNECTED:
Log.i("gattCallback", "STATE_CONNECTED");
gatt.discoverServices();
break;
}
}
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
super.onServicesDiscovered(gatt, status);
services = gatt.getServices();
for (BluetoothGattService service : services) {
Log.i("services Discovered", service.getUuid().toString());
}
BluetoothGattCharacteristic characteristic = gatt.getService(Constant.UUID_FRANK_SERVICE).getCharacteristic(Constant.UUID_ILLUMINATION_CONTROL_POINT_CHARACTERISTICS);
Log.d("Notification Enabled", "" + enableNotificationsForCharacteristic(characteristic));
//getAuthenticated();
}
#Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
super.onCharacteristicChanged(gatt, characteristic);
Log.d(CHARACTERISTICS_CHANGED_TAG, "Received from Characteristic UUID");
}
#Override
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
super.onCharacteristicWrite(gatt, characteristic, status);
Log.d("onCharacteristicWrite", "Value is written...");
}
#Override
public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
super.onDescriptorWrite(gatt, descriptor, status);
Log.d("onDescriptorWrite", "Descriptior is written...");
Log.d("onDescriptorWrite" , "" + mBluetoothGatt.readDescriptor(descriptor));
}
#Override
public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
super.onDescriptorRead(gatt, descriptor, status);
Log.d("onDescriptorRead" , "" + status);
}
#Override
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
super.onCharacteristicRead(gatt, characteristic, status);
}
};
Enabling The Notifications:
private boolean enableNotificationsForCharacteristic(BluetoothGattCharacteristic characteristic) {
BluetoothGattDescriptor descriptor = characteristic.getDescriptor(UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"));
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
if (mBluetoothGatt != null) {
mBluetoothGatt.setCharacteristicNotification(characteristic, true);
if (mBluetoothGatt.writeDescriptor(descriptor)) {
return true;
}
}
return false;
}
Writing to Characteristic:
private boolean writeToCharacteristic(BluetoothGattService service, BluetoothGattCharacteristic characteristic, byte[] aValue, boolean aWithResponse) {
boolean ret = false;
if (service != null) {
if (characteristic != null) {
characteristic.setValue(aValue);
characteristic.setWriteType(aWithResponse ? BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT : BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE);
ret = mBluetoothGatt.writeCharacteristic(characteristic);
} else {
Log.e(TAG, "writeToCharacteristic() - Characteristic is null! " + service + " - " + characteristic);
}
} else {
Log.e(TAG, "writeToCharacteristic() - Service is null! " + service);
}
return ret;
}
What i am expecting:
After setting notification descriptor, i am getting a GATT_SUCCESS but when i am writing a characteristic, it is not triggering onCharacteristicChanged(). I am expecting it to trigger so that i can read the notification response. The device is behaving properly because i have confirmed the notification using Nordic Connect App
What have i tried:
Tried verifying the descriptor, to see if it is being written properly. It does.
Cross checking the name of services and characteristics. They are all fine.
Tried putting delay before write descriptor. It is being written properly.
Can anyone help me? Why it is not triggering onCharacteristicChanged?

How to notify user if connection fails to BLE device in Android?

How do I notify users if the device they are trying to connect to does not connect, besides waiting and testing for a connection. There does not seem to be any callback for a failed connection after trying connectGatt().
Thanks!
The method: connGATT() has 3 parameters. The third one is a callback:
mBluetoothGatt = device.connectGatt(this, false, mGattCallback);
if you want to know the connection is success or not, you should add override the method:
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status,
int newState)
Here is the link.https://developer.android.com/guide/topics/connectivity/bluetooth-le.html
The whole callback looks like this:
private final BluetoothGattCallback mGattCallback =
new BluetoothGattCallback() {
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status,
int newState) {
String intentAction;
if (newState == BluetoothProfile.STATE_CONNECTED) {
intentAction = ACTION_GATT_CONNECTED;
mConnectionState = STATE_CONNECTED;
broadcastUpdate(intentAction);
Log.i(TAG, "Connected to GATT server.");
Log.i(TAG, "Attempting to start service discovery:" +
mBluetoothGatt.discoverServices());
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
intentAction = ACTION_GATT_DISCONNECTED;
mConnectionState = STATE_DISCONNECTED;
Log.i(TAG, "Disconnected from GATT server.");
broadcastUpdate(intentAction);
}
}
#Override
// New services discovered
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED);
} else {
Log.w(TAG, "onServicesDiscovered received: " + status);
}
}
#Override
// Result of a characteristic read operation
public void onCharacteristicRead(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic,
int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
}
}
...
};
...
}

Android BLE: List of discovered characteristics in service is incomplete

Attempting to read characteristics from a GATT service, the list is incomplete compared to the list I get from an iOS device, or the manufacturer guide.
I am reading the characteristics as follows:
private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status,
int newState) {
if (newState == BluetoothProfile.STATE_CONNECTED) {
mConnectionState = STATE_CONNECTED;
mBluetoothGatt = gatt;
if (shouldStartWriting && writeCharacteristicsQueue.peek() != null) {
mBluetoothGatt.writeCharacteristic(writeCharacteristicsQueue.poll());
} else {
EventBus.getDefault().post(new BTGattStatusEvent(BTGattStatusEvent.Status.CONNECTED));
Log.i(TAG, "Attempting to start service discovery:" +
gatt.discoverServices());
}
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
mConnectionState = STATE_DISCONNECTED;
mBluetoothGatt = null;
EventBus.getDefault().post(new BTGattDisconnectedEvent());
}
}
#Override
// New services discovered
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
EventBus.getDefault().post(new BTGattStatusEvent(BTGattStatusEvent.Status.DISCOVERED));
if (status == BluetoothGatt.GATT_SUCCESS) {
for (BluetoothGattService service : gatt.getServices()) {
LOGD(TAG, "Found Service " + service.getUuid().toString());
discoverCharacteristics(service);
}
gatt.readCharacteristic(readCharacteristicsQueue.poll());
} else {
Log.w(TAG, "onServicesDiscovered received: " + status);
}
}
#Override
// Result of a characteristic read operation
public void onCharacteristicRead(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic,
int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
parseCharacteristic(characteristic);
LOGD(TAG, String.format("%s | %s ", characteristic.getUuid(), characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT16, 0)));//(BluetoothGattCharacteristic.FORMAT_UINT16));
if (readCharacteristicsQueue.peek() != null) {
gatt.readCharacteristic(readCharacteristicsQueue.poll());
} else {
EventBus.getDefault().post(new BTGattStatusEvent(BTGattStatusEvent.Status.DONE_DISCOVERING));
}
}
}
and
private void discoverCharacteristics(BluetoothGattService service) {
for (BluetoothGattCharacteristic gattCharacteristic : service.getCharacteristics()) {
LOGD(TAG, "Discovered UUID: " + gattCharacteristic.getUuid());
readCharacteristicsQueue.add(gattCharacteristic);
}
}
I also attempted to get this characteristic using getCharacteristic, but I received a null.
The characteristics found are:
Discovered UUID: 0000fff1-0000-1000-8000-00805f9b34fb
Discovered UUID: 0000fff2-0000-1000-8000-00805f9b34fb
Discovered UUID: 0000fff3-0000-1000-8000-00805f9b34fb
Discovered UUID: 0000fff4-0000-1000-8000-00805f9b34fb
Discovered UUID: 0000fff5-0000-1000-8000-00805f9b34fb
However, on iOS and according to the manufacturer, there should also be a 0000fff7.
Why isn't this characteristic being read?
UPDATE:
Nothing happened here. Not one of Android's BLE scanning apps can discover it.

Bluetooth Low Energy on Android: Get event when RSSI changes

I can scan for Bluetooth LE devices through startLeScan or via the new getBluetoothLeScanner and that works fine. However even though it keeps on scanning it never detects the same device twice. That's unfortunate because I would like to receive events when the rssi of a beacon changes. Does Android support that?
Implement a BluetoothGattCallback and override the onReadRemoteRssi method.
private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
String intentAction;
if (newState == BluetoothProfile.STATE_CONNECTED) {
broadcastUpdate(intentAction);
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
broadcastUpdate(intentAction);
}
}
#Override
public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
super.onReadRemoteRssi(gatt, rssi, status);
// use rssi value here
}
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED);
} else {
Log.w(TAG, "onServicesDiscovered received: " + status);
}
}
#Override
public void onCharacteristicRead(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic,
int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
}
}
#Override
public void onCharacteristicChanged(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic) {
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
}
};
Two solutions which I used.
1) Make a connection, call readRemoteRssi(); of gatt and override onReadRemoteRssi, and have your own check to see if the RSSI is changed.
2) StrartLEScan every 20 Sec(20 sec is enough time to receive new advertisement packets) and have a check on onLeScan callback to see if the device is found, if yes then compare RSSI.
RSSI is the value which your device(scanner) derives.
Also if you have code for GATT STACK, you will get onLEScan called many times for single device, it is GattService which truncate duplicate results.

Nexus 9 in Peripheral mode is not accepting connection from clients or not responding to client requests?

I am using Nexus 9 in peripheral mode. I have created a instance of GATT server:
mGattServer = mBluetoothManager.openGattServer(this, mBluetoothGattServerCallback);
I have created a BluetoothGattService & BluetoothGattCharacteristic.
Added service to GATT server & characteristic to service.
BluetoothGattService service =new BluetoothGattService(SERVICE_UUID,
BluetoothGattService.SERVICE_TYPE_PRIMARY);
BluetoothGattCharacteristic offsetCharacteristic =
new BluetoothGattCharacteristic(CHARACTERISTIC_NUM_UUID,
//Read+write permissions
BluetoothGattCharacteristic.PROPERTY_READ | BluetoothGattCharacteristic.PROPERTY_WRITE,
BluetoothGattCharacteristic.PERMISSION_READ | BluetoothGattCharacteristic.PERMISSION_WRITE);
service.addCharacteristic(offsetCharacteristic);
mGattServer.addService(service);
Instance of BluetoothGattServerCallBack:
private BluetoothGattServerCallback mBluetoothGattServerCallback = new BluetoothGattServerCallback() {
#Override
public void onConnectionStateChange(BluetoothDevice device, int status, int newState) {
//super.onConnectionStateChange(device, status, newState);
Log.i(TAG, "onConnectionStateChange "
+ getStatusDescription(status) + " "
+ getStateDescription(newState));
if (newState == BluetoothProfile.STATE_CONNECTED) {
Log.i(TAG, "Connected..");
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
Log.i(TAG, "Disconnected..");
}
}
#Override
public void onServiceAdded(int status, BluetoothGattService service) {
//super.onServiceAdded(status, service);
Log.i(TAG, "onServiceAdded");
}
#Override
public void onCharacteristicWriteRequest(BluetoothDevice device, int requestId, BluetoothGattCharacteristic characteristic, boolean preparedWrite, boolean responseNeeded, int offset, byte[] value) {
super.onCharacteristicWriteRequest(device, requestId, characteristic, preparedWrite, responseNeeded, offset, value);
Log.i(TAG, "onCharacteristicWriteRequest");
}
#Override
public void onCharacteristicReadRequest(BluetoothDevice device, int requestId, int offset, BluetoothGattCharacteristic characteristic) {
super.onCharacteristicReadRequest(device, requestId, offset, characteristic);
Log.i(TAG, "onCharacteristicReadRequest");
}
#Override
public void onDescriptorReadRequest(BluetoothDevice device, int requestId, int offset, BluetoothGattDescriptor descriptor) {
super.onDescriptorReadRequest(device, requestId, offset, descriptor);
Log.i(TAG, "onDescriptorReadRequest");
}
#Override
public void onDescriptorWriteRequest(BluetoothDevice device, int requestId, BluetoothGattDescriptor descriptor, boolean preparedWrite, boolean responseNeeded, int offset, byte[] value) {
super.onDescriptorWriteRequest(device, requestId, descriptor, preparedWrite, responseNeeded, offset, value);
Log.i(TAG, "onDescriptorWriteRequest");
}
#Override
public void onExecuteWrite(BluetoothDevice device, int requestId, boolean execute) {
super.onExecuteWrite(device, requestId, execute);
Log.i(TAG, "onExecuteWrite");
}
#Override
public void onNotificationSent(BluetoothDevice device, int status) {
super.onNotificationSent(device, status);
Log.i(TAG, "onNotificationSent");
}
};
Now when I am trying to connect a GATT client to this server, onConnectionStateChange() method of BluetoothGattServerCallback never invoked.
Code from Client Side app:
To connect to GATT server running on Nexus 9
mConnectedGatt = device.connectGatt(this, false, mGattCallback);
Instance of BluetoothGattCallback:
private BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
if (status == BluetoothGatt.GATT_SUCCESS && newState == BluetoothProfile.STATE_CONNECTED) {
Log.i(TAG, "Connected to server");
gatt.discoverServices();
} else if (status == BluetoothGatt.GATT_SUCCESS && newState == BluetoothProfile.STATE_DISCONNECTED) {
Log.i(TAG, "Disconnected from server");
} else if (status != BluetoothGatt.GATT_SUCCESS) {
gatt.disconnect();
}
}
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
}
#Override
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
}
#Override
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
}
#Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
}
#Override
public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
}
};
Device(Nexus 9) is discoverable & I am getting it in onLeScan(). But when I am trying to connect to GATT server running on Nexus 9, status in onConnectionStateChange it always STATE_DISCONNECTED.
I tried to connect from some third party applications like "B-BLE", "BLE Scanner", "Bluetooth 4.0 Explorer". Nexus 9 is discoverable in these applications but when I am trying to connect to GATT server, status in onConnectionStateChange() is always STATE_DISCONNECTED.
Any type of help will be appreciated.
Thanks in advance.
As a first step, check if the addService(..) method returns true - only then has the service successfully been added.
Also, try removing the GATT_SUCCESS check from the onConnectionStateChange() method. As far as I know you don't need to test for this there...

Categories

Resources