1
0
mirror of https://codeberg.org/Freeyourgadget/Gadgetbridge synced 2025-01-11 18:35:49 +01:00

More workout types and parser for rowing and for treadmill

This commit is contained in:
AndrewP 2024-11-30 20:26:56 +01:00 committed by José Rebelo
parent b5edfd8c17
commit 16a8efb7ee
3 changed files with 144 additions and 20 deletions

View File

@ -197,14 +197,14 @@ public class XiaomiActivityFileId implements Comparable<XiaomiActivityFileId> {
ACTIVITY_SLEEP(Type.ACTIVITY, 0x08),
SPORTS_OUTDOOR_RUNNING(Type.SPORTS, 0x01),
SPORTS_OUTDOOR_WALKING_V1(Type.SPORTS, 0x02),
SPORTS_TREADMILL(Type.SPORTS, 0x03), // TODO
SPORTS_TREADMILL(Type.SPORTS, 0x03),
SPORTS_OUTDOOR_CYCLING_V2(Type.SPORTS, 0x06), // TODO
SPORTS_INDOOR_CYCLING(Type.SPORTS, 0x07),
SPORTS_FREESTYLE(Type.SPORTS, 0x08),
SPORTS_POOL_SWIMMING(Type.SPORTS, 0x09),
SPORTS_HIIT(Type.SPORTS, 0x10),
SPORTS_ELLIPTICAL(Type.SPORTS, 0x0B),
SPORTS_ROWING(Type.SPORTS, 0x0D), // TODO
SPORTS_ROWING(Type.SPORTS, 0x0D),
SPORTS_ROPESKIPPING(Type.SPORTS, 0x0E), // TODO
SPORTS_OUTDOOR_WALKING_V2(Type.SPORTS, 0x16),
SPORTS_OUTDOOR_CYCLING(Type.SPORTS, 0x17),

View File

@ -193,7 +193,6 @@ public class WorkoutSummaryParser extends XiaomiActivityParser implements Activi
break;
case SPORTS_FREESTYLE:
summary.setActivityKind(ActivityKind.EXERCISE.getCode());
// summary.setActivityKind(ActivityKind.STRENGTH_TRAINING.getCode());
parser = getFreestyleParser(fileId);
break;
case SPORTS_POOL_SWIMMING:
@ -202,7 +201,6 @@ public class WorkoutSummaryParser extends XiaomiActivityParser implements Activi
break;
case SPORTS_HIIT:
summary.setActivityKind(ActivityKind.HIIT.getCode());
// summary.setActivityKind(ActivityKind.EXERCISE.getCode());
parser = getHiitParser(fileId);
break;
case SPORTS_ELLIPTICAL:
@ -215,6 +213,14 @@ public class WorkoutSummaryParser extends XiaomiActivityParser implements Activi
case SPORTS_OUTDOOR_CYCLING:
parser = getOutdoorCyclingParser(fileId);
break;
case SPORTS_TREADMILL:
summary.setActivityKind(ActivityKind.TREADMILL.getCode());
parser = getTreadmillParser(fileId);
break;
case SPORTS_ROWING:
summary.setActivityKind(ActivityKind.ROWING.getCode());
parser = getRowingParser(fileId);
break;
default:
LOG.warn("No workout summary parser for {}", fileId.getSubtypeCode());
break;
@ -269,22 +275,9 @@ public class WorkoutSummaryParser extends XiaomiActivityParser implements Activi
builder.addInt(HR_ZONE_FAT_BURN, UNIT_SECONDS);
builder.addInt(HR_ZONE_WARM_UP, UNIT_SECONDS);
if (version == 5) {
builder.addUnknown(11);
// TODO: next byte is FreestyleType?
// indoor cycling 0x07
// freestyle 0x08
// yoga 0x0c
// HIIT 0x10
// stair climbing 0x2d
// core training 0x2f
// flexibility 0x30
// pilates 0x31
// stretching 0x33
// strength 0x34
// aerobics 0x36
// roller skating 0xca
builder.addUnknown(1); // FREESTYLE_TYPE
builder.addUnknown(1);
builder.addUnknown(10);
builder.addShort(XIAOMI_WORKOUT_TYPE, UNIT_NONE);
builder.addUnknown(8);
} else {
builder.addUnknown(2);
builder.addUnknown(4);
@ -679,4 +672,78 @@ public class WorkoutSummaryParser extends XiaomiActivityParser implements Activi
return builder.build();
}
@Nullable
private XiaomiSimpleActivityParser getRowingParser(final XiaomiActivityFileId fileId) {
final int version = fileId.getVersion();
final int headerSize;
switch (version) {
case 4:
headerSize = 4;
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.addShort(CALORIES_BURNT, UNIT_KCAL);
builder.addByte(HR_AVG, UNIT_BPM);
builder.addByte(HR_MAX, UNIT_BPM);
builder.addByte(HR_MIN, UNIT_BPM);
builder.addUnknown(7);
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(2);
builder.addInt(STROKES, UNIT_STROKES);
builder.addInt(STROKE_RATE_AVG, UNIT_STROKES_PER_MINUTE);
builder.addUnknown(4); // STROKE_RATE_MAX, UNIT_STROKES_PER_MINUTE
builder.addUnknown(31);
return builder.build();
}
@Nullable
private XiaomiSimpleActivityParser getTreadmillParser(final XiaomiActivityFileId fileId) {
final int version = fileId.getVersion();
final int headerSize;
switch (version) {
case 5:
headerSize = 4;
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(4);
builder.addUnknown(4);
builder.addInt(STEPS, UNIT_STEPS);
builder.addUnknown(2); // MAX_STEPS_PER_MINUTE, UNIT_STEPS_PER_MINUTE
builder.addByte(HR_AVG, UNIT_BPM);
builder.addByte(HR_MAX, UNIT_BPM);
builder.addByte(HR_MIN, UNIT_BPM);
builder.addUnknown(8);
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(32);
return builder.build();
}
}

View File

@ -106,12 +106,69 @@ public class XiaomiSimpleActivityParser {
case 2:
summary.setActivityKind(ActivityKind.WALKING.getCode());
break;
case 4:
summary.setActivityKind(ActivityKind.TREKKING.getCode());
break;
case 6:
summary.setActivityKind(ActivityKind.OUTDOOR_CYCLING.getCode());
break;
case 7: // indoor cycling 0x0007
summary.setActivityKind(ActivityKind.INDOOR_CYCLING.getCode());
break;
case 8: // freestyle 0x0008
summary.setActivityKind(ActivityKind.FREE_TRAINING.getCode());
break;
case 12: // yoga 0x000c
summary.setActivityKind(ActivityKind.YOGA.getCode());
break;
case 15:
summary.setActivityKind(ActivityKind.OUTDOOR_WALKING.getCode());
break;
case 16: // HIIT 0x0010
summary.setActivityKind(ActivityKind.HIIT.getCode());
break;
case 201: // skateboard 0x00c9
summary.setActivityKind(ActivityKind.SKATEBOARDING.getCode());
break;
case 202: // roller skating 0x00ca
summary.setActivityKind(ActivityKind.ROLLER_SKATING.getCode());
break;
case 301: // stair climbing 0x012d
summary.setActivityKind(ActivityKind.STAIR_CLIMBER.getCode());
break;
case 303: // core training 0x012f
summary.setActivityKind(ActivityKind.CORE_TRAINING.getCode());
break;
case 304: // flexibility 0x0130
summary.setActivityKind(ActivityKind.FLEXIBILITY.getCode());
break;
case 305: // pilates 0x0131
summary.setActivityKind(ActivityKind.PILATES.getCode());
break;
case 307: // stretching 0x0133
summary.setActivityKind(ActivityKind.STRETCHING.getCode());
break;
case 308: // strength 0x0134
summary.setActivityKind(ActivityKind.STRENGTH_TRAINING.getCode());
break;
case 310: // aerobics 0x0136
summary.setActivityKind(ActivityKind.AEROBICS.getCode());
break;
case 499: // dancing 0x01f3
summary.setActivityKind(ActivityKind.PLAZA_DANCING.getCode());
break;
case 607: // table tennis 0x025f
summary.setActivityKind(ActivityKind.TABLE_TENNIS.getCode());
break;
case 609: // tennis 0x0261
summary.setActivityKind(ActivityKind.TENNIS.getCode());
break;
case 700: // ice skating 0x02bc
summary.setActivityKind(ActivityKind.ICE_SKATING.getCode());
break;
case 709: // skiing 0x02c5
summary.setActivityKind(ActivityKind.SKIING.getCode());
break;
default:
summary.setActivityKind(ActivityKind.UNKNOWN.getCode());
}