mirror of
https://github.com/home-assistant/core.git
synced 2025-07-25 14:17:45 +00:00
Use EntityDescription - fitbit (#55925)
This commit is contained in:
parent
60bb3121b6
commit
fed5f5e3b9
@ -1,8 +1,10 @@
|
|||||||
"""Constants for the Fitbit platform."""
|
"""Constants for the Fitbit platform."""
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from dataclasses import dataclass
|
||||||
from typing import Final
|
from typing import Final
|
||||||
|
|
||||||
|
from homeassistant.components.sensor import SensorEntityDescription
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
CONF_CLIENT_ID,
|
CONF_CLIENT_ID,
|
||||||
CONF_CLIENT_SECRET,
|
CONF_CLIENT_SECRET,
|
||||||
@ -43,66 +45,230 @@ DEFAULT_CONFIG: Final[dict[str, str]] = {
|
|||||||
}
|
}
|
||||||
DEFAULT_CLOCK_FORMAT: Final = "24H"
|
DEFAULT_CLOCK_FORMAT: Final = "24H"
|
||||||
|
|
||||||
FITBIT_RESOURCES_LIST: Final[dict[str, tuple[str, str | None, str]]] = {
|
|
||||||
"activities/activityCalories": ("Activity Calories", "cal", "fire"),
|
@dataclass
|
||||||
"activities/calories": ("Calories", "cal", "fire"),
|
class FitbitRequiredKeysMixin:
|
||||||
"activities/caloriesBMR": ("Calories BMR", "cal", "fire"),
|
"""Mixin for required keys."""
|
||||||
"activities/distance": ("Distance", "", "map-marker"),
|
|
||||||
"activities/elevation": ("Elevation", "", "walk"),
|
unit_type: str | None
|
||||||
"activities/floors": ("Floors", "floors", "walk"),
|
|
||||||
"activities/heart": ("Resting Heart Rate", "bpm", "heart-pulse"),
|
|
||||||
"activities/minutesFairlyActive": ("Minutes Fairly Active", TIME_MINUTES, "walk"),
|
@dataclass
|
||||||
"activities/minutesLightlyActive": ("Minutes Lightly Active", TIME_MINUTES, "walk"),
|
class FitbitSensorEntityDescription(SensorEntityDescription, FitbitRequiredKeysMixin):
|
||||||
"activities/minutesSedentary": (
|
"""Describes Fitbit sensor entity."""
|
||||||
"Minutes Sedentary",
|
|
||||||
TIME_MINUTES,
|
|
||||||
"seat-recline-normal",
|
FITBIT_RESOURCES_LIST: Final[tuple[FitbitSensorEntityDescription, ...]] = (
|
||||||
|
FitbitSensorEntityDescription(
|
||||||
|
key="activities/activityCalories",
|
||||||
|
name="Activity Calories",
|
||||||
|
unit_type="cal",
|
||||||
|
icon="mdi:fire",
|
||||||
),
|
),
|
||||||
"activities/minutesVeryActive": ("Minutes Very Active", TIME_MINUTES, "run"),
|
FitbitSensorEntityDescription(
|
||||||
"activities/steps": ("Steps", "steps", "walk"),
|
key="activities/calories",
|
||||||
"activities/tracker/activityCalories": ("Tracker Activity Calories", "cal", "fire"),
|
name="Calories",
|
||||||
"activities/tracker/calories": ("Tracker Calories", "cal", "fire"),
|
unit_type="cal",
|
||||||
"activities/tracker/distance": ("Tracker Distance", "", "map-marker"),
|
icon="mdi:fire",
|
||||||
"activities/tracker/elevation": ("Tracker Elevation", "", "walk"),
|
|
||||||
"activities/tracker/floors": ("Tracker Floors", "floors", "walk"),
|
|
||||||
"activities/tracker/minutesFairlyActive": (
|
|
||||||
"Tracker Minutes Fairly Active",
|
|
||||||
TIME_MINUTES,
|
|
||||||
"walk",
|
|
||||||
),
|
),
|
||||||
"activities/tracker/minutesLightlyActive": (
|
FitbitSensorEntityDescription(
|
||||||
"Tracker Minutes Lightly Active",
|
key="activities/caloriesBMR",
|
||||||
TIME_MINUTES,
|
name="Calories BMR",
|
||||||
"walk",
|
unit_type="cal",
|
||||||
|
icon="mdi:fire",
|
||||||
),
|
),
|
||||||
"activities/tracker/minutesSedentary": (
|
FitbitSensorEntityDescription(
|
||||||
"Tracker Minutes Sedentary",
|
key="activities/distance",
|
||||||
TIME_MINUTES,
|
name="Distance",
|
||||||
"seat-recline-normal",
|
unit_type="",
|
||||||
|
icon="mdi:map-marker",
|
||||||
),
|
),
|
||||||
"activities/tracker/minutesVeryActive": (
|
FitbitSensorEntityDescription(
|
||||||
"Tracker Minutes Very Active",
|
key="activities/elevation",
|
||||||
TIME_MINUTES,
|
name="Elevation",
|
||||||
"run",
|
unit_type="",
|
||||||
|
icon="mdi:walk",
|
||||||
),
|
),
|
||||||
"activities/tracker/steps": ("Tracker Steps", "steps", "walk"),
|
FitbitSensorEntityDescription(
|
||||||
"body/bmi": ("BMI", "BMI", "human"),
|
key="activities/floors",
|
||||||
"body/fat": ("Body Fat", PERCENTAGE, "human"),
|
name="Floors",
|
||||||
"body/weight": ("Weight", "", "human"),
|
unit_type="floors",
|
||||||
"devices/battery": ("Battery", None, "battery"),
|
icon="mdi:walk",
|
||||||
"sleep/awakeningsCount": ("Awakenings Count", "times awaken", "sleep"),
|
|
||||||
"sleep/efficiency": ("Sleep Efficiency", PERCENTAGE, "sleep"),
|
|
||||||
"sleep/minutesAfterWakeup": ("Minutes After Wakeup", TIME_MINUTES, "sleep"),
|
|
||||||
"sleep/minutesAsleep": ("Sleep Minutes Asleep", TIME_MINUTES, "sleep"),
|
|
||||||
"sleep/minutesAwake": ("Sleep Minutes Awake", TIME_MINUTES, "sleep"),
|
|
||||||
"sleep/minutesToFallAsleep": (
|
|
||||||
"Sleep Minutes to Fall Asleep",
|
|
||||||
TIME_MINUTES,
|
|
||||||
"sleep",
|
|
||||||
),
|
),
|
||||||
"sleep/startTime": ("Sleep Start Time", None, "clock"),
|
FitbitSensorEntityDescription(
|
||||||
"sleep/timeInBed": ("Sleep Time in Bed", TIME_MINUTES, "hotel"),
|
key="activities/heart",
|
||||||
}
|
name="Resting Heart Rate",
|
||||||
|
unit_type="bpm",
|
||||||
|
icon="mdi:heart-pulse",
|
||||||
|
),
|
||||||
|
FitbitSensorEntityDescription(
|
||||||
|
key="activities/minutesFairlyActive",
|
||||||
|
name="Minutes Fairly Active",
|
||||||
|
unit_type=TIME_MINUTES,
|
||||||
|
icon="mdi:walk",
|
||||||
|
),
|
||||||
|
FitbitSensorEntityDescription(
|
||||||
|
key="activities/minutesLightlyActive",
|
||||||
|
name="Minutes Lightly Active",
|
||||||
|
unit_type=TIME_MINUTES,
|
||||||
|
icon="mdi:walk",
|
||||||
|
),
|
||||||
|
FitbitSensorEntityDescription(
|
||||||
|
key="activities/minutesSedentary",
|
||||||
|
name="Minutes Sedentary",
|
||||||
|
unit_type=TIME_MINUTES,
|
||||||
|
icon="mdi:seat-recline-normal",
|
||||||
|
),
|
||||||
|
FitbitSensorEntityDescription(
|
||||||
|
key="activities/minutesVeryActive",
|
||||||
|
name="Minutes Very Active",
|
||||||
|
unit_type=TIME_MINUTES,
|
||||||
|
icon="mdi:run",
|
||||||
|
),
|
||||||
|
FitbitSensorEntityDescription(
|
||||||
|
key="activities/steps",
|
||||||
|
name="Steps",
|
||||||
|
unit_type="steps",
|
||||||
|
icon="mdi:walk",
|
||||||
|
),
|
||||||
|
FitbitSensorEntityDescription(
|
||||||
|
key="activities/tracker/activityCalories",
|
||||||
|
name="Tracker Activity Calories",
|
||||||
|
unit_type="cal",
|
||||||
|
icon="mdi:fire",
|
||||||
|
),
|
||||||
|
FitbitSensorEntityDescription(
|
||||||
|
key="activities/tracker/calories",
|
||||||
|
name="Tracker Calories",
|
||||||
|
unit_type="cal",
|
||||||
|
icon="mdi:fire",
|
||||||
|
),
|
||||||
|
FitbitSensorEntityDescription(
|
||||||
|
key="activities/tracker/distance",
|
||||||
|
name="Tracker Distance",
|
||||||
|
unit_type="",
|
||||||
|
icon="mdi:map-marker",
|
||||||
|
),
|
||||||
|
FitbitSensorEntityDescription(
|
||||||
|
key="activities/tracker/elevation",
|
||||||
|
name="Tracker Elevation",
|
||||||
|
unit_type="",
|
||||||
|
icon="mdi:walk",
|
||||||
|
),
|
||||||
|
FitbitSensorEntityDescription(
|
||||||
|
key="activities/tracker/floors",
|
||||||
|
name="Tracker Floors",
|
||||||
|
unit_type="floors",
|
||||||
|
icon="mdi:walk",
|
||||||
|
),
|
||||||
|
FitbitSensorEntityDescription(
|
||||||
|
key="activities/tracker/minutesFairlyActive",
|
||||||
|
name="Tracker Minutes Fairly Active",
|
||||||
|
unit_type=TIME_MINUTES,
|
||||||
|
icon="mdi:walk",
|
||||||
|
),
|
||||||
|
FitbitSensorEntityDescription(
|
||||||
|
key="activities/tracker/minutesLightlyActive",
|
||||||
|
name="Tracker Minutes Lightly Active",
|
||||||
|
unit_type=TIME_MINUTES,
|
||||||
|
icon="mdi:walk",
|
||||||
|
),
|
||||||
|
FitbitSensorEntityDescription(
|
||||||
|
key="activities/tracker/minutesSedentary",
|
||||||
|
name="Tracker Minutes Sedentary",
|
||||||
|
unit_type=TIME_MINUTES,
|
||||||
|
icon="mdi:seat-recline-normal",
|
||||||
|
),
|
||||||
|
FitbitSensorEntityDescription(
|
||||||
|
key="activities/tracker/minutesVeryActive",
|
||||||
|
name="Tracker Minutes Very Active",
|
||||||
|
unit_type=TIME_MINUTES,
|
||||||
|
icon="mdi:run",
|
||||||
|
),
|
||||||
|
FitbitSensorEntityDescription(
|
||||||
|
key="activities/tracker/steps",
|
||||||
|
name="Tracker Steps",
|
||||||
|
unit_type="steps",
|
||||||
|
icon="mdi:walk",
|
||||||
|
),
|
||||||
|
FitbitSensorEntityDescription(
|
||||||
|
key="body/bmi",
|
||||||
|
name="BMI",
|
||||||
|
unit_type="BMI",
|
||||||
|
icon="mdi:human",
|
||||||
|
),
|
||||||
|
FitbitSensorEntityDescription(
|
||||||
|
key="body/fat",
|
||||||
|
name="Body Fat",
|
||||||
|
unit_type=PERCENTAGE,
|
||||||
|
icon="mdi:human",
|
||||||
|
),
|
||||||
|
FitbitSensorEntityDescription(
|
||||||
|
key="body/weight",
|
||||||
|
name="Weight",
|
||||||
|
unit_type="",
|
||||||
|
icon="mdi:human",
|
||||||
|
),
|
||||||
|
FitbitSensorEntityDescription(
|
||||||
|
key="sleep/awakeningsCount",
|
||||||
|
name="Awakenings Count",
|
||||||
|
unit_type="times awaken",
|
||||||
|
icon="mdi:sleep",
|
||||||
|
),
|
||||||
|
FitbitSensorEntityDescription(
|
||||||
|
key="sleep/efficiency",
|
||||||
|
name="Sleep Efficiency",
|
||||||
|
unit_type=PERCENTAGE,
|
||||||
|
icon="mdi:sleep",
|
||||||
|
),
|
||||||
|
FitbitSensorEntityDescription(
|
||||||
|
key="sleep/minutesAfterWakeup",
|
||||||
|
name="Minutes After Wakeup",
|
||||||
|
unit_type=TIME_MINUTES,
|
||||||
|
icon="mdi:sleep",
|
||||||
|
),
|
||||||
|
FitbitSensorEntityDescription(
|
||||||
|
key="sleep/minutesAsleep",
|
||||||
|
name="Sleep Minutes Asleep",
|
||||||
|
unit_type=TIME_MINUTES,
|
||||||
|
icon="mdi:sleep",
|
||||||
|
),
|
||||||
|
FitbitSensorEntityDescription(
|
||||||
|
key="sleep/minutesAwake",
|
||||||
|
name="Sleep Minutes Awake",
|
||||||
|
unit_type=TIME_MINUTES,
|
||||||
|
icon="mdi:sleep",
|
||||||
|
),
|
||||||
|
FitbitSensorEntityDescription(
|
||||||
|
key="sleep/minutesToFallAsleep",
|
||||||
|
name="Sleep Minutes to Fall Asleep",
|
||||||
|
unit_type=TIME_MINUTES,
|
||||||
|
icon="mdi:sleep",
|
||||||
|
),
|
||||||
|
FitbitSensorEntityDescription(
|
||||||
|
key="sleep/startTime",
|
||||||
|
name="Sleep Start Time",
|
||||||
|
unit_type=None,
|
||||||
|
icon="mdi:clock",
|
||||||
|
),
|
||||||
|
FitbitSensorEntityDescription(
|
||||||
|
key="sleep/timeInBed",
|
||||||
|
name="Sleep Time in Bed",
|
||||||
|
unit_type=TIME_MINUTES,
|
||||||
|
icon="mdi:hotel",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
FITBIT_RESOURCE_BATTERY = FitbitSensorEntityDescription(
|
||||||
|
key="devices/battery",
|
||||||
|
name="Battery",
|
||||||
|
unit_type=None,
|
||||||
|
icon="mdi:battery",
|
||||||
|
)
|
||||||
|
|
||||||
|
FITBIT_RESOURCES_KEYS: Final[list[str]] = [
|
||||||
|
desc.key for desc in (*FITBIT_RESOURCES_LIST, FITBIT_RESOURCE_BATTERY)
|
||||||
|
]
|
||||||
|
|
||||||
FITBIT_MEASUREMENTS: Final[dict[str, dict[str, str]]] = {
|
FITBIT_MEASUREMENTS: Final[dict[str, dict[str, str]]] = {
|
||||||
"en_US": {
|
"en_US": {
|
||||||
|
@ -48,7 +48,10 @@ from .const import (
|
|||||||
FITBIT_CONFIG_FILE,
|
FITBIT_CONFIG_FILE,
|
||||||
FITBIT_DEFAULT_RESOURCES,
|
FITBIT_DEFAULT_RESOURCES,
|
||||||
FITBIT_MEASUREMENTS,
|
FITBIT_MEASUREMENTS,
|
||||||
|
FITBIT_RESOURCE_BATTERY,
|
||||||
|
FITBIT_RESOURCES_KEYS,
|
||||||
FITBIT_RESOURCES_LIST,
|
FITBIT_RESOURCES_LIST,
|
||||||
|
FitbitSensorEntityDescription,
|
||||||
)
|
)
|
||||||
|
|
||||||
_LOGGER: Final = logging.getLogger(__name__)
|
_LOGGER: Final = logging.getLogger(__name__)
|
||||||
@ -61,7 +64,7 @@ PLATFORM_SCHEMA: Final = PARENT_PLATFORM_SCHEMA.extend(
|
|||||||
{
|
{
|
||||||
vol.Optional(
|
vol.Optional(
|
||||||
CONF_MONITORED_RESOURCES, default=FITBIT_DEFAULT_RESOURCES
|
CONF_MONITORED_RESOURCES, default=FITBIT_DEFAULT_RESOURCES
|
||||||
): vol.All(cv.ensure_list, [vol.In(FITBIT_RESOURCES_LIST)]),
|
): vol.All(cv.ensure_list, [vol.In(FITBIT_RESOURCES_KEYS)]),
|
||||||
vol.Optional(CONF_CLOCK_FORMAT, default=DEFAULT_CLOCK_FORMAT): vol.In(
|
vol.Optional(CONF_CLOCK_FORMAT, default=DEFAULT_CLOCK_FORMAT): vol.In(
|
||||||
["12H", "24H"]
|
["12H", "24H"]
|
||||||
),
|
),
|
||||||
@ -188,8 +191,7 @@ def setup_platform(
|
|||||||
if int(time.time()) - expires_at > 3600:
|
if int(time.time()) - expires_at > 3600:
|
||||||
authd_client.client.refresh_token()
|
authd_client.client.refresh_token()
|
||||||
|
|
||||||
unit_system = config.get(CONF_UNIT_SYSTEM)
|
if (unit_system := config[CONF_UNIT_SYSTEM]) == "default":
|
||||||
if unit_system == "default":
|
|
||||||
authd_client.system = authd_client.user_profile_get()["user"]["locale"]
|
authd_client.system = authd_client.user_profile_get()["user"]["locale"]
|
||||||
if authd_client.system != "en_GB":
|
if authd_client.system != "en_GB":
|
||||||
if hass.config.units.is_metric:
|
if hass.config.units.is_metric:
|
||||||
@ -199,35 +201,35 @@ def setup_platform(
|
|||||||
else:
|
else:
|
||||||
authd_client.system = unit_system
|
authd_client.system = unit_system
|
||||||
|
|
||||||
dev = []
|
|
||||||
registered_devs = authd_client.get_devices()
|
registered_devs = authd_client.get_devices()
|
||||||
clock_format = config.get(CONF_CLOCK_FORMAT, DEFAULT_CLOCK_FORMAT)
|
clock_format = config[CONF_CLOCK_FORMAT]
|
||||||
for resource in config.get(CONF_MONITORED_RESOURCES, FITBIT_DEFAULT_RESOURCES):
|
monitored_resources = config[CONF_MONITORED_RESOURCES]
|
||||||
|
entities = [
|
||||||
# monitor battery for all linked FitBit devices
|
FitbitSensor(
|
||||||
if resource == "devices/battery":
|
authd_client,
|
||||||
for dev_extra in registered_devs:
|
config_path,
|
||||||
dev.append(
|
description,
|
||||||
FitbitSensor(
|
hass.config.units.is_metric,
|
||||||
authd_client,
|
clock_format,
|
||||||
config_path,
|
)
|
||||||
resource,
|
for description in FITBIT_RESOURCES_LIST
|
||||||
hass.config.units.is_metric,
|
if description.key in monitored_resources
|
||||||
clock_format,
|
]
|
||||||
dev_extra,
|
if "devices/battery" in monitored_resources:
|
||||||
)
|
entities.extend(
|
||||||
)
|
[
|
||||||
else:
|
|
||||||
dev.append(
|
|
||||||
FitbitSensor(
|
FitbitSensor(
|
||||||
authd_client,
|
authd_client,
|
||||||
config_path,
|
config_path,
|
||||||
resource,
|
FITBIT_RESOURCE_BATTERY,
|
||||||
hass.config.units.is_metric,
|
hass.config.units.is_metric,
|
||||||
clock_format,
|
clock_format,
|
||||||
|
dev_extra,
|
||||||
)
|
)
|
||||||
)
|
for dev_extra in registered_devs
|
||||||
add_entities(dev, True)
|
]
|
||||||
|
)
|
||||||
|
add_entities(entities, True)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
oauth = FitbitOauth2Client(
|
oauth = FitbitOauth2Client(
|
||||||
@ -335,28 +337,28 @@ class FitbitAuthCallbackView(HomeAssistantView):
|
|||||||
class FitbitSensor(SensorEntity):
|
class FitbitSensor(SensorEntity):
|
||||||
"""Implementation of a Fitbit sensor."""
|
"""Implementation of a Fitbit sensor."""
|
||||||
|
|
||||||
|
entity_description: FitbitSensorEntityDescription
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
client: Fitbit,
|
client: Fitbit,
|
||||||
config_path: str,
|
config_path: str,
|
||||||
resource_type: str,
|
description: FitbitSensorEntityDescription,
|
||||||
is_metric: bool,
|
is_metric: bool,
|
||||||
clock_format: str,
|
clock_format: str,
|
||||||
extra: dict[str, str] | None = None,
|
extra: dict[str, str] | None = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Initialize the Fitbit sensor."""
|
"""Initialize the Fitbit sensor."""
|
||||||
|
self.entity_description = description
|
||||||
self.client = client
|
self.client = client
|
||||||
self.config_path = config_path
|
self.config_path = config_path
|
||||||
self.resource_type = resource_type
|
|
||||||
self.is_metric = is_metric
|
self.is_metric = is_metric
|
||||||
self.clock_format = clock_format
|
self.clock_format = clock_format
|
||||||
self.extra = extra
|
self.extra = extra
|
||||||
self._name = FITBIT_RESOURCES_LIST[self.resource_type][0]
|
|
||||||
if self.extra is not None:
|
if self.extra is not None:
|
||||||
self._name = f"{self.extra.get('deviceVersion')} Battery"
|
self._attr_name = f"{self.extra.get('deviceVersion')} Battery"
|
||||||
unit_type = FITBIT_RESOURCES_LIST[self.resource_type][1]
|
if (unit_type := description.unit_type) == "":
|
||||||
if unit_type == "":
|
split_resource = description.key.rsplit("/", maxsplit=1)[-1]
|
||||||
split_resource = self.resource_type.split("/")
|
|
||||||
try:
|
try:
|
||||||
measurement_system = FITBIT_MEASUREMENTS[self.client.system]
|
measurement_system = FITBIT_MEASUREMENTS[self.client.system]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
@ -364,43 +366,24 @@ class FitbitSensor(SensorEntity):
|
|||||||
measurement_system = FITBIT_MEASUREMENTS["metric"]
|
measurement_system = FITBIT_MEASUREMENTS["metric"]
|
||||||
else:
|
else:
|
||||||
measurement_system = FITBIT_MEASUREMENTS["en_US"]
|
measurement_system = FITBIT_MEASUREMENTS["en_US"]
|
||||||
unit_type = measurement_system[split_resource[-1]]
|
unit_type = measurement_system[split_resource]
|
||||||
self._unit_of_measurement = unit_type
|
self._attr_native_unit_of_measurement = unit_type
|
||||||
self._state: str | None = None
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self) -> str:
|
def icon(self) -> str | None:
|
||||||
"""Return the name of the sensor."""
|
|
||||||
return self._name
|
|
||||||
|
|
||||||
@property
|
|
||||||
def native_value(self) -> str | None:
|
|
||||||
"""Return the state of the sensor."""
|
|
||||||
return self._state
|
|
||||||
|
|
||||||
@property
|
|
||||||
def native_unit_of_measurement(self) -> str | None:
|
|
||||||
"""Return the unit of measurement of this entity, if any."""
|
|
||||||
return self._unit_of_measurement
|
|
||||||
|
|
||||||
@property
|
|
||||||
def icon(self) -> str:
|
|
||||||
"""Icon to use in the frontend, if any."""
|
"""Icon to use in the frontend, if any."""
|
||||||
if self.resource_type == "devices/battery" and self.extra is not None:
|
if self.entity_description.key == "devices/battery" and self.extra is not None:
|
||||||
extra_battery = self.extra.get("battery")
|
extra_battery = self.extra.get("battery")
|
||||||
if extra_battery is not None:
|
if extra_battery is not None:
|
||||||
battery_level = BATTERY_LEVELS.get(extra_battery)
|
battery_level = BATTERY_LEVELS.get(extra_battery)
|
||||||
if battery_level is not None:
|
if battery_level is not None:
|
||||||
return icon_for_battery_level(battery_level=battery_level)
|
return icon_for_battery_level(battery_level=battery_level)
|
||||||
fitbit_ressource = FITBIT_RESOURCES_LIST[self.resource_type]
|
return self.entity_description.icon
|
||||||
return f"mdi:{fitbit_ressource[2]}"
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def extra_state_attributes(self) -> dict[str, str | None]:
|
def extra_state_attributes(self) -> dict[str, str | None]:
|
||||||
"""Return the state attributes."""
|
"""Return the state attributes."""
|
||||||
attrs: dict[str, str | None] = {}
|
attrs: dict[str, str | None] = {ATTR_ATTRIBUTION: ATTRIBUTION}
|
||||||
|
|
||||||
attrs[ATTR_ATTRIBUTION] = ATTRIBUTION
|
|
||||||
|
|
||||||
if self.extra is not None:
|
if self.extra is not None:
|
||||||
attrs["model"] = self.extra.get("deviceVersion")
|
attrs["model"] = self.extra.get("deviceVersion")
|
||||||
@ -411,31 +394,32 @@ class FitbitSensor(SensorEntity):
|
|||||||
|
|
||||||
def update(self) -> None:
|
def 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."""
|
||||||
if self.resource_type == "devices/battery" and self.extra is not None:
|
resource_type = self.entity_description.key
|
||||||
|
if resource_type == "devices/battery" and self.extra is not None:
|
||||||
registered_devs: list[dict[str, Any]] = self.client.get_devices()
|
registered_devs: list[dict[str, Any]] = self.client.get_devices()
|
||||||
device_id = self.extra.get("id")
|
device_id = self.extra.get("id")
|
||||||
self.extra = list(
|
self.extra = list(
|
||||||
filter(lambda device: device.get("id") == device_id, registered_devs)
|
filter(lambda device: device.get("id") == device_id, registered_devs)
|
||||||
)[0]
|
)[0]
|
||||||
self._state = self.extra.get("battery")
|
self._attr_native_value = self.extra.get("battery")
|
||||||
|
|
||||||
else:
|
else:
|
||||||
container = self.resource_type.replace("/", "-")
|
container = resource_type.replace("/", "-")
|
||||||
response = self.client.time_series(self.resource_type, period="7d")
|
response = self.client.time_series(resource_type, period="7d")
|
||||||
raw_state = response[container][-1].get("value")
|
raw_state = response[container][-1].get("value")
|
||||||
if self.resource_type == "activities/distance":
|
if resource_type == "activities/distance":
|
||||||
self._state = format(float(raw_state), ".2f")
|
self._attr_native_value = format(float(raw_state), ".2f")
|
||||||
elif self.resource_type == "activities/tracker/distance":
|
elif resource_type == "activities/tracker/distance":
|
||||||
self._state = format(float(raw_state), ".2f")
|
self._attr_native_value = format(float(raw_state), ".2f")
|
||||||
elif self.resource_type == "body/bmi":
|
elif resource_type == "body/bmi":
|
||||||
self._state = format(float(raw_state), ".1f")
|
self._attr_native_value = format(float(raw_state), ".1f")
|
||||||
elif self.resource_type == "body/fat":
|
elif resource_type == "body/fat":
|
||||||
self._state = format(float(raw_state), ".1f")
|
self._attr_native_value = format(float(raw_state), ".1f")
|
||||||
elif self.resource_type == "body/weight":
|
elif resource_type == "body/weight":
|
||||||
self._state = format(float(raw_state), ".1f")
|
self._attr_native_value = format(float(raw_state), ".1f")
|
||||||
elif self.resource_type == "sleep/startTime":
|
elif resource_type == "sleep/startTime":
|
||||||
if raw_state == "":
|
if raw_state == "":
|
||||||
self._state = "-"
|
self._attr_native_value = "-"
|
||||||
elif self.clock_format == "12H":
|
elif self.clock_format == "12H":
|
||||||
hours, minutes = raw_state.split(":")
|
hours, minutes = raw_state.split(":")
|
||||||
hours, minutes = int(hours), int(minutes)
|
hours, minutes = int(hours), int(minutes)
|
||||||
@ -445,20 +429,22 @@ class FitbitSensor(SensorEntity):
|
|||||||
hours -= 12
|
hours -= 12
|
||||||
elif hours == 0:
|
elif hours == 0:
|
||||||
hours = 12
|
hours = 12
|
||||||
self._state = f"{hours}:{minutes:02d} {setting}"
|
self._attr_native_value = f"{hours}:{minutes:02d} {setting}"
|
||||||
else:
|
else:
|
||||||
self._state = raw_state
|
self._attr_native_value = raw_state
|
||||||
else:
|
else:
|
||||||
if self.is_metric:
|
if self.is_metric:
|
||||||
self._state = raw_state
|
self._attr_native_value = raw_state
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
self._state = f"{int(raw_state):,}"
|
self._attr_native_value = f"{int(raw_state):,}"
|
||||||
except TypeError:
|
except TypeError:
|
||||||
self._state = raw_state
|
self._attr_native_value = raw_state
|
||||||
|
|
||||||
if self.resource_type == "activities/heart":
|
if resource_type == "activities/heart":
|
||||||
self._state = response[container][-1].get("value").get("restingHeartRate")
|
self._attr_native_value = (
|
||||||
|
response[container][-1].get("value").get("restingHeartRate")
|
||||||
|
)
|
||||||
|
|
||||||
token = self.client.client.session.token
|
token = self.client.client.session.token
|
||||||
config_contents = {
|
config_contents = {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user