Separate coordinator and support instances for Mi1 and Mi2 #323

+ Some more testing stuff for Mi2
master
cpfeiffer 2016-08-17 00:53:16 +02:00
parent 26d490ffd6
commit fbf06c1fe3
12 changed files with 142 additions and 25 deletions

View File

@ -7,10 +7,22 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceCandidate;
public abstract class AbstractDeviceCoordinator implements DeviceCoordinator {
private static final Logger LOG = LoggerFactory.getLogger(AbstractDeviceCoordinator.class);
@Override
public boolean supports(GBDevice device) {
return getDeviceType().equals(device.getType());
}
@Override
public GBDevice createDevice(GBDeviceCandidate candidate) {
return new GBDevice(candidate.getDevice().getAddress(), candidate.getName(), getDeviceType());
}
public boolean allowFetchActivityData(GBDevice device) {
return device.isInitialized() && !device.isBusy() && supportsActivityDataFetching();
}

View File

@ -1,6 +1,7 @@
package nodomain.freeyourgadget.gadgetbridge.devices;
import android.app.Activity;
import android.bluetooth.BluetoothDevice;
import android.content.Context;
import android.net.Uri;
@ -40,6 +41,8 @@ public interface DeviceCoordinator {
*/
boolean supports(GBDevice device);
GBDevice createDevice(GBDeviceCandidate candidate);
/**
* Returns the kind of device type this coordinator supports.
*

View File

@ -76,11 +76,6 @@ public class UnknownDeviceCoordinator extends AbstractDeviceCoordinator {
return false;
}
@Override
public boolean supports(GBDevice device) {
return getDeviceType().equals(device.getType());
}
@Override
public DeviceType getDeviceType() {
return DeviceType.UNKNOWN;

View File

@ -0,0 +1,42 @@
package nodomain.freeyourgadget.gadgetbridge.devices.miband;
import android.bluetooth.BluetoothDevice;
import android.content.Context;
import android.net.Uri;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import nodomain.freeyourgadget.gadgetbridge.devices.InstallHandler;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceCandidate;
import nodomain.freeyourgadget.gadgetbridge.model.DeviceType;
public class MiBand2Coordinator extends MiBandCoordinator {
private static final Logger LOG = LoggerFactory.getLogger(MiBand2Coordinator.class);
@Override
public DeviceType getDeviceType() {
return DeviceType.MIBAND2;
}
@Override
public boolean supports(GBDeviceCandidate candidate) {
// and a heuristic
try {
BluetoothDevice device = candidate.getDevice();
if (isHealthWearable(device)) {
String name = device.getName();
return name != null && name.equalsIgnoreCase(MiBandConst.MI_BAND2_NAME);
}
} catch (Exception ex) {
LOG.error("unable to check device support", ex);
}
return false;
}
@Override
public InstallHandler findInstallHandler(Uri uri, Context context) {
return null; // not supported at the moment
}
}

View File

@ -13,8 +13,19 @@ public class MiBand2Service {
public static final UUID UUID_SERVICE_MIBAND2_SERVICE = UUID.fromString(String.format(BASE_UUID, "FEE1"));
public static final UUID UUID_SERVICE_HEART_RATE = UUID.fromString(String.format(BASE_UUID, "180D"));
public static final UUID UUID_SERVICE_WEIGHT_SERVICE = UUID.fromString("00001530-0000-3512-2118-0009af100700");
public static final UUID UUID_UNKNOQN_CHARACTERISTIC0 = UUID.fromString("00000000-0000-3512-2118-0009af100700");
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");
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");
public static final UUID UUID_UNKNOWN_CHARACTERISTIC8 = UUID.fromString("00000008-0000-3512-2118-0009af100700");
public static final UUID UUID_UNKNOWN_CHARACTERISTIC10 = UUID.fromString("00000010-0000-3512-2118-0009af100700");
// set metric distance
// set 12 hour time mode
// public static final UUID UUID_CHARACTERISTIC_DEVICE_INFO = UUID.fromString(String.format(BASE_UUID, "FF01"));

View File

@ -25,6 +25,7 @@ public final class MiBandConst {
public static final String ORIGIN_PEBBLEMSG = "pebblemsg";
public static final String ORIGIN_GENERIC = "generic";
public static final String MI_GENERAL_NAME_PREFIX = "MI";
public static final String MI_BAND2_NAME = "MI Band 2";
public static final String MI_1 = "1";
public static final String MI_1A = "1A";
public static final String MI_1S = "1S";

View File

@ -35,7 +35,8 @@ public class MiBandCoordinator extends AbstractDeviceCoordinator {
|| macAddress.startsWith(MiBandService.MAC_ADDRESS_FILTER_1S)) {
return true;
}
if (candidate.supportsService(MiBandService.UUID_SERVICE_MIBAND_SERVICE)) {
if (candidate.supportsService(MiBandService.UUID_SERVICE_MIBAND_SERVICE)
&& !candidate.supportsService(MiBandService.UUID_SERVICE_MIBAND2_SERVICE)) {
return true;
}
// and a heuristic
@ -51,11 +52,6 @@ public class MiBandCoordinator extends AbstractDeviceCoordinator {
return false;
}
@Override
public boolean supports(GBDevice device) {
return getDeviceType().equals(device.getType());
}
@Override
public DeviceType getDeviceType() {
return DeviceType.MIBAND;

View File

@ -27,11 +27,6 @@ public class PebbleCoordinator extends AbstractDeviceCoordinator {
return name != null && name.startsWith("Pebble");
}
@Override
public boolean supports(GBDevice device) {
return getDeviceType().equals(device.getType());
}
@Override
public DeviceType getDeviceType() {
return DeviceType.PEBBLE;

View File

@ -46,10 +46,21 @@ public class BLETypeConversions {
fromUint8(timestamp.get(Calendar.MINUTE)),
fromUint8(timestamp.get(Calendar.SECOND)),
dayOfWeekToRawBytes(timestamp),
0 // fractions256 (not set)
0, // fractions256 (not set)
// 0 (DST offset?) Mi2
// k (tz) Mi2
};
}
private static int getMiBand2TimeZone(int rawOffset) {
int offsetMinutes = rawOffset / 1000 / 60;
rawOffset = offsetMinutes < 0 ? -1 : 1;
offsetMinutes = Math.abs(offsetMinutes);
int offsetHours = offsetMinutes / 60;
rawOffset *= offsetMinutes % 60 / 15 + offsetHours * 4;
return rawOffset;
}
private static byte dayOfWeekToRawBytes(Calendar cal) {
int calValue = cal.get(Calendar.DAY_OF_WEEK);
switch (calValue) {
@ -139,8 +150,8 @@ public class BLETypeConversions {
* @return sint8 value from -48..+56
*/
public static byte mapTimeZone(TimeZone timeZone) {
int utcOffsetInMinutes = (timeZone.getRawOffset() / (1000 * 60 * 60));
return (byte) (utcOffsetInMinutes * 4);
int utcOffsetInHours = (timeZone.getRawOffset() / (1000 * 60 * 60));
return (byte) (utcOffsetInHours * 4);
}
/**

View File

@ -142,9 +142,15 @@ public class DeviceInfoProfile<T extends AbstractBTLEDeviceSupport> extends Abst
}
private void handlePnpId(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
String pnpId = characteristic.getStringValue(0);
deviceInfo.setPnpId(pnpId);
notify(createIntent(deviceInfo));
byte[] value = characteristic.getValue();
if (value.length == 7) {
// int vendorSource
//
// deviceInfo.setPnpId(pnpId);
notify(createIntent(deviceInfo));
} else {
// TODO: LOG warning
}
}
private Intent createIntent(DeviceInfo deviceInfo) {

View File

@ -26,6 +26,7 @@ import nodomain.freeyourgadget.gadgetbridge.GBApplication;
import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventBatteryInfo;
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventVersionInfo;
import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBand2Service;
import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst;
import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandCoordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandDateConverter;
@ -45,6 +46,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec;
import nodomain.freeyourgadget.gadgetbridge.model.MusicStateSpec;
import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
import nodomain.freeyourgadget.gadgetbridge.service.btle.AbstractBTLEDeviceSupport;
import nodomain.freeyourgadget.gadgetbridge.service.btle.BLETypeConversions;
import nodomain.freeyourgadget.gadgetbridge.service.btle.BtLEAction;
import nodomain.freeyourgadget.gadgetbridge.service.btle.GattCharacteristic;
import nodomain.freeyourgadget.gadgetbridge.service.btle.GattService;
@ -147,6 +149,7 @@ public class MiBand2Support extends AbstractBTLEDeviceSupport {
// this is apparently not needed anymore, and actually causes problems when bonding is not used/does not work
// so we simply not use the UUID_PAIR characteristic.
// .pair(builder)
.testInit(builder)
.requestDeviceInfo(builder)
.requestBatteryInfo(builder);
// .sendUserInfo(builder)
@ -162,6 +165,38 @@ public class MiBand2Support extends AbstractBTLEDeviceSupport {
return builder;
}
private MiBand2Support testInit(TransactionBuilder builder) {
builder.read(getCharacteristic(MiBand2Service.UUID_UNKNOWN_CHARACTERISTIC6)); // example read value: 0f6200e0070804072b2c20e00708040625372064
builder.read(getCharacteristic(MiBand2Service.UUID_UNKNOWN_CHARACTERISTIC7)); // example read value: 0019000000
setCurrentTimeWithService(builder);
builder.write(getCharacteristic(MiBand2Service.UUID_UNKNOWN_CHARACTERISTIC4), new byte[] { 0x01, 0x01, (byte) 0xe0, 0x07, 0x07, 0x17, 0x15, 0x04, 0x00, 0x04 });
builder.write(getCharacteristic(MiBand2Service.UUID_UNKNOWN_CHARACTERISTIC4), new byte[] { 0x02 });
builder.read(getCharacteristic(MiBand2Service.UUID_UNKNOWN_CHARACTERISTIC6)); // probably superfluous
builder.write(getCharacteristic(MiBand2Service.UUID_UNKNOWN_CHARACTERISTIC8), new byte[] { 0x20, 0x00, 0x00, 0x02 });
return this;
}
// private MiBand2Support maybeAuth(TransactionBuilder builder) {
// builder.write(getCharacteristic(MiBand2Service.UUID_UNKNOQN_CHARACTERISTIC0), new byte[] {0x20, 0x00});
// builder.write(getCharacteristic(MiBand2Service.UUID_UNKNOQN_CHARACTERISTIC0), new byte[] {0x03,0x00,(byte)0x8e,(byte)0xce,0x5a,0x09,(byte)0xb3,(byte)0xd8,0x55,0x57,0x10,0x2a,(byte)0xed,0x7d,0x6b,0x78,(byte)0xc5,(byte)0xd2});
// return this;
// }
private MiBand2Support setCurrentTimeWithService(TransactionBuilder builder) {
GregorianCalendar now = BLETypeConversions.createCalendar();
byte[] bytes = BLETypeConversions.calendarToRawBytes(now, true);
byte[] tail = new byte[] { 0, BLETypeConversions.mapTimeZone(now.getTimeZone()) }; // 0 = adjust reason bitflags? or DST offset?? , timezone
// byte[] tail = new byte[] { 0x2 }; // reason
byte[] all = BLETypeConversions.join(bytes, tail);
builder.write(getCharacteristic(GattCharacteristic.UUID_CHARACTERISTIC_CURRENT_TIME), all);
// byte[] localtime = BLETypeConversions.calendarToLocalTimeBytes(now);
// builder.write(getCharacteristic(GattCharacteristic.UUID_CHARACTERISTIC_LOCAL_TIME_INFORMATION), localtime);
// builder.write(getCharacteristic(GattCharacteristic.UUID_CHARACTERISTIC_CURRENT_TIME), new byte[] {0x2, 0x00});
// builder.write(getCharacteristic(MiBand2Service.UUID_UNKNOQN_CHARACTERISTIC0), new byte[] {0x03,0x00,(byte)0x8e,(byte)0xce,0x5a,0x09,(byte)0xb3,(byte)0xd8,0x55,0x57,0x10,0x2a,(byte)0xed,0x7d,0x6b,0x78,(byte)0xc5,(byte)0xd2});
return this;
}
private MiBand2Support readDate(TransactionBuilder builder) {
// NAVL
// builder.read(getCharacteristic(MiBandService.UUID_CHARACTERISTIC_DATE_TIME));
@ -201,6 +236,7 @@ public class MiBand2Support extends AbstractBTLEDeviceSupport {
// TODO: tear down the notifications on quit
private MiBand2Support enableNotifications(TransactionBuilder builder, boolean enable) {
builder.notify(getCharacteristic(MiBandService.UUID_CHARACTERISTIC_NOTIFICATION), enable);
builder.notify(getCharacteristic(GattService.UUID_SERVICE_CURRENT_TIME), enable);
return this;
}
@ -844,6 +880,9 @@ public class MiBand2Support extends AbstractBTLEDeviceSupport {
} else if (MiBandService.UUID_CHARACTERISTIC_HEART_RATE_MEASUREMENT.equals(characteristicUUID)) {
handleHeartrate(characteristic.getValue());
return true;
// } else if (MiBand2Service.UUID_UNKNOQN_CHARACTERISTIC0.equals(characteristicUUID)) {
// handleUnknownCharacteristic(characteristic.getValue());
// return true;
} else {
LOG.info("Unhandled characteristic changed: " + characteristicUUID);
logMessageContent(characteristic.getValue());
@ -851,6 +890,10 @@ public class MiBand2Support extends AbstractBTLEDeviceSupport {
return false;
}
private void handleUnknownCharacteristic(byte[] value) {
}
@Override
public boolean onCharacteristicRead(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic, int status) {

View File

@ -17,6 +17,7 @@ import nodomain.freeyourgadget.gadgetbridge.GBApplication;
import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.devices.DeviceCoordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.UnknownDeviceCoordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBand2Coordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst;
import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandCoordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.pebble.PebbleCoordinator;
@ -113,11 +114,11 @@ public class DeviceHelper {
GBDeviceCandidate candidate = new GBDeviceCandidate(device, GBDevice.RSSI_UNKNOWN);
if (coordinator != null && coordinator.supports(candidate)) {
return new GBDevice(device.getAddress(), candidate.getName(), coordinator.getDeviceType());
return coordinator.createDevice(candidate);
}
for (DeviceCoordinator coordinator : getAllCoordinators()) {
if (coordinator.supports(candidate)) {
return new GBDevice(device.getAddress(), candidate.getName(), coordinator.getDeviceType());
coordinator.createDevice(candidate);
}
}
return null;
@ -162,6 +163,7 @@ public class DeviceHelper {
private List<DeviceCoordinator> createCoordinators() {
List<DeviceCoordinator> result = new ArrayList<>(2);
result.add(new MiBand2Coordinator()); // Note: MiBand2 must come before MiBand because detection is hacky, atm
result.add(new MiBandCoordinator());
result.add(new PebbleCoordinator());
return result;