1
0
mirror of https://codeberg.org/Freeyourgadget/Gadgetbridge synced 2024-12-24 01:25: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_WALKING_V1(Type.SPORTS, 0x02),
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_FREESTYLE(Type.SPORTS, 0x08),
SPORTS_POOL_SWIMMING(Type.SPORTS, 0x09),

View File

@ -58,6 +58,9 @@ public class WorkoutGpsParser extends XiaomiActivityParser {
final int sampleSize;
switch (version) {
case 1:
headerSize = 1;
sampleSize = 12;
break;
case 2:
headerSize = 1;
sampleSize = 18;
@ -85,21 +88,34 @@ public class WorkoutGpsParser extends XiaomiActivityParser {
final ActivityTrack activityTrack = new ActivityTrack();
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;
// GPS V1 contains no speed data, therefore second while loop to avoid too many ifs within the loop
if (version == 1) {
while (buf.position() < buf.limit()) {
final int ts = buf.getInt();
final float longitude = buf.getFloat();
final float latitude = buf.getFloat();
final ActivityPoint ap = new ActivityPoint(new Date(ts * 1000L));
ap.setLocation(new GPSCoordinate(longitude, latitude, 0));
activityTrack.addTrackPoint(ap);
final ActivityPoint ap = new ActivityPoint(new Date(ts * 1000L));
ap.setLocation(new GPSCoordinate(longitude, latitude, 0));
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 Device device = DBHelper.getDevice(support.getDevice(), 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:
parser = getOutdoorWalkingV2Parser(fileId);
break;
case SPORTS_OUTDOOR_CYCLING_V2:
summary.setActivityKind(ActivityKind.OUTDOOR_CYCLING.getCode());
parser = getOutdoorCyclingV2Parser(fileId);
break;
case SPORTS_OUTDOOR_CYCLING:
parser = getOutdoorCyclingParser(fileId);
break;
@ -277,7 +281,10 @@ public class WorkoutSummaryParser extends XiaomiActivityParser implements Activi
if (version == 5) {
builder.addUnknown(10);
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 {
builder.addUnknown(2);
builder.addUnknown(4);
@ -749,4 +756,42 @@ public class WorkoutSummaryParser extends XiaomiActivityParser implements Activi
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();
}
}