fix: find keys
This commit is contained in:
@@ -6,14 +6,13 @@ metadata:
|
|||||||
data:
|
data:
|
||||||
sync.py: |
|
sync.py: |
|
||||||
import os
|
import os
|
||||||
|
import json
|
||||||
import time
|
import time
|
||||||
from datetime import date, timedelta
|
from datetime import date, timedelta
|
||||||
import psycopg2
|
|
||||||
from garminconnect import Garmin
|
from garminconnect import Garmin
|
||||||
|
|
||||||
email = os.environ["GARMIN_EMAIL"]
|
email = os.environ["GARMIN_EMAIL"]
|
||||||
password = os.environ["GARMIN_PASSWORD"]
|
password = os.environ["GARMIN_PASSWORD"]
|
||||||
db_url = os.environ["DATABASE_URL"]
|
|
||||||
|
|
||||||
client = Garmin(email, password)
|
client = Garmin(email, password)
|
||||||
for attempt in range(5):
|
for attempt in range(5):
|
||||||
@@ -31,232 +30,21 @@ data:
|
|||||||
else:
|
else:
|
||||||
raise Exception("Login nach 5 Versuchen fehlgeschlagen")
|
raise Exception("Login nach 5 Versuchen fehlgeschlagen")
|
||||||
|
|
||||||
today = date.today()
|
d = (date.today() - timedelta(days=1)).isoformat()
|
||||||
start = today - timedelta(days=365 * 3)
|
print(f"=== Debug fuer {d} ===")
|
||||||
|
|
||||||
conn = psycopg2.connect(db_url)
|
for name, fn, args in [
|
||||||
cur = conn.cursor()
|
("stats", client.get_stats, [d]),
|
||||||
|
("stress", client.get_stress_data, [d]),
|
||||||
# ── Schema ────────────────────────────────────────────────────────────────
|
("bb", client.get_body_battery, [d, d]),
|
||||||
|
("spo2", client.get_spo2_data, [d]),
|
||||||
cur.execute("""
|
("resp", client.get_respiration_data, [d]),
|
||||||
CREATE TABLE IF NOT EXISTS activities (
|
("hrv", client.get_hrv_data, [d]),
|
||||||
id BIGINT PRIMARY KEY,
|
("sleep", client.get_sleep_data, [d]),
|
||||||
name TEXT,
|
]:
|
||||||
type TEXT,
|
|
||||||
start_time TIMESTAMP,
|
|
||||||
duration_seconds FLOAT,
|
|
||||||
distance_meters FLOAT,
|
|
||||||
avg_hr INTEGER,
|
|
||||||
max_hr INTEGER,
|
|
||||||
avg_pace FLOAT,
|
|
||||||
vo2max FLOAT,
|
|
||||||
calories FLOAT,
|
|
||||||
elevation_gain FLOAT,
|
|
||||||
steps INTEGER,
|
|
||||||
cadence FLOAT,
|
|
||||||
hr_zone_1 FLOAT,
|
|
||||||
hr_zone_2 FLOAT,
|
|
||||||
hr_zone_3 FLOAT,
|
|
||||||
hr_zone_4 FLOAT,
|
|
||||||
hr_zone_5 FLOAT
|
|
||||||
)
|
|
||||||
""")
|
|
||||||
|
|
||||||
cur.execute("""
|
|
||||||
CREATE TABLE IF NOT EXISTS daily_health (
|
|
||||||
date DATE PRIMARY KEY,
|
|
||||||
resting_hr INTEGER,
|
|
||||||
total_steps INTEGER,
|
|
||||||
total_distance_meters FLOAT,
|
|
||||||
active_calories FLOAT,
|
|
||||||
total_calories FLOAT,
|
|
||||||
stress_avg INTEGER,
|
|
||||||
stress_max INTEGER,
|
|
||||||
body_battery_high INTEGER,
|
|
||||||
body_battery_low INTEGER,
|
|
||||||
spo2_avg FLOAT,
|
|
||||||
spo2_min FLOAT,
|
|
||||||
respiration_avg FLOAT,
|
|
||||||
hrv_weekly_avg FLOAT,
|
|
||||||
hrv_last_night FLOAT,
|
|
||||||
hrv_status TEXT,
|
|
||||||
sleep_duration_seconds INTEGER,
|
|
||||||
sleep_deep_seconds INTEGER,
|
|
||||||
sleep_light_seconds INTEGER,
|
|
||||||
sleep_rem_seconds INTEGER,
|
|
||||||
sleep_awake_seconds INTEGER,
|
|
||||||
sleep_score INTEGER,
|
|
||||||
sleep_feedback TEXT
|
|
||||||
)
|
|
||||||
""")
|
|
||||||
|
|
||||||
conn.commit()
|
|
||||||
|
|
||||||
# ── Activities ────────────────────────────────────────────────────────────
|
|
||||||
|
|
||||||
activities = client.get_activities_by_date(
|
|
||||||
start.isoformat(), today.isoformat()
|
|
||||||
)
|
|
||||||
|
|
||||||
for a in activities:
|
|
||||||
cur.execute("""
|
|
||||||
INSERT INTO activities
|
|
||||||
(id, name, type, start_time, duration_seconds, distance_meters,
|
|
||||||
avg_hr, max_hr, avg_pace, vo2max, calories, elevation_gain,
|
|
||||||
steps, cadence, hr_zone_1, hr_zone_2, hr_zone_3, hr_zone_4, hr_zone_5)
|
|
||||||
VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)
|
|
||||||
ON CONFLICT (id) DO UPDATE SET
|
|
||||||
duration_seconds = EXCLUDED.duration_seconds,
|
|
||||||
distance_meters = EXCLUDED.distance_meters,
|
|
||||||
avg_hr = EXCLUDED.avg_hr,
|
|
||||||
max_hr = EXCLUDED.max_hr,
|
|
||||||
avg_pace = EXCLUDED.avg_pace,
|
|
||||||
vo2max = EXCLUDED.vo2max,
|
|
||||||
calories = EXCLUDED.calories,
|
|
||||||
elevation_gain = EXCLUDED.elevation_gain,
|
|
||||||
steps = EXCLUDED.steps,
|
|
||||||
cadence = EXCLUDED.cadence,
|
|
||||||
hr_zone_1 = EXCLUDED.hr_zone_1,
|
|
||||||
hr_zone_2 = EXCLUDED.hr_zone_2,
|
|
||||||
hr_zone_3 = EXCLUDED.hr_zone_3,
|
|
||||||
hr_zone_4 = EXCLUDED.hr_zone_4,
|
|
||||||
hr_zone_5 = EXCLUDED.hr_zone_5
|
|
||||||
""", (
|
|
||||||
a.get("activityId"),
|
|
||||||
a.get("activityName"),
|
|
||||||
a.get("activityType", {}).get("typeKey"),
|
|
||||||
a.get("startTimeLocal"),
|
|
||||||
a.get("duration"),
|
|
||||||
a.get("distance"),
|
|
||||||
a.get("averageHR"),
|
|
||||||
a.get("maxHR"),
|
|
||||||
a.get("averageSpeed"),
|
|
||||||
a.get("vO2MaxValue"),
|
|
||||||
a.get("calories"),
|
|
||||||
a.get("elevationGain"),
|
|
||||||
a.get("steps"),
|
|
||||||
a.get("averageRunningCadenceInStepsPerMinute"),
|
|
||||||
a.get("hrTimeInZone_1"),
|
|
||||||
a.get("hrTimeInZone_2"),
|
|
||||||
a.get("hrTimeInZone_3"),
|
|
||||||
a.get("hrTimeInZone_4"),
|
|
||||||
a.get("hrTimeInZone_5"),
|
|
||||||
))
|
|
||||||
|
|
||||||
conn.commit()
|
|
||||||
print(f"Synced {len(activities)} activities")
|
|
||||||
|
|
||||||
# ── Daily Health (letzte 7 Tage, inkrementell) ────────────────────────────
|
|
||||||
|
|
||||||
def safe_get(fn, *args):
|
|
||||||
try:
|
try:
|
||||||
return fn(*args)
|
result = fn(*args)
|
||||||
|
print(f"\n=== {name} ===")
|
||||||
|
print(json.dumps(result, indent=2, default=str)[:3000])
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f" Warnung {fn.__name__}: {e}")
|
print(f"\n=== {name} FEHLER: {e} ===")
|
||||||
return None
|
|
||||||
|
|
||||||
health_start = today - timedelta(days=7)
|
|
||||||
check_date = health_start
|
|
||||||
synced = 0
|
|
||||||
|
|
||||||
while check_date <= today:
|
|
||||||
d = check_date.isoformat()
|
|
||||||
|
|
||||||
stats = safe_get(client.get_stats, d) or {}
|
|
||||||
stress = safe_get(client.get_stress_data, d) or {}
|
|
||||||
bb_list = safe_get(client.get_body_battery, d, d) or []
|
|
||||||
spo2 = safe_get(client.get_spo2_data, d) or {}
|
|
||||||
resp = safe_get(client.get_respiration_data, d) or {}
|
|
||||||
hrv_raw = safe_get(client.get_hrv_data, d) or {}
|
|
||||||
sleep_raw = safe_get(client.get_sleep_data, d) or {}
|
|
||||||
|
|
||||||
hrv = hrv_raw.get("hrvSummary", {})
|
|
||||||
sleep = sleep_raw.get("dailySleepDTO", {})
|
|
||||||
|
|
||||||
bb_high = max((e.get("charged", 0) for e in bb_list), default=None)
|
|
||||||
bb_low = min((e.get("drained", 0) for e in bb_list), default=None)
|
|
||||||
|
|
||||||
cur.execute("""
|
|
||||||
INSERT INTO daily_health (
|
|
||||||
date,
|
|
||||||
resting_hr, total_steps, total_distance_meters,
|
|
||||||
active_calories, total_calories,
|
|
||||||
stress_avg, stress_max,
|
|
||||||
body_battery_high, body_battery_low,
|
|
||||||
spo2_avg, spo2_min,
|
|
||||||
respiration_avg,
|
|
||||||
hrv_weekly_avg, hrv_last_night, hrv_status,
|
|
||||||
sleep_duration_seconds, sleep_deep_seconds,
|
|
||||||
sleep_light_seconds, sleep_rem_seconds, sleep_awake_seconds,
|
|
||||||
sleep_score, sleep_feedback
|
|
||||||
) VALUES (
|
|
||||||
%s,
|
|
||||||
%s,%s,%s,
|
|
||||||
%s,%s,
|
|
||||||
%s,%s,
|
|
||||||
%s,%s,
|
|
||||||
%s,%s,
|
|
||||||
%s,
|
|
||||||
%s,%s,%s,
|
|
||||||
%s,%s,
|
|
||||||
%s,%s,%s,
|
|
||||||
%s,%s
|
|
||||||
)
|
|
||||||
ON CONFLICT (date) DO UPDATE SET
|
|
||||||
resting_hr = EXCLUDED.resting_hr,
|
|
||||||
total_steps = EXCLUDED.total_steps,
|
|
||||||
total_distance_meters = EXCLUDED.total_distance_meters,
|
|
||||||
active_calories = EXCLUDED.active_calories,
|
|
||||||
total_calories = EXCLUDED.total_calories,
|
|
||||||
stress_avg = EXCLUDED.stress_avg,
|
|
||||||
stress_max = EXCLUDED.stress_max,
|
|
||||||
body_battery_high = EXCLUDED.body_battery_high,
|
|
||||||
body_battery_low = EXCLUDED.body_battery_low,
|
|
||||||
spo2_avg = EXCLUDED.spo2_avg,
|
|
||||||
spo2_min = EXCLUDED.spo2_min,
|
|
||||||
respiration_avg = EXCLUDED.respiration_avg,
|
|
||||||
hrv_weekly_avg = EXCLUDED.hrv_weekly_avg,
|
|
||||||
hrv_last_night = EXCLUDED.hrv_last_night,
|
|
||||||
hrv_status = EXCLUDED.hrv_status,
|
|
||||||
sleep_duration_seconds = EXCLUDED.sleep_duration_seconds,
|
|
||||||
sleep_deep_seconds = EXCLUDED.sleep_deep_seconds,
|
|
||||||
sleep_light_seconds = EXCLUDED.sleep_light_seconds,
|
|
||||||
sleep_rem_seconds = EXCLUDED.sleep_rem_seconds,
|
|
||||||
sleep_awake_seconds = EXCLUDED.sleep_awake_seconds,
|
|
||||||
sleep_score = EXCLUDED.sleep_score,
|
|
||||||
sleep_feedback = EXCLUDED.sleep_feedback
|
|
||||||
""", (
|
|
||||||
check_date,
|
|
||||||
stats.get("restingHeartRate"),
|
|
||||||
stats.get("totalSteps"),
|
|
||||||
stats.get("totalDistanceMeters"),
|
|
||||||
stats.get("activeKilocalories"),
|
|
||||||
stats.get("totalKilocalories"),
|
|
||||||
stress.get("avgStressLevel"),
|
|
||||||
stress.get("maxStressLevel"),
|
|
||||||
bb_high,
|
|
||||||
bb_low,
|
|
||||||
spo2.get("avgSpo2"),
|
|
||||||
spo2.get("lowestSpo2"),
|
|
||||||
resp.get("avgWakingRespirationValue"),
|
|
||||||
hrv.get("weeklyAvg"),
|
|
||||||
hrv.get("lastNight"),
|
|
||||||
hrv.get("status"),
|
|
||||||
sleep.get("sleepTimeSeconds"),
|
|
||||||
sleep.get("deepSleepSeconds"),
|
|
||||||
sleep.get("lightSleepSeconds"),
|
|
||||||
sleep.get("remSleepSeconds"),
|
|
||||||
sleep.get("awakeSleepSeconds"),
|
|
||||||
(sleep.get("sleepScores") or {}).get("overall", {}).get("value"),
|
|
||||||
(sleep.get("sleepScores") or {}).get("overall", {}).get("qualifierKey"),
|
|
||||||
))
|
|
||||||
|
|
||||||
conn.commit()
|
|
||||||
synced += 1
|
|
||||||
check_date += timedelta(days=1)
|
|
||||||
time.sleep(0.5)
|
|
||||||
|
|
||||||
cur.close()
|
|
||||||
conn.close()
|
|
||||||
print(f"Synced {synced} daily health records")
|
|
||||||
Reference in New Issue
Block a user