182 lines
5.7 KiB
Python
182 lines
5.7 KiB
Python
"""
|
|
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",
|
|
}
|