Alexander Hryk Alexander Hryk - 7 months ago 46
Java Question

Heart Rate measuring using Xiaomi MiBand and BLE

I'm trying to implement simple sdk for working with fitness tracker Xiaomi Mi Band. Currently I can track steps, actuate the vibration, handle the sensor touch but I have a problem with heart rate measuring. My sdk based on https://github.com/pangliang/miband-sdk-android. To measure heart rate, I need to write descriptor to appropriate characteristic to enable handling callback when the value of this characteristic was changed and then write appropriate data to heart rate control point characteristic to directly start the heart rate measure process. The problem is that the heart rate measuring process was not started after the data to initiate this process was successfully written to the characteristic (when the Mi Band starts to measure heart rate then the bottom sensor blinks green). This can be caused by a new firmware of fitness tracker (firmware version: 4.15.12.10; HeartRate version: 1.3.74.64) or there are some defects in my code:

/-------- MiBandProfile --------/
public static final UUID UUID_SERVICE_HEARTRATE = UUID.fromString("0000180d-0000-1000-8000-00805f9b34fb");
public static final UUID UUID_NOTIFICATION_HEARTRATE = UUID.fromString("00002a37-0000-1000-8000-00805f9b34fb");
public static final UUID UUID_CHAR_HEARTRATE = UUID.fromString("00002a39-0000-1000-8000-00805f9b34fb");
public static final UUID UUID_DESCRIPTOR_UPDATE_NOTIFICATION = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb");

/-------- MiBandProtocol --------/
public static final byte[] START_HEART_RATE_SCAN = {21, 1, 1};

/-------- BleProvider --------/
public class BleProvider extends BluetoothGattCallback {

public interface NotifyListener {
void onNotify(byte[] data);
}

private HashMap<UUID, NotifyListener> mNotifyListeners = new HashMap<UUID, NotifyListener>();
.
.
.
public void setNotifyListener(UUID serviceUUID, UUID charaUUID, NotifyListener listener) {
//enable chara notofication
if (this.mGatt == null || !this.mIsServicesDiscovered) {
if (DBG) Log.d(Debug.TAG, "Device is not connected or services are not discovered");
return;
}

BluetoothGattCharacteristic chara = this.mGatt.getService(serviceUUID).getCharacteristic(charaUUID);

if (DBG) Log.d(Debug.TAG, "setCharacteristicNotification: " + this.mGatt.setCharacteristicNotification(chara, true));
BluetoothGattDescriptor descriptor = chara.getDescriptor(MiBandProfile.UUID_DESCRIPTOR_UPDATE_NOTIFICATION);
if (DBG) Log.d(Debug.TAG, "setValue: " + descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE));
if (DBG) Log.d(Debug.TAG, "writeDescriptor: " + this.mGatt.writeDescriptor(descriptor));
this.mNotifyListeners.put(charaUUID, listener);
}

@Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
//this method must be called when the characteristic value was changed but nothing happened :(
super.onCharacteristicChanged(gatt, characteristic);

if (this.mNotifyListeners.containsKey(characteristic.getUuid())) {
this.mNotifyListeners.get(characteristic.getUuid()).onNotify(characteristic.getValue());
}
}
} //end BleProvider

.
.
.

setNotifyListener(MiBandProfile.UUID_SERVICE_HEARTRATE, MiBandProfile.UUID_NOTIFICATION_HEARTRATE, new BleProvider.NotifyListener(){...});
//waiting few seconds
writeCharacteristic(MiBandProfile.UUID_SERVICE_HEARTRATE, MiBandProfile.UUID_CHAR_HEARTRATE, MiBandProtocol.START_HEART_RATE_SCAN);


Maybe the protocol is deprecated and there are people who can share me a new protocol. I will be very glad) Thanks.

Answer

I solved the problem! Before calling setNotifyListener to track the change of pulse value you must to write User Information (age, weight) to appropriate characteristic, because without this Mi Band doesn't start the measuring.