Merge pull request 'Garmin: enhance activity summaries' (#5996)

Reviewed-on: https://codeberg.org/Freeyourgadget/Gadgetbridge/pulls/5996
This commit is contained in:
José Rebelo
2026-04-14 22:27:18 +02:00
20 changed files with 867 additions and 128 deletions
@@ -100,6 +100,9 @@ object ActivitySummaryGroup {
ActivitySummaryEntries.HR_AVG,
ActivitySummaryEntries.HR_MAX,
ActivitySummaryEntries.HR_MIN,
ActivitySummaryEntries.RECOVERY_HR,
ActivitySummaryEntries.HR_USER_RESTING,
ActivitySummaryEntries.HR_USER_MAX,
)
)
@@ -180,6 +183,7 @@ object ActivitySummaryGroup {
ActivitySummaryEntries.AVG_RIGHT_POWER_PHASE_PEAK,
ActivitySummaryEntries.AVG_POWER_SEATING,
ActivitySummaryEntries.AVG_POWER_STANDING,
ActivitySummaryEntries.TOTAL_WORK,
)
)
@@ -240,6 +244,10 @@ object ActivitySummaryGroup {
ActivitySummaryEntries.MAX_CADENCE_SEATING,
ActivitySummaryEntries.FRONT_GEAR_SHIFTS,
ActivitySummaryEntries.REAR_GEAR_SHIFTS,
ActivitySummaryEntries.BATTERY_LEVEL_EBIKE_START,
ActivitySummaryEntries.BATTERY_LEVEL_EBIKE_END,
ActivitySummaryEntries.MOUNTAIN_BIKE_GRIT_SCORE,
ActivitySummaryEntries.MOUNTAIN_BIKE_FLOW_SCORE,
)
)
@@ -248,13 +256,19 @@ object ActivitySummaryGroup {
ActivitySummaryEntries.GROUP_TRAINING_EFFECT, listOf<String>(
ActivitySummaryEntries.TRAINING_EFFECT_AEROBIC,
ActivitySummaryEntries.TRAINING_EFFECT_ANAEROBIC,
ActivitySummaryEntries.TRAINING_EFFECT_TOTAL,
ActivitySummaryEntries.WORKOUT_LOAD,
ActivitySummaryEntries.TRAINING_LOAD,
ActivitySummaryEntries.INTENSITY_FACTOR,
ActivitySummaryEntries.TRAINING_STRESS_SCORE,
ActivitySummaryEntries.MAXIMUM_OXYGEN_UPTAKE,
ActivitySummaryEntries.RECOVERY_TIME_REMAINING_AT_START,
ActivitySummaryEntries.RECOVERY_TIME,
ActivitySummaryEntries.BODY_ENERGY_AT_START,
ActivitySummaryEntries.BODY_ENERGY_AT_END,
ActivitySummaryEntries.LACTATE_THRESHOLD_HR,
ActivitySummaryEntries.RATING_OF_PERCEIVED_EXERTION,
ActivitySummaryEntries.WORKOUT_FEEL,
)
)
@@ -298,9 +312,14 @@ object ActivitySummaryGroup {
ActivitySummaryEntries.BOTTOM_TIME,
ActivitySummaryEntries.OXYGEN_TOXICITY,
ActivitySummaryEntries.SURFACE_INTERVAL,
ActivitySummaryEntries.PRESSURE_SAC_AVG,
ActivitySummaryEntries.WATER_TYPE
)
)
// Diving Gas
put(ActivitySummaryEntries.GROUP_GAS, listOf())
// Recovery Heart Rate
put(ActivitySummaryEntries.GROUP_RECOVERY_HEART_RATE, listOf<String>())
@@ -359,6 +378,16 @@ object ActivitySummaryGroup {
ActivitySummaryEntries.STRIDE_TOTAL,
))
// Gear Info - e.g. last battery level
put(
ActivitySummaryEntries.GROUP_GEAR_INFO, listOf(
ActivitySummaryEntries.BATTERY_LEVEL_START,
ActivitySummaryEntries.BATTERY_LEVEL_END,
ActivitySummaryEntries.BATTERY_GAIN
)
)
// Other
put(
ActivitySummaryEntries.GROUP_OTHER, listOf<String>(
@@ -367,6 +396,10 @@ object ActivitySummaryGroup {
ActivitySummaryEntries.CALORIES_BURNT,
ActivitySummaryEntries.CALORIES_TOTAL,
ActivitySummaryEntries.CALORIES_RESTING,
ActivitySummaryEntries.CALORIES_CONSUMED,
ActivitySummaryEntries.SPO2_AVG,
ActivitySummaryEntries.STRESS_AVG,
ActivitySummaryEntries.SOLAR_INTENSITY,
)
)
}
@@ -27,6 +27,10 @@ public class ActivitySummaryTableBuilder {
rows.put(rowId, row);
}
public boolean hasRows() {
return !rows.isEmpty();
}
public void addToSummaryData(final ActivitySummaryData summaryData) {
final int numColumns = headerColumns.size();
final boolean[] anyNonNullOrZero = new boolean[numColumns];
@@ -32,7 +32,9 @@ import java.util.Arrays;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.TreeMap;
import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.activities.workouts.charts.DefaultWorkoutCharts;
@@ -51,9 +53,14 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.FitFile;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.RecordData;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.enums.GarminSport;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.exception.FitParseException;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionBatteryStatus.BatteryStatus;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionExerciseCategory.ExerciseCategory;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionMeasurementSystem;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionWaterType.WaterType;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.messages.FitDeviceInfo;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.messages.FitDeviceStatus;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.messages.FitDiveGas;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.messages.FitDiveSettings;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.messages.FitDiveSummary;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.messages.FitLap;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.messages.FitPhysiologicalMetrics;
@@ -62,7 +69,9 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.messages.
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.messages.FitSet;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.messages.FitSport;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.messages.FitTimeInZone;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.messages.FitUserMetrics;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.messages.FitUserProfile;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.messages.FitWorkout;
import nodomain.freeyourgadget.gadgetbridge.util.FileUtils;
import nodomain.freeyourgadget.gadgetbridge.util.StringUtils;
@@ -76,12 +85,25 @@ public class GarminWorkoutParser implements ActivitySummaryParser {
private List<ActivityPoint> sessionActivityPoints;
private FitSession session = null;
private FitSport sport = null;
private FitUserMetrics userMetrics = null;
private FitUserProfile userProfile = null;
private FitPhysiologicalMetrics physiologicalMetrics = null;
private FitDiveSettings diveSettings = null;
private FitDiveSummary diveSummary = null;
private final List<FitDiveGas> diveGases = new ArrayList<>();
private final List<FitSet> sets = new ArrayList<>();
private final List<FitLap> laps = new ArrayList<>();
private final Map<Integer, FitDeviceInfo> deviceInfos = new TreeMap<>();
@Nullable
private FitDeviceStatus deviceStatusStart = null;
@Nullable
private FitDeviceStatus deviceStatusEnd = null;
@Nullable
private Number ebikeBatteryStart = null;
@Nullable
private Number ebikeBatteryEnd = null;
@Nullable
private FitWorkout workout = null;
public GarminWorkoutParser(final Context context) {
this.context = context;
@@ -161,17 +183,33 @@ public class GarminWorkoutParser implements ActivitySummaryParser {
activityPoints.clear();
session = null;
sport = null;
userMetrics = null;
userProfile = null;
physiologicalMetrics = null;
diveSettings = null;
diveSummary = null;
diveGases.clear();
sets.clear();
laps.clear();
deviceInfos.clear();
deviceStatusStart = null;
deviceStatusEnd = null;
ebikeBatteryStart = null;
ebikeBatteryEnd = null;
workout = null;
}
public boolean handleRecord(final RecordData record) {
if (record instanceof FitRecord) {
activityPoints.add(((FitRecord) record).toActivityPoint());
if (record instanceof FitRecord fitRecord) {
activityPoints.add(fitRecord.toActivityPoint());
final Integer ebikeBattery = fitRecord.getEbikeBatteryLevel();
if (ebikeBattery != null) {
if (ebikeBatteryStart == null) {
ebikeBatteryStart = ebikeBattery;
} else {
ebikeBatteryEnd = ebikeBattery;
}
}
} else if (record instanceof FitSession) {
LOG.debug("Session: {}", record);
if (session != null) {
@@ -209,6 +247,12 @@ public class GarminWorkoutParser implements ActivitySummaryParser {
// We only support 1 user profile
userProfile = (FitUserProfile) record;
}
} else if (record instanceof FitUserMetrics metrics) {
if (userMetrics != null) {
LOG.warn("Got multiple user metrics - NOT SUPPORTED: {}", record);
} else {
userMetrics = metrics;
}
} else if (record instanceof FitDiveSummary newDiveSummary) {
LOG.trace("Dive summary: {}", record);
if (diveSummary != null) {
@@ -229,6 +273,53 @@ public class GarminWorkoutParser implements ActivitySummaryParser {
} else if (record instanceof FitDiveGas) {
LOG.trace("Dive gas: {}", record);
diveGases.add((FitDiveGas) record);
}else if(record instanceof FitDiveSettings settings){
if (diveSettings != null) {
LOG.warn("Got multiple dive settings - NOT SUPPORTED: {}", record);
} else {
diveSettings = settings;
}
} else if (record instanceof FitDeviceInfo deviceInfo) {
Integer deviceIndex = deviceInfo.getDeviceIndex();
if (deviceIndex == null) {
// Suunto quirk
deviceIndex = Integer.MAX_VALUE;
}
boolean relevant = false;
// extract the latest battery related information
final Integer level = deviceInfo.getBatteryLevel();
if (level != null && level != 0) {
relevant = true;
} else {
final Float volt = deviceInfo.getBatteryVoltage();
if (volt != null && volt != 0) {
relevant = true;
} else {
BatteryStatus batteryStatus = deviceInfo.getBatteryStatus();
if (batteryStatus != null && batteryStatus != BatteryStatus.Unknown) {
relevant = true;
}
}
}
if (relevant) {
deviceInfos.put(deviceIndex, deviceInfo);
}
} else if (record instanceof FitDeviceStatus deviceStatus) {
if (deviceStatusStart == null) {
deviceStatusStart = deviceStatus;
} else {
deviceStatusEnd = deviceStatus;
}
// FitImporter implements the main processing for these records
return false;
} else if (record instanceof FitWorkout fitWorkout) {
if (workout != null) {
LOG.warn("Got multiple workout - NOT SUPPORTED: {}", record);
} else {
workout = fitWorkout;
}
} else {
return false;
}
@@ -245,13 +336,28 @@ public class GarminWorkoutParser implements ActivitySummaryParser {
}
final ActivityKind activityKind;
if (sport != null) {
if (StringUtils.isNullOrEmpty(summary.getName())) {
summary.setName(sport.getName());
// prioritize names: FitWorkout > FitSession > FitSport
if (StringUtils.isNullOrEmpty(summary.getName())) {
String workoutName = null;
if (workout != null) {
workoutName = workout.getName();
}
activityKind = getActivityKind(sport.getSport(), sport.getSubSport());
} else {
if (StringUtils.isNullOrEmpty(workoutName)) {
workoutName = session.getSportProfileName();
}
if (StringUtils.isNullOrEmpty(workoutName) && sport != null) {
workoutName = sport.getName();
}
if (!StringUtils.isNullOrEmpty(workoutName)) {
summary.setName(workoutName);
}
}
if (sport == null || session.getSport() != null) {
activityKind = getActivityKind(session.getSport(), session.getSubSport());
} else {
activityKind = getActivityKind(sport.getSport(), sport.getSubSport());
}
final ActivityKind.CycleUnit cycleUnit = ActivityKind.getCycleUnit(activityKind);
@@ -274,12 +380,8 @@ public class GarminWorkoutParser implements ActivitySummaryParser {
if (session.getTotalDistance() != null) {
summaryData.add(DISTANCE_METERS, session.getTotalDistance() / 100f, UNIT_METERS);
}
if (session.getPoolLength() != null) {
summaryData.add(POOL_LENGTH, session.getPoolLength(), UNIT_METERS);
}
if (session.getAvgSwolf() != null) {
summaryData.add(SWOLF_AVG, session.getAvgSwolf(), UNIT_NONE);
}
summaryData.add(POOL_LENGTH, session.getPoolLength(), UNIT_METERS);
summaryData.add(SWOLF_AVG, session.getAvgSwolf(), UNIT_NONE);
if (session.getTotalCycles() != null && cycleUnit != ActivityKind.CycleUnit.NONE) {
if (cycleUnit == ActivityKind.CycleUnit.STEPS) {
summaryData.addTotal(session.getTotalCycles() * 2, cycleUnit);
@@ -297,39 +399,30 @@ public class GarminWorkoutParser implements ActivitySummaryParser {
summaryData.add(CALORIES_RESTING, session.getRestingCalories(), UNIT_KCAL);
}
}
if (session.getFluidConsumed() != null) {
summaryData.add(FLUID_CONSUMED, session.getFluidConsumed(), UNIT_ML);
}
if (session.getEstimatedSweatLoss() != null) {
summaryData.add(ESTIMATED_SWEAT_LOSS, session.getEstimatedSweatLoss(), UNIT_ML);
}
if (session.getAverageHeartRate() != null) {
summaryData.add(HR_AVG, session.getAverageHeartRate(), UNIT_BPM);
}
if (session.getMaxHeartRate() != null) {
summaryData.add(HR_MAX, session.getMaxHeartRate(), UNIT_BPM);
}
if (session.getHrvSdrr() != null) {
summaryData.add(HRV_SDRR, session.getHrvSdrr(), UNIT_MILLISECONDS);
}
if (session.getHrvRmssd() != null) {
summaryData.add(HRV_RMSSD, session.getHrvRmssd(), UNIT_MILLISECONDS);
}
if (session.getAvgSpo2() != null) {
summaryData.add(SPO2_AVG, session.getAvgSpo2(), UNIT_PERCENTAGE);
}
if (session.getEnhancedMinRespirationRate() != null) {
summaryData.add(RESPIRATION_MIN, session.getEnhancedMinRespirationRate(), UNIT_BREATHS_PER_MIN);
}
if (session.getEnhancedMaxRespirationRate() != null) {
summaryData.add(RESPIRATION_MAX, session.getEnhancedMaxRespirationRate(), UNIT_BREATHS_PER_MIN);
}
if (session.getEnhancedAvgRespirationRate() != null) {
summaryData.add(RESPIRATION_AVG, session.getEnhancedAvgRespirationRate(), UNIT_BREATHS_PER_MIN);
}
if (session.getAvgStress() != null) {
summaryData.add(STRESS_AVG, session.getAvgStress(), UNIT_NONE);
}
summaryData.add(FLUID_CONSUMED, session.getFluidConsumed(), UNIT_ML);
summaryData.add(ESTIMATED_SWEAT_LOSS, session.getEstimatedSweatLoss(), UNIT_ML);
summaryData.add(HR_MIN, session.getMinHeartRate(), UNIT_BPM);
summaryData.add(HR_AVG, session.getAverageHeartRate(), UNIT_BPM);
summaryData.add(HR_MAX, session.getMaxHeartRate(), UNIT_BPM);
summaryData.add(HRV_SDRR, session.getHrvSdrr(), UNIT_MILLISECONDS);
summaryData.add(HRV_RMSSD, session.getHrvRmssd(), UNIT_MILLISECONDS);
summaryData.add(SPO2_AVG, session.getAvgSpo2(), UNIT_PERCENTAGE);
summaryData.add(RESPIRATION_MIN, UNIT_BREATHS_PER_MIN,
session.getEnhancedMinRespirationRate(), session.getMinRespirationRate());
summaryData.add(RESPIRATION_MAX, UNIT_BREATHS_PER_MIN,
session.getEnhancedMaxRespirationRate(), session.getMaxRespirationRate());
summaryData.add(RESPIRATION_AVG, UNIT_BREATHS_PER_MIN,
session.getEnhancedAvgRespirationRate(), session.getAvgRespirationRate());
summaryData.add(ALTITUDE_MIN, UNIT_METERS,
session.getEnhancedMinAltitude(), session.getMinAltitude());
summaryData.add(ALTITUDE_MAX, UNIT_METERS,
session.getEnhancedMaxAltitude(), session.getMaxAltitude());
summaryData.add(ALTITUDE_AVG, UNIT_METERS,
session.getEnhancedAvgAltitude(), session.getAvgAltitude());
summaryData.add(STRESS_AVG, session.getAvgStress(), UNIT_NONE);
if (session.getAvgCadence() != null) {
if (cycleUnit == ActivityKind.CycleUnit.STEPS) {
summaryData.addCadenceAvg(session.getAvgCadence() * 2, cycleUnit);
@@ -346,46 +439,51 @@ public class GarminWorkoutParser implements ActivitySummaryParser {
summaryData.addCadenceMax(session.getMaxCadence(), cycleUnit);
}
}
if (session.getTotalAscent() != null && !ActivityKind.isDiving(activityKind)) {
if (!ActivityKind.isDiving(activityKind)) {
summaryData.add(TOTAL_ASCENT, session.getTotalAscent(), UNIT_METERS);
}
if (session.getTotalDescent() != null && !ActivityKind.isDiving(activityKind)) {
summaryData.add(TOTAL_DESCENT, session.getTotalDescent(), UNIT_METERS);
if (session.getAvgVam() != null) {
summaryData.add(AVERAGE_ASCENT_VELOCITY, session.getAvgVam() * 3600, UNIT_METERS_PER_HOUR);
}
}
if (session.getAvgVam() != null && !ActivityKind.isDiving(activityKind)) {
summaryData.add(AVERAGE_ASCENT_VELOCITY, session.getAvgVam() * 3600, UNIT_METERS_PER_HOUR);
}
if (session.getAvgSwimCadence() != null) {
summaryData.add(SWIM_AVG_CADENCE, session.getAvgSwimCadence(), UNIT_STROKES_PER_LENGTH);
}
summaryData.add(SWIM_AVG_CADENCE, session.getAvgSwimCadence(), UNIT_STROKES_PER_LENGTH);
if (session.getEnhancedAvgSpeed() != null) {
Number speedAvg = session.getEnhancedAvgSpeed();
if(speedAvg == null){
speedAvg = session.getAvgSpeed();
}
if (speedAvg != null) {
if (ActivityKind.isPaceActivity(activityKind)) {
summaryData.add(PACE_AVG_SECONDS_KM, Math.round((60 / (session.getEnhancedAvgSpeed() * 3.6)) * 60), UNIT_SECONDS);
summaryData.add(PACE_AVG_SECONDS_KM, Math.round((60 / (speedAvg.doubleValue() * 3.6)) * 60), UNIT_SECONDS);
} else if (ActivityKind.isDiving(activityKind)) {
// Hide speed for diving activities
} else {
summaryData.add(SPEED_AVG, Math.round((session.getEnhancedAvgSpeed() * 3600 / 1000) * 100.0) / 100.0, UNIT_KMPH);
summaryData.add(SPEED_AVG, speedAvg.doubleValue() * 3600 / 1000, UNIT_KMPH);
}
}
if (session.getEnhancedMaxSpeed() != null) {
Number speedMax = session.getEnhancedMaxSpeed();
if(speedMax == null){
speedMax = session.getMaxSpeed();
}
if (speedMax != null) {
if (ActivityKind.isPaceActivity(activityKind)) {
summaryData.add(PACE_MAX, Math.round((60 / (session.getEnhancedMaxSpeed() * 3.6)) * 60), UNIT_SECONDS);
} else if (ActivityKind.isDiving(activityKind)) { // Hide average speed for diving activities
summaryData.add(PACE_MAX, Math.round((60 / (speedMax.doubleValue() * 3.6)) * 60), UNIT_SECONDS);
} else if (ActivityKind.isDiving(activityKind)) {
// Hide speed for diving activities
} else {
summaryData.add(SPEED_MAX, Math.round((session.getEnhancedMaxSpeed() * 3600 / 1000) * 100.0) / 100.0, UNIT_KMPH);
summaryData.add(SPEED_MAX, speedMax.doubleValue() * 3600 / 1000, UNIT_KMPH);
}
}
if (session.getRecoveryHeartRate() != null){
summaryData.add(RECOVERY_HR, session.getRecoveryHeartRate(), UNIT_BPM);
}
if (session.getWorkoutRpe() != null){
summaryData.add(RATING_OF_PERCEIVED_EXERTION, session.getWorkoutRpe(), UNIT_PERCENTAGE);
}
summaryData.add(RECOVERY_HR, session.getRecoveryHeartRate(), UNIT_BPM);
summaryData.add(RATING_OF_PERCEIVED_EXERTION, session.getWorkoutRpe(), UNIT_PERCENTAGE);
summaryData.add(WORKOUT_FEEL, session.getWorkoutFeel(), UNIT_PERCENTAGE);
summaryData.add(AVG_POWER, session.getAvgPower(), UNIT_WATT);
summaryData.add(MAX_POWER, session.getMaxPower(), UNIT_WATT);
summaryData.add(NORMALIZED_POWER, session.getNormalizedPower(), UNIT_WATT);
summaryData.add(TOTAL_WORK, session.getTotalWork(), UNIT_JOULE);
if (session.getStandTime() != null) {
summaryData.add(STANDING_TIME, session.getStandTime() / 1000, UNIT_SECONDS);
@@ -596,63 +694,61 @@ public class GarminWorkoutParser implements ActivitySummaryParser {
if (physiologicalMetrics.getRecoveryTime() != null) {
summaryData.add(RECOVERY_TIME, physiologicalMetrics.getRecoveryTime() * 60, UNIT_SECONDS);
}
if (physiologicalMetrics.getLactateThresholdHeartRate() != null) {
summaryData.add(LACTATE_THRESHOLD_HR, physiologicalMetrics.getLactateThresholdHeartRate(), UNIT_BPM);
}
summaryData.add(LACTATE_THRESHOLD_HR, physiologicalMetrics.getLactateThresholdHeartRate(), UNIT_BPM);
}
summaryData.add(TRAINING_LOAD, safeRound(session.getTrainingLoadPeak()), UNIT_NONE);
if (diveSummary != null) {
if (diveSummary.getDiveNumber() != null) {
summaryData.add(DIVE_NUMBER, diveSummary.getDiveNumber(), UNIT_NONE);
}
if (diveSummary.getBottomTime() != null) {
summaryData.add(BOTTOM_TIME, diveSummary.getBottomTime(), UNIT_SECONDS);
}
if (diveSummary.getAvgDepth() != null) {
summaryData.add(AVG_DEPTH, diveSummary.getAvgDepth(), UNIT_METERS);
}
if (diveSummary.getMaxDepth() != null) {
summaryData.add(MAX_DEPTH, diveSummary.getMaxDepth(), UNIT_METERS);
}
summaryData.add(DIVE_NUMBER, diveSummary.getDiveNumber(), UNIT_NONE);
summaryData.add(BOTTOM_TIME, diveSummary.getBottomTime(), UNIT_SECONDS);
summaryData.add(AVG_DEPTH, diveSummary.getAvgDepth(), UNIT_METERS);
summaryData.add(MAX_DEPTH, diveSummary.getMaxDepth(), UNIT_METERS);
if (diveSummary.getStartCns() != null) {
summaryData.add(START_CNS, diveSummary.getStartCns(), UNIT_PERCENTAGE, true);
}
if (diveSummary.getEndCns() != null) {
summaryData.add(END_CNS, diveSummary.getEndCns(), UNIT_PERCENTAGE);
}
summaryData.add(END_CNS, diveSummary.getEndCns(), UNIT_PERCENTAGE);
if (diveSummary.getStartN2() != null) {
summaryData.add(START_N2, diveSummary.getStartN2(), UNIT_PERCENTAGE, true);
}
if (diveSummary.getEndN2() != null) {
summaryData.add(END_N2, diveSummary.getEndN2(), UNIT_PERCENTAGE);
}
if (diveSummary.getO2Toxicity() != null) {
summaryData.add(OXYGEN_TOXICITY, diveSummary.getO2Toxicity(), UNIT_OXYGEN_TOXICITY_UNITs);
}
if (diveSummary.getSurfaceInterval() != null) {
summaryData.add(SURFACE_INTERVAL, diveSummary.getSurfaceInterval(), UNIT_SECONDS);
summaryData.add(END_N2, diveSummary.getEndN2(), UNIT_PERCENTAGE);
summaryData.add(OXYGEN_TOXICITY, diveSummary.getO2Toxicity(), UNIT_OXYGEN_TOXICITY_UNITs);
summaryData.add(SURFACE_INTERVAL, diveSummary.getSurfaceInterval(), UNIT_SECONDS);
summaryData.add(PRESSURE_SAC_AVG, diveSummary.getAvgPressureSac(), UNIT_BAR_PER_MINUTE);
}
if (diveSettings != null) {
if (diveSettings.getWaterDensity() != null) {
summaryData.add(WATER_TYPE, diveSettings.getWaterDensity(), UNIT_KG_PER_M3);
} else {
WaterType waterType = diveSettings.getWaterType();
if (waterType != null) {
summaryData.add(WATER_TYPE, waterType.toString(context));
}
}
}
summaryData.add(TEMPERATURE_MIN, session.getMinTemperature(), UNIT_CELSIUS);
summaryData.add(TEMPERATURE_MAX, session.getMaxTemperature(), UNIT_CELSIUS);
summaryData.add(TEMPERATURE_AVG, session.getAvgTemperature(), UNIT_CELSIUS);
// MTB-specific metrics
summaryData.add("activity_type_mountain_bike", MOUNTAIN_BIKE_GRIT_SCORE, session.getTotalGrit(), UNIT_NONE);
summaryData.add("activity_type_mountain_bike", MOUNTAIN_BIKE_FLOW_SCORE, session.getAvgFlow(), UNIT_NONE);
summaryData.add(BATTERY_LEVEL_EBIKE_START, ebikeBatteryStart, UNIT_PERCENTAGE);
summaryData.add(BATTERY_LEVEL_EBIKE_END, ebikeBatteryEnd, UNIT_PERCENTAGE);
summaryData.add(TRAINING_LOAD, safeRound(session.getTrainingLoadPeak()), UNIT_NONE);
// MTB-specific metrics
summaryData.add(MOUNTAIN_BIKE_GRIT_SCORE, session.getTotalGrit(), UNIT_NONE);
summaryData.add(MOUNTAIN_BIKE_FLOW_SCORE, session.getAvgFlow(), UNIT_NONE);
summaryData.add(TRAINING_LOAD, session.getTrainingLoadPeak(), UNIT_NONE);
summaryData.add(INTENSITY_FACTOR, session.getIntensityFactor(), UNIT_NONE);
summaryData.add(TRAINING_STRESS_SCORE, session.getTrainingStressScore(), UNIT_NONE);
summaryData.add(TRAINING_EFFECT_TOTAL, session.getTotalTrainingEffect(), UNIT_NONE);
summaryData.add(BODY_ENERGY_AT_START, session.getBeginningBodyBattery(), UNIT_PERCENTAGE);
summaryData.add(BODY_ENERGY_AT_END, session.getEndingBodyBattery(), UNIT_PERCENTAGE);
summaryData.add(SOLAR_INTENSITY, safeRound(session.getSolarIntensity()), UNIT_PERCENTAGE);
if (session.getBatteryGain() != null) {
summaryData.add(BATTERY_GAIN, session.getBatteryGain(), UNIT_SECONDS);
}
summaryData.add(BATTERY_GAIN, session.getBatteryGain(), UNIT_SECONDS);
if (!diveGases.isEmpty()) {
final ActivitySummaryTableBuilder tableBuilder = new ActivitySummaryTableBuilder(GAS, "gases_header", Arrays.asList(
final ActivitySummaryTableBuilder tableBuilder = new ActivitySummaryTableBuilder(GROUP_GAS, "gases_header", Arrays.asList(
"diving_gas",
"helium_content",
"oxygen_content",
@@ -661,6 +757,12 @@ public class GarminWorkoutParser implements ActivitySummaryParser {
int i = 1;
for (final FitDiveGas gas : diveGases) {
final Integer gasStatus = gas.getStatus();
if (gasStatus != null && gasStatus == 0) {
// ignore disabled gasses
continue;
}
int helium = gas.getHeliumContent() != null ? gas.getHeliumContent() : 0;
int oxygen = gas.getOxygenContent() != null ? gas.getOxygenContent() : 0;
int nitrogen = 100 - helium - oxygen;
@@ -676,7 +778,89 @@ public class GarminWorkoutParser implements ActivitySummaryParser {
i++;
}
tableBuilder.addToSummaryData(summaryData);
if (tableBuilder.hasRows()) {
tableBuilder.addToSummaryData(summaryData);
}
}
if (userProfile != null) {
summaryData.add(HR_USER_RESTING, userProfile.getRestingHeartRate(), UNIT_BPM);
}
if (userMetrics != null) {
final Integer remainingRecoveryTime = userMetrics.getRemainingRecoveryTime();
if (remainingRecoveryTime != null && remainingRecoveryTime > 1) {
summaryData.add(RECOVERY_TIME_REMAINING_AT_START, userMetrics.getRemainingRecoveryTime() * 60, UNIT_SECONDS);
}
summaryData.add(HR_USER_MAX, userMetrics.getMaxHr(), UNIT_BPM);
}
if (!deviceInfos.isEmpty()) {
final ActivitySummaryTableBuilder tableBuilder = new ActivitySummaryTableBuilder(GROUP_GEAR_INFO, "gear_info_header", Arrays.asList(
"device",
"battery_status",
"battery_level"
));
for (final Map.Entry<Integer, FitDeviceInfo> entry : deviceInfos.entrySet()) {
final Integer deviceIndex = entry.getKey();
final FitDeviceInfo deviceInfo = entry.getValue();
Object device = deviceInfo.getProductName();
if (device == null) {
device = deviceInfo.getSerialNumber();
if (device == null) {
device = deviceIndex;
}
}
BatteryStatus rawStatus = deviceInfo.getBatteryStatus();
@Nullable final String status;
if (rawStatus != null) {
status = rawStatus.toString(context);
} else {
status = null;
}
Number level = deviceInfo.getBatteryLevel();
String level_uom = UNIT_PERCENTAGE;
if (level == null) {
level = deviceInfo.getBatteryVoltage();
level_uom = UNIT_VOLT;
}
tableBuilder.addRow(
"device_info_" + deviceIndex,
Arrays.asList(
new ActivitySummaryValue(device, UNIT_NONE),
new ActivitySummaryValue(status),
new ActivitySummaryValue(level, level_uom)
)
);
}
if (tableBuilder.hasRows()) {
tableBuilder.addToSummaryData(summaryData);
}
}
if (deviceStatusStart != null) {
Number batteryLevel = deviceStatusStart.getBatteryLevel();
String batteryUom = UNIT_PERCENTAGE;
if (batteryLevel == null) {
batteryLevel = deviceStatusStart.getBatteryVoltage();
batteryUom = UNIT_VOLT;
}
summaryData.add(BATTERY_LEVEL_START, batteryLevel, batteryUom);
}
if (deviceStatusEnd != null) {
Number batteryLevel = deviceStatusEnd.getBatteryLevel();
String batteryUom = UNIT_PERCENTAGE;
if (batteryLevel == null) {
batteryLevel = deviceStatusEnd.getBatteryVoltage();
batteryUom = UNIT_VOLT;
}
summaryData.add(BATTERY_LEVEL_END, batteryLevel, batteryUom);
}
if (!sets.isEmpty()) {
@@ -112,7 +112,7 @@ public class ActivityPoint {
/// nitrogen (N2) tissue load (e.g. Diving)
/// @see ActivitySummaryEntries#UNIT_PERCENTAGE
public float getN2Load() {
return cnsToxicity;
return n2Load;
}
/// @see ActivitySummaryEntries#UNIT_METERS
@@ -66,6 +66,14 @@ public class ActivitySummaryData {
add(null, key, value, unit, false);
}
public void add(final String key, final String unit, final Number value, final Number valueFallback) {
if (value != null) {
add(null, key, value, unit, false);
} else {
add(null, key, valueFallback, unit, false);
}
}
public void add(final String key, final Number value, final String unit, boolean forceDisplay) {
add(null, key, value, unit, forceDisplay);
}
@@ -123,6 +123,8 @@ public class ActivitySummaryEntries {
public static final String HR_AVG = "averageHR";
public static final String HR_MAX = "maxHR";
public static final String HR_MIN = "minHR";
public static final String HR_USER_RESTING = "hr_user_resting";
public static final String HR_USER_MAX = "hr_user_max";
public static final String HR_ZONE_NA = "hrZoneNa";
public static final String HR_ZONE_WARM_UP = "hrZoneWarmUp";
public static final String HR_ZONE_EASY = "hrZoneEasy";
@@ -182,6 +184,7 @@ public class ActivitySummaryEntries {
public static final String CALORIES_RESTING = "restingCalories";
public static final String TRAINING_EFFECT_AEROBIC = "aerobicTrainingEffect";
public static final String TRAINING_EFFECT_ANAEROBIC = "anaerobicTrainingEffect";
public static final String TRAINING_EFFECT_TOTAL = "training_effect_total";
public static final String WORKOUT_LOAD = "currentWorkoutLoad";
public static final String MAXIMUM_OXYGEN_UPTAKE = "maximumOxygenUptake";
public static final String RECOVERY_TIME = "recoveryTime";
@@ -190,6 +193,7 @@ public class ActivitySummaryEntries {
public static final String ESTIMATED_SWEAT_LOSS = "estimatedSweatLoss";
public static final String LACTATE_THRESHOLD_HR = "lactateThresholdHeartRate";
public static final String RATING_OF_PERCEIVED_EXERTION = "ratingOfPerceivedExertion";
public static final String WORKOUT_FEEL = "workout_feel";
public static final String CYCLING_POWER_AVERAGE = "cyclingPowerAverage";
public static final String CYCLING_POWER_MIN = "cyclingPowerMin";
@@ -258,6 +262,9 @@ public class ActivitySummaryEntries {
public static final String UNIT_KNOTS = "knots";
public static final String UNIT_CELSIUS = "unit_celsius";
public static final String UNIT_OXYGEN_TOXICITY_UNITs = "unit_oxygen_toxicity_units";
public static final String UNIT_BAR_PER_MINUTE = "unit_bar_per_minute";
public static final String UNIT_VOLT = "unit_volt";
public static final String UNIT_KG_PER_M3 = "unit_kg_per_m3";
public static final String GROUP_PACE = "Pace";
public static final String GROUP_ACTIVITY = "Activity";
@@ -283,6 +290,8 @@ public class ActivitySummaryEntries {
public static final String GROUP_MOVEMENT_EVALUATION = "movement_evaluation";
public static final String GROUP_DISTANCE = "Distance";
public static final String GROUP_STEPS = "Steps";
public static final String GROUP_BIKE = "activity_type_biking";
public static final String GROUP_GEAR_INFO = "Gear";
public static final String AVG_DEPTH = "diving_avg_depth";
public static final String START_CNS = "diving_start_cns";
public static final String END_CNS = "diving_end_cns";
@@ -292,11 +301,19 @@ public class ActivitySummaryEntries {
public static final String BOTTOM_TIME = "diving_bottom_time";
public static final String OXYGEN_TOXICITY = "diving_oxygen_toxicity";
public static final String SURFACE_INTERVAL = "diving_surface_interval";
public static final String PRESSURE_SAC_AVG = "diving_pressure_sac_avg";
public static final String RECOVERY_TIME_REMAINING_AT_START = "recovery_time_remaining_at_start";
public static final String BODY_ENERGY_AT_START = "body_energy_at_start";
public static final String BODY_ENERGY_AT_END = "body_energy_at_end";
public static final String TOTAL_WORK = "total_work";
public static final String BATTERY_LEVEL_START = "battery_level_start";
public static final String BATTERY_LEVEL_END = "battery_level_end";
public static final String BATTERY_LEVEL_EBIKE_START = "battery_level_ebike_start";
public static final String BATTERY_LEVEL_EBIKE_END = "battery_level_ebike_end";
// DIVING parameters
public static final String MAX_DEPTH = "diving_maximum_diving_depth";
public static final String WATER_TYPE = "diving_water_type";
public static final String GAS = "diving_gas";
public static final String GROUP_GAS = "diving_gas";
/**
* Used to signal that this activity has a gps track. This is currently used by ActivitySummaryDetail
@@ -4,6 +4,7 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.baseTypes
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionAlarm;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionAlarmLabel;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionArray;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionBatteryStatus;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionBoolean;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionCoordinate;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionCoursePoint;
@@ -12,6 +13,7 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefi
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionFileType;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionGoalSource;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionGoalType;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionWaterType;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionWeatherReport;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionHrTimeInZone;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionHrZoneHighBoundary;
@@ -56,6 +58,8 @@ public class FieldDefinitionFactory {
case LOCATION_SYMBOL -> new FieldDefinitionLocationSymbol(localNumber, size, baseType, name, scale, offset);
case COURSE_POINT -> new FieldDefinitionCoursePoint(localNumber, size, baseType, name, scale, offset);
case WEATHER_REPORT -> new FieldDefinitionWeatherReport(localNumber, size, baseType, name);
case BATTERY_STATUS -> new FieldDefinitionBatteryStatus(localNumber, size, baseType, name, scale, offset);
case WATER_TYPE -> new FieldDefinitionWaterType(localNumber, size, baseType, name, scale, offset);
};
}
@@ -84,5 +88,7 @@ public class FieldDefinitionFactory {
LOCATION_SYMBOL,
COURSE_POINT,
WEATHER_REPORT,
BATTERY_STATUS,
WATER_TYPE
}
}
@@ -281,6 +281,7 @@ public class NativeFITMessage {
new FieldDefinitionPrimitive(69, BaseType.UINT32, "avg_lap_time", 1000, 0), // s
new FieldDefinitionPrimitive(70, BaseType.UINT16, "best_lap_index"),
new FieldDefinitionPrimitive(71, BaseType.UINT16, "min_altitude", 5, 500), // m
new FieldDefinitionPrimitive(78, BaseType.UINT32, "work_time"), // ms
new FieldDefinitionPrimitive(79, BaseType.UINT16, "avg_swim_cadence", 10, 0), // rpm
new FieldDefinitionPrimitive(80, BaseType.UINT16, "avg_swolf"),
new FieldDefinitionPrimitive(82, BaseType.UINT16, "player_score"),
@@ -347,6 +348,8 @@ public class NativeFITMessage {
new FieldDefinitionPrimitive(148, BaseType.UINT8, "max_respiration_rate"),
new FieldDefinitionPrimitive(149, BaseType.UINT8, "min_respiration_rate"),
new FieldDefinitionPrimitive(150, BaseType.SINT8, "min_temperature"), // C
new FieldDefinitionPrimitive(151, BaseType.UINT16, "total_sets"),
new FieldDefinitionPrimitive(152, BaseType.UINT32, "volume", 100, 0), // kg
new FieldDefinitionPrimitive(155, BaseType.UINT16, "o2_toxicity"), // OTUs
new FieldDefinitionPrimitive(156, BaseType.UINT32, "dive_number"),
new FieldDefinitionPrimitive(168, BaseType.SINT32, "training_load_peak", 65536, 0),
@@ -359,6 +362,7 @@ public class NativeFITMessage {
new FieldDefinitionPrimitive(181, BaseType.FLOAT32, "total_grit"),
new FieldDefinitionPrimitive(182, BaseType.FLOAT32, "total_flow"),
new FieldDefinitionPrimitive(183, BaseType.UINT16, "jump_count"),
new FieldDefinitionPrimitive(185, BaseType.UINT8, "execution_score"), // %
new FieldDefinitionPrimitive(186, BaseType.FLOAT32, "avg_grit"),
new FieldDefinitionPrimitive(187, BaseType.FLOAT32, "avg_flow"),
new FieldDefinitionPrimitive(188, BaseType.ENUM, "primary_benefit"), // 1 recovery
@@ -380,8 +384,16 @@ public class NativeFITMessage {
new FieldDefinitionPrimitive(208, BaseType.UINT16, "avg_core_temperature", 100, 0), // °C
new FieldDefinitionPrimitive(209, BaseType.UINT16, "min_core_temperature", 100, 0), // °C
new FieldDefinitionPrimitive(210, BaseType.UINT16, "max_core_temperature", 100, 0), // °C
new FieldDefinitionPrimitive(211, BaseType.UINT32, "grade_adjusted_speed", 1000, 0), // m/s
new FieldDefinitionPrimitive(212, BaseType.ENUM, "wind_data"),
new FieldDefinitionPrimitive(215, BaseType.UINT8, "beginning_body_battery"),
new FieldDefinitionPrimitive(216, BaseType.UINT8, "ending_body_battery"),
new FieldDefinitionPrimitive(220, BaseType.UINT16, "pack_weight", 10, 0), // kg
new FieldDefinitionPrimitive(222, BaseType.UINT16, "step_speed_loss", 100, 0),
new FieldDefinitionPrimitive(223, BaseType.UINT16, "step_speed_loss_percentage", 100, 0),
new FieldDefinitionPrimitive(224, BaseType.SINT32, "avg_force", 1000, 0), // N
new FieldDefinitionPrimitive(225, BaseType.SINT32, "max_force", 1000, 0), // N
new FieldDefinitionPrimitive(226, BaseType.SINT32, "normalized_force", 1000, 0), // N
new FieldDefinitionPrimitive(253, BaseType.UINT32, "timestamp", FieldDefinitionFactory.FIELD.TIMESTAMP),
new FieldDefinitionPrimitive(254, BaseType.UINT16, "message_index")
));
@@ -414,6 +426,10 @@ public class NativeFITMessage {
new FieldDefinitionPrimitive(24, BaseType.ENUM, "lap_trigger"), // 0 manual
new FieldDefinitionPrimitive(25, BaseType.ENUM, "sport"), // 5 swimming
new FieldDefinitionPrimitive(26, BaseType.UINT8, "event_group"),
new FieldDefinitionPrimitive(25, BaseType.SINT32, "nec_lat", FieldDefinitionFactory.FIELD.COORDINATE),
new FieldDefinitionPrimitive(26, BaseType.SINT32, "nec_long", FieldDefinitionFactory.FIELD.COORDINATE),
new FieldDefinitionPrimitive(27, BaseType.SINT32, "swc_lat", FieldDefinitionFactory.FIELD.COORDINATE),
new FieldDefinitionPrimitive(28, BaseType.SINT32, "swc_long", FieldDefinitionFactory.FIELD.COORDINATE),
new FieldDefinitionPrimitive(32, BaseType.UINT16, "num_lengths"),
new FieldDefinitionPrimitive(33, BaseType.UINT16, "normalized_power"), // watt
new FieldDefinitionPrimitive(34, BaseType.UINT16, "left_right_balance"),
@@ -497,11 +513,13 @@ public class NativeFITMessage {
new FieldDefinitionPrimitive(124, BaseType.SINT8, "min_temperature"), // °C
new FieldDefinitionPrimitive(136, BaseType.UINT16, "enhanced_avg_respiration_rate", 100, 0), // breath / min
new FieldDefinitionPrimitive(137, BaseType.UINT16, "enhanced_max_respiration_rate", 100, 0), // breath / min
new FieldDefinitionPrimitive(145, BaseType.UINT16, "est_sweat_loss"),
new FieldDefinitionPrimitive(147, BaseType.UINT8, "avg_respiration_rate"),
new FieldDefinitionPrimitive(148, BaseType.UINT8, "max_respiration_rate"),
new FieldDefinitionPrimitive(149, BaseType.FLOAT32, "total_grit"),
new FieldDefinitionPrimitive(150, BaseType.FLOAT32, "total_flow"),
new FieldDefinitionPrimitive(151, BaseType.UINT16, "jump_count"),
new FieldDefinitionPrimitive(152, BaseType.UINT8, "execution_score"),
new FieldDefinitionPrimitive(153, BaseType.FLOAT32, "avg_grit"),
new FieldDefinitionPrimitive(154, BaseType.FLOAT32, "avg_flow"),
new FieldDefinitionPrimitive(156, BaseType.UINT8, "total_fractional_ascent", 100, 0), // m
@@ -573,6 +591,7 @@ public class NativeFITMessage {
new FieldDefinitionPrimitive(84, BaseType.UINT16, "stance_time_balance", 100, 0), // %
new FieldDefinitionPrimitive(85, BaseType.UINT16, "step_length", 10, 0), // mm
new FieldDefinitionPrimitive(87, BaseType.UINT16, "cycle_length16", 100, 0), // m
new FieldDefinitionPrimitive(90, BaseType.SINT8, "performance_condition"),
new FieldDefinitionPrimitive(91, BaseType.UINT32, "absolute_pressure", 1, 0), // Pa
new FieldDefinitionPrimitive(92, BaseType.UINT32, "depth", 1000, 0), // m
new FieldDefinitionPrimitive(93, BaseType.UINT32, "next_stop_depth", 1000, 0), // m
@@ -590,17 +609,23 @@ public class NativeFITMessage {
new FieldDefinitionPrimitive(118, BaseType.UINT8, "ebike_battery_level"), // %
new FieldDefinitionPrimitive(119, BaseType.UINT8, "ebike_assist_mode"),
new FieldDefinitionPrimitive(120, BaseType.UINT8, "ebike_assist_level_percent"), // %
new FieldDefinitionPrimitive(121, BaseType.UINT16, "total_ascent"), // m
new FieldDefinitionPrimitive(123, BaseType.UINT32, "air_time_remaining"), // s
new FieldDefinitionPrimitive(124, BaseType.UINT16, "pressure_sac", 100, 0), // bar / min
new FieldDefinitionPrimitive(125, BaseType.UINT16, "volume_sac", 100, 0), // liter / min
new FieldDefinitionPrimitive(126, BaseType.UINT16, "rmv", 100, 0), // liter / min
new FieldDefinitionPrimitive(127, BaseType.SINT32, "ascent_rate", 1000, 0), // m/s
new FieldDefinitionPrimitive(129, BaseType.UINT8, "po2", 100, 0), // %
new FieldDefinitionPrimitive(136, BaseType.UINT8, "wrist_heart_rate"),
new FieldDefinitionPrimitive(136, BaseType.UINT8, "wrist_heart_rate"), // BPM
new FieldDefinitionPrimitive(137, BaseType.UINT8, "stamina_potential"), // %
new FieldDefinitionPrimitive(138, BaseType.UINT8, "stamina"), // %
new FieldDefinitionPrimitive(139, BaseType.UINT16, "core_temperature", 100, 0), // °C
new FieldDefinitionPrimitive(140, BaseType.UINT32, "grade_adjusted_speed", 1000, 0), // m/s
new FieldDefinitionPrimitive(143, BaseType.UINT8, "body_battery"),
new FieldDefinitionPrimitive(144, BaseType.UINT8, "external_heart_rate"), // BPM
new FieldDefinitionPrimitive(146, BaseType.UINT16, "step_speed_loss_distance", 100, 0), // cm/s
new FieldDefinitionPrimitive(147, BaseType.UINT16, "step_speed_loss_percentage", 100, 0), // %
new FieldDefinitionPrimitive(148, BaseType.SINT32, "force", 1000, 0), // N
new FieldDefinitionPrimitive(253, BaseType.UINT32, "timestamp", FieldDefinitionFactory.FIELD.TIMESTAMP)
));
@@ -646,7 +671,7 @@ public class NativeFITMessage {
new FieldDefinitionPrimitive(6, BaseType.UINT8, "hardware_version"),
new FieldDefinitionPrimitive(7, BaseType.UINT32, "cum_operating_time"), // s
new FieldDefinitionPrimitive(10, BaseType.UINT16, "battery_voltage", 256, 0), // V
new FieldDefinitionPrimitive(11, BaseType.UINT8, "battery_status"),
new FieldDefinitionPrimitive(11, BaseType.UINT8, "battery_status", FieldDefinitionFactory.FIELD.BATTERY_STATUS),
new FieldDefinitionPrimitive(18, BaseType.ENUM, "sensor_position"),
new FieldDefinitionPrimitive(19, BaseType.STRING, "descriptor"),
new FieldDefinitionPrimitive(20, BaseType.UINT8Z, "ant_transmission_type"),
@@ -861,6 +886,8 @@ public class NativeFITMessage {
new FieldDefinitionPrimitive(32, BaseType.UINT32, "descent", 1000, 0), // m
new FieldDefinitionPrimitive(33, BaseType.UINT16, "moderate_activity_minutes"),
new FieldDefinitionPrimitive(34, BaseType.UINT16, "vigorous_activity_minutes"),
new FieldDefinitionPrimitive(35, BaseType.UINT32, "total_ascent", 1000, 0), // m
new FieldDefinitionPrimitive(36, BaseType.UINT32, "total_descent", 1000, 0), // m
new FieldDefinitionPrimitive(253, BaseType.UINT32, "timestamp", FieldDefinitionFactory.FIELD.TIMESTAMP)
));
@@ -1519,7 +1546,7 @@ public class NativeFITMessage {
new FieldDefinitionPrimitive(1, BaseType.ENUM, "model"),
new FieldDefinitionPrimitive(2, BaseType.UINT8, "gf_low"), // %
new FieldDefinitionPrimitive(3, BaseType.UINT8, "gf_high"), // %
new FieldDefinitionPrimitive(4, BaseType.ENUM, "water_type"), // %
new FieldDefinitionPrimitive(4, BaseType.ENUM, "water_type", FieldDefinitionFactory.FIELD.WATER_TYPE),
new FieldDefinitionPrimitive(5, BaseType.FLOAT32, "water_density"), // kg/m^3
new FieldDefinitionPrimitive(6, BaseType.UINT8, "po2_warn", 100, 0), // %
new FieldDefinitionPrimitive(7, BaseType.UINT8, "po2_critical", 100, 0), // %
@@ -1811,15 +1838,15 @@ public class NativeFITMessage {
public static NativeFITMessage ECG_SUMMARY = new NativeFITMessage(336, "ECG_SUMMARY", Arrays.asList(
new FieldDefinitionPrimitive(0, BaseType.UINT16, "unknown_0"), // 10103
new FieldDefinitionPrimitive(1, BaseType.ENUM, "unknown_1"), // 3
new FieldDefinitionPrimitive(2, BaseType.FLOAT32, "unknown_2"), // 512
new FieldDefinitionPrimitive(3, BaseType.FLOAT32, "unknown_3"), // 128
new FieldDefinitionPrimitive(2, BaseType.FLOAT32, "raw_sample_rate"), // 512
new FieldDefinitionPrimitive(3, BaseType.FLOAT32, "smooth_sample_rate"), // 128
new FieldDefinitionPrimitive(4, BaseType.UINT32, "ecg_timestamp", FieldDefinitionFactory.FIELD.TIMESTAMP),
new FieldDefinitionPrimitive(5, BaseType.UINT32, "local_timestamp"), // garmin timestamp, but in user timezone
new FieldDefinitionPrimitive(6, BaseType.ENUM, "unknown_6"), // 1
new FieldDefinitionPrimitive(7, BaseType.FLOAT32, "average_heart_rate"), // bpm
new FieldDefinitionPrimitive(10, BaseType.STRING, "unknown_10"), // ?
new FieldDefinitionPrimitive(11, BaseType.UINT16, "unknown_11"), // 30
new FieldDefinitionPrimitive(12, BaseType.UINT8, "unknown_12") // 39
new FieldDefinitionPrimitive(11, BaseType.UINT16, "sample_time"), // s
new FieldDefinitionPrimitive(12, BaseType.UINT8, "sdrr_hrv") // ms
));
public static NativeFITMessage ECG_RAW_SAMPLE = new NativeFITMessage(337, "ECG_RAW_SAMPLE", Arrays.asList(
@@ -29,10 +29,12 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.RecordDef
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.RecordHeader;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.baseTypes.BaseType;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionAlarmLabel;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionBatteryStatus;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionCoursePoint;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionExerciseCategory;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionGoalSource;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionGoalType;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionWaterType;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionWeatherReport;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionHrvStatus;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionLanguage;
@@ -366,6 +368,8 @@ public class FitCodeGen {
case LOCATION_SYMBOL -> FieldDefinitionLocationSymbol.LocationSymbol.class;
case COURSE_POINT -> FieldDefinitionCoursePoint.CoursePoint.class;
case WEATHER_REPORT -> FieldDefinitionWeatherReport.Type.class;
case BATTERY_STATUS -> FieldDefinitionBatteryStatus.BatteryStatus.class;
case WATER_TYPE -> FieldDefinitionWaterType.WaterType.class;
};
}
@@ -120,6 +120,7 @@ public enum GarminSport {
SOFTBALL(50, 0, ActivityKind.SOFTBALL),
SOFTBALL_SLOW_PITCH(51, 0, ActivityKind.SOFTBALL_SLOW_PITCH),
STOPWATCH(52, 0, ActivityKind.STOP_WATCH),
DIVING(53, 0, ActivityKind.DIVING),
SINGLE_GAS_DIVING(53, 53, ActivityKind.SCUBA_DIVING),
MULTI_GAS_DIVING(53, 54, ActivityKind.SCUBA_DIVING),
GAUGE_DIVING(53, 55, ActivityKind.DIVING),
@@ -0,0 +1,78 @@
package nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions;
import android.content.Context;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
import java.nio.ByteBuffer;
import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.FieldDefinition;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.baseTypes.BaseType;
public class FieldDefinitionBatteryStatus extends FieldDefinition {
public FieldDefinitionBatteryStatus(int localNumber, int size, BaseType baseType, String name, int scale, int offset) {
super(localNumber, size, baseType, name, scale, offset);
}
@Nullable
@Override
public Object decode(ByteBuffer byteBuffer) {
final Object rawObj = baseType.decode(byteBuffer, scale, offset);
if (rawObj != null) {
final int raw = (int) rawObj;
return BatteryStatus.fromId(raw);
}
return null;
}
@Override
public void encode(ByteBuffer byteBuffer, Object o) {
if (o instanceof BatteryStatus) {
baseType.encode(byteBuffer, (((BatteryStatus) o).getId()), scale, offset);
return;
}
baseType.encode(byteBuffer, o, scale, offset);
}
public enum BatteryStatus {
New(1, R.string.battery_status_new),
Good(2, R.string.battery_status_good),
Ok(3, R.string.battery_status_ok),
Low(4, R.string.battery_status_low),
Critical(5, R.string.battery_status_critical),
Charging(6, R.string.battery_status_charging),
Unknown(7, R.string.battery_status_unknown),
;
private final int id;
@StringRes
private final int stringRes;
BatteryStatus(int i, @StringRes int text) {
id = i;
stringRes = text;
}
@Nullable
public static BatteryStatus fromId(int id) {
for (BatteryStatus batteryStatus : values()) {
if (id == batteryStatus.id) {
return batteryStatus;
}
}
return null;
}
public int getId() {
return id;
}
public String toString(@NonNull Context context) {
return context.getString(stringRes);
}
}
}
@@ -0,0 +1,75 @@
package nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions;
import android.content.Context;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
import java.nio.ByteBuffer;
import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.FieldDefinition;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.baseTypes.BaseType;
public class FieldDefinitionWaterType extends FieldDefinition {
public FieldDefinitionWaterType(int localNumber, int size, BaseType baseType, String name, int scale, int offset) {
super(localNumber, size, baseType, name, scale, offset);
}
@Nullable
@Override
public Object decode(ByteBuffer byteBuffer) {
final Object rawObj = baseType.decode(byteBuffer, scale, offset);
if (rawObj != null) {
final int raw = (int) rawObj;
return WaterType.fromId(raw);
}
return null;
}
@Override
public void encode(ByteBuffer byteBuffer, Object o) {
if (o instanceof WaterType) {
baseType.encode(byteBuffer, (((WaterType) o).getId()), scale, offset);
return;
}
baseType.encode(byteBuffer, o, scale, offset);
}
public enum WaterType {
Fresh(0, R.string.water_type_fresh),
Salt(1, R.string.water_type_salt),
En13319(2, R.string.water_type_en13319),
Custom(3, R.string.water_type_custom),
;
private final int id;
@StringRes
private final int stringRes;
WaterType(int i, @StringRes int text) {
id = i;
stringRes = text;
}
@Nullable
public static WaterType fromId(int id) {
for (WaterType waterType : values()) {
if (id == waterType.id) {
return waterType;
}
}
return null;
}
public int getId() {
return id;
}
public String toString(@NonNull Context context) {
return context.getString(stringRes);
}
}
}
@@ -22,6 +22,7 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.FitRecord
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.RecordData;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.RecordDefinition;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.RecordHeader;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionBatteryStatus.BatteryStatus;
/**
* WARNING: This class was auto-generated, please avoid modifying it directly.
@@ -85,8 +86,8 @@ public class FitDeviceInfo extends RecordData {
}
@Nullable
public Integer getBatteryStatus() {
return getFieldByNumber(11, Integer.class);
public BatteryStatus getBatteryStatus() {
return getFieldByNumber(11, BatteryStatus.class);
}
@Nullable
@@ -192,7 +193,7 @@ public class FitDeviceInfo extends RecordData {
return this;
}
public Builder setBatteryStatus(final Integer value) {
public Builder setBatteryStatus(final BatteryStatus value) {
setFieldByNumber(11, value);
return this;
}
@@ -22,6 +22,7 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.FitRecord
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.RecordData;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.RecordDefinition;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.RecordHeader;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionWaterType.WaterType;
/**
* WARNING: This class was auto-generated, please avoid modifying it directly.
@@ -60,8 +61,8 @@ public class FitDiveSettings extends RecordData {
}
@Nullable
public Integer getWaterType() {
return getFieldByNumber(4, Integer.class);
public WaterType getWaterType() {
return getFieldByNumber(4, WaterType.class);
}
@Nullable
@@ -242,7 +243,7 @@ public class FitDiveSettings extends RecordData {
return this;
}
public Builder setWaterType(final Integer value) {
public Builder setWaterType(final WaterType value) {
setFieldByNumber(4, value);
return this;
}
@@ -50,12 +50,12 @@ public class FitEcgSummary extends RecordData {
}
@Nullable
public Float getUnknown2() {
public Float getRawSampleRate() {
return getFieldByNumber(2, Float.class);
}
@Nullable
public Float getUnknown3() {
public Float getSmoothSampleRate() {
return getFieldByNumber(3, Float.class);
}
@@ -85,12 +85,12 @@ public class FitEcgSummary extends RecordData {
}
@Nullable
public Integer getUnknown11() {
public Integer getSampleTime() {
return getFieldByNumber(11, Integer.class);
}
@Nullable
public Integer getUnknown12() {
public Integer getSdrrHrv() {
return getFieldByNumber(12, Integer.class);
}
@@ -112,12 +112,12 @@ public class FitEcgSummary extends RecordData {
return this;
}
public Builder setUnknown2(final Float value) {
public Builder setRawSampleRate(final Float value) {
setFieldByNumber(2, value);
return this;
}
public Builder setUnknown3(final Float value) {
public Builder setSmoothSampleRate(final Float value) {
setFieldByNumber(3, value);
return this;
}
@@ -147,12 +147,12 @@ public class FitEcgSummary extends RecordData {
return this;
}
public Builder setUnknown11(final Integer value) {
public Builder setSampleTime(final Integer value) {
setFieldByNumber(11, value);
return this;
}
public Builder setUnknown12(final Integer value) {
public Builder setSdrrHrv(final Integer value) {
setFieldByNumber(12, value);
return this;
}
@@ -175,6 +175,26 @@ public class FitLap extends RecordData {
return getFieldByNumber(26, Integer.class);
}
@Nullable
public Double getNecLat() {
return getFieldByNumber(25, Double.class);
}
@Nullable
public Double getNecLong() {
return getFieldByNumber(26, Double.class);
}
@Nullable
public Double getSwcLat() {
return getFieldByNumber(27, Double.class);
}
@Nullable
public Double getSwcLong() {
return getFieldByNumber(28, Double.class);
}
@Nullable
public Integer getNumLengths() {
return getFieldByNumber(32, Integer.class);
@@ -590,6 +610,11 @@ public class FitLap extends RecordData {
return getFieldByNumber(137, Float.class);
}
@Nullable
public Integer getEstSweatLoss() {
return getFieldByNumber(145, Integer.class);
}
@Nullable
public Integer getAvgRespirationRate() {
return getFieldByNumber(147, Integer.class);
@@ -615,6 +640,11 @@ public class FitLap extends RecordData {
return getFieldByNumber(151, Integer.class);
}
@Nullable
public Integer getExecutionScore() {
return getFieldByNumber(152, Integer.class);
}
@Nullable
public Float getAvgGrit() {
return getFieldByNumber(153, Float.class);
@@ -803,6 +833,26 @@ public class FitLap extends RecordData {
return this;
}
public Builder setNecLat(final Double value) {
setFieldByNumber(25, value);
return this;
}
public Builder setNecLong(final Double value) {
setFieldByNumber(26, value);
return this;
}
public Builder setSwcLat(final Double value) {
setFieldByNumber(27, value);
return this;
}
public Builder setSwcLong(final Double value) {
setFieldByNumber(28, value);
return this;
}
public Builder setNumLengths(final Integer value) {
setFieldByNumber(32, value);
return this;
@@ -1218,6 +1268,11 @@ public class FitLap extends RecordData {
return this;
}
public Builder setEstSweatLoss(final Integer value) {
setFieldByNumber(145, value);
return this;
}
public Builder setAvgRespirationRate(final Integer value) {
setFieldByNumber(147, value);
return this;
@@ -1243,6 +1298,11 @@ public class FitLap extends RecordData {
return this;
}
public Builder setExecutionScore(final Integer value) {
setFieldByNumber(152, value);
return this;
}
public Builder setAvgGrit(final Float value) {
setFieldByNumber(153, value);
return this;
@@ -182,6 +182,16 @@ public class FitMonitoring extends RecordData {
return getFieldByNumber(34, Integer.class);
}
@Nullable
public Double getTotalAscent() {
return getFieldByNumber(35, Double.class);
}
@Nullable
public Double getTotalDescent() {
return getFieldByNumber(36, Double.class);
}
@Nullable
public Long getTimestamp() {
return getFieldByNumber(253, Long.class);
@@ -335,6 +345,16 @@ public class FitMonitoring extends RecordData {
return this;
}
public Builder setTotalAscent(final Double value) {
setFieldByNumber(35, value);
return this;
}
public Builder setTotalDescent(final Double value) {
setFieldByNumber(36, value);
return this;
}
public Builder setTimestamp(final Long value) {
setFieldByNumber(253, value);
return this;
@@ -335,6 +335,11 @@ public class FitRecord extends RecordData {
return getFieldByNumber(87, Float.class);
}
@Nullable
public Integer getPerformanceCondition() {
return getFieldByNumber(90, Integer.class);
}
@Nullable
public Long getAbsolutePressure() {
return getFieldByNumber(91, Long.class);
@@ -420,6 +425,11 @@ public class FitRecord extends RecordData {
return getFieldByNumber(120, Integer.class);
}
@Nullable
public Integer getTotalAscent() {
return getFieldByNumber(121, Integer.class);
}
@Nullable
public Long getAirTimeRemaining() {
return getFieldByNumber(123, Long.class);
@@ -470,11 +480,36 @@ public class FitRecord extends RecordData {
return getFieldByNumber(139, Float.class);
}
@Nullable
public Double getGradeAdjustedSpeed() {
return getFieldByNumber(140, Double.class);
}
@Nullable
public Integer getBodyBattery() {
return getFieldByNumber(143, Integer.class);
}
@Nullable
public Integer getExternalHeartRate() {
return getFieldByNumber(144, Integer.class);
}
@Nullable
public Float getStepSpeedLossDistance() {
return getFieldByNumber(146, Float.class);
}
@Nullable
public Float getStepSpeedLossPercentage() {
return getFieldByNumber(147, Float.class);
}
@Nullable
public Double getForce() {
return getFieldByNumber(148, Double.class);
}
@Nullable
public Long getTimestamp() {
return getFieldByNumber(253, Long.class);
@@ -783,6 +818,11 @@ public class FitRecord extends RecordData {
return this;
}
public Builder setPerformanceCondition(final Integer value) {
setFieldByNumber(90, value);
return this;
}
public Builder setAbsolutePressure(final Long value) {
setFieldByNumber(91, value);
return this;
@@ -868,6 +908,11 @@ public class FitRecord extends RecordData {
return this;
}
public Builder setTotalAscent(final Integer value) {
setFieldByNumber(121, value);
return this;
}
public Builder setAirTimeRemaining(final Long value) {
setFieldByNumber(123, value);
return this;
@@ -918,11 +963,36 @@ public class FitRecord extends RecordData {
return this;
}
public Builder setGradeAdjustedSpeed(final Double value) {
setFieldByNumber(140, value);
return this;
}
public Builder setBodyBattery(final Integer value) {
setFieldByNumber(143, value);
return this;
}
public Builder setExternalHeartRate(final Integer value) {
setFieldByNumber(144, value);
return this;
}
public Builder setStepSpeedLossDistance(final Float value) {
setFieldByNumber(146, value);
return this;
}
public Builder setStepSpeedLossPercentage(final Float value) {
setFieldByNumber(147, value);
return this;
}
public Builder setForce(final Double value) {
setFieldByNumber(148, value);
return this;
}
public Builder setTimestamp(final Long value) {
setFieldByNumber(253, value);
return this;
@@ -395,6 +395,11 @@ public class FitSession extends RecordData {
return getFieldByNumber(71, Float.class);
}
@Nullable
public Long getWorkTime() {
return getFieldByNumber(78, Long.class);
}
@Nullable
public Float getAvgSwimCadence() {
return getFieldByNumber(79, Float.class);
@@ -725,6 +730,16 @@ public class FitSession extends RecordData {
return getFieldByNumber(150, Integer.class);
}
@Nullable
public Integer getTotalSets() {
return getFieldByNumber(151, Integer.class);
}
@Nullable
public Double getVolume() {
return getFieldByNumber(152, Double.class);
}
@Nullable
public Integer getO2Toxicity() {
return getFieldByNumber(155, Integer.class);
@@ -785,6 +800,11 @@ public class FitSession extends RecordData {
return getFieldByNumber(183, Integer.class);
}
@Nullable
public Integer getExecutionScore() {
return getFieldByNumber(185, Integer.class);
}
@Nullable
public Float getAvgGrit() {
return getFieldByNumber(186, Float.class);
@@ -890,6 +910,31 @@ public class FitSession extends RecordData {
return getFieldByNumber(210, Float.class);
}
@Nullable
public Double getGradeAdjustedSpeed() {
return getFieldByNumber(211, Double.class);
}
@Nullable
public Integer getWindData() {
return getFieldByNumber(212, Integer.class);
}
@Nullable
public Integer getBeginningBodyBattery() {
return getFieldByNumber(215, Integer.class);
}
@Nullable
public Integer getEndingBodyBattery() {
return getFieldByNumber(216, Integer.class);
}
@Nullable
public Float getPackWeight() {
return getFieldByNumber(220, Float.class);
}
@Nullable
public Float getStepSpeedLoss() {
return getFieldByNumber(222, Float.class);
@@ -900,6 +945,21 @@ public class FitSession extends RecordData {
return getFieldByNumber(223, Float.class);
}
@Nullable
public Double getAvgForce() {
return getFieldByNumber(224, Double.class);
}
@Nullable
public Double getMaxForce() {
return getFieldByNumber(225, Double.class);
}
@Nullable
public Double getNormalizedForce() {
return getFieldByNumber(226, Double.class);
}
@Nullable
public Long getTimestamp() {
return getFieldByNumber(253, Long.class);
@@ -1268,6 +1328,11 @@ public class FitSession extends RecordData {
return this;
}
public Builder setWorkTime(final Long value) {
setFieldByNumber(78, value);
return this;
}
public Builder setAvgSwimCadence(final Float value) {
setFieldByNumber(79, value);
return this;
@@ -1598,6 +1663,16 @@ public class FitSession extends RecordData {
return this;
}
public Builder setTotalSets(final Integer value) {
setFieldByNumber(151, value);
return this;
}
public Builder setVolume(final Double value) {
setFieldByNumber(152, value);
return this;
}
public Builder setO2Toxicity(final Integer value) {
setFieldByNumber(155, value);
return this;
@@ -1658,6 +1733,11 @@ public class FitSession extends RecordData {
return this;
}
public Builder setExecutionScore(final Integer value) {
setFieldByNumber(185, value);
return this;
}
public Builder setAvgGrit(final Float value) {
setFieldByNumber(186, value);
return this;
@@ -1763,6 +1843,31 @@ public class FitSession extends RecordData {
return this;
}
public Builder setGradeAdjustedSpeed(final Double value) {
setFieldByNumber(211, value);
return this;
}
public Builder setWindData(final Integer value) {
setFieldByNumber(212, value);
return this;
}
public Builder setBeginningBodyBattery(final Integer value) {
setFieldByNumber(215, value);
return this;
}
public Builder setEndingBodyBattery(final Integer value) {
setFieldByNumber(216, value);
return this;
}
public Builder setPackWeight(final Float value) {
setFieldByNumber(220, value);
return this;
}
public Builder setStepSpeedLoss(final Float value) {
setFieldByNumber(222, value);
return this;
@@ -1773,6 +1878,21 @@ public class FitSession extends RecordData {
return this;
}
public Builder setAvgForce(final Double value) {
setFieldByNumber(224, value);
return this;
}
public Builder setMaxForce(final Double value) {
setFieldByNumber(225, value);
return this;
}
public Builder setNormalizedForce(final Double value) {
setFieldByNumber(226, value);
return this;
}
public Builder setTimestamp(final Long value) {
setFieldByNumber(253, value);
return this;
+30
View File
@@ -2703,6 +2703,36 @@
<string name="cycling">Cycling</string>
<string name="aerobicTrainingEffect">Aerobic Effect</string>
<string name="anaerobicTrainingEffect">Anaerobic Effect</string>
<string name="battery_level_ebike_end">Final Battery Level</string>
<string name="battery_level_ebike_start">Initial Battery Level</string>
<string name="battery_level_end">Final Battery Level</string>
<string name="battery_level_start">Initial Battery Level</string>
<string name="battery_status">Battery Status</string>
<string name="battery_status_charging">Charging</string>
<string name="battery_status_critical">Critical</string>
<string name="battery_status_good">Good</string>
<string name="battery_status_invalid">Invalid</string>
<string name="battery_status_low">Low</string>
<string name="battery_status_new">New</string>
<string name="battery_status_ok">Ok</string>
<string name="battery_status_unknown">Unknown</string>
<string name="body_energy_at_end">Finishing body energy</string>
<string name="body_energy_at_start">Initial body energy</string>
<string name="device">Device</string>
<string name="diving_pressure_sac_avg">Surface air consumption</string>
<string name="hr_user_max">User Max Heart Rate</string>
<string name="hr_user_resting">Resting Heart Rate</string>
<string name="recovery_time_remaining_at_start">Initial recovery time</string>
<string name="total_work">Total Work</string>
<string name="training_effect_total">Total Effect</string>
<string name="unit_bar_per_minute">bar/min</string>
<string name="unit_kg_per_m3">kg/m³</string>
<string name="unit_volt">V</string>
<string name="water_type_custom">Custom</string>
<string name="water_type_en13319">EN13319</string>
<string name="water_type_fresh">Fresh</string>
<string name="water_type_salt">Salt</string>
<string name="workout_feel">Workout Feel</string>
<string name="currentWorkoutLoad">Workout Load</string>
<string name="maximumOxygenUptake">Maximum Oxygen Uptake</string>
<string name="fluid_consumed">Fluid consumed</string>