Add fitbit nutrition sensors (#101626)

* Add fitbit nutrition sensors

* Add test coverage for unit systems
This commit is contained in:
Allen Porter 2023-10-08 01:09:26 -07:00 committed by GitHub
parent d3a67cd984
commit 7d202f78f5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 112 additions and 0 deletions

View file

@ -33,6 +33,7 @@ from homeassistant.const import (
UnitOfLength,
UnitOfMass,
UnitOfTime,
UnitOfVolume,
)
from homeassistant.core import HomeAssistant
from homeassistant.data_entry_flow import FlowResultType
@ -122,6 +123,13 @@ def _elevation_unit(unit_system: FitbitUnitSystem) -> UnitOfLength:
return UnitOfLength.METERS
def _water_unit(unit_system: FitbitUnitSystem) -> UnitOfVolume:
"""Determine the water unit."""
if unit_system == FitbitUnitSystem.EN_US:
return UnitOfVolume.FLUID_OUNCES
return UnitOfVolume.MILLILITERS
@dataclass
class FitbitSensorEntityDescription(SensorEntityDescription):
"""Describes Fitbit sensor entity."""
@ -453,6 +461,24 @@ FITBIT_RESOURCES_LIST: Final[tuple[FitbitSensorEntityDescription, ...]] = (
state_class=SensorStateClass.TOTAL_INCREASING,
entity_category=EntityCategory.DIAGNOSTIC,
),
FitbitSensorEntityDescription(
key="foods/log/caloriesIn",
name="Calories In",
native_unit_of_measurement="cal",
icon="mdi:food-apple",
state_class=SensorStateClass.TOTAL_INCREASING,
scope="nutrition",
entity_category=EntityCategory.DIAGNOSTIC,
),
FitbitSensorEntityDescription(
key="foods/log/water",
name="Water",
icon="mdi:cup-water",
unit_fn=_water_unit,
state_class=SensorStateClass.TOTAL_INCREASING,
scope="nutrition",
entity_category=EntityCategory.DIAGNOSTIC,
),
)
# Different description depending on clock format

View file

@ -1,4 +1,52 @@
# serializer version: 1
# name: test_nutrition_scope_config_entry[scopes0-unit_system0]
tuple(
'99',
ReadOnlyDict({
'attribution': 'Data provided by Fitbit.com',
'friendly_name': 'Water',
'icon': 'mdi:cup-water',
'state_class': <SensorStateClass.TOTAL_INCREASING: 'total_increasing'>,
'unit_of_measurement': <UnitOfVolume.MILLILITERS: 'mL'>,
}),
)
# ---
# name: test_nutrition_scope_config_entry[scopes0-unit_system0].1
tuple(
'1600',
ReadOnlyDict({
'attribution': 'Data provided by Fitbit.com',
'friendly_name': 'Calories In',
'icon': 'mdi:food-apple',
'state_class': <SensorStateClass.TOTAL_INCREASING: 'total_increasing'>,
'unit_of_measurement': 'cal',
}),
)
# ---
# name: test_nutrition_scope_config_entry[scopes1-unit_system1]
tuple(
'99',
ReadOnlyDict({
'attribution': 'Data provided by Fitbit.com',
'friendly_name': 'Water',
'icon': 'mdi:cup-water',
'state_class': <SensorStateClass.TOTAL_INCREASING: 'total_increasing'>,
'unit_of_measurement': <UnitOfVolume.FLUID_OUNCES: 'fl. oz.'>,
}),
)
# ---
# name: test_nutrition_scope_config_entry[scopes1-unit_system1].1
tuple(
'1600',
ReadOnlyDict({
'attribution': 'Data provided by Fitbit.com',
'friendly_name': 'Calories In',
'icon': 'mdi:food-apple',
'state_class': <SensorStateClass.TOTAL_INCREASING: 'total_increasing'>,
'unit_of_measurement': 'cal',
}),
)
# ---
# name: test_sensors[monitored_resources0-sensor.activity_calories-activities/activityCalories-135]
tuple(
'135',

View file

@ -14,6 +14,11 @@ from homeassistant.const import Platform
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er
from homeassistant.helpers.entity_component import async_update_entity
from homeassistant.util.unit_system import (
METRIC_SYSTEM,
US_CUSTOMARY_SYSTEM,
UnitSystem,
)
from .conftest import (
DEVICES_API_URL,
@ -426,6 +431,39 @@ async def test_heartrate_scope_config_entry(
}
@pytest.mark.parametrize(
("scopes", "unit_system"),
[(["nutrition"], METRIC_SYSTEM), (["nutrition"], US_CUSTOMARY_SYSTEM)],
)
async def test_nutrition_scope_config_entry(
hass: HomeAssistant,
setup_credentials: None,
integration_setup: Callable[[], Awaitable[bool]],
register_timeseries: Callable[[str, dict[str, Any]], None],
unit_system: UnitSystem,
snapshot: SnapshotAssertion,
) -> None:
"""Test nutrition sensors are enabled."""
hass.config.units = unit_system
register_timeseries(
"foods/log/water",
timeseries_response("foods-log-water", "99"),
)
register_timeseries(
"foods/log/caloriesIn",
timeseries_response("foods-log-caloriesIn", "1600"),
)
assert await integration_setup()
state = hass.states.get("sensor.water")
assert state
assert (state.state, state.attributes) == snapshot
state = hass.states.get("sensor.calories_in")
assert state
assert (state.state, state.attributes) == snapshot
@pytest.mark.parametrize(
("scopes"),
[(["sleep"])],