Modernize Fitbit entity names (#130828)

* Modernize fitbit entity names

* Use placeholder with tracker device name

* Make names sentence case

* Apply name simplifications from PR feedback

* Remove translations that are duplicate of device class

* Update homeassistant/components/fitbit/sensor.py

Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>

* Add a test for tracker distance and update snapshots

---------

Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
This commit is contained in:
Allen Porter 2024-11-18 22:47:15 -08:00 committed by GitHub
parent c7f0745f48
commit 1941850685
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 493 additions and 333 deletions

View File

@ -24,7 +24,7 @@ from homeassistant.const import (
UnitOfVolume, UnitOfVolume,
) )
from homeassistant.core import HomeAssistant, callback from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.device_registry import DeviceInfo from homeassistant.helpers.device_registry import DeviceEntryType, DeviceInfo
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.icon import icon_for_battery_level from homeassistant.helpers.icon import icon_for_battery_level
from homeassistant.helpers.update_coordinator import CoordinatorEntity from homeassistant.helpers.update_coordinator import CoordinatorEntity
@ -41,6 +41,8 @@ _CONFIGURING: dict[str, str] = {}
SCAN_INTERVAL: Final = datetime.timedelta(minutes=30) SCAN_INTERVAL: Final = datetime.timedelta(minutes=30)
FITBIT_TRACKER_SUBSTRING = "/tracker/"
def _default_value_fn(result: dict[str, Any]) -> str: def _default_value_fn(result: dict[str, Any]) -> str:
"""Parse a Fitbit timeseries API responses.""" """Parse a Fitbit timeseries API responses."""
@ -122,11 +124,34 @@ class FitbitSensorEntityDescription(SensorEntityDescription):
unit_fn: Callable[[FitbitUnitSystem], str | None] = lambda x: None unit_fn: Callable[[FitbitUnitSystem], str | None] = lambda x: None
scope: FitbitScope | None = None scope: FitbitScope | None = None
@property
def is_tracker(self) -> bool:
"""Return if the entity is a tracker."""
return FITBIT_TRACKER_SUBSTRING in self.key
def _build_device_info(
config_entry: ConfigEntry, entity_description: FitbitSensorEntityDescription
) -> DeviceInfo:
"""Build device info for sensor entities info across devices."""
unique_id = cast(str, config_entry.unique_id)
if entity_description.is_tracker:
return DeviceInfo(
entry_type=DeviceEntryType.SERVICE,
identifiers={(DOMAIN, f"{unique_id}_tracker")},
translation_key="tracker",
translation_placeholders={"display_name": config_entry.title},
)
return DeviceInfo(
entry_type=DeviceEntryType.SERVICE,
identifiers={(DOMAIN, unique_id)},
)
FITBIT_RESOURCES_LIST: Final[tuple[FitbitSensorEntityDescription, ...]] = ( FITBIT_RESOURCES_LIST: Final[tuple[FitbitSensorEntityDescription, ...]] = (
FitbitSensorEntityDescription( FitbitSensorEntityDescription(
key="activities/activityCalories", key="activities/activityCalories",
name="Activity Calories", translation_key="activity_calories",
native_unit_of_measurement="cal", native_unit_of_measurement="cal",
icon="mdi:fire", icon="mdi:fire",
scope=FitbitScope.ACTIVITY, scope=FitbitScope.ACTIVITY,
@ -135,7 +160,7 @@ FITBIT_RESOURCES_LIST: Final[tuple[FitbitSensorEntityDescription, ...]] = (
), ),
FitbitSensorEntityDescription( FitbitSensorEntityDescription(
key="activities/calories", key="activities/calories",
name="Calories", translation_key="calories",
native_unit_of_measurement="cal", native_unit_of_measurement="cal",
icon="mdi:fire", icon="mdi:fire",
scope=FitbitScope.ACTIVITY, scope=FitbitScope.ACTIVITY,
@ -143,7 +168,7 @@ FITBIT_RESOURCES_LIST: Final[tuple[FitbitSensorEntityDescription, ...]] = (
), ),
FitbitSensorEntityDescription( FitbitSensorEntityDescription(
key="activities/caloriesBMR", key="activities/caloriesBMR",
name="Calories BMR", translation_key="calories_bmr",
native_unit_of_measurement="cal", native_unit_of_measurement="cal",
icon="mdi:fire", icon="mdi:fire",
scope=FitbitScope.ACTIVITY, scope=FitbitScope.ACTIVITY,
@ -153,7 +178,6 @@ FITBIT_RESOURCES_LIST: Final[tuple[FitbitSensorEntityDescription, ...]] = (
), ),
FitbitSensorEntityDescription( FitbitSensorEntityDescription(
key="activities/distance", key="activities/distance",
name="Distance",
icon="mdi:map-marker", icon="mdi:map-marker",
device_class=SensorDeviceClass.DISTANCE, device_class=SensorDeviceClass.DISTANCE,
value_fn=_distance_value_fn, value_fn=_distance_value_fn,
@ -163,7 +187,7 @@ FITBIT_RESOURCES_LIST: Final[tuple[FitbitSensorEntityDescription, ...]] = (
), ),
FitbitSensorEntityDescription( FitbitSensorEntityDescription(
key="activities/elevation", key="activities/elevation",
name="Elevation", translation_key="elevation",
icon="mdi:walk", icon="mdi:walk",
device_class=SensorDeviceClass.DISTANCE, device_class=SensorDeviceClass.DISTANCE,
unit_fn=_elevation_unit, unit_fn=_elevation_unit,
@ -173,7 +197,7 @@ FITBIT_RESOURCES_LIST: Final[tuple[FitbitSensorEntityDescription, ...]] = (
), ),
FitbitSensorEntityDescription( FitbitSensorEntityDescription(
key="activities/floors", key="activities/floors",
name="Floors", translation_key="floors",
native_unit_of_measurement="floors", native_unit_of_measurement="floors",
icon="mdi:walk", icon="mdi:walk",
scope=FitbitScope.ACTIVITY, scope=FitbitScope.ACTIVITY,
@ -182,7 +206,7 @@ FITBIT_RESOURCES_LIST: Final[tuple[FitbitSensorEntityDescription, ...]] = (
), ),
FitbitSensorEntityDescription( FitbitSensorEntityDescription(
key="activities/heart", key="activities/heart",
name="Resting Heart Rate", translation_key="resting_heart_rate",
native_unit_of_measurement="bpm", native_unit_of_measurement="bpm",
icon="mdi:heart-pulse", icon="mdi:heart-pulse",
value_fn=_int_value_or_none("restingHeartRate"), value_fn=_int_value_or_none("restingHeartRate"),
@ -191,7 +215,7 @@ FITBIT_RESOURCES_LIST: Final[tuple[FitbitSensorEntityDescription, ...]] = (
), ),
FitbitSensorEntityDescription( FitbitSensorEntityDescription(
key="activities/minutesFairlyActive", key="activities/minutesFairlyActive",
name="Minutes Fairly Active", translation_key="minutes_fairly_active",
native_unit_of_measurement=UnitOfTime.MINUTES, native_unit_of_measurement=UnitOfTime.MINUTES,
icon="mdi:walk", icon="mdi:walk",
device_class=SensorDeviceClass.DURATION, device_class=SensorDeviceClass.DURATION,
@ -201,7 +225,7 @@ FITBIT_RESOURCES_LIST: Final[tuple[FitbitSensorEntityDescription, ...]] = (
), ),
FitbitSensorEntityDescription( FitbitSensorEntityDescription(
key="activities/minutesLightlyActive", key="activities/minutesLightlyActive",
name="Minutes Lightly Active", translation_key="minutes_lightly_active",
native_unit_of_measurement=UnitOfTime.MINUTES, native_unit_of_measurement=UnitOfTime.MINUTES,
icon="mdi:walk", icon="mdi:walk",
device_class=SensorDeviceClass.DURATION, device_class=SensorDeviceClass.DURATION,
@ -211,7 +235,7 @@ FITBIT_RESOURCES_LIST: Final[tuple[FitbitSensorEntityDescription, ...]] = (
), ),
FitbitSensorEntityDescription( FitbitSensorEntityDescription(
key="activities/minutesSedentary", key="activities/minutesSedentary",
name="Minutes Sedentary", translation_key="minutes_sedentary",
native_unit_of_measurement=UnitOfTime.MINUTES, native_unit_of_measurement=UnitOfTime.MINUTES,
icon="mdi:seat-recline-normal", icon="mdi:seat-recline-normal",
device_class=SensorDeviceClass.DURATION, device_class=SensorDeviceClass.DURATION,
@ -221,7 +245,7 @@ FITBIT_RESOURCES_LIST: Final[tuple[FitbitSensorEntityDescription, ...]] = (
), ),
FitbitSensorEntityDescription( FitbitSensorEntityDescription(
key="activities/minutesVeryActive", key="activities/minutesVeryActive",
name="Minutes Very Active", translation_key="minutes_very_active",
native_unit_of_measurement=UnitOfTime.MINUTES, native_unit_of_measurement=UnitOfTime.MINUTES,
icon="mdi:run", icon="mdi:run",
device_class=SensorDeviceClass.DURATION, device_class=SensorDeviceClass.DURATION,
@ -231,7 +255,7 @@ FITBIT_RESOURCES_LIST: Final[tuple[FitbitSensorEntityDescription, ...]] = (
), ),
FitbitSensorEntityDescription( FitbitSensorEntityDescription(
key="activities/steps", key="activities/steps",
name="Steps", translation_key="steps",
native_unit_of_measurement="steps", native_unit_of_measurement="steps",
icon="mdi:walk", icon="mdi:walk",
scope=FitbitScope.ACTIVITY, scope=FitbitScope.ACTIVITY,
@ -239,7 +263,7 @@ FITBIT_RESOURCES_LIST: Final[tuple[FitbitSensorEntityDescription, ...]] = (
), ),
FitbitSensorEntityDescription( FitbitSensorEntityDescription(
key="activities/tracker/activityCalories", key="activities/tracker/activityCalories",
name="Tracker Activity Calories", translation_key="activity_calories",
native_unit_of_measurement="cal", native_unit_of_measurement="cal",
icon="mdi:fire", icon="mdi:fire",
scope=FitbitScope.ACTIVITY, scope=FitbitScope.ACTIVITY,
@ -249,7 +273,7 @@ FITBIT_RESOURCES_LIST: Final[tuple[FitbitSensorEntityDescription, ...]] = (
), ),
FitbitSensorEntityDescription( FitbitSensorEntityDescription(
key="activities/tracker/calories", key="activities/tracker/calories",
name="Tracker Calories", translation_key="calories",
native_unit_of_measurement="cal", native_unit_of_measurement="cal",
icon="mdi:fire", icon="mdi:fire",
scope=FitbitScope.ACTIVITY, scope=FitbitScope.ACTIVITY,
@ -259,7 +283,6 @@ FITBIT_RESOURCES_LIST: Final[tuple[FitbitSensorEntityDescription, ...]] = (
), ),
FitbitSensorEntityDescription( FitbitSensorEntityDescription(
key="activities/tracker/distance", key="activities/tracker/distance",
name="Tracker Distance",
icon="mdi:map-marker", icon="mdi:map-marker",
device_class=SensorDeviceClass.DISTANCE, device_class=SensorDeviceClass.DISTANCE,
value_fn=_distance_value_fn, value_fn=_distance_value_fn,
@ -271,7 +294,7 @@ FITBIT_RESOURCES_LIST: Final[tuple[FitbitSensorEntityDescription, ...]] = (
), ),
FitbitSensorEntityDescription( FitbitSensorEntityDescription(
key="activities/tracker/elevation", key="activities/tracker/elevation",
name="Tracker Elevation", translation_key="elevation",
icon="mdi:walk", icon="mdi:walk",
device_class=SensorDeviceClass.DISTANCE, device_class=SensorDeviceClass.DISTANCE,
unit_fn=_elevation_unit, unit_fn=_elevation_unit,
@ -282,7 +305,7 @@ FITBIT_RESOURCES_LIST: Final[tuple[FitbitSensorEntityDescription, ...]] = (
), ),
FitbitSensorEntityDescription( FitbitSensorEntityDescription(
key="activities/tracker/floors", key="activities/tracker/floors",
name="Tracker Floors", translation_key="floors",
native_unit_of_measurement="floors", native_unit_of_measurement="floors",
icon="mdi:walk", icon="mdi:walk",
scope=FitbitScope.ACTIVITY, scope=FitbitScope.ACTIVITY,
@ -292,7 +315,7 @@ FITBIT_RESOURCES_LIST: Final[tuple[FitbitSensorEntityDescription, ...]] = (
), ),
FitbitSensorEntityDescription( FitbitSensorEntityDescription(
key="activities/tracker/minutesFairlyActive", key="activities/tracker/minutesFairlyActive",
name="Tracker Minutes Fairly Active", translation_key="minutes_fairly_active",
native_unit_of_measurement=UnitOfTime.MINUTES, native_unit_of_measurement=UnitOfTime.MINUTES,
icon="mdi:walk", icon="mdi:walk",
device_class=SensorDeviceClass.DURATION, device_class=SensorDeviceClass.DURATION,
@ -303,7 +326,7 @@ FITBIT_RESOURCES_LIST: Final[tuple[FitbitSensorEntityDescription, ...]] = (
), ),
FitbitSensorEntityDescription( FitbitSensorEntityDescription(
key="activities/tracker/minutesLightlyActive", key="activities/tracker/minutesLightlyActive",
name="Tracker Minutes Lightly Active", translation_key="minutes_lightly_active",
native_unit_of_measurement=UnitOfTime.MINUTES, native_unit_of_measurement=UnitOfTime.MINUTES,
icon="mdi:walk", icon="mdi:walk",
device_class=SensorDeviceClass.DURATION, device_class=SensorDeviceClass.DURATION,
@ -314,7 +337,7 @@ FITBIT_RESOURCES_LIST: Final[tuple[FitbitSensorEntityDescription, ...]] = (
), ),
FitbitSensorEntityDescription( FitbitSensorEntityDescription(
key="activities/tracker/minutesSedentary", key="activities/tracker/minutesSedentary",
name="Tracker Minutes Sedentary", translation_key="minutes_sedentary",
native_unit_of_measurement=UnitOfTime.MINUTES, native_unit_of_measurement=UnitOfTime.MINUTES,
icon="mdi:seat-recline-normal", icon="mdi:seat-recline-normal",
device_class=SensorDeviceClass.DURATION, device_class=SensorDeviceClass.DURATION,
@ -325,7 +348,7 @@ FITBIT_RESOURCES_LIST: Final[tuple[FitbitSensorEntityDescription, ...]] = (
), ),
FitbitSensorEntityDescription( FitbitSensorEntityDescription(
key="activities/tracker/minutesVeryActive", key="activities/tracker/minutesVeryActive",
name="Tracker Minutes Very Active", translation_key="minutes_very_active",
native_unit_of_measurement=UnitOfTime.MINUTES, native_unit_of_measurement=UnitOfTime.MINUTES,
icon="mdi:run", icon="mdi:run",
device_class=SensorDeviceClass.DURATION, device_class=SensorDeviceClass.DURATION,
@ -336,7 +359,7 @@ FITBIT_RESOURCES_LIST: Final[tuple[FitbitSensorEntityDescription, ...]] = (
), ),
FitbitSensorEntityDescription( FitbitSensorEntityDescription(
key="activities/tracker/steps", key="activities/tracker/steps",
name="Tracker Steps", translation_key="steps",
native_unit_of_measurement="steps", native_unit_of_measurement="steps",
icon="mdi:walk", icon="mdi:walk",
scope=FitbitScope.ACTIVITY, scope=FitbitScope.ACTIVITY,
@ -346,7 +369,7 @@ FITBIT_RESOURCES_LIST: Final[tuple[FitbitSensorEntityDescription, ...]] = (
), ),
FitbitSensorEntityDescription( FitbitSensorEntityDescription(
key="body/bmi", key="body/bmi",
name="BMI", translation_key="bmi",
native_unit_of_measurement="BMI", native_unit_of_measurement="BMI",
icon="mdi:human", icon="mdi:human",
state_class=SensorStateClass.MEASUREMENT, state_class=SensorStateClass.MEASUREMENT,
@ -357,7 +380,7 @@ FITBIT_RESOURCES_LIST: Final[tuple[FitbitSensorEntityDescription, ...]] = (
), ),
FitbitSensorEntityDescription( FitbitSensorEntityDescription(
key="body/fat", key="body/fat",
name="Body Fat", translation_key="body_fat",
native_unit_of_measurement=PERCENTAGE, native_unit_of_measurement=PERCENTAGE,
icon="mdi:human", icon="mdi:human",
state_class=SensorStateClass.MEASUREMENT, state_class=SensorStateClass.MEASUREMENT,
@ -368,7 +391,6 @@ FITBIT_RESOURCES_LIST: Final[tuple[FitbitSensorEntityDescription, ...]] = (
), ),
FitbitSensorEntityDescription( FitbitSensorEntityDescription(
key="body/weight", key="body/weight",
name="Weight",
icon="mdi:human", icon="mdi:human",
state_class=SensorStateClass.MEASUREMENT, state_class=SensorStateClass.MEASUREMENT,
device_class=SensorDeviceClass.WEIGHT, device_class=SensorDeviceClass.WEIGHT,
@ -378,7 +400,7 @@ FITBIT_RESOURCES_LIST: Final[tuple[FitbitSensorEntityDescription, ...]] = (
), ),
FitbitSensorEntityDescription( FitbitSensorEntityDescription(
key="sleep/awakeningsCount", key="sleep/awakeningsCount",
name="Awakenings Count", translation_key="awakenings_count",
native_unit_of_measurement="times awaken", native_unit_of_measurement="times awaken",
icon="mdi:sleep", icon="mdi:sleep",
scope=FitbitScope.SLEEP, scope=FitbitScope.SLEEP,
@ -387,7 +409,7 @@ FITBIT_RESOURCES_LIST: Final[tuple[FitbitSensorEntityDescription, ...]] = (
), ),
FitbitSensorEntityDescription( FitbitSensorEntityDescription(
key="sleep/efficiency", key="sleep/efficiency",
name="Sleep Efficiency", translation_key="sleep_efficiency",
native_unit_of_measurement=PERCENTAGE, native_unit_of_measurement=PERCENTAGE,
icon="mdi:sleep", icon="mdi:sleep",
state_class=SensorStateClass.MEASUREMENT, state_class=SensorStateClass.MEASUREMENT,
@ -396,7 +418,7 @@ FITBIT_RESOURCES_LIST: Final[tuple[FitbitSensorEntityDescription, ...]] = (
), ),
FitbitSensorEntityDescription( FitbitSensorEntityDescription(
key="sleep/minutesAfterWakeup", key="sleep/minutesAfterWakeup",
name="Minutes After Wakeup", translation_key="minutes_after_wakeup",
native_unit_of_measurement=UnitOfTime.MINUTES, native_unit_of_measurement=UnitOfTime.MINUTES,
icon="mdi:sleep", icon="mdi:sleep",
device_class=SensorDeviceClass.DURATION, device_class=SensorDeviceClass.DURATION,
@ -406,7 +428,7 @@ FITBIT_RESOURCES_LIST: Final[tuple[FitbitSensorEntityDescription, ...]] = (
), ),
FitbitSensorEntityDescription( FitbitSensorEntityDescription(
key="sleep/minutesAsleep", key="sleep/minutesAsleep",
name="Sleep Minutes Asleep", translation_key="sleep_minutes_asleep",
native_unit_of_measurement=UnitOfTime.MINUTES, native_unit_of_measurement=UnitOfTime.MINUTES,
icon="mdi:sleep", icon="mdi:sleep",
device_class=SensorDeviceClass.DURATION, device_class=SensorDeviceClass.DURATION,
@ -416,7 +438,7 @@ FITBIT_RESOURCES_LIST: Final[tuple[FitbitSensorEntityDescription, ...]] = (
), ),
FitbitSensorEntityDescription( FitbitSensorEntityDescription(
key="sleep/minutesAwake", key="sleep/minutesAwake",
name="Sleep Minutes Awake", translation_key="sleep_minutes_awake",
native_unit_of_measurement=UnitOfTime.MINUTES, native_unit_of_measurement=UnitOfTime.MINUTES,
icon="mdi:sleep", icon="mdi:sleep",
device_class=SensorDeviceClass.DURATION, device_class=SensorDeviceClass.DURATION,
@ -426,7 +448,7 @@ FITBIT_RESOURCES_LIST: Final[tuple[FitbitSensorEntityDescription, ...]] = (
), ),
FitbitSensorEntityDescription( FitbitSensorEntityDescription(
key="sleep/minutesToFallAsleep", key="sleep/minutesToFallAsleep",
name="Sleep Minutes to Fall Asleep", translation_key="sleep_minutes_to_fall_asleep",
native_unit_of_measurement=UnitOfTime.MINUTES, native_unit_of_measurement=UnitOfTime.MINUTES,
icon="mdi:sleep", icon="mdi:sleep",
device_class=SensorDeviceClass.DURATION, device_class=SensorDeviceClass.DURATION,
@ -436,7 +458,7 @@ FITBIT_RESOURCES_LIST: Final[tuple[FitbitSensorEntityDescription, ...]] = (
), ),
FitbitSensorEntityDescription( FitbitSensorEntityDescription(
key="sleep/timeInBed", key="sleep/timeInBed",
name="Sleep Time in Bed", translation_key="sleep_time_in_bed",
native_unit_of_measurement=UnitOfTime.MINUTES, native_unit_of_measurement=UnitOfTime.MINUTES,
icon="mdi:hotel", icon="mdi:hotel",
device_class=SensorDeviceClass.DURATION, device_class=SensorDeviceClass.DURATION,
@ -446,7 +468,7 @@ FITBIT_RESOURCES_LIST: Final[tuple[FitbitSensorEntityDescription, ...]] = (
), ),
FitbitSensorEntityDescription( FitbitSensorEntityDescription(
key="foods/log/caloriesIn", key="foods/log/caloriesIn",
name="Calories In", translation_key="calories_in",
native_unit_of_measurement="cal", native_unit_of_measurement="cal",
icon="mdi:food-apple", icon="mdi:food-apple",
state_class=SensorStateClass.TOTAL_INCREASING, state_class=SensorStateClass.TOTAL_INCREASING,
@ -455,7 +477,7 @@ FITBIT_RESOURCES_LIST: Final[tuple[FitbitSensorEntityDescription, ...]] = (
), ),
FitbitSensorEntityDescription( FitbitSensorEntityDescription(
key="foods/log/water", key="foods/log/water",
name="Water", translation_key="water",
icon="mdi:cup-water", icon="mdi:cup-water",
unit_fn=_water_unit, unit_fn=_water_unit,
state_class=SensorStateClass.TOTAL_INCREASING, state_class=SensorStateClass.TOTAL_INCREASING,
@ -467,14 +489,14 @@ FITBIT_RESOURCES_LIST: Final[tuple[FitbitSensorEntityDescription, ...]] = (
# Different description depending on clock format # Different description depending on clock format
SLEEP_START_TIME = FitbitSensorEntityDescription( SLEEP_START_TIME = FitbitSensorEntityDescription(
key="sleep/startTime", key="sleep/startTime",
name="Sleep Start Time", translation_key="sleep_start_time",
icon="mdi:clock", icon="mdi:clock",
scope=FitbitScope.SLEEP, scope=FitbitScope.SLEEP,
entity_category=EntityCategory.DIAGNOSTIC, entity_category=EntityCategory.DIAGNOSTIC,
) )
SLEEP_START_TIME_12HR = FitbitSensorEntityDescription( SLEEP_START_TIME_12HR = FitbitSensorEntityDescription(
key="sleep/startTime", key="sleep/startTime",
name="Sleep Start Time", translation_key="sleep_start_time",
icon="mdi:clock", icon="mdi:clock",
value_fn=_clock_format_12h, value_fn=_clock_format_12h,
scope=FitbitScope.SLEEP, scope=FitbitScope.SLEEP,
@ -540,6 +562,7 @@ async def async_setup_entry(
description, description,
units=description.unit_fn(unit_system), units=description.unit_fn(unit_system),
enable_default_override=is_explicit_enable(description), enable_default_override=is_explicit_enable(description),
device_info=_build_device_info(entry, description),
) )
for description in resource_list for description in resource_list
if is_allowed_resource(description) if is_allowed_resource(description)
@ -574,6 +597,7 @@ class FitbitSensor(SensorEntity):
entity_description: FitbitSensorEntityDescription entity_description: FitbitSensorEntityDescription
_attr_attribution = ATTRIBUTION _attr_attribution = ATTRIBUTION
_attr_has_entity_name = True
def __init__( def __init__(
self, self,
@ -583,6 +607,7 @@ class FitbitSensor(SensorEntity):
description: FitbitSensorEntityDescription, description: FitbitSensorEntityDescription,
units: str | None, units: str | None,
enable_default_override: bool, enable_default_override: bool,
device_info: DeviceInfo,
) -> None: ) -> None:
"""Initialize the Fitbit sensor.""" """Initialize the Fitbit sensor."""
self.config_entry = config_entry self.config_entry = config_entry
@ -590,6 +615,7 @@ class FitbitSensor(SensorEntity):
self.api = api self.api = api
self._attr_unique_id = f"{user_profile_id}_{description.key}" self._attr_unique_id = f"{user_profile_id}_{description.key}"
self._attr_device_info = device_info
if units is not None: if units is not None:
self._attr_native_unit_of_measurement = units self._attr_native_unit_of_measurement = units

View File

@ -38,7 +38,82 @@
}, },
"battery_level": { "battery_level": {
"name": "Battery level" "name": "Battery level"
},
"activity_calories": {
"name": "Activity calories"
},
"calories": {
"name": "Calories"
},
"calories_bmr": {
"name": "Calories BMR"
},
"elevation": {
"name": "Elevation"
},
"floors": {
"name": "Floors"
},
"resting_heart_rate": {
"name": "Resting heart rate"
},
"minutes_fairly_active": {
"name": "Minutes fairly active"
},
"minutes_lightly_active": {
"name": "Minutes lightly active"
},
"minutes_sedentary": {
"name": "Minutes sedentary"
},
"minutes_very_active": {
"name": "Minutes very active"
},
"sleep_start_time": {
"name": "Sleep start time"
},
"steps": {
"name": "Steps"
},
"bmi": {
"name": "BMI"
},
"body_fat": {
"name": "Body fat"
},
"awakenings_count": {
"name": "Awakenings count"
},
"sleep_efficiency": {
"name": "Sleep efficiency"
},
"minutes_after_wakeup": {
"name": "Minutes after wakeup"
},
"sleep_minutes_asleep": {
"name": "Sleep minutes asleep"
},
"sleep_minutes_awake": {
"name": "Sleep minutes awake"
},
"sleep_minutes_to_fall_asleep": {
"name": "Sleep minutes to fall asleep"
},
"sleep_time_in_bed": {
"name": "Sleep time in bed"
},
"calories_in": {
"name": "Calories in"
},
"water": {
"name": "Water"
} }
} }
},
"device": {
"tracker": {
"name": "{display_name} tracker"
}
} }
} }

View File

@ -90,6 +90,7 @@ def mock_config_entry(
**imported_config_data, **imported_config_data,
}, },
unique_id=PROFILE_USER_ID, unique_id=PROFILE_USER_ID,
title=DISPLAY_NAME,
) )

View File

@ -4,7 +4,7 @@
'99', '99',
ReadOnlyDict({ ReadOnlyDict({
'attribution': 'Data provided by Fitbit.com', 'attribution': 'Data provided by Fitbit.com',
'friendly_name': 'Water', 'friendly_name': 'First L. Water',
'icon': 'mdi:cup-water', 'icon': 'mdi:cup-water',
'state_class': <SensorStateClass.TOTAL_INCREASING: 'total_increasing'>, 'state_class': <SensorStateClass.TOTAL_INCREASING: 'total_increasing'>,
'unit_of_measurement': <UnitOfVolume.MILLILITERS: 'mL'>, 'unit_of_measurement': <UnitOfVolume.MILLILITERS: 'mL'>,
@ -16,7 +16,7 @@
'1600', '1600',
ReadOnlyDict({ ReadOnlyDict({
'attribution': 'Data provided by Fitbit.com', 'attribution': 'Data provided by Fitbit.com',
'friendly_name': 'Calories In', 'friendly_name': 'First L. Calories in',
'icon': 'mdi:food-apple', 'icon': 'mdi:food-apple',
'state_class': <SensorStateClass.TOTAL_INCREASING: 'total_increasing'>, 'state_class': <SensorStateClass.TOTAL_INCREASING: 'total_increasing'>,
'unit_of_measurement': 'cal', 'unit_of_measurement': 'cal',
@ -28,7 +28,7 @@
'99', '99',
ReadOnlyDict({ ReadOnlyDict({
'attribution': 'Data provided by Fitbit.com', 'attribution': 'Data provided by Fitbit.com',
'friendly_name': 'Water', 'friendly_name': 'First L. Water',
'icon': 'mdi:cup-water', 'icon': 'mdi:cup-water',
'state_class': <SensorStateClass.TOTAL_INCREASING: 'total_increasing'>, 'state_class': <SensorStateClass.TOTAL_INCREASING: 'total_increasing'>,
'unit_of_measurement': <UnitOfVolume.FLUID_OUNCES: 'fl. oz.'>, 'unit_of_measurement': <UnitOfVolume.FLUID_OUNCES: 'fl. oz.'>,
@ -40,19 +40,19 @@
'1600', '1600',
ReadOnlyDict({ ReadOnlyDict({
'attribution': 'Data provided by Fitbit.com', 'attribution': 'Data provided by Fitbit.com',
'friendly_name': 'Calories In', 'friendly_name': 'First L. Calories in',
'icon': 'mdi:food-apple', 'icon': 'mdi:food-apple',
'state_class': <SensorStateClass.TOTAL_INCREASING: 'total_increasing'>, 'state_class': <SensorStateClass.TOTAL_INCREASING: 'total_increasing'>,
'unit_of_measurement': 'cal', 'unit_of_measurement': 'cal',
}), }),
) )
# --- # ---
# name: test_sensors[monitored_resources0-sensor.activity_calories-activities/activityCalories-135] # name: test_sensors[monitored_resources0-sensor.first_l_activity_calories-activities/activityCalories-135]
tuple( tuple(
'135', '135',
ReadOnlyDict({ ReadOnlyDict({
'attribution': 'Data provided by Fitbit.com', 'attribution': 'Data provided by Fitbit.com',
'friendly_name': 'Activity Calories', 'friendly_name': 'First L. Activity calories',
'icon': 'mdi:fire', 'icon': 'mdi:fire',
'state_class': <SensorStateClass.TOTAL_INCREASING: 'total_increasing'>, 'state_class': <SensorStateClass.TOTAL_INCREASING: 'total_increasing'>,
'unit_of_measurement': 'cal', 'unit_of_measurement': 'cal',
@ -60,254 +60,26 @@
'fitbit-api-user-id-1_activities/activityCalories', 'fitbit-api-user-id-1_activities/activityCalories',
) )
# --- # ---
# name: test_sensors[monitored_resources1-sensor.calories-activities/calories-139] # name: test_sensors[monitored_resources1-sensor.first_l_tracker_activity_calories-activities/tracker/activityCalories-135]
tuple( tuple(
'139', '135',
ReadOnlyDict({ ReadOnlyDict({
'attribution': 'Data provided by Fitbit.com', 'attribution': 'Data provided by Fitbit.com',
'friendly_name': 'Calories', 'friendly_name': 'First L. tracker Activity calories',
'icon': 'mdi:fire', 'icon': 'mdi:fire',
'state_class': <SensorStateClass.TOTAL_INCREASING: 'total_increasing'>, 'state_class': <SensorStateClass.TOTAL_INCREASING: 'total_increasing'>,
'unit_of_measurement': 'cal', 'unit_of_measurement': 'cal',
}), }),
'fitbit-api-user-id-1_activities/calories', 'fitbit-api-user-id-1_activities/tracker/activityCalories',
) )
# --- # ---
# name: test_sensors[monitored_resources10-sensor.steps-activities/steps-5600] # name: test_sensors[monitored_resources10-sensor.first_l_minutes_lightly_active-activities/minutesLightlyActive-95]
tuple(
'5600',
ReadOnlyDict({
'attribution': 'Data provided by Fitbit.com',
'friendly_name': 'Steps',
'icon': 'mdi:walk',
'state_class': <SensorStateClass.TOTAL_INCREASING: 'total_increasing'>,
'unit_of_measurement': 'steps',
}),
'fitbit-api-user-id-1_activities/steps',
)
# ---
# name: test_sensors[monitored_resources11-sensor.weight-body/weight-175]
tuple(
'175.0',
ReadOnlyDict({
'attribution': 'Data provided by Fitbit.com',
'device_class': 'weight',
'friendly_name': 'Weight',
'icon': 'mdi:human',
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
'unit_of_measurement': <UnitOfMass.KILOGRAMS: 'kg'>,
}),
'fitbit-api-user-id-1_body/weight',
)
# ---
# name: test_sensors[monitored_resources12-sensor.body_fat-body/fat-18]
tuple(
'18.0',
ReadOnlyDict({
'attribution': 'Data provided by Fitbit.com',
'friendly_name': 'Body Fat',
'icon': 'mdi:human',
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
'unit_of_measurement': '%',
}),
'fitbit-api-user-id-1_body/fat',
)
# ---
# name: test_sensors[monitored_resources13-sensor.bmi-body/bmi-23.7]
tuple(
'23.7',
ReadOnlyDict({
'attribution': 'Data provided by Fitbit.com',
'friendly_name': 'BMI',
'icon': 'mdi:human',
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
'unit_of_measurement': 'BMI',
}),
'fitbit-api-user-id-1_body/bmi',
)
# ---
# name: test_sensors[monitored_resources14-sensor.awakenings_count-sleep/awakeningsCount-7]
tuple(
'7',
ReadOnlyDict({
'attribution': 'Data provided by Fitbit.com',
'friendly_name': 'Awakenings Count',
'icon': 'mdi:sleep',
'state_class': <SensorStateClass.TOTAL_INCREASING: 'total_increasing'>,
'unit_of_measurement': 'times awaken',
}),
'fitbit-api-user-id-1_sleep/awakeningsCount',
)
# ---
# name: test_sensors[monitored_resources15-sensor.sleep_efficiency-sleep/efficiency-80]
tuple(
'80',
ReadOnlyDict({
'attribution': 'Data provided by Fitbit.com',
'friendly_name': 'Sleep Efficiency',
'icon': 'mdi:sleep',
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
'unit_of_measurement': '%',
}),
'fitbit-api-user-id-1_sleep/efficiency',
)
# ---
# name: test_sensors[monitored_resources16-sensor.minutes_after_wakeup-sleep/minutesAfterWakeup-17]
tuple(
'17',
ReadOnlyDict({
'attribution': 'Data provided by Fitbit.com',
'device_class': 'duration',
'friendly_name': 'Minutes After Wakeup',
'icon': 'mdi:sleep',
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
'unit_of_measurement': <UnitOfTime.MINUTES: 'min'>,
}),
'fitbit-api-user-id-1_sleep/minutesAfterWakeup',
)
# ---
# name: test_sensors[monitored_resources17-sensor.sleep_minutes_asleep-sleep/minutesAsleep-360]
tuple(
'360',
ReadOnlyDict({
'attribution': 'Data provided by Fitbit.com',
'device_class': 'duration',
'friendly_name': 'Sleep Minutes Asleep',
'icon': 'mdi:sleep',
'state_class': <SensorStateClass.TOTAL_INCREASING: 'total_increasing'>,
'unit_of_measurement': <UnitOfTime.MINUTES: 'min'>,
}),
'fitbit-api-user-id-1_sleep/minutesAsleep',
)
# ---
# name: test_sensors[monitored_resources18-sensor.sleep_minutes_awake-sleep/minutesAwake-35]
tuple(
'35',
ReadOnlyDict({
'attribution': 'Data provided by Fitbit.com',
'device_class': 'duration',
'friendly_name': 'Sleep Minutes Awake',
'icon': 'mdi:sleep',
'state_class': <SensorStateClass.TOTAL_INCREASING: 'total_increasing'>,
'unit_of_measurement': <UnitOfTime.MINUTES: 'min'>,
}),
'fitbit-api-user-id-1_sleep/minutesAwake',
)
# ---
# name: test_sensors[monitored_resources19-sensor.sleep_minutes_to_fall_asleep-sleep/minutesToFallAsleep-35]
tuple(
'35',
ReadOnlyDict({
'attribution': 'Data provided by Fitbit.com',
'device_class': 'duration',
'friendly_name': 'Sleep Minutes to Fall Asleep',
'icon': 'mdi:sleep',
'state_class': <SensorStateClass.TOTAL_INCREASING: 'total_increasing'>,
'unit_of_measurement': <UnitOfTime.MINUTES: 'min'>,
}),
'fitbit-api-user-id-1_sleep/minutesToFallAsleep',
)
# ---
# name: test_sensors[monitored_resources2-sensor.distance-activities/distance-12.7]
tuple(
'12.70',
ReadOnlyDict({
'attribution': 'Data provided by Fitbit.com',
'device_class': 'distance',
'friendly_name': 'Distance',
'icon': 'mdi:map-marker',
'state_class': <SensorStateClass.TOTAL_INCREASING: 'total_increasing'>,
'unit_of_measurement': <UnitOfLength.KILOMETERS: 'km'>,
}),
'fitbit-api-user-id-1_activities/distance',
)
# ---
# name: test_sensors[monitored_resources20-sensor.sleep_start_time-sleep/startTime-2020-01-27T00:17:30.000]
tuple(
'2020-01-27T00:17:30.000',
ReadOnlyDict({
'attribution': 'Data provided by Fitbit.com',
'friendly_name': 'Sleep Start Time',
'icon': 'mdi:clock',
}),
'fitbit-api-user-id-1_sleep/startTime',
)
# ---
# name: test_sensors[monitored_resources21-sensor.sleep_time_in_bed-sleep/timeInBed-462]
tuple(
'462',
ReadOnlyDict({
'attribution': 'Data provided by Fitbit.com',
'device_class': 'duration',
'friendly_name': 'Sleep Time in Bed',
'icon': 'mdi:hotel',
'state_class': <SensorStateClass.TOTAL_INCREASING: 'total_increasing'>,
'unit_of_measurement': <UnitOfTime.MINUTES: 'min'>,
}),
'fitbit-api-user-id-1_sleep/timeInBed',
)
# ---
# name: test_sensors[monitored_resources3-sensor.elevation-activities/elevation-7600.24]
tuple(
'7600.24',
ReadOnlyDict({
'attribution': 'Data provided by Fitbit.com',
'device_class': 'distance',
'friendly_name': 'Elevation',
'icon': 'mdi:walk',
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
'unit_of_measurement': <UnitOfLength.METERS: 'm'>,
}),
'fitbit-api-user-id-1_activities/elevation',
)
# ---
# name: test_sensors[monitored_resources4-sensor.floors-activities/floors-8]
tuple(
'8',
ReadOnlyDict({
'attribution': 'Data provided by Fitbit.com',
'friendly_name': 'Floors',
'icon': 'mdi:walk',
'state_class': <SensorStateClass.TOTAL_INCREASING: 'total_increasing'>,
'unit_of_measurement': 'floors',
}),
'fitbit-api-user-id-1_activities/floors',
)
# ---
# name: test_sensors[monitored_resources5-sensor.resting_heart_rate-activities/heart-api_value5]
tuple(
'76',
ReadOnlyDict({
'attribution': 'Data provided by Fitbit.com',
'friendly_name': 'Resting Heart Rate',
'icon': 'mdi:heart-pulse',
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
'unit_of_measurement': 'bpm',
}),
'fitbit-api-user-id-1_activities/heart',
)
# ---
# name: test_sensors[monitored_resources6-sensor.minutes_fairly_active-activities/minutesFairlyActive-35]
tuple(
'35',
ReadOnlyDict({
'attribution': 'Data provided by Fitbit.com',
'device_class': 'duration',
'friendly_name': 'Minutes Fairly Active',
'icon': 'mdi:walk',
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
'unit_of_measurement': <UnitOfTime.MINUTES: 'min'>,
}),
'fitbit-api-user-id-1_activities/minutesFairlyActive',
)
# ---
# name: test_sensors[monitored_resources7-sensor.minutes_lightly_active-activities/minutesLightlyActive-95]
tuple( tuple(
'95', '95',
ReadOnlyDict({ ReadOnlyDict({
'attribution': 'Data provided by Fitbit.com', 'attribution': 'Data provided by Fitbit.com',
'device_class': 'duration', 'device_class': 'duration',
'friendly_name': 'Minutes Lightly Active', 'friendly_name': 'First L. Minutes lightly active',
'icon': 'mdi:walk', 'icon': 'mdi:walk',
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>, 'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
'unit_of_measurement': <UnitOfTime.MINUTES: 'min'>, 'unit_of_measurement': <UnitOfTime.MINUTES: 'min'>,
@ -315,13 +87,13 @@
'fitbit-api-user-id-1_activities/minutesLightlyActive', 'fitbit-api-user-id-1_activities/minutesLightlyActive',
) )
# --- # ---
# name: test_sensors[monitored_resources8-sensor.minutes_sedentary-activities/minutesSedentary-18] # name: test_sensors[monitored_resources11-sensor.first_l_minutes_sedentary-activities/minutesSedentary-18]
tuple( tuple(
'18', '18',
ReadOnlyDict({ ReadOnlyDict({
'attribution': 'Data provided by Fitbit.com', 'attribution': 'Data provided by Fitbit.com',
'device_class': 'duration', 'device_class': 'duration',
'friendly_name': 'Minutes Sedentary', 'friendly_name': 'First L. Minutes sedentary',
'icon': 'mdi:seat-recline-normal', 'icon': 'mdi:seat-recline-normal',
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>, 'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
'unit_of_measurement': <UnitOfTime.MINUTES: 'min'>, 'unit_of_measurement': <UnitOfTime.MINUTES: 'min'>,
@ -329,13 +101,13 @@
'fitbit-api-user-id-1_activities/minutesSedentary', 'fitbit-api-user-id-1_activities/minutesSedentary',
) )
# --- # ---
# name: test_sensors[monitored_resources9-sensor.minutes_very_active-activities/minutesVeryActive-20] # name: test_sensors[monitored_resources12-sensor.first_l_minutes_very_active-activities/minutesVeryActive-20]
tuple( tuple(
'20', '20',
ReadOnlyDict({ ReadOnlyDict({
'attribution': 'Data provided by Fitbit.com', 'attribution': 'Data provided by Fitbit.com',
'device_class': 'duration', 'device_class': 'duration',
'friendly_name': 'Minutes Very Active', 'friendly_name': 'First L. Minutes very active',
'icon': 'mdi:run', 'icon': 'mdi:run',
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>, 'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
'unit_of_measurement': <UnitOfTime.MINUTES: 'min'>, 'unit_of_measurement': <UnitOfTime.MINUTES: 'min'>,
@ -343,3 +115,271 @@
'fitbit-api-user-id-1_activities/minutesVeryActive', 'fitbit-api-user-id-1_activities/minutesVeryActive',
) )
# --- # ---
# name: test_sensors[monitored_resources13-sensor.first_l_steps-activities/steps-5600]
tuple(
'5600',
ReadOnlyDict({
'attribution': 'Data provided by Fitbit.com',
'friendly_name': 'First L. Steps',
'icon': 'mdi:walk',
'state_class': <SensorStateClass.TOTAL_INCREASING: 'total_increasing'>,
'unit_of_measurement': 'steps',
}),
'fitbit-api-user-id-1_activities/steps',
)
# ---
# name: test_sensors[monitored_resources14-sensor.first_l_weight-body/weight-175]
tuple(
'175.0',
ReadOnlyDict({
'attribution': 'Data provided by Fitbit.com',
'device_class': 'weight',
'friendly_name': 'First L. Weight',
'icon': 'mdi:human',
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
'unit_of_measurement': <UnitOfMass.KILOGRAMS: 'kg'>,
}),
'fitbit-api-user-id-1_body/weight',
)
# ---
# name: test_sensors[monitored_resources15-sensor.first_l_body_fat-body/fat-18]
tuple(
'18.0',
ReadOnlyDict({
'attribution': 'Data provided by Fitbit.com',
'friendly_name': 'First L. Body fat',
'icon': 'mdi:human',
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
'unit_of_measurement': '%',
}),
'fitbit-api-user-id-1_body/fat',
)
# ---
# name: test_sensors[monitored_resources16-sensor.first_l_bmi-body/bmi-23.7]
tuple(
'23.7',
ReadOnlyDict({
'attribution': 'Data provided by Fitbit.com',
'friendly_name': 'First L. BMI',
'icon': 'mdi:human',
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
'unit_of_measurement': 'BMI',
}),
'fitbit-api-user-id-1_body/bmi',
)
# ---
# name: test_sensors[monitored_resources17-sensor.first_l_awakenings_count-sleep/awakeningsCount-7]
tuple(
'7',
ReadOnlyDict({
'attribution': 'Data provided by Fitbit.com',
'friendly_name': 'First L. Awakenings count',
'icon': 'mdi:sleep',
'state_class': <SensorStateClass.TOTAL_INCREASING: 'total_increasing'>,
'unit_of_measurement': 'times awaken',
}),
'fitbit-api-user-id-1_sleep/awakeningsCount',
)
# ---
# name: test_sensors[monitored_resources18-sensor.first_l_sleep_efficiency-sleep/efficiency-80]
tuple(
'80',
ReadOnlyDict({
'attribution': 'Data provided by Fitbit.com',
'friendly_name': 'First L. Sleep efficiency',
'icon': 'mdi:sleep',
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
'unit_of_measurement': '%',
}),
'fitbit-api-user-id-1_sleep/efficiency',
)
# ---
# name: test_sensors[monitored_resources19-sensor.first_l_minutes_after_wakeup-sleep/minutesAfterWakeup-17]
tuple(
'17',
ReadOnlyDict({
'attribution': 'Data provided by Fitbit.com',
'device_class': 'duration',
'friendly_name': 'First L. Minutes after wakeup',
'icon': 'mdi:sleep',
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
'unit_of_measurement': <UnitOfTime.MINUTES: 'min'>,
}),
'fitbit-api-user-id-1_sleep/minutesAfterWakeup',
)
# ---
# name: test_sensors[monitored_resources2-sensor.first_l_calories-activities/calories-139]
tuple(
'139',
ReadOnlyDict({
'attribution': 'Data provided by Fitbit.com',
'friendly_name': 'First L. Calories',
'icon': 'mdi:fire',
'state_class': <SensorStateClass.TOTAL_INCREASING: 'total_increasing'>,
'unit_of_measurement': 'cal',
}),
'fitbit-api-user-id-1_activities/calories',
)
# ---
# name: test_sensors[monitored_resources20-sensor.first_l_sleep_minutes_asleep-sleep/minutesAsleep-360]
tuple(
'360',
ReadOnlyDict({
'attribution': 'Data provided by Fitbit.com',
'device_class': 'duration',
'friendly_name': 'First L. Sleep minutes asleep',
'icon': 'mdi:sleep',
'state_class': <SensorStateClass.TOTAL_INCREASING: 'total_increasing'>,
'unit_of_measurement': <UnitOfTime.MINUTES: 'min'>,
}),
'fitbit-api-user-id-1_sleep/minutesAsleep',
)
# ---
# name: test_sensors[monitored_resources21-sensor.first_l_sleep_minutes_awake-sleep/minutesAwake-35]
tuple(
'35',
ReadOnlyDict({
'attribution': 'Data provided by Fitbit.com',
'device_class': 'duration',
'friendly_name': 'First L. Sleep minutes awake',
'icon': 'mdi:sleep',
'state_class': <SensorStateClass.TOTAL_INCREASING: 'total_increasing'>,
'unit_of_measurement': <UnitOfTime.MINUTES: 'min'>,
}),
'fitbit-api-user-id-1_sleep/minutesAwake',
)
# ---
# name: test_sensors[monitored_resources22-sensor.first_l_sleep_minutes_to_fall_asleep-sleep/minutesToFallAsleep-35]
tuple(
'35',
ReadOnlyDict({
'attribution': 'Data provided by Fitbit.com',
'device_class': 'duration',
'friendly_name': 'First L. Sleep minutes to fall asleep',
'icon': 'mdi:sleep',
'state_class': <SensorStateClass.TOTAL_INCREASING: 'total_increasing'>,
'unit_of_measurement': <UnitOfTime.MINUTES: 'min'>,
}),
'fitbit-api-user-id-1_sleep/minutesToFallAsleep',
)
# ---
# name: test_sensors[monitored_resources23-sensor.first_l_sleep_start_time-sleep/startTime-2020-01-27T00:17:30.000]
tuple(
'2020-01-27T00:17:30.000',
ReadOnlyDict({
'attribution': 'Data provided by Fitbit.com',
'friendly_name': 'First L. Sleep start time',
'icon': 'mdi:clock',
}),
'fitbit-api-user-id-1_sleep/startTime',
)
# ---
# name: test_sensors[monitored_resources24-sensor.first_l_sleep_time_in_bed-sleep/timeInBed-462]
tuple(
'462',
ReadOnlyDict({
'attribution': 'Data provided by Fitbit.com',
'device_class': 'duration',
'friendly_name': 'First L. Sleep time in bed',
'icon': 'mdi:hotel',
'state_class': <SensorStateClass.TOTAL_INCREASING: 'total_increasing'>,
'unit_of_measurement': <UnitOfTime.MINUTES: 'min'>,
}),
'fitbit-api-user-id-1_sleep/timeInBed',
)
# ---
# name: test_sensors[monitored_resources3-sensor.first_l_tracker_calories-activities/tracker/calories-139]
tuple(
'139',
ReadOnlyDict({
'attribution': 'Data provided by Fitbit.com',
'friendly_name': 'First L. tracker Calories',
'icon': 'mdi:fire',
'state_class': <SensorStateClass.TOTAL_INCREASING: 'total_increasing'>,
'unit_of_measurement': 'cal',
}),
'fitbit-api-user-id-1_activities/tracker/calories',
)
# ---
# name: test_sensors[monitored_resources4-sensor.first_l_distance-activities/distance-12.7]
tuple(
'12.70',
ReadOnlyDict({
'attribution': 'Data provided by Fitbit.com',
'device_class': 'distance',
'friendly_name': 'First L. Distance',
'icon': 'mdi:map-marker',
'state_class': <SensorStateClass.TOTAL_INCREASING: 'total_increasing'>,
'unit_of_measurement': <UnitOfLength.KILOMETERS: 'km'>,
}),
'fitbit-api-user-id-1_activities/distance',
)
# ---
# name: test_sensors[monitored_resources5-sensor.first_l_tracker_distance-activities/distance-12.7]
tuple(
'unknown',
ReadOnlyDict({
'attribution': 'Data provided by Fitbit.com',
'device_class': 'distance',
'friendly_name': 'First L. tracker Distance',
'icon': 'mdi:map-marker',
'state_class': <SensorStateClass.TOTAL_INCREASING: 'total_increasing'>,
'unit_of_measurement': <UnitOfLength.KILOMETERS: 'km'>,
}),
'fitbit-api-user-id-1_activities/tracker/distance',
)
# ---
# name: test_sensors[monitored_resources6-sensor.first_l_elevation-activities/elevation-7600.24]
tuple(
'7600.24',
ReadOnlyDict({
'attribution': 'Data provided by Fitbit.com',
'device_class': 'distance',
'friendly_name': 'First L. Elevation',
'icon': 'mdi:walk',
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
'unit_of_measurement': <UnitOfLength.METERS: 'm'>,
}),
'fitbit-api-user-id-1_activities/elevation',
)
# ---
# name: test_sensors[monitored_resources7-sensor.first_l_floors-activities/floors-8]
tuple(
'8',
ReadOnlyDict({
'attribution': 'Data provided by Fitbit.com',
'friendly_name': 'First L. Floors',
'icon': 'mdi:walk',
'state_class': <SensorStateClass.TOTAL_INCREASING: 'total_increasing'>,
'unit_of_measurement': 'floors',
}),
'fitbit-api-user-id-1_activities/floors',
)
# ---
# name: test_sensors[monitored_resources8-sensor.first_l_resting_heart_rate-activities/heart-api_value8]
tuple(
'76',
ReadOnlyDict({
'attribution': 'Data provided by Fitbit.com',
'friendly_name': 'First L. Resting heart rate',
'icon': 'mdi:heart-pulse',
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
'unit_of_measurement': 'bpm',
}),
'fitbit-api-user-id-1_activities/heart',
)
# ---
# name: test_sensors[monitored_resources9-sensor.first_l_minutes_fairly_active-activities/minutesFairlyActive-35]
tuple(
'35',
ReadOnlyDict({
'attribution': 'Data provided by Fitbit.com',
'device_class': 'duration',
'friendly_name': 'First L. Minutes fairly active',
'icon': 'mdi:walk',
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
'unit_of_measurement': <UnitOfTime.MINUTES: 'min'>,
}),
'fitbit-api-user-id-1_activities/minutesFairlyActive',
)
# ---

View File

@ -78,133 +78,151 @@ def mock_token_refresh(requests_mock: Mocker) -> None:
[ [
( (
["activities/activityCalories"], ["activities/activityCalories"],
"sensor.activity_calories", "sensor.first_l_activity_calories",
"activities/activityCalories", "activities/activityCalories",
"135", "135",
), ),
(
["activities/tracker/activityCalories"],
"sensor.first_l_tracker_activity_calories",
"activities/tracker/activityCalories",
"135",
),
( (
["activities/calories"], ["activities/calories"],
"sensor.calories", "sensor.first_l_calories",
"activities/calories", "activities/calories",
"139", "139",
), ),
(
["activities/tracker/calories"],
"sensor.first_l_tracker_calories",
"activities/tracker/calories",
"139",
),
( (
["activities/distance"], ["activities/distance"],
"sensor.distance", "sensor.first_l_distance",
"activities/distance",
"12.7",
),
(
["activities/tracker/distance"],
"sensor.first_l_tracker_distance",
"activities/distance", "activities/distance",
"12.7", "12.7",
), ),
( (
["activities/elevation"], ["activities/elevation"],
"sensor.elevation", "sensor.first_l_elevation",
"activities/elevation", "activities/elevation",
"7600.24", "7600.24",
), ),
( (
["activities/floors"], ["activities/floors"],
"sensor.floors", "sensor.first_l_floors",
"activities/floors", "activities/floors",
"8", "8",
), ),
( (
["activities/heart"], ["activities/heart"],
"sensor.resting_heart_rate", "sensor.first_l_resting_heart_rate",
"activities/heart", "activities/heart",
{"restingHeartRate": 76}, {"restingHeartRate": 76},
), ),
( (
["activities/minutesFairlyActive"], ["activities/minutesFairlyActive"],
"sensor.minutes_fairly_active", "sensor.first_l_minutes_fairly_active",
"activities/minutesFairlyActive", "activities/minutesFairlyActive",
35, 35,
), ),
( (
["activities/minutesLightlyActive"], ["activities/minutesLightlyActive"],
"sensor.minutes_lightly_active", "sensor.first_l_minutes_lightly_active",
"activities/minutesLightlyActive", "activities/minutesLightlyActive",
95, 95,
), ),
( (
["activities/minutesSedentary"], ["activities/minutesSedentary"],
"sensor.minutes_sedentary", "sensor.first_l_minutes_sedentary",
"activities/minutesSedentary", "activities/minutesSedentary",
18, 18,
), ),
( (
["activities/minutesVeryActive"], ["activities/minutesVeryActive"],
"sensor.minutes_very_active", "sensor.first_l_minutes_very_active",
"activities/minutesVeryActive", "activities/minutesVeryActive",
20, 20,
), ),
( (
["activities/steps"], ["activities/steps"],
"sensor.steps", "sensor.first_l_steps",
"activities/steps", "activities/steps",
"5600", "5600",
), ),
( (
["body/weight"], ["body/weight"],
"sensor.weight", "sensor.first_l_weight",
"body/weight", "body/weight",
"175", "175",
), ),
( (
["body/fat"], ["body/fat"],
"sensor.body_fat", "sensor.first_l_body_fat",
"body/fat", "body/fat",
"18", "18",
), ),
( (
["body/bmi"], ["body/bmi"],
"sensor.bmi", "sensor.first_l_bmi",
"body/bmi", "body/bmi",
"23.7", "23.7",
), ),
( (
["sleep/awakeningsCount"], ["sleep/awakeningsCount"],
"sensor.awakenings_count", "sensor.first_l_awakenings_count",
"sleep/awakeningsCount", "sleep/awakeningsCount",
"7", "7",
), ),
( (
["sleep/efficiency"], ["sleep/efficiency"],
"sensor.sleep_efficiency", "sensor.first_l_sleep_efficiency",
"sleep/efficiency", "sleep/efficiency",
"80", "80",
), ),
( (
["sleep/minutesAfterWakeup"], ["sleep/minutesAfterWakeup"],
"sensor.minutes_after_wakeup", "sensor.first_l_minutes_after_wakeup",
"sleep/minutesAfterWakeup", "sleep/minutesAfterWakeup",
"17", "17",
), ),
( (
["sleep/minutesAsleep"], ["sleep/minutesAsleep"],
"sensor.sleep_minutes_asleep", "sensor.first_l_sleep_minutes_asleep",
"sleep/minutesAsleep", "sleep/minutesAsleep",
"360", "360",
), ),
( (
["sleep/minutesAwake"], ["sleep/minutesAwake"],
"sensor.sleep_minutes_awake", "sensor.first_l_sleep_minutes_awake",
"sleep/minutesAwake", "sleep/minutesAwake",
"35", "35",
), ),
( (
["sleep/minutesToFallAsleep"], ["sleep/minutesToFallAsleep"],
"sensor.sleep_minutes_to_fall_asleep", "sensor.first_l_sleep_minutes_to_fall_asleep",
"sleep/minutesToFallAsleep", "sleep/minutesToFallAsleep",
"35", "35",
), ),
( (
["sleep/startTime"], ["sleep/startTime"],
"sensor.sleep_start_time", "sensor.first_l_sleep_start_time",
"sleep/startTime", "sleep/startTime",
"2020-01-27T00:17:30.000", "2020-01-27T00:17:30.000",
), ),
( (
["sleep/timeInBed"], ["sleep/timeInBed"],
"sensor.sleep_time_in_bed", "sensor.first_l_sleep_time_in_bed",
"sleep/timeInBed", "sleep/timeInBed",
"462", "462",
), ),
@ -359,7 +377,7 @@ async def test_profile_local(
entries = hass.config_entries.async_entries(DOMAIN) entries = hass.config_entries.async_entries(DOMAIN)
assert len(entries) == 1 assert len(entries) == 1
state = hass.states.get("sensor.weight") state = hass.states.get("sensor.first_l_weight")
assert state assert state
assert state.attributes.get("unit_of_measurement") == expected_unit assert state.attributes.get("unit_of_measurement") == expected_unit
@ -409,7 +427,7 @@ async def test_sleep_time_clock_format(
) )
assert await integration_setup() assert await integration_setup()
state = hass.states.get("sensor.sleep_start_time") state = hass.states.get("sensor.first_l_sleep_start_time")
assert state assert state
assert state.state == expected_state assert state.state == expected_state
@ -445,16 +463,16 @@ async def test_activity_scope_config_entry(
states = hass.states.async_all() states = hass.states.async_all()
assert {s.entity_id for s in states} == { assert {s.entity_id for s in states} == {
"sensor.activity_calories", "sensor.first_l_activity_calories",
"sensor.calories", "sensor.first_l_calories",
"sensor.distance", "sensor.first_l_distance",
"sensor.elevation", "sensor.first_l_elevation",
"sensor.floors", "sensor.first_l_floors",
"sensor.minutes_fairly_active", "sensor.first_l_minutes_fairly_active",
"sensor.minutes_lightly_active", "sensor.first_l_minutes_lightly_active",
"sensor.minutes_sedentary", "sensor.first_l_minutes_sedentary",
"sensor.minutes_very_active", "sensor.first_l_minutes_very_active",
"sensor.steps", "sensor.first_l_steps",
} }
@ -478,7 +496,7 @@ async def test_heartrate_scope_config_entry(
states = hass.states.async_all() states = hass.states.async_all()
assert {s.entity_id for s in states} == { assert {s.entity_id for s in states} == {
"sensor.resting_heart_rate", "sensor.first_l_resting_heart_rate",
} }
@ -506,11 +524,11 @@ async def test_nutrition_scope_config_entry(
) )
assert await integration_setup() assert await integration_setup()
state = hass.states.get("sensor.water") state = hass.states.get("sensor.first_l_water")
assert state assert state
assert (state.state, state.attributes) == snapshot assert (state.state, state.attributes) == snapshot
state = hass.states.get("sensor.calories_in") state = hass.states.get("sensor.first_l_calories_in")
assert state assert state
assert (state.state, state.attributes) == snapshot assert (state.state, state.attributes) == snapshot
@ -545,14 +563,14 @@ async def test_sleep_scope_config_entry(
states = hass.states.async_all() states = hass.states.async_all()
assert {s.entity_id for s in states} == { assert {s.entity_id for s in states} == {
"sensor.awakenings_count", "sensor.first_l_awakenings_count",
"sensor.sleep_efficiency", "sensor.first_l_sleep_efficiency",
"sensor.minutes_after_wakeup", "sensor.first_l_minutes_after_wakeup",
"sensor.sleep_minutes_asleep", "sensor.first_l_sleep_minutes_asleep",
"sensor.sleep_minutes_awake", "sensor.first_l_sleep_minutes_awake",
"sensor.sleep_minutes_to_fall_asleep", "sensor.first_l_sleep_minutes_to_fall_asleep",
"sensor.sleep_time_in_bed", "sensor.first_l_sleep_time_in_bed",
"sensor.sleep_start_time", "sensor.first_l_sleep_start_time",
} }
@ -573,7 +591,7 @@ async def test_weight_scope_config_entry(
states = hass.states.async_all() states = hass.states.async_all()
assert [s.entity_id for s in states] == [ assert [s.entity_id for s in states] == [
"sensor.weight", "sensor.first_l_weight",
] ]
@ -623,7 +641,7 @@ async def test_sensor_update_failed(
assert await integration_setup() assert await integration_setup()
state = hass.states.get("sensor.resting_heart_rate") state = hass.states.get("sensor.first_l_resting_heart_rate")
assert state assert state
assert state.state == "unavailable" assert state.state == "unavailable"
@ -655,7 +673,7 @@ async def test_sensor_update_failed_requires_reauth(
assert await integration_setup() assert await integration_setup()
state = hass.states.get("sensor.resting_heart_rate") state = hass.states.get("sensor.first_l_resting_heart_rate")
assert state assert state
assert state.state == "unavailable" assert state.state == "unavailable"
@ -698,14 +716,14 @@ async def test_sensor_update_success(
assert await integration_setup() assert await integration_setup()
state = hass.states.get("sensor.resting_heart_rate") state = hass.states.get("sensor.first_l_resting_heart_rate")
assert state assert state
assert state.state == "60" assert state.state == "60"
await async_update_entity(hass, "sensor.resting_heart_rate") await async_update_entity(hass, "sensor.first_l_resting_heart_rate")
await hass.async_block_till_done() await hass.async_block_till_done()
state = hass.states.get("sensor.resting_heart_rate") state = hass.states.get("sensor.first_l_resting_heart_rate")
assert state assert state
assert state.state == "70" assert state.state == "70"
@ -867,6 +885,6 @@ async def test_resting_heart_rate_responses(
) )
assert await integration_setup() assert await integration_setup()
state = hass.states.get("sensor.resting_heart_rate") state = hass.states.get("sensor.first_l_resting_heart_rate")
assert state assert state
assert state.state == expected_state assert state.state == expected_state