fix: support German column names in CSV imports
All checks were successful
Deploy Development / deploy (push) Successful in 44s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 14s

Problem: Import expected English column names, but German Apple Health/Omron
exports use German names with units.

Fixed:
- Apple Health: Support both English and German column names
  - "Start" OR "Datum/Uhrzeit"
  - "Resting Heart Rate" OR "Ruhepuls (count/min)"
  - "Heart Rate Variability" OR "Herzfrequenzvariabilität (ms)"
  - "VO2 Max" OR "VO2 max (ml/(kg·min))"
  - "Oxygen Saturation" OR "Blutsauerstoffsättigung (%)"
  - "Respiratory Rate" OR "Atemfrequenz (count/min)"

- Omron: Support column names with/without units
  - "Systolisch (mmHg)" OR "Systolisch"
  - "Diastolisch (mmHg)" OR "Diastolisch"
  - "Puls (bpm)" OR "Puls"
  - "Unregelmäßiger Herzschlag festgestellt" OR "Unregelmäßiger Herzschlag"
  - "Mögliches AFib" OR "Vorhofflimmern"

Added debug logging for both imports to show detected columns.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Lars 2026-03-23 16:40:49 +01:00
parent 6a7b78c3eb
commit f506a55d7b
2 changed files with 33 additions and 15 deletions

View File

@ -310,8 +310,15 @@ async def import_omron_csv(
with get_db() as conn: with get_db() as conn:
cur = get_cursor(conn) cur = get_cursor(conn)
# Log available columns for debugging
first_row = True
for row in reader: for row in reader:
try: try:
if first_row:
logger.info(f"Omron CSV Columns: {list(row.keys())}")
first_row = False
# Parse Omron German date format # Parse Omron German date format
date_str = row.get('Datum', row.get('Date')) date_str = row.get('Datum', row.get('Date'))
time_str = row.get('Zeit', row.get('Time', '08:00')) time_str = row.get('Zeit', row.get('Time', '08:00'))
@ -325,18 +332,27 @@ async def import_omron_csv(
errors += 1 errors += 1
continue continue
# Extract measurements # Extract measurements (support column names with/without units)
systolic = row.get('Systolisch', row.get('Systolic')) systolic = (row.get('Systolisch (mmHg)') or row.get('Systolisch') or
diastolic = row.get('Diastolisch', row.get('Diastolic')) row.get('Systolic (mmHg)') or row.get('Systolic'))
pulse = row.get('Puls', row.get('Pulse')) diastolic = (row.get('Diastolisch (mmHg)') or row.get('Diastolisch') or
row.get('Diastolic (mmHg)') or row.get('Diastolic'))
pulse = (row.get('Puls (bpm)') or row.get('Puls') or
row.get('Pulse (bpm)') or row.get('Pulse'))
if not systolic or not diastolic: if not systolic or not diastolic:
logger.warning(f"Skipped row {date_str} {time_str}: Missing BP values (sys={systolic}, dia={diastolic})")
skipped += 1 skipped += 1
continue continue
# Parse warning flags # Parse warning flags (support various column names)
irregular = row.get('Unregelmäßiger Herzschlag', row.get('Irregular Heartbeat', '')) irregular = (row.get('Unregelmäßiger Herzschlag festgestellt') or
afib = row.get('Vorhofflimmern', row.get('AFib', '')) row.get('Unregelmäßiger Herzschlag') or
row.get('Irregular Heartbeat') or '')
afib = (row.get('Mögliches AFib') or
row.get('Vorhofflimmern') or
row.get('Possible AFib') or
row.get('AFib') or '')
irregular_heartbeat = irregular.lower() in ['ja', 'yes', 'true', '1'] irregular_heartbeat = irregular.lower() in ['ja', 'yes', 'true', '1']
possible_afib = afib.lower() in ['ja', 'yes', 'true', '1'] possible_afib = afib.lower() in ['ja', 'yes', 'true', '1']

View File

@ -320,18 +320,20 @@ async def import_apple_health_baseline(
logger.info(f"CSV Columns: {list(row.keys())}") logger.info(f"CSV Columns: {list(row.keys())}")
first_row = False first_row = False
date = row.get('Start')[:10] if row.get('Start') else None # Support both English and German column names
date_raw = row.get('Start') or row.get('Datum/Uhrzeit')
date = date_raw[:10] if date_raw else None
if not date: if not date:
logger.warning(f"Skipped row (no date): Start='{row.get('Start')}'") logger.warning(f"Skipped row (no date): Start='{row.get('Start')}', Datum/Uhrzeit='{row.get('Datum/Uhrzeit')}'")
skipped += 1 skipped += 1
continue continue
# Extract baseline vitals from Apple Health export # Extract baseline vitals (support English + German column names)
rhr = row.get('Resting Heart Rate') rhr = row.get('Resting Heart Rate') or row.get('Ruhepuls (count/min)')
hrv = row.get('Heart Rate Variability') hrv = row.get('Heart Rate Variability') or row.get('Herzfrequenzvariabilität (ms)')
vo2 = row.get('VO2 Max') vo2 = row.get('VO2 Max') or row.get('VO2 max (ml/(kg·min))')
spo2 = row.get('Oxygen Saturation') spo2 = row.get('Oxygen Saturation') or row.get('Blutsauerstoffsättigung (%)')
resp_rate = row.get('Respiratory Rate') resp_rate = row.get('Respiratory Rate') or row.get('Atemfrequenz (count/min)')
# Skip if no baseline vitals # Skip if no baseline vitals
if not any([rhr, hrv, vo2, spo2, resp_rate]): if not any([rhr, hrv, vo2, spo2, resp_rate]):