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