Fix VO2 max sync: robust fallback when maxmet range returns non-list or valueless entries
The previous code used `if not mm_history:` to decide whether to fall back to get_training_status(). If the maxmet API returned a non-empty list with no valid vo2max values (or a non-list type), the fallback was skipped and nothing stored. Changes: - Normalise mm_raw: only use it if it's a list (handles dict/None responses) - Check valid_from_range: fall back to training_status whenever no usable value was found in the range query, regardless of whether it returned entries - Upgrade all related log lines to INFO so the result is visible without debug mode - Guard the entry loop against non-dict items Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -332,25 +332,40 @@ def sync_wellness(garmin, user_id: int, since: Optional[datetime], db,
|
||||
if fa_data:
|
||||
fa_age = fa_data.get("fitnessAge") or fa_data.get("achievableFitnessAge")
|
||||
|
||||
mm_entries = []
|
||||
try:
|
||||
mm_history = garmin.connectapi(
|
||||
mm_raw = garmin.connectapi(
|
||||
f"/metrics-service/metrics/maxmet/daily/{start_date.isoformat()}/{today_str}"
|
||||
)
|
||||
logger.info("maxmet range query returned type=%s len=%s",
|
||||
type(mm_raw).__name__,
|
||||
len(mm_raw) if isinstance(mm_raw, (list, dict)) else "n/a")
|
||||
if isinstance(mm_raw, list):
|
||||
mm_entries = mm_raw
|
||||
except Exception as exc:
|
||||
logger.debug("maxmet history fetch failed: %s", exc)
|
||||
mm_history = []
|
||||
logger.info("maxmet history fetch failed: %s", exc)
|
||||
|
||||
# Fall back to most-recent from training status if history is empty
|
||||
if not mm_history:
|
||||
# Check whether the range query yielded any usable vo2max values
|
||||
valid_from_range = any(
|
||||
(entry.get("vo2MaxPreciseValue") or entry.get("vo2MaxValue") or 0)
|
||||
for entry in mm_entries
|
||||
if isinstance(entry, dict)
|
||||
)
|
||||
|
||||
# Always fall back to training_status when the range query had no valid data
|
||||
if not valid_from_range:
|
||||
ts_data = _safe(garmin.get_training_status, today_str)
|
||||
generic = (ts_data or {}).get("mostRecentVO2Max", {}).get("generic") or {}
|
||||
generic = ((ts_data or {}).get("mostRecentVO2Max") or {}).get("generic") or {}
|
||||
v = generic.get("vo2MaxPreciseValue") or generic.get("vo2MaxValue")
|
||||
logger.info("training_status vo2max=%s at %s", v, generic.get("calendarDate"))
|
||||
if v and float(v) > 0:
|
||||
mm_history = [{"calendarDate": generic.get("calendarDate") or today_str,
|
||||
mm_entries = [{"calendarDate": generic.get("calendarDate") or today_str,
|
||||
"vo2MaxPreciseValue": float(v)}]
|
||||
|
||||
stored = 0
|
||||
for entry in (mm_history or []):
|
||||
for entry in mm_entries:
|
||||
if not isinstance(entry, dict):
|
||||
continue
|
||||
v = entry.get("vo2MaxPreciseValue") or entry.get("vo2MaxValue")
|
||||
if not v or float(v) <= 0:
|
||||
continue
|
||||
@@ -372,8 +387,7 @@ def sync_wellness(garmin, user_id: int, since: Optional[datetime], db,
|
||||
logger.warning("Failed to upsert VO2 max for %s: %s", entry_date, exc)
|
||||
db.rollback()
|
||||
|
||||
if stored:
|
||||
logger.info("Stored %d VO2 max data points", stored)
|
||||
logger.info("VO2 max: stored=%d from range_valid=%s", stored, valid_from_range)
|
||||
|
||||
return processed
|
||||
|
||||
|
||||
Reference in New Issue
Block a user