diff --git a/CHANGELOG.md b/CHANGELOG.md index a824d4fb..f6719b89 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ ###Changelog +####Version 0.13.6 +* Mi Band 2: Support for multiple alarms (3 at the moment) +* Mi Band 2: Fix for alarms not working when just one is enabled + ####Version 0.13.5 * Mi Band 2: Support setting one alarm * Pebble: Health compatibility for Firmware 4.2 diff --git a/app/build.gradle b/app/build.gradle index ce9afe7e..6e232ed6 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -26,8 +26,8 @@ android { targetSdkVersion 23 // note: always bump BOTH versionCode and versionName! - versionName "0.13.5" - versionCode 67 + versionName "0.13.6" + versionCode 68 vectorDrawables.useSupportLibrary = true } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBand2Service.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBand2Service.java index a893d0aa..064ac7b6 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBand2Service.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBand2Service.java @@ -16,8 +16,8 @@ public class MiBand2Service { public static final UUID UUID_UNKNOWN_CHARACTERISTIC0 = UUID.fromString("00000000-0000-3512-2118-0009af100700"); public static final UUID UUID_UNKNOWN_CHARACTERISTIC1 = UUID.fromString("00000001-0000-3512-2118-0009af100700"); public static final UUID UUID_UNKNOWN_CHARACTERISTIC2 = UUID.fromString("00000002-0000-3512-2118-0009af100700"); - public static final UUID UUID_UNKNOWN_CHARACTERISTIC3 = UUID.fromString("00000003-0000-3512-2118-0009af100700"); - public static final UUID UUID_UNKNOWN_CHARACTERISTIC4 = UUID.fromString("00000004-0000-3512-2118-0009af100700"); // Alarm related + public static final UUID UUID_UNKNOWN_CHARACTERISTIC3 = UUID.fromString("00000003-0000-3512-2118-0009af100700"); // Alarm related + public static final UUID UUID_UNKNOWN_CHARACTERISTIC4 = UUID.fromString("00000004-0000-3512-2118-0009af100700"); public static final UUID UUID_UNKNOWN_CHARACTERISTIC5 = UUID.fromString("00000005-0000-3512-2118-0009af100700"); public static final UUID UUID_UNKNOWN_CHARACTERISTIC6 = UUID.fromString("00000006-0000-3512-2118-0009af100700"); public static final UUID UUID_UNKNOWN_CHARACTERISTIC7 = UUID.fromString("00000007-0000-3512-2118-0009af100700"); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/profiles/heartrate/HeartRateProfile.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/profiles/heartrate/HeartRateProfile.java index db0ff14f..f5495124 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/profiles/heartrate/HeartRateProfile.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/profiles/heartrate/HeartRateProfile.java @@ -2,16 +2,23 @@ package nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.heartrate; import android.bluetooth.BluetoothGatt; import android.bluetooth.BluetoothGattCharacteristic; +import android.widget.Toast; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import nodomain.freeyourgadget.gadgetbridge.service.btle.AbstractBTLEDeviceSupport; import nodomain.freeyourgadget.gadgetbridge.service.btle.GattCharacteristic; import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder; import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.AbstractBleProfile; +import nodomain.freeyourgadget.gadgetbridge.util.GB; /** * https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.service.heart_rate.xml */ public class HeartRateProfile extends AbstractBleProfile { + private static final Logger LOG = LoggerFactory.getLogger(HeartRateProfile.class); + /** * Returned when a request to the heart rate control point is not supported by the device */ @@ -26,29 +33,36 @@ public class HeartRateProfile extends Abstr } protected void writeToControlPoint(byte value, TransactionBuilder builder) { - builder.write(getCharacteristic(GattCharacteristic.UUID_CHARACTERISTIC_HEART_RATE_CONTROL_POINT), new byte[] { value }); + writeToControlPoint(new byte[] { value }, builder); + } + + protected void writeToControlPoint(byte[] value, TransactionBuilder builder) { + builder.write(getCharacteristic(GattCharacteristic.UUID_CHARACTERISTIC_HEART_RATE_CONTROL_POINT), value); } public void requestBodySensorLocation(TransactionBuilder builder) { } + // TODO: I didn't find anything in the spec to request heart rate readings, so probably this + // should be done in a device specific way. public void requestHeartRateMeasurement(TransactionBuilder builder) { - + writeToControlPoint(new byte[] { 0x15, 0x02, 0x01}, builder); } @Override public boolean onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) { -// if (UUID_HEART_RATE_MEASUREMENT.equals(characteristic.getUuid())) { -// int flag = characteristic.getProperties(); -// int format = -1; -// if ((flag & 0x01) != 0) { -// format = BluetoothGattCharacteristic.FORMAT_UINT16; -// } else { -// format = BluetoothGattCharacteristic.FORMAT_UINT8; -// } -// final int heartRate = characteristic.getIntValue(format, 1); -// } + if (GattCharacteristic.UUID_CHARACTERISTIC_HEART_RATE_MEASUREMENT.equals(characteristic.getUuid())) { + int flag = characteristic.getProperties(); + int format = -1; + if ((flag & 0x01) != 0) { + format = BluetoothGattCharacteristic.FORMAT_UINT16; + } else { + format = BluetoothGattCharacteristic.FORMAT_UINT8; + } + final int heartRate = characteristic.getIntValue(format, 1); + GB.toast(getContext(), "Heart rate: " + heartRate, Toast.LENGTH_LONG, GB.INFO); + } return false; } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/MiBand2Support.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/MiBand2Support.java index de8debc7..d16edfc1 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/MiBand2Support.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/MiBand2Support.java @@ -57,6 +57,7 @@ import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.ConditionalWrit import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.SetDeviceStateAction; import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.WriteAction; import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.deviceinfo.DeviceInfoProfile; +import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.heartrate.HeartRateProfile; import nodomain.freeyourgadget.gadgetbridge.service.devices.miband2.Mi2NotificationStrategy; import nodomain.freeyourgadget.gadgetbridge.service.devices.miband2.operations.InitOperation; import nodomain.freeyourgadget.gadgetbridge.util.DateTimeUtils; @@ -86,6 +87,7 @@ public class MiBand2Support extends AbstractBTLEDeviceSupport { private static final Logger LOG = LoggerFactory.getLogger(MiBand2Support.class); private final DeviceInfoProfile deviceInfoProfile; + private final HeartRateProfile heartRateProfile; private final BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { @@ -119,6 +121,8 @@ public class MiBand2Support extends AbstractBTLEDeviceSupport { deviceInfoProfile = new DeviceInfoProfile<>(this); addSupportedProfile(deviceInfoProfile); + heartRateProfile = new HeartRateProfile(this); + addSupportedProfile(heartRateProfile); LocalBroadcastManager broadcastManager = LocalBroadcastManager.getInstance(getContext()); IntentFilter intentFilter = new IntentFilter(); @@ -230,6 +234,7 @@ public class MiBand2Support extends AbstractBTLEDeviceSupport { builder.notify(getCharacteristic(MiBand2Service.UUID_CHARACTERISTIC_AUTH), enable); builder.notify(getCharacteristic(MiBand2Service.UUID_UNKNOWN_CHARACTERISTIC3), enable); builder.notify(getCharacteristic(MiBand2Service.UUID_UNKNOWN_CHARACTERISTIC4), enable); + builder.notify(getCharacteristic(GattCharacteristic.UUID_CHARACTERISTIC_HEART_RATE_MEASUREMENT), enable); return this; } @@ -673,12 +678,14 @@ public class MiBand2Support extends AbstractBTLEDeviceSupport { if (supportsHeartRate()) { try { TransactionBuilder builder = performInitialized("HeartRateTest"); - builder.write(getCharacteristic(MiBandService.UUID_CHARACTERISTIC_HEART_RATE_CONTROL_POINT), stopHeartMeasurementContinuous); - builder.write(getCharacteristic(MiBandService.UUID_CHARACTERISTIC_HEART_RATE_CONTROL_POINT), stopHeartMeasurementManual); - builder.write(getCharacteristic(MiBandService.UUID_CHARACTERISTIC_HEART_RATE_CONTROL_POINT), startHeartMeasurementManual); + heartRateProfile.requestHeartRateMeasurement(builder); +// profile.resetEnergyExpended(builder); +// builder.write(getCharacteristic(MiBandService.UUID_CHARACTERISTIC_HEART_RATE_CONTROL_POINT), stopHeartMeasurementContinuous); +// builder.write(getCharacteristic(MiBandService.UUID_CHARACTERISTIC_HEART_RATE_CONTROL_POINT), stopHeartMeasurementManual); +// builder.write(getCharacteristic(MiBandService.UUID_CHARACTERISTIC_HEART_RATE_CONTROL_POINT), startHeartMeasurementManual); builder.queue(getQueue()); } catch (IOException ex) { - LOG.error("Unable to read HearRate in MI1S", ex); + LOG.error("Unable to read HearRate with MI2", ex); } } else { GB.toast(getContext(), "Heart rate is not supported on this device", Toast.LENGTH_LONG, GB.ERROR); @@ -1056,43 +1063,27 @@ public class MiBand2Support extends AbstractBTLEDeviceSupport { Calendar calendar = alarm.getAlarmCal(); int daysMask = 0; - if (alarm.getIndex() != 0 && alarm.isEnabled()) { - GB.toast(getContext(), "Only the first alarm is currently supported.", Toast.LENGTH_LONG, GB.WARN); + int maxAlarms = 5; // arbitrary at the moment... + if (alarm.getIndex() >= maxAlarms) { + if (alarm.isEnabled()) { + GB.toast(getContext(), "Only 5 alarms are currently supported.", Toast.LENGTH_LONG, GB.WARN); + } return; } if (alarm.isEnabled()) { - if (alarm.getRepetition(Alarm.ALARM_MON)) { - daysMask |= 1; - } - if (alarm.getRepetition(Alarm.ALARM_TUE)) { - daysMask |= 2; - } - if (alarm.getRepetition(Alarm.ALARM_WED)) { - daysMask |= 4; - } - if (alarm.getRepetition(Alarm.ALARM_THU)) { - daysMask |= 8; - } - if (alarm.getRepetition(Alarm.ALARM_FRI)) { - daysMask |= 16; - } - if (alarm.getRepetition(Alarm.ALARM_SAT)) { - daysMask |= 32; - } - if (alarm.getRepetition(Alarm.ALARM_SUN)) { - daysMask |= 64; - } + daysMask = alarm.getRepetitionMask(); } byte[] alarmMessage = new byte[] { - (byte) 0x2, // TODO what is this? 0x1 does not work - (byte) 128, // TODO: what is this? + (byte) 0x2, // TODO what is this? + (byte) (128 + alarm.getIndex()), // 128 is the base, alarm slot is added (byte) calendar.get(Calendar.HOUR_OF_DAY), (byte) calendar.get(Calendar.MINUTE), (byte) daysMask, }; builder.write(characteristic, alarmMessage); + // TODO: react on 0x10, 0x02, 0x01 on notification (success) } private void handleControlPointResult(byte[] value, int status) { diff --git a/app/src/main/res/xml/changelog_master.xml b/app/src/main/res/xml/changelog_master.xml index 0378690b..6459f604 100644 --- a/app/src/main/res/xml/changelog_master.xml +++ b/app/src/main/res/xml/changelog_master.xml @@ -1,5 +1,9 @@ + + Mi Band 2: Support multiple alarms (3 at the moment) + Mi Band 2: Fix for alarms not working when just one is enabled + Mi Band 2: Support setting one alarm Pebble: Health compatibility for Firmware 4.2