Fix VO2 max extraction — use fitnessage API not daily stats
get_stats() does not include VO2 max. Switch to get_fitnessage_data() which hits /fitnessage-service/fitnessage and returns the current VO2 max estimate and fitness age. Called once per sync (today only) since VO2 max is a slow-changing metric; the frontend carry-forward shows it on older days. Remove the incorrect stats.get() attempt from _parse_day. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user