mirror of
https://github.com/sstent/GarminSync.git
synced 2026-01-25 08:35:02 +00:00
checkpoint 1
This commit is contained in:
80
patches/garth_data_weight.py
Normal file
80
patches/garth_data_weight.py
Normal file
@@ -0,0 +1,80 @@
|
||||
from datetime import date, datetime, timedelta
|
||||
from itertools import chain
|
||||
|
||||
from pydantic import Field, ValidationInfo, field_validator
|
||||
from pydantic.dataclasses import dataclass
|
||||
from typing_extensions import Self
|
||||
|
||||
from .. import http
|
||||
from ..utils import (
|
||||
camel_to_snake_dict,
|
||||
format_end_date,
|
||||
get_localized_datetime,
|
||||
)
|
||||
from ._base import MAX_WORKERS, Data
|
||||
|
||||
|
||||
@dataclass
|
||||
class WeightData(Data):
|
||||
sample_pk: int
|
||||
calendar_date: date
|
||||
weight: int
|
||||
source_type: str
|
||||
weight_delta: float
|
||||
datetime_utc: datetime = Field(..., alias="timestamp_gmt")
|
||||
datetime_local: datetime = Field(..., alias="date")
|
||||
bmi: float | None = None
|
||||
body_fat: float | None = None
|
||||
body_water: float | None = None
|
||||
bone_mass: int | None = None
|
||||
muscle_mass: int | None = None
|
||||
physique_rating: float | None = None
|
||||
visceral_fat: float | None = None
|
||||
metabolic_age: int | None = None
|
||||
|
||||
@field_validator("datetime_local", mode="before")
|
||||
@classmethod
|
||||
def to_localized_datetime(cls, v: int, info: ValidationInfo) -> datetime:
|
||||
return get_localized_datetime(info.data["datetime_utc"].timestamp() * 1000, v)
|
||||
|
||||
@classmethod
|
||||
def get(
|
||||
cls, day: date | str, *, client: http.Client | None = None
|
||||
) -> Self | None:
|
||||
client = client or http.client
|
||||
path = f"/weight-service/weight/dayview/{day}"
|
||||
data = client.connectapi(path)
|
||||
day_weight_list = data["dateWeightList"] if data else []
|
||||
|
||||
if not day_weight_list:
|
||||
return None
|
||||
|
||||
# Get first (most recent) weight entry for the day
|
||||
weight_data = camel_to_snake_dict(day_weight_list[0])
|
||||
return cls(**weight_data)
|
||||
|
||||
@classmethod
|
||||
def list(
|
||||
cls,
|
||||
end: date | str | None = None,
|
||||
days: int = 1,
|
||||
*,
|
||||
client: http.Client | None = None,
|
||||
max_workers: int = MAX_WORKERS,
|
||||
) -> list[Self]:
|
||||
client = client or http.client
|
||||
end = format_end_date(end)
|
||||
start = end - timedelta(days=days - 1)
|
||||
|
||||
data = client.connectapi(
|
||||
f"/weight-service/weight/range/{start}/{end}?includeAll=true"
|
||||
)
|
||||
weight_summaries = data["dailyWeightSummaries"] if data else []
|
||||
weight_metrics = chain.from_iterable(
|
||||
summary["allWeightMetrics"] for summary in weight_summaries
|
||||
)
|
||||
weight_data_list = (
|
||||
cls(**camel_to_snake_dict(weight_data))
|
||||
for weight_data in weight_metrics
|
||||
)
|
||||
return sorted(weight_data_list, key=lambda d: d.datetime_utc)
|
||||
Reference in New Issue
Block a user