Fix avg_hr_day: remove dead averageHeartRate lookup; add max_hr_day from UDS export
Build and push images / validate (push) Successful in 18s
Build and push images / build-backend (push) Successful in 30s
Build and push images / build-worker (push) Successful in 29s
Build and push images / build-frontend (push) Successful in 30s

garmin.get_stats() never returns averageHeartRate — avg_hr_day is only computable
from intraday HR which Garmin's API only serves for recent dates (~90-120 days).
The dead lookup gave false confidence that historical backfill would work.

Also populate max_hr_day from the Garmin export's UDS daily summaries (maxHeartRate
field is present for the full history), so historical max HR is available after
re-importing the export.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-08 12:25:11 +01:00
parent 2d94f99356
commit bc4d68da07
2 changed files with 5 additions and 3 deletions
+1 -1
View File
@@ -524,7 +524,7 @@ def _parse_day(stats, sleep_data, hrv_data) -> dict:
if stats:
_set(row, "resting_hr", stats.get("restingHeartRate"))
_set(row, "avg_hr_day", stats.get("averageHeartRate"))
# averageHeartRate is absent from get_stats; avg_hr_day is computed below from intraday HR
_set(row, "max_hr_day", stats.get("maxHeartRate"))
_set(row, "steps", stats.get("totalSteps"))
_set(row, "floors_climbed", stats.get("floorsAscended"))
+4 -2
View File
@@ -422,12 +422,13 @@ def process_garmin_health_zip(zip_path: str, user_id: int):
from sqlalchemy import text
INSERT_SQL = text("""
INSERT INTO health_metrics (user_id, date, resting_hr, steps,
INSERT INTO health_metrics (user_id, date, resting_hr, max_hr_day, steps,
floors_climbed, active_calories, total_calories, avg_stress, spo2_avg)
VALUES (:user_id, :date, :resting_hr, :steps,
VALUES (:user_id, :date, :resting_hr, :max_hr_day, :steps,
:floors, :active_cal, :total_cal, :stress, :spo2)
ON CONFLICT (user_id, date) DO UPDATE SET
resting_hr = COALESCE(EXCLUDED.resting_hr, health_metrics.resting_hr),
max_hr_day = COALESCE(EXCLUDED.max_hr_day, health_metrics.max_hr_day),
steps = COALESCE(EXCLUDED.steps, health_metrics.steps),
floors_climbed = COALESCE(EXCLUDED.floors_climbed, health_metrics.floors_climbed),
active_calories = COALESCE(EXCLUDED.active_calories, health_metrics.active_calories),
@@ -463,6 +464,7 @@ def process_garmin_health_zip(zip_path: str, user_id: int):
db.execute(INSERT_SQL, {
"user_id": user_id, "date": date_dt,
"resting_hr": item.get("restingHeartRate"),
"max_hr_day": item.get("maxHeartRate"),
"steps": item.get("totalSteps"),
"floors": _floors_from_item(item),
"active_cal": item.get("activeKilocalories"),