mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge
synced 2024-11-25 03:16:51 +01:00
Extract hardcoded activity summary entries to constants
This commit is contained in:
parent
4e54f8137d
commit
ab894ae433
@ -17,6 +17,8 @@
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.activities;
|
||||
|
||||
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.*;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.content.Context;
|
||||
@ -86,7 +88,6 @@ import nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryJsonSummary;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryParser;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.AndroidUtils;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.DateTimeUtils;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.DeviceHelper;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.FileUtils;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.SwipeEvents;
|
||||
@ -464,13 +465,13 @@ public class ActivitySummaryDetail extends AbstractGBActivity {
|
||||
if (!show_raw_data) {
|
||||
//special casing here + imperial units handling
|
||||
switch (unit) {
|
||||
case "cm":
|
||||
case UNIT_CM:
|
||||
if (units.equals(UNIT_IMPERIAL)) {
|
||||
value = value * 0.0328084;
|
||||
unit = "ft";
|
||||
}
|
||||
break;
|
||||
case "meters_second":
|
||||
case UNIT_METERS_PER_SECOND:
|
||||
if (units.equals(UNIT_IMPERIAL)) {
|
||||
value = value * 2.236936D;
|
||||
unit = "mi_h";
|
||||
@ -479,7 +480,7 @@ public class ActivitySummaryDetail extends AbstractGBActivity {
|
||||
unit = "km_h";
|
||||
}
|
||||
break;
|
||||
case "seconds_m":
|
||||
case UNIT_SECONDS_PER_M:
|
||||
if (units.equals(UNIT_IMPERIAL)) {
|
||||
value = value * (1609.344 / 60D);
|
||||
unit = "minutes_mi";
|
||||
@ -488,7 +489,7 @@ public class ActivitySummaryDetail extends AbstractGBActivity {
|
||||
unit = "minutes_km";
|
||||
}
|
||||
break;
|
||||
case "seconds_km":
|
||||
case UNIT_SECONDS_PER_KM:
|
||||
if (units.equals(UNIT_IMPERIAL)) {
|
||||
value = value / 60D * 1.609344;
|
||||
unit = "minutes_mi";
|
||||
@ -497,7 +498,7 @@ public class ActivitySummaryDetail extends AbstractGBActivity {
|
||||
unit = "minutes_km";
|
||||
}
|
||||
break;
|
||||
case "meters":
|
||||
case UNIT_METERS:
|
||||
if (units.equals(UNIT_IMPERIAL)) {
|
||||
value = value * 3.28084D;
|
||||
unit = "ft";
|
||||
|
@ -16,6 +16,8 @@
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.devices.huami;
|
||||
|
||||
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.*;
|
||||
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
@ -73,7 +75,7 @@ public class Huami2021ActivitySummaryParser extends HuamiActivitySummaryParser {
|
||||
if (summaryProto.hasTime()) {
|
||||
int totalDuration = summaryProto.getTime().getTotalDuration();
|
||||
summary.setEndTime(new Date(startTime.getTime() + totalDuration * 1000L));
|
||||
addSummaryData("activeSeconds", summaryProto.getTime().getWorkoutDuration(), "seconds");
|
||||
addSummaryData(ACTIVE_SECONDS, summaryProto.getTime().getWorkoutDuration(), UNIT_SECONDS);
|
||||
// TODO pause durations
|
||||
}
|
||||
|
||||
@ -82,93 +84,94 @@ public class Huami2021ActivitySummaryParser extends HuamiActivitySummaryParser {
|
||||
summary.setBaseLatitude(summaryProto.getLocation().getBaseLatitude());
|
||||
summary.setBaseAltitude(summaryProto.getLocation().getBaseAltitude() / 2);
|
||||
// TODO: Min/Max Latitude/Longitude
|
||||
addSummaryData("baseAltitude", summaryProto.getLocation().getBaseAltitude() / 2, "meters");
|
||||
addSummaryData(ALTITUDE_BASE, summaryProto.getLocation().getBaseAltitude() / 2, UNIT_METERS);
|
||||
}
|
||||
|
||||
if (summaryProto.hasHeartRate()) {
|
||||
addSummaryData("averageHR", summaryProto.getHeartRate().getAvg(), "bpm");
|
||||
addSummaryData("maxHR", summaryProto.getHeartRate().getMax(), "bpm");
|
||||
addSummaryData("minHR", summaryProto.getHeartRate().getMin(), "bpm");
|
||||
addSummaryData(HR_AVG, summaryProto.getHeartRate().getAvg(), UNIT_BPM);
|
||||
addSummaryData(HR_MAX, summaryProto.getHeartRate().getMax(), UNIT_BPM);
|
||||
addSummaryData(HR_MIN, summaryProto.getHeartRate().getMin(), UNIT_BPM);
|
||||
}
|
||||
|
||||
if (summaryProto.hasSteps()) {
|
||||
addSummaryData("maxCadence", summaryProto.getSteps().getMaxCadence() * 60, "spm");
|
||||
addSummaryData("averageCadence", summaryProto.getSteps().getAvgCadence() * 60, "spm");
|
||||
addSummaryData("averageStride", summaryProto.getSteps().getAvgStride(), "cm");
|
||||
addSummaryData("steps", summaryProto.getSteps().getSteps(), "steps_unit");
|
||||
addSummaryData(CADENCE_MAX, summaryProto.getSteps().getMaxCadence() * 60, UNIT_SPM);
|
||||
addSummaryData(CADENCE_AVG, summaryProto.getSteps().getAvgCadence() * 60, UNIT_SPM);
|
||||
addSummaryData(STRIDE_AVG, summaryProto.getSteps().getAvgStride(), UNIT_CM);
|
||||
addSummaryData(STEPS, summaryProto.getSteps().getSteps(), UNIT_STEPS);
|
||||
}
|
||||
|
||||
if (summaryProto.hasDistance()) {
|
||||
addSummaryData("distanceMeters", summaryProto.getDistance().getDistance(), "meters");
|
||||
addSummaryData(DISTANCE_METERS, summaryProto.getDistance().getDistance(), UNIT_METERS);
|
||||
}
|
||||
|
||||
if (summaryProto.hasPace()) {
|
||||
addSummaryData("maxPace", summaryProto.getPace().getBest(), "seconds_m");
|
||||
addSummaryData("averageKMPaceSeconds", summaryProto.getPace().getAvg() * 1000, "seconds_km");
|
||||
addSummaryData(PACE_MAX, summaryProto.getPace().getBest(), UNIT_SECONDS_PER_M);
|
||||
addSummaryData(PACE_AVG_SECONDS_KM, summaryProto.getPace().getAvg() * 1000, UNIT_SECONDS_PER_KM);
|
||||
}
|
||||
|
||||
if (summaryProto.hasCalories()) {
|
||||
addSummaryData("caloriesBurnt", summaryProto.getCalories().getCalories(), "calories_unit");
|
||||
addSummaryData(CALORIES_BURNT, summaryProto.getCalories().getCalories(), UNIT_KCAL);
|
||||
}
|
||||
|
||||
if (summaryProto.hasHeartRateZones()) {
|
||||
// TODO hr zones bpm?
|
||||
if (summaryProto.getHeartRateZones().getZoneTimeCount() == 6) {
|
||||
addSummaryData("hrZoneNa", summaryProto.getHeartRateZones().getZoneTime(0), "seconds");
|
||||
addSummaryData("hrZoneWarmUp", summaryProto.getHeartRateZones().getZoneTime(1), "seconds");
|
||||
addSummaryData("hrZoneFatBurn", summaryProto.getHeartRateZones().getZoneTime(2), "seconds");
|
||||
addSummaryData("hrZoneAerobic", summaryProto.getHeartRateZones().getZoneTime(3), "seconds");
|
||||
addSummaryData("hrZoneAnaerobic", summaryProto.getHeartRateZones().getZoneTime(4), "seconds");
|
||||
addSummaryData("hrZoneExtreme", summaryProto.getHeartRateZones().getZoneTime(5), "seconds");
|
||||
addSummaryData(HR_ZONE_NA, summaryProto.getHeartRateZones().getZoneTime(0), UNIT_SECONDS);
|
||||
addSummaryData(HR_ZONE_WARM_UP, summaryProto.getHeartRateZones().getZoneTime(1), UNIT_SECONDS);
|
||||
addSummaryData(HR_ZONE_FAT_BURN, summaryProto.getHeartRateZones().getZoneTime(2), UNIT_SECONDS);
|
||||
addSummaryData(HR_ZONE_AEROBIC, summaryProto.getHeartRateZones().getZoneTime(3), UNIT_SECONDS);
|
||||
addSummaryData(HR_ZONE_ANAEROBIC, summaryProto.getHeartRateZones().getZoneTime(4), UNIT_SECONDS);
|
||||
addSummaryData(HR_ZONE_EXTREME, summaryProto.getHeartRateZones().getZoneTime(5), UNIT_SECONDS);
|
||||
} else {
|
||||
LOG.warn("Unexpected number of HR zones {}", summaryProto.getHeartRateZones().getZoneTimeCount());
|
||||
}
|
||||
}
|
||||
|
||||
if (summaryProto.hasTrainingEffect()) {
|
||||
addSummaryData("aerobicTrainingEffect", summaryProto.getTrainingEffect().getAerobicTrainingEffect(), "");
|
||||
addSummaryData("anaerobicTrainingEffect", summaryProto.getTrainingEffect().getAnaerobicTrainingEffect(), "");
|
||||
addSummaryData("currentWorkoutLoad", summaryProto.getTrainingEffect().getCurrentWorkoutLoad(), "");
|
||||
addSummaryData("maximumOxygenUptake", summaryProto.getTrainingEffect().getMaximumOxygenUptake(), "ml/kg/min");
|
||||
addSummaryData(TRAINING_EFFECT_AEROBIC, summaryProto.getTrainingEffect().getAerobicTrainingEffect(), UNIT_NONE);
|
||||
addSummaryData(TRAINING_EFFECT_ANAEROBIC, summaryProto.getTrainingEffect().getAnaerobicTrainingEffect(), UNIT_NONE);
|
||||
addSummaryData(WORKOUT_LOAD, summaryProto.getTrainingEffect().getCurrentWorkoutLoad(), UNIT_NONE);
|
||||
addSummaryData(MAXIMUM_OXYGEN_UPTAKE, summaryProto.getTrainingEffect().getMaximumOxygenUptake(), UNIT_ML_KG_MIN);
|
||||
}
|
||||
|
||||
if (summaryProto.hasAltitude()) {
|
||||
addSummaryData("maxAltitude", summaryProto.getAltitude().getMaxAltitude() / 200, "meters");
|
||||
addSummaryData("minAltitude", summaryProto.getAltitude().getMinAltitude() / 200, "meters");
|
||||
addSummaryData("averageAltitude", summaryProto.getAltitude().getAvgAltitude() / 200, "meters");
|
||||
addSummaryData(ALTITUDE_MAX, summaryProto.getAltitude().getMaxAltitude() / 200, UNIT_METERS);
|
||||
addSummaryData(ALTITUDE_MIN, summaryProto.getAltitude().getMinAltitude() / 200, UNIT_METERS);
|
||||
addSummaryData(ALTITUDE_AVG, summaryProto.getAltitude().getAvgAltitude() / 200, UNIT_METERS);
|
||||
// TODO totalClimbing
|
||||
addSummaryData("elevationGain", summaryProto.getAltitude().getElevationGain() / 100, "meters");
|
||||
addSummaryData("elevationLoss", summaryProto.getAltitude().getElevationLoss() / 100, "meters");
|
||||
addSummaryData(ELEVATION_GAIN, summaryProto.getAltitude().getElevationGain() / 100, UNIT_METERS);
|
||||
addSummaryData(ELEVATION_LOSS, summaryProto.getAltitude().getElevationLoss() / 100, UNIT_METERS);
|
||||
}
|
||||
|
||||
if (summaryProto.hasElevation()) {
|
||||
addSummaryData("ascentSeconds", summaryProto.getElevation().getUphillTime(), "seconds");
|
||||
addSummaryData("descentSeconds", summaryProto.getElevation().getDownhillTime(), "seconds");
|
||||
addSummaryData(ASCENT_SECONDS, summaryProto.getElevation().getUphillTime(), UNIT_SECONDS);
|
||||
addSummaryData(DESCENT_SECONDS, summaryProto.getElevation().getDownhillTime(), UNIT_SECONDS);
|
||||
}
|
||||
|
||||
if (summaryProto.hasSwimmingData()) {
|
||||
addSummaryData("laps", summaryProto.getSwimmingData().getLaps(), "laps_unit");
|
||||
addSummaryData(LAPS, summaryProto.getSwimmingData().getLaps(), UNIT_LAPS);
|
||||
switch (summaryProto.getSwimmingData().getLaneLengthUnit()) {
|
||||
case 0:
|
||||
addSummaryData("laneLength", summaryProto.getSwimmingData().getLaneLength(), "meters");
|
||||
addSummaryData(LANE_LENGTH, summaryProto.getSwimmingData().getLaneLength(), UNIT_METERS);
|
||||
break;
|
||||
case 1:
|
||||
addSummaryData("laneLength", summaryProto.getSwimmingData().getLaneLength(), "yard");
|
||||
addSummaryData(LANE_LENGTH, summaryProto.getSwimmingData().getLaneLength(), UNIT_YARD);
|
||||
break;
|
||||
}
|
||||
switch (summaryProto.getSwimmingData().getStyle()) {
|
||||
// TODO i18n these
|
||||
case 1:
|
||||
addSummaryData("swimStyle", "breaststroke");
|
||||
addSummaryData(SWIM_STYLE, "breaststroke");
|
||||
break;
|
||||
case 2:
|
||||
addSummaryData("swimStyle", "freestyle");
|
||||
addSummaryData(SWIM_STYLE, "freestyle");
|
||||
break;
|
||||
}
|
||||
addSummaryData("strokes", summaryProto.getSwimmingData().getStrokes(), "strokes_unit");
|
||||
addSummaryData("avgStrokeRate", summaryProto.getSwimmingData().getAvgStrokeRate(), "strokes_minute");
|
||||
addSummaryData("maxStrokeRate", summaryProto.getSwimmingData().getMaxStrokeRate(), "strokes_minute");
|
||||
addSummaryData("averageStrokeDistance", summaryProto.getSwimmingData().getAvgDps(), "cm");
|
||||
addSummaryData("swolfIndex", summaryProto.getSwimmingData().getSwolf(), "");
|
||||
addSummaryData(STROKES, summaryProto.getSwimmingData().getStrokes(), UNIT_STROKES);
|
||||
addSummaryData(STROKE_RATE_AVG, summaryProto.getSwimmingData().getAvgStrokeRate(), UNIT_STROKES_PER_MINUTE);
|
||||
addSummaryData(STROKE_RATE_MAX, summaryProto.getSwimmingData().getMaxStrokeRate(), UNIT_STROKES_PER_MINUTE);
|
||||
addSummaryData(STROKE_DISTANCE_AVG, summaryProto.getSwimmingData().getAvgDps(), UNIT_CM);
|
||||
addSummaryData(SWOLF_INDEX, summaryProto.getSwimmingData().getSwolf(), UNIT_NONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -17,6 +17,8 @@
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.devices.huami;
|
||||
|
||||
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.*;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import org.slf4j.Logger;
|
||||
@ -273,9 +275,9 @@ public class HuamiActivitySummaryParser implements ActivitySummaryParser {
|
||||
buffer.getInt(); // unknown probably flatDistance = buffer.getFloat();
|
||||
flatSeconds = buffer.getInt() / 1000; // ms?
|
||||
|
||||
addSummaryData("ascentSeconds", ascentSeconds, "seconds");
|
||||
addSummaryData("descentSeconds", descentSeconds, "seconds");
|
||||
addSummaryData("flatSeconds", flatSeconds, "seconds");
|
||||
addSummaryData(ASCENT_SECONDS, ascentSeconds, UNIT_SECONDS);
|
||||
addSummaryData(DESCENT_SECONDS, descentSeconds, UNIT_SECONDS);
|
||||
addSummaryData(FLAT_SECONDS, flatSeconds, UNIT_SECONDS);
|
||||
}
|
||||
|
||||
averageHR = buffer.getShort();
|
||||
@ -308,62 +310,62 @@ public class HuamiActivitySummaryParser implements ActivitySummaryParser {
|
||||
// summary.setAveragePace(BLETypeConversions.toUnsigned(averagePace);
|
||||
// summary.setAverageStride(BLETypeConversions.toUnsigned(averageStride);
|
||||
|
||||
addSummaryData("ascentSeconds", ascentSeconds, "seconds");
|
||||
addSummaryData("descentSeconds", descentSeconds, "seconds");
|
||||
addSummaryData("flatSeconds", flatSeconds, "seconds");
|
||||
addSummaryData("ascentDistance", ascentDistance, "meters");
|
||||
addSummaryData("descentDistance", descentDistance, "meters");
|
||||
addSummaryData("flatDistance", flatDistance, "meters");
|
||||
addSummaryData(ASCENT_SECONDS, ascentSeconds, UNIT_SECONDS);
|
||||
addSummaryData(DESCENT_SECONDS, descentSeconds, UNIT_SECONDS);
|
||||
addSummaryData(FLAT_SECONDS, flatSeconds, UNIT_SECONDS);
|
||||
addSummaryData(ASCENT_DISTANCE, ascentDistance, UNIT_METERS);
|
||||
addSummaryData(DESCENT_DISTANCE, descentDistance, UNIT_METERS);
|
||||
addSummaryData(FLAT_DISTANCE, flatDistance, UNIT_METERS);
|
||||
|
||||
addSummaryData("distanceMeters", distanceMeters, "meters");
|
||||
// addSummaryData("distanceMeters2", distanceMeters2, "meters");
|
||||
addSummaryData("ascentMeters", ascentMeters, "meters");
|
||||
addSummaryData("descentMeters", descentMeters, "meters");
|
||||
addSummaryData(DISTANCE_METERS, distanceMeters, UNIT_METERS);
|
||||
// addSummaryData("distanceMeters2", distanceMeters2, UNIT_METERS);
|
||||
addSummaryData(ASCENT_METERS, ascentMeters, UNIT_METERS);
|
||||
addSummaryData(DESCENT_METERS, descentMeters, UNIT_METERS);
|
||||
if (maxAltitude != -100000) {
|
||||
addSummaryData("maxAltitude", maxAltitude, "meters");
|
||||
addSummaryData(ALTITUDE_MAX, maxAltitude, UNIT_METERS);
|
||||
}
|
||||
if (minAltitude != 100000) {
|
||||
addSummaryData("minAltitude", minAltitude, "meters");
|
||||
addSummaryData(ALTITUDE_MIN, minAltitude, UNIT_METERS);
|
||||
}
|
||||
if (minAltitude != 100000) {
|
||||
addSummaryData("averageAltitude", averageAltitude, "meters");
|
||||
addSummaryData(ALTITUDE_AVG, averageAltitude, UNIT_METERS);
|
||||
}
|
||||
addSummaryData("steps", steps, "steps_unit");
|
||||
addSummaryData("activeSeconds", activeSeconds, "seconds");
|
||||
addSummaryData("caloriesBurnt", caloriesBurnt, "calories_unit");
|
||||
addSummaryData("maxSpeed", maxSpeed, "meters_second");
|
||||
addSummaryData("minSpeed", minSpeed, "meters_second");
|
||||
addSummaryData("averageSpeed", averageSpeed, "meters_second");
|
||||
addSummaryData("maxCadence", maxCadence, "spm");
|
||||
addSummaryData("minCadence", minCadence, "spm");
|
||||
addSummaryData("averageCadence", averageCadence, "spm");
|
||||
addSummaryData(STEPS, steps, UNIT_STEPS);
|
||||
addSummaryData(ACTIVE_SECONDS, activeSeconds, UNIT_SECONDS);
|
||||
addSummaryData(CALORIES_BURNT, caloriesBurnt, UNIT_KCAL);
|
||||
addSummaryData(SPEED_MAX, maxSpeed, UNIT_METERS_PER_SECOND);
|
||||
addSummaryData(SPEED_MIN, minSpeed, UNIT_METERS_PER_SECOND);
|
||||
addSummaryData(SPEED_AVG, averageSpeed, UNIT_METERS_PER_SECOND);
|
||||
addSummaryData(CADENCE_MAX, maxCadence, UNIT_SPM);
|
||||
addSummaryData(CADENCE_MIN, minCadence, UNIT_SPM);
|
||||
addSummaryData(CADENCE_AVG, averageCadence, UNIT_SPM);
|
||||
|
||||
if (!(activityKind == ActivityKind.TYPE_ELLIPTICAL_TRAINER ||
|
||||
activityKind == ActivityKind.TYPE_JUMP_ROPING ||
|
||||
activityKind == ActivityKind.TYPE_EXERCISE ||
|
||||
activityKind == ActivityKind.TYPE_YOGA ||
|
||||
activityKind == ActivityKind.TYPE_INDOOR_CYCLING)) {
|
||||
addSummaryData("minPace", minPace, "seconds_m");
|
||||
addSummaryData("maxPace", maxPace, "seconds_m");
|
||||
// addSummaryData("averagePace", averagePace, "seconds_m");
|
||||
addSummaryData(PACE_MIN, minPace, UNIT_SECONDS_PER_M);
|
||||
addSummaryData(PACE_MAX, maxPace, UNIT_SECONDS_PER_M);
|
||||
// addSummaryData("averagePace", averagePace, UNIT_SECONDS_PER_M);
|
||||
}
|
||||
|
||||
addSummaryData("totalStride", totalStride, "meters");
|
||||
addSummaryData("averageHR", averageHR, "bpm");
|
||||
addSummaryData("maxHR", maxHR, "bpm");
|
||||
addSummaryData("minHR", minHR, "bpm");
|
||||
addSummaryData("averageKMPaceSeconds", averageKMPaceSeconds, "seconds_km");
|
||||
addSummaryData("averageStride", averageStride, "cm");
|
||||
addSummaryData("maxStride", maxStride, "cm");
|
||||
addSummaryData("minStride", minStride, "cm");
|
||||
// addSummaryData("averageStride2", averageStride2, "cm");
|
||||
addSummaryData(STRIDE_TOTAL, totalStride, UNIT_METERS);
|
||||
addSummaryData(HR_AVG, averageHR, UNIT_BPM);
|
||||
addSummaryData(HR_MAX, maxHR, UNIT_BPM);
|
||||
addSummaryData(HR_MIN, minHR, UNIT_BPM);
|
||||
addSummaryData(PACE_AVG_SECONDS_KM, averageKMPaceSeconds, UNIT_SECONDS_PER_KM);
|
||||
addSummaryData(STRIDE_AVG, averageStride, UNIT_CM);
|
||||
addSummaryData(STRIDE_MAX, maxStride, UNIT_CM);
|
||||
addSummaryData(STRIDE_MIN, minStride, UNIT_CM);
|
||||
// addSummaryData("averageStride2", averageStride2, UNIT_CM);
|
||||
|
||||
if (activityKind == ActivityKind.TYPE_SWIMMING || activityKind == ActivityKind.TYPE_SWIMMING_OPENWATER) {
|
||||
addSummaryData("averageStrokeDistance", averageStrokeDistance, "meters");
|
||||
addSummaryData("averageStrokesPerSecond", averageStrokesPerSecond, "strokes_second");
|
||||
addSummaryData("averageLapPace", averageLapPace, "second");
|
||||
addSummaryData("strokes", strokes, "strokes");
|
||||
addSummaryData("swolfIndex", swolfIndex, "swolf_index");
|
||||
addSummaryData(STROKE_DISTANCE_AVG, averageStrokeDistance, UNIT_METERS);
|
||||
addSummaryData(STROKE_AVG_PER_SECOND, averageStrokesPerSecond, UNIT_STROKES_PER_SECOND);
|
||||
addSummaryData(LAP_PACE_AVERAGE, averageLapPace, "second");
|
||||
addSummaryData(STROKES, strokes, "strokes");
|
||||
addSummaryData(SWOLF_INDEX, swolfIndex, "swolf_index");
|
||||
String swimStyleName = "unknown"; // TODO: translate here or keep as string identifier here?
|
||||
switch (swimStyle) {
|
||||
case 1:
|
||||
@ -379,8 +381,8 @@ public class HuamiActivitySummaryParser implements ActivitySummaryParser {
|
||||
swimStyleName = "medley";
|
||||
break;
|
||||
}
|
||||
addSummaryData("swimStyle", swimStyleName);
|
||||
addSummaryData("laps", laps, "laps");
|
||||
addSummaryData(SWIM_STYLE, swimStyleName);
|
||||
addSummaryData(LAPS, laps, "laps");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,109 @@
|
||||
/* Copyright (C) 2023 José Rebelo
|
||||
|
||||
This file is part of Gadgetbridge.
|
||||
|
||||
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Gadgetbridge is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.model;
|
||||
|
||||
public class ActivitySummaryEntries {
|
||||
public static final String TIME_START = "startTime";
|
||||
public static final String TIME_END = "endTime";
|
||||
public static final String ACTIVE_SECONDS = "activeSeconds";
|
||||
|
||||
public static final String ALTITUDE_AVG = "averageAltitude";
|
||||
public static final String ALTITUDE_BASE = "baseAltitude";
|
||||
public static final String ALTITUDE_MAX = "maxAltitude";
|
||||
public static final String ALTITUDE_MIN = "minAltitude";
|
||||
|
||||
public static final String ASCENT_DISTANCE = "ascentDistance";
|
||||
public static final String ASCENT_METERS = "ascentMeters";
|
||||
public static final String ASCENT_SECONDS = "ascentSeconds";
|
||||
public static final String DESCENT_DISTANCE = "descentDistance";
|
||||
public static final String DESCENT_METERS = "descentMeters";
|
||||
public static final String DESCENT_SECONDS = "descentSeconds";
|
||||
public static final String FLAT_DISTANCE = "flatDistance";
|
||||
public static final String FLAT_SECONDS = "flatSeconds";
|
||||
|
||||
public static final String CADENCE_AVG = "averageCadence";
|
||||
public static final String CADENCE_MAX = "maxCadence";
|
||||
public static final String CADENCE_MIN = "minCadence";
|
||||
|
||||
public static final String SPEED_AVG = "averageSpeed";
|
||||
public static final String SPEED_MAX = "maxSpeed";
|
||||
public static final String SPEED_MIN = "minSpeed";
|
||||
|
||||
public static final String DISTANCE_METERS = "distanceMeters";
|
||||
public static final String ELEVATION_GAIN = "elevationGain";
|
||||
public static final String ELEVATION_LOSS = "elevationLoss";
|
||||
|
||||
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_ZONE_NA = "hrZoneNa";
|
||||
public static final String HR_ZONE_WARM_UP = "hrZoneWarmUp";
|
||||
public static final String HR_ZONE_FAT_BURN = "hrZoneFatBurn";
|
||||
public static final String HR_ZONE_AEROBIC = "hrZoneAerobic";
|
||||
public static final String HR_ZONE_ANAEROBIC = "hrZoneAnaerobic";
|
||||
public static final String HR_ZONE_EXTREME = "hrZoneExtreme";
|
||||
|
||||
public static final String LANE_LENGTH = "laneLength";
|
||||
public static final String LAPS = "laps";
|
||||
public static final String LAP_PACE_AVERAGE = "averageLapPace";
|
||||
|
||||
public static final String PACE_AVG_SECONDS_KM = "averageKMPaceSeconds";
|
||||
public static final String PACE_MAX = "maxPace";
|
||||
public static final String PACE_MIN = "minPace";
|
||||
public static final String STEPS = "steps";
|
||||
public static final String STRIDE_AVG = "averageStride";
|
||||
public static final String STRIDE_MAX = "maxStride";
|
||||
public static final String STRIDE_MIN = "minStride";
|
||||
public static final String STRIDE_TOTAL = "totalStride";
|
||||
|
||||
public static final String STROKE_DISTANCE_AVG = "averageStrokeDistance";
|
||||
public static final String STROKE_AVG_PER_SECOND = "averageStrokesPerSecond";
|
||||
public static final String STROKE_RATE_AVG = "avgStrokeRate";
|
||||
public static final String STROKE_RATE_MAX = "maxStrokeRate";
|
||||
public static final String STROKES = "strokes";
|
||||
|
||||
public static final String SWIM_STYLE = "swimStyle";
|
||||
public static final String SWOLF_INDEX = "swolfIndex";
|
||||
|
||||
public static final String CALORIES_BURNT = "caloriesBurnt";
|
||||
public static final String TRAINING_EFFECT_AEROBIC = "aerobicTrainingEffect";
|
||||
public static final String TRAINING_EFFECT_ANAEROBIC = "anaerobicTrainingEffect";
|
||||
public static final String WORKOUT_LOAD = "currentWorkoutLoad";
|
||||
public static final String MAXIMUM_OXYGEN_UPTAKE = "maximumOxygenUptake";
|
||||
public static final String RECOVERY_TIME = "recoveryTime";
|
||||
|
||||
public static final String UNIT_BPM = "bpm";
|
||||
public static final String UNIT_CM = "cm";
|
||||
public static final String UNIT_UNIX_EPOCH_SECONDS = "unix_epoch_seconds";
|
||||
public static final String UNIT_KCAL = "calories_unit";
|
||||
public static final String UNIT_LAPS = "laps_unit";
|
||||
public static final String UNIT_METERS = "meters";
|
||||
public static final String UNIT_ML_KG_MIN = "ml/kg/min";
|
||||
public static final String UNIT_NONE = "";
|
||||
public static final String UNIT_HOURS = "hours";
|
||||
public static final String UNIT_SECONDS = "seconds";
|
||||
public static final String UNIT_SECONDS_PER_KM = "seconds_km";
|
||||
public static final String UNIT_SECONDS_PER_M = "seconds_m";
|
||||
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";
|
||||
public static final String UNIT_STEPS = "steps_unit";
|
||||
public static final String UNIT_STROKES = "strokes_unit";
|
||||
public static final String UNIT_STROKES_PER_MINUTE = "strokes_minute";
|
||||
public static final String UNIT_STROKES_PER_SECOND = "strokes_second";
|
||||
public static final String UNIT_YARD = "yard";
|
||||
}
|
@ -1,5 +1,7 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.model;
|
||||
|
||||
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.*;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
@ -153,35 +155,35 @@ public class ActivitySummaryJsonSummary {
|
||||
private JSONObject createActivitySummaryGroups(){
|
||||
final Map<String, List<String>> groupDefinitions = new HashMap<String, List<String>>() {{
|
||||
put("Strokes", Arrays.asList(
|
||||
"averageStrokeDistance", "averageStrokesPerSecond", "strokes",
|
||||
"avgStrokeRate", "maxStrokeRate"
|
||||
STROKE_DISTANCE_AVG, STROKE_AVG_PER_SECOND, STROKES,
|
||||
STROKE_RATE_AVG, STROKE_RATE_MAX
|
||||
));
|
||||
put("Swimming", Arrays.asList(
|
||||
"swolfIndex", "swimStyle"
|
||||
SWOLF_INDEX, SWIM_STYLE
|
||||
));
|
||||
put("Elevation", Arrays.asList(
|
||||
"ascentMeters", "descentMeters", "maxAltitude", "minAltitude", "averageAltitude",
|
||||
"baseAltitude", "ascentSeconds", "descentSeconds", "flatSeconds", "ascentDistance",
|
||||
"descentDistance", "flatDistance", "elevationGain", "elevationLoss"
|
||||
ASCENT_METERS, DESCENT_METERS, ALTITUDE_MAX, ALTITUDE_MIN, ALTITUDE_AVG,
|
||||
ALTITUDE_BASE, ASCENT_SECONDS, DESCENT_SECONDS, FLAT_SECONDS, ASCENT_DISTANCE,
|
||||
DESCENT_DISTANCE, FLAT_DISTANCE, ELEVATION_GAIN, ELEVATION_LOSS
|
||||
));
|
||||
put("Speed", Arrays.asList(
|
||||
"averageSpeed", "maxSpeed", "minSpeed", "averageKMPaceSeconds", "minPace",
|
||||
"maxPace", "averageSpeed2", "averageCadence", "maxCadence", "minCadence"
|
||||
SPEED_AVG, SPEED_MAX, SPEED_MIN, PACE_AVG_SECONDS_KM, PACE_MIN,
|
||||
PACE_MAX, "averageSpeed2", CADENCE_AVG, CADENCE_MAX, CADENCE_MIN
|
||||
));
|
||||
put("Activity", Arrays.asList(
|
||||
"distanceMeters", "steps", "activeSeconds", "caloriesBurnt", "totalStride",
|
||||
"averageHR", "maxHR", "minHR", "averageStride", "maxStride", "minStride"
|
||||
DISTANCE_METERS, STEPS, ACTIVE_SECONDS, CALORIES_BURNT, STRIDE_TOTAL,
|
||||
HR_AVG, HR_MAX, HR_MIN, STRIDE_AVG, STRIDE_MAX, STRIDE_MIN
|
||||
));
|
||||
put("HeartRateZones", Arrays.asList(
|
||||
"hrZoneNa", "hrZoneWarmUp", "hrZoneFatBurn", "hrZoneAerobic", "hrZoneAnaerobic",
|
||||
"hrZoneExtreme"
|
||||
HR_ZONE_NA, HR_ZONE_WARM_UP, HR_ZONE_FAT_BURN, HR_ZONE_AEROBIC, HR_ZONE_ANAEROBIC,
|
||||
HR_ZONE_EXTREME
|
||||
));
|
||||
put("TrainingEffect", Arrays.asList(
|
||||
"aerobicTrainingEffect", "anaerobicTrainingEffect", "currentWorkoutLoad",
|
||||
"maximumOxygenUptake"
|
||||
TRAINING_EFFECT_AEROBIC, TRAINING_EFFECT_ANAEROBIC, WORKOUT_LOAD,
|
||||
MAXIMUM_OXYGEN_UPTAKE
|
||||
));
|
||||
put("laps", Arrays.asList(
|
||||
"averageLapPace", "laps", "laneLength"
|
||||
LAP_PACE_AVERAGE, LAPS, LANE_LENGTH
|
||||
));
|
||||
}};
|
||||
|
||||
|
@ -16,13 +16,46 @@
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.xiaomi.activity.impl;
|
||||
|
||||
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.ACTIVE_SECONDS;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.CADENCE_AVG;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.CALORIES_BURNT;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.DISTANCE_METERS;
|
||||
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_MIN;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.HR_ZONE_AEROBIC;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.HR_ZONE_ANAEROBIC;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.HR_ZONE_EXTREME;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.HR_ZONE_FAT_BURN;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.HR_ZONE_WARM_UP;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.PACE_MAX;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.PACE_MIN;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.RECOVERY_TIME;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.SPEED_MAX;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.STEPS;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.TIME_END;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.TIME_START;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.TRAINING_EFFECT_AEROBIC;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.TRAINING_EFFECT_ANAEROBIC;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.UNIT_BPM;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.UNIT_HOURS;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.UNIT_KCAL;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.UNIT_KMPH;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.UNIT_METERS;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.UNIT_NONE;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.UNIT_SECONDS;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.UNIT_SECONDS_PER_M;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.UNIT_SPM;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.UNIT_STEPS;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.UNIT_UNIX_EPOCH_SECONDS;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.WORKOUT_LOAD;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.service.devices.xiaomi.activity.impl.XiaomiSimpleActivityParser.XIAOMI_WORKOUT_TYPE;
|
||||
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@ -152,50 +185,52 @@ public class WorkoutSummaryParser extends XiaomiActivityParser implements Activi
|
||||
|
||||
final XiaomiSimpleActivityParser.Builder builder = new XiaomiSimpleActivityParser.Builder();
|
||||
builder.setHeaderSize(headerSize);
|
||||
builder.addInt("startTime", "seconds");
|
||||
builder.addInt("endTime", "seconds");
|
||||
builder.addInt("activeSeconds", "seconds");
|
||||
builder.addInt(TIME_START, UNIT_UNIX_EPOCH_SECONDS);
|
||||
builder.addInt(TIME_END, UNIT_UNIX_EPOCH_SECONDS);
|
||||
builder.addInt(ACTIVE_SECONDS, UNIT_SECONDS);
|
||||
builder.addUnknown(4);
|
||||
builder.addShort("caloriesBurnt", "calories_unit");
|
||||
builder.addShort(CALORIES_BURNT, UNIT_KCAL);
|
||||
builder.addUnknown(4);
|
||||
builder.addByte("averageHR", "bpm");
|
||||
builder.addByte("maxHR", "bpm");
|
||||
builder.addByte("minHR", "bpm");
|
||||
builder.addFloat("aerobicTrainingEffect", "");
|
||||
builder.addByte(HR_AVG, UNIT_BPM);
|
||||
builder.addByte(HR_MAX, UNIT_BPM);
|
||||
builder.addByte(HR_MIN, UNIT_BPM);
|
||||
builder.addFloat(TRAINING_EFFECT_AEROBIC, UNIT_NONE);
|
||||
builder.addUnknown(1);
|
||||
builder.addUnknown(1);
|
||||
builder.addShort(RECOVERY_TIME, UNIT_HOURS);
|
||||
builder.addInt(HR_ZONE_EXTREME, UNIT_SECONDS);
|
||||
builder.addInt(HR_ZONE_ANAEROBIC, UNIT_SECONDS);
|
||||
builder.addInt(HR_ZONE_AEROBIC, UNIT_SECONDS);
|
||||
builder.addInt(HR_ZONE_FAT_BURN, UNIT_SECONDS);
|
||||
builder.addInt(HR_ZONE_WARM_UP, UNIT_SECONDS);
|
||||
builder.addUnknown(2);
|
||||
builder.addShort("recoveryTime", "hours");
|
||||
builder.addInt("hrZoneExtreme", "seconds");
|
||||
builder.addInt("hrZoneAnaerobic", "seconds");
|
||||
builder.addInt("hrZoneAerobic", "seconds");
|
||||
builder.addInt("hrZoneFatBurn", "seconds");
|
||||
builder.addInt("hrZoneWarmUp", "seconds");
|
||||
builder.addUnknown(6);
|
||||
builder.addFloat("anaerobicTrainingEffect", "");
|
||||
builder.addUnknown(4);
|
||||
builder.addFloat(TRAINING_EFFECT_ANAEROBIC, UNIT_NONE);
|
||||
// FIXME identify field lengths to align with the header
|
||||
builder.addUnknown(3);
|
||||
builder.addInt("configuredTimeGoal", "seconds");
|
||||
builder.addShort("configuredCaloriesGoal", "calories_unit");
|
||||
builder.addShort("maximumCaloriesGoal", "calories_unit"); // TODO: mhm?
|
||||
builder.addInt("configuredTimeGoal", UNIT_SECONDS);
|
||||
builder.addShort("configuredCaloriesGoal", UNIT_KCAL);
|
||||
builder.addShort("maximumCaloriesGoal", UNIT_KCAL); // TODO: mhm?
|
||||
builder.addUnknown(28);
|
||||
builder.addShort("trainingLoad", "");
|
||||
builder.addShort(WORKOUT_LOAD, UNIT_NONE); // training load
|
||||
builder.addUnknown(24);
|
||||
builder.addByte("configuredSets", "");
|
||||
builder.addByte("configuredSets", UNIT_NONE);
|
||||
builder.addUnknown(13);
|
||||
builder.addInt("startTime2", "seconds");
|
||||
builder.addInt("endTime2", "seconds");
|
||||
builder.addInt("goal", ""); // TODO match against goalType
|
||||
builder.addInt("duration2", "seconds");
|
||||
builder.addInt("intervalTime", "seconds");
|
||||
builder.addInt("startTime2", UNIT_SECONDS);
|
||||
builder.addInt("endTime2", UNIT_SECONDS);
|
||||
builder.addInt("goal", UNIT_NONE); // TODO match against goalType
|
||||
builder.addInt("duration2", UNIT_SECONDS);
|
||||
builder.addInt("intervalTime", UNIT_SECONDS);
|
||||
builder.addUnknown(56);
|
||||
builder.addInt("hrZoneExtreme2", "seconds");
|
||||
builder.addInt("hrZoneAnaerobic2", "seconds");
|
||||
builder.addInt("hrZoneAerobic2", "seconds");
|
||||
builder.addInt("hrZoneFatBurn2", "seconds");
|
||||
builder.addInt("hrZoneWarmUp2", "seconds");
|
||||
builder.addInt("hrZoneExtreme2", UNIT_SECONDS);
|
||||
builder.addInt("hrZoneAnaerobic2", UNIT_SECONDS);
|
||||
builder.addInt("hrZoneAerobic2", UNIT_SECONDS);
|
||||
builder.addInt("hrZoneFatBurn2", UNIT_SECONDS);
|
||||
builder.addInt("hrZoneWarmUp2", UNIT_SECONDS);
|
||||
builder.addUnknown(16);
|
||||
builder.addShort("vitality_gain", "");
|
||||
builder.addShort("training_load2", "");
|
||||
builder.addShort("recovery_time2", "hours");
|
||||
|
||||
builder.addShort("vitality_gain", UNIT_NONE);
|
||||
builder.addShort("training_load2", UNIT_NONE);
|
||||
builder.addShort("recovery_time2", UNIT_HOURS);
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
@ -215,30 +250,31 @@ public class WorkoutSummaryParser extends XiaomiActivityParser implements Activi
|
||||
|
||||
final XiaomiSimpleActivityParser.Builder builder = new XiaomiSimpleActivityParser.Builder();
|
||||
builder.setHeaderSize(headerSize);
|
||||
builder.addInt("startTime", "seconds");
|
||||
builder.addInt("endTime", "seconds");
|
||||
builder.addInt("activeSeconds", "seconds");
|
||||
builder.addInt("distanceMeters", "meters");
|
||||
builder.addInt("caloriesBurnt", "calories_unit");
|
||||
builder.addInt("maxPace", "seconds_m");
|
||||
builder.addInt("minPace", "seconds_m");
|
||||
builder.addInt(TIME_START, UNIT_UNIX_EPOCH_SECONDS);
|
||||
builder.addInt(TIME_END, UNIT_UNIX_EPOCH_SECONDS);
|
||||
builder.addInt(ACTIVE_SECONDS, UNIT_SECONDS);
|
||||
builder.addInt(DISTANCE_METERS, UNIT_METERS);
|
||||
builder.addInt(CALORIES_BURNT, UNIT_KCAL);
|
||||
builder.addInt(PACE_MAX, UNIT_SECONDS_PER_M);
|
||||
builder.addInt(PACE_MIN, UNIT_SECONDS_PER_M);
|
||||
builder.addUnknown(4);
|
||||
builder.addInt("steps", "steps_unit");
|
||||
builder.addInt(STEPS, UNIT_STEPS);
|
||||
builder.addUnknown(2); // pace?
|
||||
builder.addByte("averageHR", "bpm");
|
||||
builder.addByte("maxHR", "bpm");
|
||||
builder.addByte("minHR", "bpm");
|
||||
builder.addByte(HR_AVG, UNIT_BPM);
|
||||
builder.addByte(HR_MAX, UNIT_BPM);
|
||||
builder.addByte(HR_MIN, UNIT_BPM);
|
||||
// FIXME identify field lengths to align with the header
|
||||
builder.addUnknown(20);
|
||||
builder.addFloat("recoveryValue", "recoveryValue");
|
||||
builder.addUnknown(9);
|
||||
builder.addByte("recoveryTime", "seconds");
|
||||
builder.addByte(RECOVERY_TIME, UNIT_SECONDS);
|
||||
builder.addUnknown(2);
|
||||
builder.addInt("hrZoneExtreme", "seconds");
|
||||
builder.addInt("hrZoneAnaerobic", "seconds");
|
||||
builder.addInt("hrZoneAerobic", "seconds");
|
||||
builder.addInt("hrZoneFatBurn", "seconds");
|
||||
builder.addInt("hrZoneWarmUp", "seconds");
|
||||
builder.addInt("configured_time_goal", "seconds");
|
||||
builder.addInt(HR_ZONE_EXTREME, UNIT_SECONDS);
|
||||
builder.addInt(HR_ZONE_ANAEROBIC, UNIT_SECONDS);
|
||||
builder.addInt(HR_ZONE_AEROBIC, UNIT_SECONDS);
|
||||
builder.addInt(HR_ZONE_FAT_BURN, UNIT_SECONDS);
|
||||
builder.addInt(HR_ZONE_WARM_UP, UNIT_SECONDS);
|
||||
builder.addInt("configured_time_goal", UNIT_SECONDS);
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
@ -258,41 +294,41 @@ public class WorkoutSummaryParser extends XiaomiActivityParser implements Activi
|
||||
|
||||
final XiaomiSimpleActivityParser.Builder builder = new XiaomiSimpleActivityParser.Builder();
|
||||
builder.setHeaderSize(headerSize);
|
||||
builder.addShort("xiaomiActivityType", "xiaomiActivityType");
|
||||
builder.addInt("startTime", "seconds");
|
||||
builder.addInt("endTime", "seconds");
|
||||
builder.addInt("activeSeconds", "seconds");
|
||||
builder.addShort(XIAOMI_WORKOUT_TYPE, XIAOMI_WORKOUT_TYPE);
|
||||
builder.addInt(TIME_START, UNIT_UNIX_EPOCH_SECONDS);
|
||||
builder.addInt(TIME_END, UNIT_UNIX_EPOCH_SECONDS);
|
||||
builder.addInt(ACTIVE_SECONDS, UNIT_SECONDS);
|
||||
builder.addUnknown(4);
|
||||
builder.addInt("distanceMeters", "meters");
|
||||
builder.addInt(DISTANCE_METERS, UNIT_METERS);
|
||||
builder.addUnknown(2);
|
||||
builder.addShort("caloriesBurnt", "calories_unit");
|
||||
builder.addShort(CALORIES_BURNT, UNIT_KCAL);
|
||||
builder.addUnknown(12);
|
||||
builder.addInt("steps", "steps_unit");
|
||||
builder.addInt(STEPS, UNIT_STEPS);
|
||||
builder.addUnknown(2);
|
||||
builder.addByte("averageHR", "bpm");
|
||||
builder.addByte("maxHR", "bpm");
|
||||
builder.addByte("minHR", "bpm");
|
||||
builder.addByte(HR_AVG, UNIT_BPM);
|
||||
builder.addByte(HR_MAX, UNIT_BPM);
|
||||
builder.addByte(HR_MIN, UNIT_BPM);
|
||||
builder.addUnknown(20);
|
||||
builder.addFloat("recoveryValue", "?");
|
||||
builder.addUnknown(9);
|
||||
builder.addByte("recoveryTime", "hours");
|
||||
builder.addByte(RECOVERY_TIME, UNIT_HOURS);
|
||||
builder.addUnknown(2);
|
||||
builder.addInt("hrZoneExtreme", "seconds");
|
||||
builder.addInt("hrZoneAnaerobic", "seconds");
|
||||
builder.addInt("hrZoneAerobic", "seconds");
|
||||
builder.addInt("hrZoneFatBurn", "seconds");
|
||||
builder.addInt("hrZoneWarmUp", "seconds");
|
||||
builder.addInt("configuredTimeGoal", "seconds");
|
||||
builder.addShort("configuredCaloriesGoal", "calories_unit");
|
||||
builder.addInt("configuredDistanceGoal", "meters");
|
||||
builder.addInt(HR_ZONE_EXTREME, UNIT_SECONDS);
|
||||
builder.addInt(HR_ZONE_ANAEROBIC, UNIT_SECONDS);
|
||||
builder.addInt(HR_ZONE_AEROBIC, UNIT_SECONDS);
|
||||
builder.addInt(HR_ZONE_FAT_BURN, UNIT_SECONDS);
|
||||
builder.addInt(HR_ZONE_WARM_UP, UNIT_SECONDS);
|
||||
builder.addInt("configuredTimeGoal", UNIT_SECONDS);
|
||||
builder.addShort("configuredCaloriesGoal", UNIT_KCAL);
|
||||
builder.addInt("configuredDistanceGoal", UNIT_METERS);
|
||||
builder.addUnknown(11);
|
||||
builder.addShort("trainingLoad", "");
|
||||
builder.addShort(WORKOUT_LOAD, UNIT_NONE); // training load
|
||||
builder.addUnknown(24);
|
||||
builder.addByte("averageHR2", "bpm");
|
||||
builder.addByte("maxHR2", "bpm");
|
||||
builder.addByte("minHR2", "bpm");
|
||||
builder.addByte("averageHR2", UNIT_BPM);
|
||||
builder.addByte("maxHR2", UNIT_BPM);
|
||||
builder.addByte("minHR2", UNIT_BPM);
|
||||
builder.addUnknown(2);
|
||||
builder.addByte("averageCadence", "spm");
|
||||
builder.addByte(CADENCE_AVG, UNIT_SPM);
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
@ -312,19 +348,20 @@ public class WorkoutSummaryParser extends XiaomiActivityParser implements Activi
|
||||
|
||||
final XiaomiSimpleActivityParser.Builder builder = new XiaomiSimpleActivityParser.Builder();
|
||||
builder.setHeaderSize(headerSize);
|
||||
builder.addShort("xiaomiWorkoutType", "xiaomiWorkoutType");
|
||||
builder.addInt("startTime", "seconds");
|
||||
builder.addInt("endTime", "seconds");
|
||||
builder.addInt("activeSeconds", "seconds");
|
||||
builder.addShort(XIAOMI_WORKOUT_TYPE, XIAOMI_WORKOUT_TYPE);
|
||||
builder.addInt(TIME_START, UNIT_UNIX_EPOCH_SECONDS);
|
||||
builder.addInt(TIME_END, UNIT_UNIX_EPOCH_SECONDS);
|
||||
builder.addInt(ACTIVE_SECONDS, UNIT_SECONDS);
|
||||
builder.addUnknown(4);
|
||||
builder.addInt("distanceMeters", "meters");
|
||||
builder.addInt(DISTANCE_METERS, UNIT_METERS);
|
||||
builder.addUnknown(2);
|
||||
builder.addShort("caloriesBurnt", "calories_unit");
|
||||
builder.addUnknown(8);
|
||||
builder.addFloat("maxSpeed", "km_h");
|
||||
builder.addByte("averageHR", "bpm");
|
||||
builder.addByte("maxHR", "bpm");
|
||||
builder.addByte("minHR", "bpm");
|
||||
builder.addShort(CALORIES_BURNT, UNIT_KCAL);
|
||||
builder.addUnknown(4);
|
||||
builder.addUnknown(4);
|
||||
builder.addFloat(SPEED_MAX, UNIT_KMPH);
|
||||
builder.addByte(HR_AVG, UNIT_BPM);
|
||||
builder.addByte(HR_MAX, UNIT_BPM);
|
||||
builder.addByte(HR_MIN, UNIT_BPM);
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
@ -16,8 +16,14 @@
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.xiaomi.activity.impl;
|
||||
|
||||
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.TIME_END;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.TIME_START;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries.UNIT_UNIX_EPOCH_SECONDS;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
@ -26,8 +32,13 @@ import java.util.List;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.BaseActivitySummary;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.ActivityKind;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||
|
||||
public class XiaomiSimpleActivityParser {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(XiaomiSimpleActivityParser.class);
|
||||
|
||||
public static final String XIAOMI_WORKOUT_TYPE = "xiaomiWorkoutType";
|
||||
|
||||
private final int headerSize;
|
||||
private final List<XiaomiSimpleDataEntry> dataEntries;
|
||||
|
||||
@ -42,19 +53,35 @@ public class XiaomiSimpleActivityParser {
|
||||
final byte[] header = new byte[headerSize];
|
||||
buf.get(header);
|
||||
|
||||
for (final XiaomiSimpleDataEntry dataEntry : dataEntries) {
|
||||
LOG.debug("Header: {}", GB.hexdump(header));
|
||||
|
||||
for (int i = 0; i < dataEntries.size(); i++) {
|
||||
final XiaomiSimpleDataEntry dataEntry = dataEntries.get(i);
|
||||
|
||||
final Number value = dataEntry.get(buf);
|
||||
if (value == null) {
|
||||
LOG.debug("Skipping unknown field {}", i);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (dataEntry.getKey().equals("endTime")) {
|
||||
if (dataEntry.getUnit().equals("seconds")) {
|
||||
// Each bit in the header marks whether the data is valid or not, in order of the fields
|
||||
final boolean validData = (header[i / 8] & (1 << (7 - (i % 8)))) != 0;
|
||||
// FIXME: We can't use the header before identifying the correct field lenggths for unknown fields
|
||||
// or parsing gets out of sync with the header and we will potentially ignore valid data
|
||||
//if (!validData) {
|
||||
// LOG.debug("Ignoring non-valid data {}", i);
|
||||
// continue;
|
||||
//}
|
||||
|
||||
if (dataEntry.getKey().equals(TIME_END)) {
|
||||
if (dataEntry.getUnit().equals(UNIT_UNIX_EPOCH_SECONDS)) {
|
||||
summary.setEndTime(new Date(value.intValue() * 1000L));
|
||||
} else {
|
||||
throw new IllegalArgumentException("endTime should be in seconds");
|
||||
throw new IllegalArgumentException("endTime should be an unix epoch");
|
||||
}
|
||||
} if (dataEntry.getKey().equals("xiaomiWorkoutType")) {
|
||||
} else if (dataEntry.getKey().equals(TIME_START)) {
|
||||
// ignored
|
||||
} else if (dataEntry.getKey().equals(XIAOMI_WORKOUT_TYPE)) {
|
||||
// TODO use XiaomiWorkoutType
|
||||
switch (value.intValue()) {
|
||||
case 2:
|
||||
|
Loading…
Reference in New Issue
Block a user