mirror of
https://github.com/home-assistant/core.git
synced 2025-07-25 14:17:45 +00:00
Update Fitbit to avoid a KeyError when restingHeartRate
is not present (#103872)
* Update Fitbit to avoid a KeyError when `restingHeartRate` is not present * Explicitly handle none response values
This commit is contained in:
parent
efe33d815f
commit
64c9aa0cff
@ -135,6 +135,17 @@ def _water_unit(unit_system: FitbitUnitSystem) -> UnitOfVolume:
|
|||||||
return UnitOfVolume.MILLILITERS
|
return UnitOfVolume.MILLILITERS
|
||||||
|
|
||||||
|
|
||||||
|
def _int_value_or_none(field: str) -> Callable[[dict[str, Any]], int | None]:
|
||||||
|
"""Value function that will parse the specified field if present."""
|
||||||
|
|
||||||
|
def convert(result: dict[str, Any]) -> int | None:
|
||||||
|
if (value := result["value"].get(field)) is not None:
|
||||||
|
return int(value)
|
||||||
|
return None
|
||||||
|
|
||||||
|
return convert
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class FitbitSensorEntityDescription(SensorEntityDescription):
|
class FitbitSensorEntityDescription(SensorEntityDescription):
|
||||||
"""Describes Fitbit sensor entity."""
|
"""Describes Fitbit sensor entity."""
|
||||||
@ -207,7 +218,7 @@ FITBIT_RESOURCES_LIST: Final[tuple[FitbitSensorEntityDescription, ...]] = (
|
|||||||
name="Resting Heart Rate",
|
name="Resting Heart Rate",
|
||||||
native_unit_of_measurement="bpm",
|
native_unit_of_measurement="bpm",
|
||||||
icon="mdi:heart-pulse",
|
icon="mdi:heart-pulse",
|
||||||
value_fn=lambda result: int(result["value"]["restingHeartRate"]),
|
value_fn=_int_value_or_none("restingHeartRate"),
|
||||||
scope=FitbitScope.HEART_RATE,
|
scope=FitbitScope.HEART_RATE,
|
||||||
state_class=SensorStateClass.MEASUREMENT,
|
state_class=SensorStateClass.MEASUREMENT,
|
||||||
),
|
),
|
||||||
|
@ -808,3 +808,60 @@ async def test_device_battery_level_reauth_required(
|
|||||||
flows = hass.config_entries.flow.async_progress()
|
flows = hass.config_entries.flow.async_progress()
|
||||||
assert len(flows) == 1
|
assert len(flows) == 1
|
||||||
assert flows[0]["step_id"] == "reauth_confirm"
|
assert flows[0]["step_id"] == "reauth_confirm"
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
("scopes", "response_data", "expected_state"),
|
||||||
|
[
|
||||||
|
(["heartrate"], {}, "unknown"),
|
||||||
|
(
|
||||||
|
["heartrate"],
|
||||||
|
{
|
||||||
|
"restingHeartRate": 120,
|
||||||
|
},
|
||||||
|
"120",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
["heartrate"],
|
||||||
|
{
|
||||||
|
"restingHeartRate": 0,
|
||||||
|
},
|
||||||
|
"0",
|
||||||
|
),
|
||||||
|
],
|
||||||
|
ids=("missing", "valid", "zero"),
|
||||||
|
)
|
||||||
|
async def test_resting_heart_rate_responses(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
setup_credentials: None,
|
||||||
|
integration_setup: Callable[[], Awaitable[bool]],
|
||||||
|
register_timeseries: Callable[[str, dict[str, Any]], None],
|
||||||
|
response_data: dict[str, Any],
|
||||||
|
expected_state: str,
|
||||||
|
) -> None:
|
||||||
|
"""Test resting heart rate sensor with various values from response."""
|
||||||
|
|
||||||
|
register_timeseries(
|
||||||
|
"activities/heart",
|
||||||
|
timeseries_response(
|
||||||
|
"activities-heart",
|
||||||
|
{
|
||||||
|
"customHeartRateZones": [],
|
||||||
|
"heartRateZones": [
|
||||||
|
{
|
||||||
|
"caloriesOut": 0,
|
||||||
|
"max": 220,
|
||||||
|
"min": 159,
|
||||||
|
"minutes": 0,
|
||||||
|
"name": "Peak",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
**response_data,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
assert await integration_setup()
|
||||||
|
|
||||||
|
state = hass.states.get("sensor.resting_heart_rate")
|
||||||
|
assert state
|
||||||
|
assert state.state == expected_state
|
||||||
|
Loading…
x
Reference in New Issue
Block a user