mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge
synced 2024-11-28 04:46:51 +01:00
Separate coordinator and support instances for Mi1 and Mi2 #323
+ Some more testing stuff for Mi2
This commit is contained in:
parent
26d490ffd6
commit
fbf06c1fe3
@ -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();
|
||||
}
|
||||
|
@ -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.
|
||||
*
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
}
|
||||
}
|
@ -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"));
|
||||
|
@ -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";
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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);
|
||||
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) {
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user