Fix SDK field names - use camelCase throughout
Build and push images / validate (push) Successful in 3s
Build and push images / build-backend (push) Successful in 51s
Build and push images / build-worker (push) Successful in 6s
Build and push images / build-frontend (push) Successful in 5s

This commit is contained in:
2026-06-06 19:27:35 +01:00
parent f609931ebc
commit 0fd3ff7414
3 changed files with 297 additions and 241 deletions
+32 -30
View File
@@ -1,5 +1,6 @@
"""
FIT and GPX file parser using the official Garmin FIT Python SDK.
Field names from the SDK are camelCase as per the SDK documentation.
"""
import math
from datetime import datetime, timezone
@@ -59,6 +60,7 @@ def parse_fit_file(filepath: str) -> dict:
merge_heart_rates=True,
)
# SDK returns camelCase keys
sessions = messages.get("session", [{}])
session = sessions[0] if sessions else {}
records = messages.get("record", [])
@@ -73,12 +75,12 @@ def parse_fit_file(filepath: str) -> dict:
}
sport_type = sport_map.get(sport, sport)
start_time = _ensure_utc(session.get("start_time"))
start_time = _ensure_utc(session.get("startTime"))
coords = []
for r in records:
lat = r.get("position_lat")
lon = r.get("position_long")
lat = r.get("positionLat")
lon = r.get("positionLong")
if lat is not None and lon is not None:
if -90 <= lat <= 90 and -180 <= lon <= 180:
coords.append((lat, lon))
@@ -89,8 +91,8 @@ def parse_fit_file(filepath: str) -> dict:
normalized_points = []
for r in records:
ts = _ensure_utc(r.get("timestamp"))
lat = r.get("position_lat")
lon = r.get("position_long")
lat = r.get("positionLat")
lon = r.get("positionLong")
if lat is not None and not (-90 <= lat <= 90):
lat = None
@@ -101,10 +103,10 @@ def parse_fit_file(filepath: str) -> dict:
"timestamp": ts.isoformat() if ts else None,
"latitude": _safe_float(lat),
"longitude": _safe_float(lon),
"altitude_m": _safe_float(r.get("altitude") or r.get("enhanced_altitude")),
"heart_rate": _safe_float(r.get("heart_rate")),
"altitude_m": _safe_float(r.get("altitude") or r.get("enhancedAltitude")),
"heart_rate": _safe_float(r.get("heartRate")),
"cadence": _safe_float(r.get("cadence")),
"speed_ms": _safe_float(r.get("speed") or r.get("enhanced_speed")),
"speed_ms": _safe_float(r.get("speed") or r.get("enhancedSpeed")),
"power": _safe_float(r.get("power")),
"temperature_c": _safe_float(r.get("temperature")),
"distance_m": _safe_float(r.get("distance")),
@@ -112,16 +114,16 @@ def parse_fit_file(filepath: str) -> dict:
normalized_laps = []
for i, lap in enumerate(laps):
ls = _ensure_utc(lap.get("start_time"))
ls = _ensure_utc(lap.get("startTime"))
normalized_laps.append({
"lap_number": i + 1,
"start_time": ls.isoformat() if ls else None,
"duration_s": _safe_float(lap.get("total_elapsed_time")),
"distance_m": _safe_float(lap.get("total_distance")),
"avg_heart_rate": _safe_float(lap.get("avg_heart_rate")),
"avg_cadence": _safe_float(lap.get("avg_cadence")),
"avg_speed_ms": _safe_float(lap.get("avg_speed") or lap.get("enhanced_avg_speed")),
"avg_power": _safe_float(lap.get("avg_power")),
"duration_s": _safe_float(lap.get("totalElapsedTime")),
"distance_m": _safe_float(lap.get("totalDistance")),
"avg_heart_rate": _safe_float(lap.get("avgHeartRate")),
"avg_cadence": _safe_float(lap.get("avgCadence")),
"avg_speed_ms": _safe_float(lap.get("avgSpeed") or lap.get("enhancedAvgSpeed")),
"avg_power": _safe_float(lap.get("avgPower")),
})
name = sport_type.title()
@@ -132,21 +134,21 @@ def parse_fit_file(filepath: str) -> dict:
"name": name,
"sport_type": sport_type,
"start_time": start_time.isoformat() if start_time else None,
"distance_m": _safe_float(session.get("total_distance")),
"duration_s": _safe_float(session.get("total_elapsed_time")),
"elevation_gain_m": _safe_float(session.get("total_ascent")),
"elevation_loss_m": _safe_float(session.get("total_descent")),
"avg_heart_rate": _safe_float(session.get("avg_heart_rate")),
"max_heart_rate": _safe_float(session.get("max_heart_rate")),
"avg_cadence": _safe_float(session.get("avg_cadence")),
"avg_power": _safe_float(session.get("avg_power")),
"normalized_power": _safe_float(session.get("normalized_power")),
"avg_speed_ms": _safe_float(session.get("avg_speed") or session.get("enhanced_avg_speed")),
"max_speed_ms": _safe_float(session.get("max_speed") or session.get("enhanced_max_speed")),
"avg_temperature_c": _safe_float(session.get("avg_temperature")),
"calories": _safe_float(session.get("total_calories")),
"training_stress_score": _safe_float(session.get("training_stress_score")),
"vo2max_estimate": _safe_float(session.get("total_training_effect")),
"distance_m": _safe_float(session.get("totalDistance")),
"duration_s": _safe_float(session.get("totalElapsedTime")),
"elevation_gain_m": _safe_float(session.get("totalAscent")),
"elevation_loss_m": _safe_float(session.get("totalDescent")),
"avg_heart_rate": _safe_float(session.get("avgHeartRate")),
"max_heart_rate": _safe_float(session.get("maxHeartRate")),
"avg_cadence": _safe_float(session.get("avgCadence")),
"avg_power": _safe_float(session.get("avgPower")),
"normalized_power": _safe_float(session.get("normalizedPower")),
"avg_speed_ms": _safe_float(session.get("avgSpeed") or session.get("enhancedAvgSpeed")),
"max_speed_ms": _safe_float(session.get("maxSpeed") or session.get("enhancedMaxSpeed")),
"avg_temperature_c": _safe_float(session.get("avgTemperature")),
"calories": _safe_float(session.get("totalCalories")),
"training_stress_score": _safe_float(session.get("trainingStressScore")),
"vo2max_estimate": _safe_float(session.get("totalTrainingEffect")),
"polyline": encoded_polyline,
"bounding_box": bounding_box,
"source_type": "fit",