def weight(client: FitbitApi) -> t.Optional[dict]: data = client.get_bodyweight(period="7d") if len(data["weight"]) == 0: log.info("No weight data") return None entries = data["weight"] for entry in entries: entry["datetime"] = pendulum.parse(f"{entry['date']}T{entry['time']}") entries.sort(key=itemgetter("datetime"), reverse=True) most_recent = entries[0] log.info(f"weight data: {most_recent}") return most_recent
class FitbitUser: service = FitbitService def __init__( self, gargling_id: int, first_name: str, access_token: str, refresh_token: str, expires_at: int, service_user_id: None, ): self.gargling_id = gargling_id self.first_name = first_name self.client = FitbitApi( config.fitbit_client_id, config.fitbit_client_secret, access_token=access_token, refresh_token=refresh_token, expires_at=expires_at, refresh_cb=self.service.persist_token, system=FitbitApi.METRIC, ) def _steps_api_call(self, date: pendulum.Date) -> dict: # no test coverage kwargs = { "resource": "activities/steps", "base_date": date, "period": "1d" } exc = None data = None for _ in range(10): try: data = self.client.time_series(**kwargs) break except fitbit.exceptions.HTTPServerError as e: log.info("Error fetching fitbit data. Retrying") exc = e continue if data is None: assert exc is not None raise exc return data def steps(self, date: pendulum.Date) -> t.Optional[int]: data = self._steps_api_call(date) if not data["activities-steps"]: return 0 entry = data["activities-steps"][0] return int(entry["value"]) if entry else 0 def _weight_api_call(self, date: pendulum.Date) -> dict: # no test coverage return self.client.get_bodyweight(base_date=date, period="1w") def _bodyfat_api_call(self, date: pendulum.Date) -> dict: # no test coverage return self.client.get_bodyfat(base_date=date, period="1w") def body(self, date: pendulum.Date) -> dict: def most_recent(entries: list[dict]) -> t.Optional[dict]: if len(entries) == 0: return None for entry in entries: parsed = pendulum.parse(f"{entry['date']}T{entry['time']}") assert isinstance(parsed, pendulum.DateTime) entry["datetime"] = parsed.date() entries.sort(key=itemgetter("datetime"), reverse=True) return entries[0] weight = None elapsed = None fat = None weight_data = self._weight_api_call(date) weight_entry = most_recent(weight_data["weight"]) if weight_entry is not None: if weight_entry["datetime"] == date: weight = weight_entry["weight"] else: elapsed = (date - weight_entry["datetime"]).days fat_data = self._bodyfat_api_call(date) fat_entry = most_recent(fat_data["fat"]) if fat_entry is not None and fat_entry["datetime"] == date: fat = fat_entry["fat"] return { "weight": weight, "elapsed": elapsed, "fat": fat, }