""" Health Connect Data Models - Storage for data pushed from Android companion app. These models store health data received from the Health Connect Android app, enabling the HealthConnectProvider to serve data to the API layer. """ from sqlalchemy import Column, Integer, String, Float, Date, DateTime, ForeignKey, Text from sqlalchemy.orm import relationship from backend.database import Base import datetime class HealthConnectSyncLog(Base): """ Tracks sync operations from the Android companion app. Used for debugging and monitoring data flow. """ __tablename__ = "health_connect_sync_logs" id = Column(Integer, primary_key=True, index=True) user_id = Column(Integer, ForeignKey("users.id"), index=True) device_id = Column(String(100)) # Android device identifier sync_timestamp = Column(DateTime, default=datetime.datetime.utcnow) records_pushed = Column(Integer, default=0) status = Column(String(50)) # "success", "partial", "error" error_message = Column(Text, nullable=True) user = relationship("User") class HealthConnectDailyMetrics(Base): """ Daily health metrics received from Health Connect. Mirrors DailyHealthMetrics but with Health Connect-specific metadata. """ __tablename__ = "health_connect_daily_metrics" id = Column(Integer, primary_key=True, index=True) user_id = Column(Integer, ForeignKey("users.id"), index=True) date = Column(Date, index=True) # Data source identification data_source = Column(String(200), nullable=True) # Package name of originating app (e.g., com.huami.watch.hmwatchmanager) data_source_name = Column(String(100), nullable=True) # Friendly name (e.g., "Zepp") # Activity metrics step_count = Column(Integer, default=0) distance_meters = Column(Float, default=0.0) calories_burned = Column(Float, default=0.0) # ActiveCaloriesBurnedRecord total_calories = Column(Float, default=0.0) # TotalCaloriesBurnedRecord # Sleep metrics (from SleepSessionRecord) sleep_duration_minutes = Column(Integer, default=0) deep_sleep_minutes = Column(Integer, default=0) light_sleep_minutes = Column(Integer, default=0) rem_sleep_minutes = Column(Integer, default=0) awake_duration_minutes = Column(Integer, default=0) # Heart rate metrics (from HeartRateRecord) avg_heart_rate = Column(Integer, nullable=True) min_heart_rate = Column(Integer, nullable=True) max_heart_rate = Column(Integer, nullable=True) resting_heart_rate = Column(Integer, nullable=True) # SpO2 (from OxygenSaturationRecord) avg_spo2 = Column(Float, nullable=True) min_spo2 = Column(Float, nullable=True) max_spo2 = Column(Float, nullable=True) # Body metrics weight = Column(Float, nullable=True) # WeightRecord # Metadata last_synced = Column(DateTime, default=datetime.datetime.utcnow) sync_id = Column(Integer, ForeignKey("health_connect_sync_logs.id"), nullable=True) user = relationship("User") class HealthConnectExerciseSession(Base): """ Exercise sessions from Health Connect ExerciseSessionRecord. """ __tablename__ = "health_connect_exercise_sessions" id = Column(Integer, primary_key=True, index=True) user_id = Column(Integer, ForeignKey("users.id"), index=True) # Session timing start_time = Column(DateTime, index=True) end_time = Column(DateTime) # Exercise type (Health Connect ExerciseType enum) exercise_type = Column(Integer) # Health Connect type ID exercise_type_name = Column(String(100)) # Human-readable name # Metrics duration_seconds = Column(Integer, default=0) distance_meters = Column(Float, nullable=True) calories_burned = Column(Float, nullable=True) # Heart rate during exercise avg_heart_rate = Column(Integer, nullable=True) max_heart_rate = Column(Integer, nullable=True) min_heart_rate = Column(Integer, nullable=True) # Additional metrics steps = Column(Integer, nullable=True) elevation_gained = Column(Float, nullable=True) # Metadata notes = Column(Text, nullable=True) last_synced = Column(DateTime, default=datetime.datetime.utcnow) sync_id = Column(Integer, ForeignKey("health_connect_sync_logs.id"), nullable=True) user = relationship("User") # Health Connect Exercise Type mapping (subset) HEALTH_CONNECT_EXERCISE_TYPES = { 0: "Unknown", 2: "Badminton", 4: "Baseball", 5: "Basketball", 8: "Biking", 9: "Biking Stationary", 10: "Boot Camp", 11: "Boxing", 13: "Calisthenics", 14: "Cricket", 16: "Dancing", 25: "Elliptical", 26: "Exercise Class", 27: "Fencing", 28: "Football American", 29: "Football Australian", 31: "Frisbee Disc", 32: "Golf", 33: "Guided Breathing", 34: "Gymnastics", 35: "Handball", 36: "High Intensity Interval Training", 37: "Hiking", 38: "Ice Hockey", 39: "Ice Skating", 44: "Martial Arts", 46: "Paddling", 48: "Pilates", 50: "Racquetball", 51: "Rock Climbing", 52: "Roller Hockey", 53: "Rowing", 54: "Rowing Machine", 55: "Rugby", 56: "Running", 57: "Running Treadmill", 58: "Sailing", 59: "Scuba Diving", 60: "Skating", 61: "Skiing", 62: "Snowboarding", 63: "Snowshoeing", 64: "Soccer", 65: "Softball", 67: "Squash", 68: "Stair Climbing", 69: "Stair Climbing Machine", 70: "Strength Training", 71: "Stretching", 72: "Surfing", 73: "Swimming Open Water", 74: "Swimming Pool", 75: "Table Tennis", 76: "Tennis", 78: "Volleyball", 79: "Walking", 80: "Water Polo", 81: "Weightlifting", 82: "Wheelchair", 84: "Yoga", }