Garmin: Add step speed loss

This commit is contained in:
José Rebelo
2025-08-30 13:26:55 +01:00
parent bfc54276a1
commit 0384f62a7e
5 changed files with 90 additions and 99 deletions
@@ -1,101 +1,6 @@
package nodomain.freeyourgadget.gadgetbridge.devices.garmin;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.ACTIVE_SECONDS;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.AVG_CADENCE_SEATING;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.AVG_CADENCE_STANDING;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.AVG_DEPTH;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.AVG_GROUND_CONTACT_TIME;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.AVG_GROUND_CONTACT_TIME_BALANCE;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.AVG_LEFT_PCO;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.AVG_LEFT_POWER_PHASE;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.AVG_LEFT_POWER_PHASE_PEAK;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.AVG_PEDAL_SMOOTHNESS;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.AVG_POWER;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.AVG_POWER_SEATING;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.AVG_POWER_STANDING;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.AVG_RIGHT_PCO;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.AVG_RIGHT_POWER_PHASE;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.AVG_RIGHT_POWER_PHASE_PEAK;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.AVG_TORQUE_EFFECTIVENESS;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.AVG_VERTICAL_OSCILLATION;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.AVG_VERTICAL_RATIO;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.BOTTOM_TIME;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.CALORIES_ACTIVE;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.CALORIES_BURNT;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.CALORIES_RESTING;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.DISTANCE_METERS;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.DIVE_NUMBER;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.END_CNS;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.END_N2;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.ESTIMATED_SWEAT_LOSS;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.FRONT_GEAR_SHIFTS;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.GAS;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.GROUP_INTERVALS;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.HRV_RMSSD;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.HRV_SDRR;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.HR_AVG;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.HR_MAX;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.HR_ZONE_AEROBIC;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.HR_ZONE_EASY;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.HR_ZONE_MAXIMUM;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.HR_ZONE_NA;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.HR_ZONE_THRESHOLD;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.HR_ZONE_WARM_UP;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.INTENSITY_FACTOR;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.INTERNAL_HAS_GPS;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.LACTATE_THRESHOLD_HR;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.LEFT_RIGHT_BALANCE;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.MAXIMUM_OXYGEN_UPTAKE;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.MAX_CADENCE_SEATING;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.MAX_CADENCE_STANDING;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.MAX_DEPTH;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.MAX_POWER;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.MAX_POWER_SEATING;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.MAX_POWER_STANDING;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.NORMALIZED_POWER;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.PACE_AVG_SECONDS_KM;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.PACE_MAX;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.POOL_LENGTH;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.REAR_GEAR_SHIFTS;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.RECOVERY_TIME;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.RESPIRATION_AVG;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.RESPIRATION_MAX;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.RESPIRATION_MIN;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.SETS;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.SPEED_AVG;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.SPEED_MAX;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.SPO2_AVG;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.STANDING_COUNT;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.STANDING_TIME;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.START_CNS;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.START_N2;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.STEP_LENGTH_AVG;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.STRESS_AVG;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.SWIM_AVG_CADENCE;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.SWOLF_AVG;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.TOTAL_ASCENT;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.TOTAL_DESCENT;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.TRAINING_EFFECT_AEROBIC;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.TRAINING_EFFECT_ANAEROBIC;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.TRAINING_LOAD;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.TRAINING_STRESS_SCORE;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.UNIT_BPM;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.UNIT_BREATHS_PER_MIN;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.UNIT_KCAL;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.UNIT_KG;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.UNIT_KMPH;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.UNIT_LB;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.UNIT_METERS;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.UNIT_MILLISECONDS;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.UNIT_ML;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.UNIT_ML_KG_MIN;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.UNIT_MM;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.UNIT_NONE;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.UNIT_PERCENTAGE;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.UNIT_RPM;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.UNIT_SECONDS;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.UNIT_STROKES_PER_LENGTH;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.UNIT_WATT;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.*;
import android.content.Context;
@@ -452,6 +357,9 @@ public class GarminWorkoutParser implements ActivitySummaryParser {
);
}
summaryData.add(STEP_SPEED_LOSS, session.getStepSpeedLoss(), UNIT_CENTIMETERS_PER_SECOND);
summaryData.add(STEP_SPEED_LOSS_PERCENTAGE, session.getStepSpeedLossPercentage(), UNIT_PERCENTAGE);
final Number[] avgLeftPowerPhase = session.getAvgLeftPowerPhase();
if (avgLeftPowerPhase != null && avgLeftPowerPhase.length == 4) {
final Number startAngle = avgLeftPowerPhase[0];
@@ -103,6 +103,8 @@ public class ActivitySummaryEntries {
public static final String AVG_GROUND_CONTACT_TIME = "ground_contact_time";
public static final String AVG_VERTICAL_RATIO = "vertical_ratio";
public static final String AVG_GROUND_CONTACT_TIME_BALANCE = "ground_contact_time_balance";
public static final String STEP_SPEED_LOSS = "running_step_speed_loss";
public static final String STEP_SPEED_LOSS_PERCENTAGE = "running_step_speed_loss_percentage";
public static final String DISTANCE_METERS = "distanceMeters";
public static final String POOL_LENGTH = "poolLength";
@@ -197,6 +199,7 @@ public class ActivitySummaryEntries {
public static final String UNIT_SECONDS_PER_KM = "seconds_km";
public static final String UNIT_MINUTES_PER_KM = "minutes_km";
public static final String UNIT_SECONDS_PER_M = "seconds_m";
public static final String UNIT_CENTIMETERS_PER_SECOND = "centimeters_second";
public static final String UNIT_METERS_PER_SECOND = "meters_second";
public static final String UNIT_KMPH = "km_h";
public static final String UNIT_SPM = "spm";
@@ -95,7 +95,7 @@ public class GlobalFITMessage {
));
public static GlobalFITMessage SESSION = new GlobalFITMessage(18, "SESSION", Arrays.asList(
new FieldDefinitionPrimitive(0, BaseType.ENUM, "event"), // 9 lap
new FieldDefinitionPrimitive(0, BaseType.ENUM, "event"), // 8 session 9 lap
new FieldDefinitionPrimitive(1, BaseType.ENUM, "event_type"), // 1 stop
new FieldDefinitionPrimitive(2, BaseType.UINT32, "start_time"),
new FieldDefinitionPrimitive(3, BaseType.SINT32, "start_latitude", FieldDefinitionFactory.FIELD.COORDINATE),
@@ -104,7 +104,7 @@ public class GlobalFITMessage {
new FieldDefinitionPrimitive(6, BaseType.ENUM, "sub_sport"),
new FieldDefinitionPrimitive(7, BaseType.UINT32, "total_elapsed_time"), // with pauses
new FieldDefinitionPrimitive(8, BaseType.UINT32, "total_timer_time"), // no pauses
new FieldDefinitionPrimitive(9, BaseType.UINT32, "total_distance"),
new FieldDefinitionPrimitive(9, BaseType.UINT32, "total_distance"), // cm
new FieldDefinitionPrimitive(10, BaseType.UINT32, "total_cycles"),
new FieldDefinitionPrimitive(11, BaseType.UINT16, "total_calories"),
new FieldDefinitionPrimitive(16, BaseType.UINT8, "average_heart_rate"),
@@ -118,6 +118,7 @@ public class GlobalFITMessage {
new FieldDefinitionPrimitive(24, BaseType.UINT8, "total_training_effect", 10, 0),
new FieldDefinitionPrimitive(25, BaseType.UINT16, "first_lap_index"),
new FieldDefinitionPrimitive(26, BaseType.UINT16, "num_laps"),
new FieldDefinitionPrimitive(28, BaseType.ENUM, "trigger"),
new FieldDefinitionPrimitive(29, BaseType.SINT32, "nec_latitude", FieldDefinitionFactory.FIELD.COORDINATE),
new FieldDefinitionPrimitive(30, BaseType.SINT32, "nec_longitude", FieldDefinitionFactory.FIELD.COORDINATE),
new FieldDefinitionPrimitive(31, BaseType.SINT32, "swc_latitude", FieldDefinitionFactory.FIELD.COORDINATE),
@@ -133,6 +134,7 @@ public class GlobalFITMessage {
new FieldDefinitionPrimitive(45, BaseType.UINT16, "threshold_power"), // watt
new FieldDefinitionPrimitive(47, BaseType.UINT16, "num_active_lengths"),
new FieldDefinitionPrimitive(48, BaseType.UINT32, "total_work"), // joule
new FieldDefinitionPrimitive(64, BaseType.UINT8, "min_heart_rate"), // bpm
new FieldDefinitionPrimitive(79, BaseType.UINT16, "avg_swim_cadence", 10, 0), // rpm
new FieldDefinitionPrimitive(80, BaseType.UINT16, "avg_swolf"),
new FieldDefinitionPrimitive(89, BaseType.UINT16, "avg_vertical_oscillation", 10, 0), // mm
@@ -176,6 +178,11 @@ public class GlobalFITMessage {
new FieldDefinitionPrimitive(196, BaseType.UINT16, "resting_calories"), // kcal
new FieldDefinitionPrimitive(197, BaseType.UINT8, "hrv_sdrr"), // ms
new FieldDefinitionPrimitive(198, BaseType.UINT8, "hrv_rmssd"), // ms
new FieldDefinitionPrimitive(205, BaseType.UINT8, "beginning_potential"),
new FieldDefinitionPrimitive(206, BaseType.UINT8, "ending_potential"),
new FieldDefinitionPrimitive(207, BaseType.UINT8, "min_stamina"),
new FieldDefinitionPrimitive(222, BaseType.UINT16, "step_speed_loss", 100, 0),
new FieldDefinitionPrimitive(223, BaseType.UINT16, "step_speed_loss_percentage", 100, 0),
new FieldDefinitionPrimitive(253, BaseType.UINT32, "timestamp", FieldDefinitionFactory.FIELD.TIMESTAMP)
));
@@ -276,7 +283,7 @@ public class GlobalFITMessage {
public static GlobalFITMessage ACTIVITY = new GlobalFITMessage(34, "ACTIVITY", Arrays.asList(
new FieldDefinitionPrimitive(0, BaseType.UINT32, "total_timer_time"),
new FieldDefinitionPrimitive(1, BaseType.UINT16, "num_sessions"),
new FieldDefinitionPrimitive(2, BaseType.ENUM, "type"), // 0
new FieldDefinitionPrimitive(2, BaseType.ENUM, "type"), // 0 manual
new FieldDefinitionPrimitive(3, BaseType.ENUM, "event"), // 26 activity
new FieldDefinitionPrimitive(4, BaseType.ENUM, "event_type"), // 1 stop
new FieldDefinitionPrimitive(5, BaseType.UINT32, "local_timestamp"), // garmin timestamp, but in user timezone
@@ -136,6 +136,11 @@ public class FitSession extends RecordData {
return (Integer) getFieldByNumber(26);
}
@Nullable
public Integer getTrigger() {
return (Integer) getFieldByNumber(28);
}
@Nullable
public Double getNecLatitude() {
return (Double) getFieldByNumber(29);
@@ -211,6 +216,11 @@ public class FitSession extends RecordData {
return (Long) getFieldByNumber(48);
}
@Nullable
public Integer getMinHeartRate() {
return (Integer) getFieldByNumber(64);
}
@Nullable
public Float getAvgSwimCadence() {
return (Float) getFieldByNumber(79);
@@ -482,6 +492,31 @@ public class FitSession extends RecordData {
return (Integer) getFieldByNumber(198);
}
@Nullable
public Integer getBeginningPotential() {
return (Integer) getFieldByNumber(205);
}
@Nullable
public Integer getEndingPotential() {
return (Integer) getFieldByNumber(206);
}
@Nullable
public Integer getMinStamina() {
return (Integer) getFieldByNumber(207);
}
@Nullable
public Float getStepSpeedLoss() {
return (Float) getFieldByNumber(222);
}
@Nullable
public Float getStepSpeedLossPercentage() {
return (Float) getFieldByNumber(223);
}
@Nullable
public Long getTimestamp() {
return (Long) getFieldByNumber(253);
@@ -607,6 +642,11 @@ public class FitSession extends RecordData {
return this;
}
public Builder setTrigger(final Integer value) {
setFieldByNumber(28, value);
return this;
}
public Builder setNecLatitude(final Double value) {
setFieldByNumber(29, value);
return this;
@@ -682,6 +722,11 @@ public class FitSession extends RecordData {
return this;
}
public Builder setMinHeartRate(final Integer value) {
setFieldByNumber(64, value);
return this;
}
public Builder setAvgSwimCadence(final Float value) {
setFieldByNumber(79, value);
return this;
@@ -897,6 +942,31 @@ public class FitSession extends RecordData {
return this;
}
public Builder setBeginningPotential(final Integer value) {
setFieldByNumber(205, value);
return this;
}
public Builder setEndingPotential(final Integer value) {
setFieldByNumber(206, value);
return this;
}
public Builder setMinStamina(final Integer value) {
setFieldByNumber(207, value);
return this;
}
public Builder setStepSpeedLoss(final Float value) {
setFieldByNumber(222, value);
return this;
}
public Builder setStepSpeedLossPercentage(final Float value) {
setFieldByNumber(223, value);
return this;
}
public Builder setTimestamp(final Long value) {
setFieldByNumber(253, value);
return this;
+3
View File
@@ -2636,6 +2636,7 @@
<string name="ft">ft</string>
<string name="steps_unit">steps</string>
<string name="meters_second">m/s</string>
<string name="centimeters_second">cm/s</string>
<string name="km_h">km/h</string>
<string name="mi_h">mi/h</string>
<string name="minutes_mi">min/mi</string>
@@ -2683,6 +2684,8 @@
<string name="ground_contact_time">Ground Contact Time</string>
<string name="vertical_ratio">Vertical Ratio</string>
<string name="ground_contact_time_balance">Ground Contact Time Balance</string>
<string name="running_step_speed_loss">Step Speed Loss</string>
<string name="running_step_speed_loss_percentage">Step Speed Loss %</string>
<string name="workout_repetitions">Repetitions</string>
<string name="workout_revolutions">Revolutions</string>
<string name="workout_swings">Swings</string>