1
0
mirror of https://codeberg.org/Freeyourgadget/Gadgetbridge synced 2024-12-24 17:45:50 +01:00

Xiaomi: Outdoor Cycling and GPX fix for Smart Band 8 Active

This commit is contained in:
AndrewP 2024-12-06 19:21:01 +01:00
parent 32109507d9
commit c01607dc06
3 changed files with 74 additions and 13 deletions

View File

@ -198,7 +198,7 @@ public class XiaomiActivityFileId implements Comparable<XiaomiActivityFileId> {
SPORTS_OUTDOOR_RUNNING(Type.SPORTS, 0x01), SPORTS_OUTDOOR_RUNNING(Type.SPORTS, 0x01),
SPORTS_OUTDOOR_WALKING_V1(Type.SPORTS, 0x02), SPORTS_OUTDOOR_WALKING_V1(Type.SPORTS, 0x02),
SPORTS_TREADMILL(Type.SPORTS, 0x03), SPORTS_TREADMILL(Type.SPORTS, 0x03),
SPORTS_OUTDOOR_CYCLING_V2(Type.SPORTS, 0x06), // TODO SPORTS_OUTDOOR_CYCLING_V2(Type.SPORTS, 0x06),
SPORTS_INDOOR_CYCLING(Type.SPORTS, 0x07), SPORTS_INDOOR_CYCLING(Type.SPORTS, 0x07),
SPORTS_FREESTYLE(Type.SPORTS, 0x08), SPORTS_FREESTYLE(Type.SPORTS, 0x08),
SPORTS_POOL_SWIMMING(Type.SPORTS, 0x09), SPORTS_POOL_SWIMMING(Type.SPORTS, 0x09),

View File

@ -58,6 +58,9 @@ public class WorkoutGpsParser extends XiaomiActivityParser {
final int sampleSize; final int sampleSize;
switch (version) { switch (version) {
case 1: case 1:
headerSize = 1;
sampleSize = 12;
break;
case 2: case 2:
headerSize = 1; headerSize = 1;
sampleSize = 18; sampleSize = 18;
@ -85,21 +88,34 @@ public class WorkoutGpsParser extends XiaomiActivityParser {
final ActivityTrack activityTrack = new ActivityTrack(); final ActivityTrack activityTrack = new ActivityTrack();
while (buf.position() < buf.limit()) { // GPS V1 contains no speed data, therefore second while loop to avoid too many ifs within the loop
final int ts = buf.getInt(); if (version == 1) {
final float longitude = buf.getFloat(); while (buf.position() < buf.limit()) {
final float latitude = buf.getFloat(); final int ts = buf.getInt();
final int unk1 = buf.getInt(); // 0 final float longitude = buf.getFloat();
final float speed = (buf.getShort() >> 2) / 10.0f; final float latitude = buf.getFloat();
final ActivityPoint ap = new ActivityPoint(new Date(ts * 1000L)); final ActivityPoint ap = new ActivityPoint(new Date(ts * 1000L));
ap.setLocation(new GPSCoordinate(longitude, latitude, 0)); ap.setLocation(new GPSCoordinate(longitude, latitude, 0));
activityTrack.addTrackPoint(ap); activityTrack.addTrackPoint(ap);
LOG.trace("ActivityPoint V1: ts={} lon={} lat={}", ts, longitude, latitude);
}
} else {
while (buf.position() < buf.limit()) {
final int ts = buf.getInt();
final float longitude = buf.getFloat();
final float latitude = buf.getFloat();
final int unk1 = buf.getInt(); // 0
final float speed = (buf.getShort() >> 2) / 10.0f;
LOG.trace("ActivityPoint: ts={} lon={} lat={} unk1={} speed={}", ts, longitude, latitude, unk1, speed); final ActivityPoint ap = new ActivityPoint(new Date(ts * 1000L));
ap.setLocation(new GPSCoordinate(longitude, latitude, 0));
activityTrack.addTrackPoint(ap);
LOG.trace("ActivityPoint: ts={} lon={} lat={} unk1={} speed={}", ts, longitude, latitude, unk1, speed);
}
} }
try (DBHandler dbHandler = GBApplication.acquireDB()) { try (DBHandler dbHandler = GBApplication.acquireDB()) {
final DaoSession session = dbHandler.getDaoSession(); final DaoSession session = dbHandler.getDaoSession();
final Device device = DBHelper.getDevice(support.getDevice(), session); final Device device = DBHelper.getDevice(support.getDevice(), session);
final User user = DBHelper.getUser(session); final User user = DBHelper.getUser(session);

View File

@ -210,6 +210,10 @@ public class WorkoutSummaryParser extends XiaomiActivityParser implements Activi
case SPORTS_OUTDOOR_WALKING_V2: case SPORTS_OUTDOOR_WALKING_V2:
parser = getOutdoorWalkingV2Parser(fileId); parser = getOutdoorWalkingV2Parser(fileId);
break; break;
case SPORTS_OUTDOOR_CYCLING_V2:
summary.setActivityKind(ActivityKind.OUTDOOR_CYCLING.getCode());
parser = getOutdoorCyclingV2Parser(fileId);
break;
case SPORTS_OUTDOOR_CYCLING: case SPORTS_OUTDOOR_CYCLING:
parser = getOutdoorCyclingParser(fileId); parser = getOutdoorCyclingParser(fileId);
break; break;
@ -277,7 +281,10 @@ public class WorkoutSummaryParser extends XiaomiActivityParser implements Activi
if (version == 5) { if (version == 5) {
builder.addUnknown(10); builder.addUnknown(10);
builder.addShort(XIAOMI_WORKOUT_TYPE, UNIT_NONE); builder.addShort(XIAOMI_WORKOUT_TYPE, UNIT_NONE);
builder.addUnknown(8); builder.addUnknown(2);
builder.addUnknown(2); // configuredTimeGoal, UNIT_SECONDS
builder.addUnknown(2);
builder.addUnknown(2); // configuredCaloriesGoal, UNIT_KCAL
} else { } else {
builder.addUnknown(2); builder.addUnknown(2);
builder.addUnknown(4); builder.addUnknown(4);
@ -749,4 +756,42 @@ public class WorkoutSummaryParser extends XiaomiActivityParser implements Activi
return builder.build(); return builder.build();
} }
@Nullable
private XiaomiSimpleActivityParser getOutdoorCyclingV2Parser(final XiaomiActivityFileId fileId) {
final int version = fileId.getVersion();
final int headerSize;
switch (version) {
case 4:
headerSize = 5;
break;
default:
LOG.warn("Unable to parse workout summary version {}", fileId.getVersion());
return null;
}
final XiaomiSimpleActivityParser.Builder builder = new XiaomiSimpleActivityParser.Builder();
builder.setHeaderSize(headerSize);
builder.addInt(TIME_START, UNIT_UNIX_EPOCH_SECONDS);
builder.addInt(TIME_END, UNIT_UNIX_EPOCH_SECONDS);
builder.addInt(ACTIVE_SECONDS, UNIT_SECONDS);
builder.addInt(DISTANCE_METERS, UNIT_METERS);
builder.addShort(CALORIES_BURNT, UNIT_KCAL);
builder.addUnknown(8);
builder.addFloat(SPEED_MAX, UNIT_KMPH);
builder.addByte(HR_AVG, UNIT_BPM);
builder.addByte(HR_MAX, UNIT_BPM);
builder.addByte(HR_MIN, UNIT_BPM);
builder.addUnknown(28);
builder.addInt(HR_ZONE_EXTREME, UNIT_SECONDS);
builder.addInt(HR_ZONE_ANAEROBIC, UNIT_SECONDS);
builder.addInt(HR_ZONE_AEROBIC, UNIT_SECONDS);
builder.addInt(HR_ZONE_FAT_BURN, UNIT_SECONDS);
builder.addInt(HR_ZONE_WARM_UP, UNIT_SECONDS);
builder.addUnknown(18);
builder.addUnknown(2); // configuredTimeGoal, UNIT_SECONDS
builder.addUnknown(6);
return builder.build();
}
} }