diff --git a/backend/app/services/garmin_connect_sync.py b/backend/app/services/garmin_connect_sync.py index c82f461..a1a9603 100644 --- a/backend/app/services/garmin_connect_sync.py +++ b/backend/app/services/garmin_connect_sync.py @@ -325,6 +325,31 @@ def sync_wellness(garmin, user_id: int, since: Optional[datetime], db, logger.warning("Failed to upsert health_metrics for %s: %s", day_str, exc) db.rollback() + # Fetch current VO2 max and fitness age once (slow-changing — only update today's row) + today_str = date.today().isoformat() + fa_data = _safe(garmin.get_fitnessage_data, today_str) + if fa_data: + vo2 = (fa_data.get("vo2Max") + or fa_data.get("vo2MaxPreciseValue") + or fa_data.get("biometricProfile", {}).get("vo2Max")) + fa = fa_data.get("chronologicalAge") or fa_data.get("fitnessAge") + if vo2 and float(vo2) > 0: + try: + fa_row = {"vo2max": float(vo2)} + if fa: + fa_row["fitness_age"] = int(fa) + fa_cols = list(fa_row.keys()) + db.execute(text(f""" + INSERT INTO health_metrics (user_id, date, {", ".join(fa_cols)}) + VALUES (:user_id, :day, {", ".join(f":{c}" for c in fa_cols)}) + ON CONFLICT (user_id, date) DO UPDATE SET + {", ".join(f"{c} = EXCLUDED.{c}" for c in fa_cols)} + """), {"user_id": user_id, "day": today_str, **fa_row}) + db.commit() + except Exception as exc: + logger.warning("Failed to upsert VO2 max: %s", exc) + db.rollback() + return processed @@ -469,9 +494,6 @@ def _parse_day(stats, sleep_data, hrv_data) -> dict: _set(row, "active_calories", active) if active and bmr: _set(row, "total_calories", float(active) + float(bmr)) - vo2 = stats.get("vo2MaxPreciseValue") or stats.get("vo2Max") - if vo2 and float(vo2) > 0: - _set(row, "vo2max", float(vo2)) if sleep_data: dto = sleep_data.get("dailySleepDTO") or sleep_data