1
0
mirror of https://codeberg.org/Freeyourgadget/Gadgetbridge synced 2024-11-05 17:57:03 +01:00

Xiaomi: add swimming workout type (#3798)

Reviewed-on: https://codeberg.org/Freeyourgadget/Gadgetbridge/pulls/3798
Co-authored-by: Peter Kannewitz <peter.kannewitz@posteo.net>
Co-committed-by: Peter Kannewitz <peter.kannewitz@posteo.net>
This commit is contained in:
Peter Kannewitz 2024-05-29 20:52:26 +00:00 committed by José Rebelo
parent 72162469a1
commit 9acdd87029
3 changed files with 94 additions and 0 deletions

View File

@ -199,6 +199,7 @@ public class XiaomiActivityFileId implements Comparable<XiaomiActivityFileId> {
SPORTS_OUTDOOR_WALKING_V1(Type.SPORTS, 0x02), SPORTS_OUTDOOR_WALKING_V1(Type.SPORTS, 0x02),
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_ELLIPTICAL(Type.SPORTS, 0x0B), SPORTS_ELLIPTICAL(Type.SPORTS, 0x0B),
SPORTS_OUTDOOR_WALKING_V2(Type.SPORTS, 0x16), SPORTS_OUTDOOR_WALKING_V2(Type.SPORTS, 0x16),
SPORTS_OUTDOOR_CYCLING(Type.SPORTS, 0x17), SPORTS_OUTDOOR_CYCLING(Type.SPORTS, 0x17),

View File

@ -28,25 +28,37 @@ import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.HR_ZONE_EXTREME; import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.HR_ZONE_EXTREME;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.HR_ZONE_FAT_BURN; import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.HR_ZONE_FAT_BURN;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.HR_ZONE_WARM_UP; import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.HR_ZONE_WARM_UP;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.LANE_LENGTH;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.LAPS;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.LAP_PACE_AVERAGE;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.PACE_MAX; import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.PACE_MAX;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.PACE_MIN; import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.PACE_MIN;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.RECOVERY_TIME; import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.RECOVERY_TIME;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.SPEED_MAX; import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.SPEED_MAX;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.STEPS; import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.STEPS;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.STROKES;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.STROKE_RATE_AVG;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.SWIM_STYLE;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.SWOLF_AVG;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.SWOLF_INDEX;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.TIME_END; import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.TIME_END;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.TIME_START; import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.TIME_START;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.TRAINING_EFFECT_AEROBIC; import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.TRAINING_EFFECT_AEROBIC;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.TRAINING_EFFECT_ANAEROBIC; import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.TRAINING_EFFECT_ANAEROBIC;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.UNIT_BPM; import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.UNIT_BPM;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.UNIT_CM;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.UNIT_HOURS; import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.UNIT_HOURS;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.UNIT_KCAL; import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.UNIT_KCAL;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.UNIT_KMPH; import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.UNIT_KMPH;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.UNIT_LAPS;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.UNIT_METERS; import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.UNIT_METERS;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.UNIT_NONE; import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.UNIT_NONE;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.UNIT_SECONDS; import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.UNIT_SECONDS;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.UNIT_SECONDS_PER_M; import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.UNIT_SECONDS_PER_M;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.UNIT_SPM; import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.UNIT_SPM;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.UNIT_STEPS; import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.UNIT_STEPS;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.UNIT_STROKES;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.UNIT_STROKES_PER_MINUTE;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.UNIT_UNIX_EPOCH_SECONDS; import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.UNIT_UNIX_EPOCH_SECONDS;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.WORKOUT_LOAD; import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.WORKOUT_LOAD;
import static nodomain.freeyourgadget.gadgetbridge.service.devices.xiaomi.activity.impl.XiaomiSimpleActivityParser.XIAOMI_WORKOUT_TYPE; import static nodomain.freeyourgadget.gadgetbridge.service.devices.xiaomi.activity.impl.XiaomiSimpleActivityParser.XIAOMI_WORKOUT_TYPE;
@ -149,6 +161,10 @@ public class WorkoutSummaryParser extends XiaomiActivityParser implements Activi
summary.setActivityKind(ActivityKind.TYPE_STRENGTH_TRAINING); summary.setActivityKind(ActivityKind.TYPE_STRENGTH_TRAINING);
// TODO // TODO
break; break;
case SPORTS_POOL_SWIMMING:
summary.setActivityKind(ActivityKind.TYPE_SWIMMING);
parser = getPoolSwimmingParser(fileId);
break;
case SPORTS_ELLIPTICAL: case SPORTS_ELLIPTICAL:
summary.setActivityKind(ActivityKind.TYPE_ELLIPTICAL_TRAINER); summary.setActivityKind(ActivityKind.TYPE_ELLIPTICAL_TRAINER);
// TODO // TODO
@ -366,4 +382,63 @@ public class WorkoutSummaryParser extends XiaomiActivityParser implements Activi
return builder.build(); return builder.build();
} }
@Nullable
private XiaomiSimpleActivityParser getPoolSwimmingParser(final XiaomiActivityFileId fileId){
final int version = fileId.getVersion();
final int headerSize;
switch (version) {
case 6:
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(11);
builder.addShort(STROKES, UNIT_STROKES);
builder.addByte(SWIM_STYLE, UNIT_NONE);
builder.addUnknown(1);
builder.addShort(LAPS, UNIT_LAPS);
builder.addShort(SWOLF_AVG, UNIT_NONE);
builder.addUnknown(9);
// builder.addInt("activeSec2", UNIT_SECONDS);
builder.addInt("configuredTimeGoal", UNIT_SECONDS);
builder.addShort("configuredCaloriesGoal", UNIT_KCAL);
builder.addInt("configuredLaneLength", UNIT_CM);
builder.addUnknown(4);
builder.addByte("configuredLengthsGoal", UNIT_NONE);
builder.addUnknown(14);
builder.addByte("vitality_gain", UNIT_NONE);
builder.addUnknown(60);
// builder.addInt("startingTime2", UNIT_UNIX_EPOCH_SECONDS);
// builder.addInt("endTime2", UNIT_UNIX_EPOCH_SECONDS);
// builder.addUnknown(4);
// builder.addInt("activeSec3", UNIT_SECONDS);
// builder.addInt("activeSec4", UNIT_SECONDS);
// builder.addUnknown(8);
// builder.addInt("caloriesBurnt2", UNIT_KCAL);
// builder.addInt("distanceMeter2", UNIT_METERS);
// builder.addUnknown(4);
builder.addInt(LAP_PACE_AVERAGE, UNIT_SECONDS);
builder.addInt(PACE_MAX, UNIT_SECONDS); // not confirmed
builder.addUnknown(4);
builder.addInt(STROKE_RATE_AVG, UNIT_STROKES_PER_MINUTE);
builder.addUnknown(14);
// builder.addInt("laps2", UNIT_LAPS);
// builder.addShort("avgSWOLF2", UNIT_NONE);
builder.addShort("minSWOLF", UNIT_NONE); // not confirmed
builder.addShort("maxSWOLF", UNIT_NONE); // not confirmed
// builder.addInt("totalStrokes2", UNIT_STROKES);
return builder.build();
}
} }

View File

@ -16,6 +16,7 @@
along with this program. If not, see <https://www.gnu.org/licenses/>. */ along with this program. If not, see <https://www.gnu.org/licenses/>. */
package nodomain.freeyourgadget.gadgetbridge.service.devices.xiaomi.activity.impl; package nodomain.freeyourgadget.gadgetbridge.service.devices.xiaomi.activity.impl;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.SWIM_STYLE;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.TIME_END; import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.TIME_END;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.TIME_START; import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.TIME_START;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.UNIT_UNIX_EPOCH_SECONDS; import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.UNIT_UNIX_EPOCH_SECONDS;
@ -81,6 +82,23 @@ public class XiaomiSimpleActivityParser {
} }
} else if (dataEntry.getKey().equals(TIME_START)) { } else if (dataEntry.getKey().equals(TIME_START)) {
// ignored // ignored
} else if (dataEntry.getKey().equals(SWIM_STYLE)) {
String swimStyleName = "unknown";
Float swimStyle = value.floatValue();
if (swimStyle == 0) {
swimStyleName = "medley";
} else if (swimStyle == 1) {
swimStyleName = "breaststroke";
} else if (swimStyle == 2) {
swimStyleName = "freestyle";
} else if (swimStyle == 3) {
swimStyleName = "backstroke";
} else if (swimStyle == 4) {
swimStyleName = "butterfly";
}
addSummaryData(summaryData, dataEntry.getKey(), swimStyleName);
} else if (dataEntry.getKey().equals(XIAOMI_WORKOUT_TYPE)) { } else if (dataEntry.getKey().equals(XIAOMI_WORKOUT_TYPE)) {
// TODO use XiaomiWorkoutType // TODO use XiaomiWorkoutType
switch (value.intValue()) { switch (value.intValue()) {