From 41a39ec3c7554681841a0551bb40aae3c893a93e Mon Sep 17 00:00:00 2001 From: owain Date: Sun, 7 Jun 2026 21:59:05 +0100 Subject: [PATCH] Try training_status and stats_and_body for VO2 max (debug logging) Co-Authored-By: Claude Sonnet 4.6 --- backend/app/services/garmin_connect_sync.py | 47 ++++++++++----------- 1 file changed, 23 insertions(+), 24 deletions(-) diff --git a/backend/app/services/garmin_connect_sync.py b/backend/app/services/garmin_connect_sync.py index 0af5394..483e5a2 100644 --- a/backend/app/services/garmin_connect_sync.py +++ b/backend/app/services/garmin_connect_sync.py @@ -325,34 +325,33 @@ 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 once via maxmet endpoint (slow-changing — only update today's row) + # Fetch current VO2 max once (slow-changing — only update today's row) today_str = date.today().isoformat() - mm_data = _safe(garmin.get_max_metrics, today_str) - logger.info("maxmet raw response: %s", mm_data) + ts_data = _safe(garmin.get_training_status, today_str) + logger.info("training_status raw response: %s", ts_data) + sb_data = _safe(garmin.get_stats_and_body, today_str) + logger.info("stats_and_body raw response: %s", sb_data) fa_data = _safe(garmin.get_fitnessage_data, today_str) - logger.info("fitnessage raw response: %s", fa_data) vo2 = None - if mm_data: - # maxmet returns a list of metric dicts or a wrapper - items = mm_data if isinstance(mm_data, list) else mm_data.get("allMetrics", {}).get("metricsMap", {}) - if isinstance(items, list): - for item in items: - for key in ("vo2MaxPreciseValue", "vo2Max", "generic"): - v = item.get(key) - if v and isinstance(v, (int, float)) and float(v) > 0: - vo2 = float(v) - break - if vo2: - break - elif isinstance(items, dict): - for key in ("VO2_MAX", "vo2Max", "vo2MaxPreciseValue"): - entry = items.get(key) - if entry: - v = entry[0].get("value") if isinstance(entry, list) else entry.get("value") - if v and float(v) > 0: - vo2 = float(v) - break + # Try training status first + if ts_data and not vo2: + for key in ("vo2MaxPreciseValue", "vo2Max", "latestVO2Max"): + v = ts_data.get(key) + if v and isinstance(v, (int, float)) and float(v) > 0: + vo2 = float(v) + break + if not vo2 and isinstance(ts_data.get("mostRecentVO2Max"), dict): + v = ts_data["mostRecentVO2Max"].get("generic") or ts_data["mostRecentVO2Max"].get("value") + if v and float(v) > 0: + vo2 = float(v) + # Try stats_and_body + if sb_data and not vo2: + for key in ("vo2MaxPreciseValue", "vo2Max"): + v = sb_data.get(key) + if v and isinstance(v, (int, float)) and float(v) > 0: + vo2 = float(v) + break fa_age = None if fa_data: