mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge.git
synced 2026-07-31 07:44:24 +02:00
Garmin: enhance activity summaries
- prioritise names: workout name > session sports profile > sport name - gracefully fallback from Enhanced Respiration to plain Respiration - gracefully fallback from Enhanced Speed to plain Speed - add gear info showing last battery reading of connected devices - add altitude min/max/avg - add user heart rate (min/max/resting) - add workout feel (0 - 100%) - add device battery state (initial / final) - add ebike battery state (initial / final) - add more recovery, work, energy statistics - diving: add SAC (Surface Air Consumption) - diving: add water density with fallback to water type - diving: ignore disabled gases
This commit is contained in:
+33
@@ -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,
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
+4
@@ -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];
|
||||
|
||||
+262
-24
@@ -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);
|
||||
|
||||
@@ -295,14 +401,27 @@ public class GarminWorkoutParser implements ActivitySummaryParser {
|
||||
}
|
||||
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, session.getEnhancedMinRespirationRate(), UNIT_BREATHS_PER_MIN);
|
||||
summaryData.add(RESPIRATION_MAX, session.getEnhancedMaxRespirationRate(), UNIT_BREATHS_PER_MIN);
|
||||
summaryData.add(RESPIRATION_AVG, session.getEnhancedAvgRespirationRate(), UNIT_BREATHS_PER_MIN);
|
||||
|
||||
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) {
|
||||
@@ -329,29 +448,42 @@ public class GarminWorkoutParser implements ActivitySummaryParser {
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
@@ -564,7 +696,6 @@ public class GarminWorkoutParser implements ActivitySummaryParser {
|
||||
}
|
||||
summaryData.add(LACTATE_THRESHOLD_HR, physiologicalMetrics.getLactateThresholdHeartRate(), UNIT_BPM);
|
||||
}
|
||||
summaryData.add(TRAINING_LOAD, safeRound(session.getTrainingLoadPeak()), UNIT_NONE);
|
||||
|
||||
if (diveSummary != null) {
|
||||
summaryData.add(DIVE_NUMBER, diveSummary.getDiveNumber(), UNIT_NONE);
|
||||
@@ -581,24 +712,43 @@ public class GarminWorkoutParser implements ActivitySummaryParser {
|
||||
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);
|
||||
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",
|
||||
@@ -607,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;
|
||||
@@ -622,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()) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
+19
-2
@@ -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
|
||||
|
||||
+6
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -671,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"),
|
||||
@@ -1546,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), // %
|
||||
|
||||
+4
@@ -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;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
+1
@@ -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),
|
||||
|
||||
+78
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
+75
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
+4
-3
@@ -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;
|
||||
}
|
||||
|
||||
+4
-3
@@ -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;
|
||||
}
|
||||
|
||||
@@ -2702,6 +2702,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>
|
||||
|
||||
Reference in New Issue
Block a user