mirror of
https://github.com/home-assistant/core.git
synced 2025-07-23 13:17:32 +00:00
Update fitbit client to use asyncio (#100933)
This commit is contained in:
parent
bd40cbcb21
commit
822251a642
@ -1,7 +1,7 @@
|
|||||||
"""API for fitbit bound to Home Assistant OAuth."""
|
"""API for fitbit bound to Home Assistant OAuth."""
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
from typing import Any
|
from typing import Any, cast
|
||||||
|
|
||||||
from fitbit import Fitbit
|
from fitbit import Fitbit
|
||||||
|
|
||||||
@ -34,10 +34,12 @@ class FitbitApi:
|
|||||||
"""Property to expose the underlying client library."""
|
"""Property to expose the underlying client library."""
|
||||||
return self._client
|
return self._client
|
||||||
|
|
||||||
def get_user_profile(self) -> FitbitProfile:
|
async def async_get_user_profile(self) -> FitbitProfile:
|
||||||
"""Return the user profile from the API."""
|
"""Return the user profile from the API."""
|
||||||
if self._profile is None:
|
if self._profile is None:
|
||||||
response: dict[str, Any] = self._client.user_profile_get()
|
response: dict[str, Any] = await self._hass.async_add_executor_job(
|
||||||
|
self._client.user_profile_get
|
||||||
|
)
|
||||||
_LOGGER.debug("user_profile_get=%s", response)
|
_LOGGER.debug("user_profile_get=%s", response)
|
||||||
profile = response["user"]
|
profile = response["user"]
|
||||||
self._profile = FitbitProfile(
|
self._profile = FitbitProfile(
|
||||||
@ -47,7 +49,7 @@ class FitbitApi:
|
|||||||
)
|
)
|
||||||
return self._profile
|
return self._profile
|
||||||
|
|
||||||
def get_unit_system(self) -> FitbitUnitSystem:
|
async def async_get_unit_system(self) -> FitbitUnitSystem:
|
||||||
"""Get the unit system to use when fetching timeseries.
|
"""Get the unit system to use when fetching timeseries.
|
||||||
|
|
||||||
This is used in a couple ways. The first is to determine the request
|
This is used in a couple ways. The first is to determine the request
|
||||||
@ -62,16 +64,18 @@ class FitbitApi:
|
|||||||
return self._unit_system
|
return self._unit_system
|
||||||
# Use units consistent with the account user profile or fallback to the
|
# Use units consistent with the account user profile or fallback to the
|
||||||
# home assistant unit settings.
|
# home assistant unit settings.
|
||||||
profile = self.get_user_profile()
|
profile = await self.async_get_user_profile()
|
||||||
if profile.locale == FitbitUnitSystem.EN_GB:
|
if profile.locale == FitbitUnitSystem.EN_GB:
|
||||||
return FitbitUnitSystem.EN_GB
|
return FitbitUnitSystem.EN_GB
|
||||||
if self._hass.config.units is METRIC_SYSTEM:
|
if self._hass.config.units is METRIC_SYSTEM:
|
||||||
return FitbitUnitSystem.METRIC
|
return FitbitUnitSystem.METRIC
|
||||||
return FitbitUnitSystem.EN_US
|
return FitbitUnitSystem.EN_US
|
||||||
|
|
||||||
def get_devices(self) -> list[FitbitDevice]:
|
async def async_get_devices(self) -> list[FitbitDevice]:
|
||||||
"""Return available devices."""
|
"""Return available devices."""
|
||||||
devices: list[dict[str, str]] = self._client.get_devices()
|
devices: list[dict[str, str]] = await self._hass.async_add_executor_job(
|
||||||
|
self._client.get_devices
|
||||||
|
)
|
||||||
_LOGGER.debug("get_devices=%s", devices)
|
_LOGGER.debug("get_devices=%s", devices)
|
||||||
return [
|
return [
|
||||||
FitbitDevice(
|
FitbitDevice(
|
||||||
@ -84,13 +88,18 @@ class FitbitApi:
|
|||||||
for device in devices
|
for device in devices
|
||||||
]
|
]
|
||||||
|
|
||||||
def get_latest_time_series(self, resource_type: str) -> dict[str, Any]:
|
async def async_get_latest_time_series(self, resource_type: str) -> dict[str, Any]:
|
||||||
"""Return the most recent value from the time series for the specified resource type."""
|
"""Return the most recent value from the time series for the specified resource type."""
|
||||||
|
|
||||||
# Set request header based on the configured unit system
|
# Set request header based on the configured unit system
|
||||||
self._client.system = self.get_unit_system()
|
self._client.system = await self.async_get_unit_system()
|
||||||
|
|
||||||
response: dict[str, Any] = self._client.time_series(resource_type, period="7d")
|
def _time_series() -> dict[str, Any]:
|
||||||
|
return cast(
|
||||||
|
dict[str, Any], self._client.time_series(resource_type, period="7d")
|
||||||
|
)
|
||||||
|
|
||||||
|
response: dict[str, Any] = await self._hass.async_add_executor_job(_time_series)
|
||||||
_LOGGER.debug("time_series(%s)=%s", resource_type, response)
|
_LOGGER.debug("time_series(%s)=%s", resource_type, response)
|
||||||
key = resource_type.replace("/", "-")
|
key = resource_type.replace("/", "-")
|
||||||
dated_results: list[dict[str, Any]] = response[key]
|
dated_results: list[dict[str, Any]] = response[key]
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
"""Support for the Fitbit API."""
|
"""Support for the Fitbit API."""
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import asyncio
|
||||||
from collections.abc import Callable
|
from collections.abc import Callable
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
import datetime
|
import datetime
|
||||||
@ -518,8 +519,12 @@ def setup_platform(
|
|||||||
authd_client.client.refresh_token()
|
authd_client.client.refresh_token()
|
||||||
|
|
||||||
api = FitbitApi(hass, authd_client, config[CONF_UNIT_SYSTEM])
|
api = FitbitApi(hass, authd_client, config[CONF_UNIT_SYSTEM])
|
||||||
user_profile = api.get_user_profile()
|
user_profile = asyncio.run_coroutine_threadsafe(
|
||||||
unit_system = api.get_unit_system()
|
api.async_get_user_profile(), hass.loop
|
||||||
|
).result()
|
||||||
|
unit_system = asyncio.run_coroutine_threadsafe(
|
||||||
|
api.async_get_unit_system(), hass.loop
|
||||||
|
).result()
|
||||||
|
|
||||||
clock_format = config[CONF_CLOCK_FORMAT]
|
clock_format = config[CONF_CLOCK_FORMAT]
|
||||||
monitored_resources = config[CONF_MONITORED_RESOURCES]
|
monitored_resources = config[CONF_MONITORED_RESOURCES]
|
||||||
@ -539,7 +544,10 @@ def setup_platform(
|
|||||||
if description.key in monitored_resources
|
if description.key in monitored_resources
|
||||||
]
|
]
|
||||||
if "devices/battery" in monitored_resources:
|
if "devices/battery" in monitored_resources:
|
||||||
devices = api.get_devices()
|
devices = asyncio.run_coroutine_threadsafe(
|
||||||
|
api.async_get_devices(),
|
||||||
|
hass.loop,
|
||||||
|
).result()
|
||||||
entities.extend(
|
entities.extend(
|
||||||
[
|
[
|
||||||
FitbitSensor(
|
FitbitSensor(
|
||||||
@ -708,21 +716,24 @@ class FitbitSensor(SensorEntity):
|
|||||||
|
|
||||||
return attrs
|
return attrs
|
||||||
|
|
||||||
def update(self) -> None:
|
async def async_update(self) -> None:
|
||||||
"""Get the latest data from the Fitbit API and update the states."""
|
"""Get the latest data from the Fitbit API and update the states."""
|
||||||
resource_type = self.entity_description.key
|
resource_type = self.entity_description.key
|
||||||
if resource_type == "devices/battery" and self.device is not None:
|
if resource_type == "devices/battery" and self.device is not None:
|
||||||
device_id = self.device.id
|
device_id = self.device.id
|
||||||
registered_devs: list[FitbitDevice] = self.api.get_devices()
|
registered_devs: list[FitbitDevice] = await self.api.async_get_devices()
|
||||||
self.device = next(
|
self.device = next(
|
||||||
device for device in registered_devs if device.id == device_id
|
device for device in registered_devs if device.id == device_id
|
||||||
)
|
)
|
||||||
self._attr_native_value = self.device.battery
|
self._attr_native_value = self.device.battery
|
||||||
|
|
||||||
else:
|
else:
|
||||||
result = self.api.get_latest_time_series(resource_type)
|
result = await self.api.async_get_latest_time_series(resource_type)
|
||||||
self._attr_native_value = self.entity_description.value_fn(result)
|
self._attr_native_value = self.entity_description.value_fn(result)
|
||||||
|
|
||||||
|
self.hass.async_add_executor_job(self._update_token)
|
||||||
|
|
||||||
|
def _update_token(self) -> None:
|
||||||
token = self.api.client.client.session.token
|
token = self.api.client.client.session.token
|
||||||
config_contents = {
|
config_contents = {
|
||||||
ATTR_ACCESS_TOKEN: token.get("access_token"),
|
ATTR_ACCESS_TOKEN: token.get("access_token"),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user