Suppress the placeholder water temperature on Flo valves without the sensor (#182004)

This commit is contained in:
ajplotkin
2026-09-19 11:39:24 +02:00
committed by GitHub
parent 2329db5a05
commit 7af5bcc88a
4 changed files with 66 additions and 8 deletions
+5
View File
@@ -10,3 +10,8 @@ FLO_HOME = "home"
FLO_AWAY = "away"
FLO_SLEEP = "sleep"
FLO_MODES = [FLO_HOME, FLO_AWAY, FLO_SLEEP]
# Valves without a water-temperature sensor report a fixed placeholder instead of
# omitting tempF. No domestic supply reaches boiling, so a reading at or above
# this is a sentinel rather than a measurement.
IMPLAUSIBLE_WATER_TEMP_F = 212.0
+7 -4
View File
@@ -14,7 +14,7 @@ from homeassistant.core import HomeAssistant
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
from homeassistant.util import dt as dt_util
from .const import DOMAIN, LOGGER
from .const import DOMAIN, IMPLAUSIBLE_WATER_TEMP_F, LOGGER
type FloConfigEntry = ConfigEntry[FloRuntimeData]
@@ -144,9 +144,12 @@ class FloDeviceDataUpdateCoordinator(DataUpdateCoordinator):
return self._device_information["telemetry"]["current"]["psi"]
@property
def temperature(self) -> float:
"""Return the current temperature in degrees F."""
return self._device_information["telemetry"]["current"]["tempF"]
def temperature(self) -> float | None:
"""Return the current temperature in degrees F, or None if not measured."""
temperature = self._device_information["telemetry"]["current"]["tempF"]
if temperature is None or temperature >= IMPLAUSIBLE_WATER_TEMP_F:
return None
return temperature
@property
def humidity(self) -> float:
+14 -3
View File
@@ -11,7 +11,7 @@ from homeassistant.const import CONF_PASSWORD, CONF_USERNAME, CONTENT_TYPE_JSON
from .common import TEST_EMAIL_ADDRESS, TEST_PASSWORD, TEST_TOKEN, TEST_USER_ID
from tests.common import MockConfigEntry, load_fixture
from tests.common import MockConfigEntry, load_fixture, load_json_object_fixture
from tests.test_util.aiohttp import AiohttpClientMocker
@@ -26,7 +26,18 @@ def config_entry() -> MockConfigEntry:
@pytest.fixture
def aioclient_mock_fixture(aioclient_mock: AiohttpClientMocker) -> None:
def device_info_response(request: pytest.FixtureRequest) -> str:
"""Shutoff valve device info, with tempF overridden when parametrized."""
device_info = load_json_object_fixture("flo/device_info_response.json")
if hasattr(request, "param"):
device_info["telemetry"]["current"]["tempF"] = request.param
return json.dumps(device_info)
@pytest.fixture
def aioclient_mock_fixture(
aioclient_mock: AiohttpClientMocker, device_info_response: str
) -> None:
"""Fixture to provide a aioclient mocker."""
now = round(time.time())
# Mocks the login response for flo.
@@ -56,7 +67,7 @@ def aioclient_mock_fixture(aioclient_mock: AiohttpClientMocker) -> None:
# Mocks the devices for flo.
aioclient_mock.get(
"https://api-gw.meetflo.com/api/v2/devices/98765",
text=load_fixture("flo/device_info_response.json"),
text=device_info_response,
status=HTTPStatus.OK,
headers={"Content-Type": CONTENT_TYPE_JSON},
)
+40 -1
View File
@@ -1,5 +1,7 @@
"""Test Flo by Moen sensor entities."""
import json
import pytest
from homeassistant.components.homeassistant import (
@@ -7,7 +9,7 @@ from homeassistant.components.homeassistant import (
SERVICE_UPDATE_ENTITY,
)
from homeassistant.components.sensor import ATTR_STATE_CLASS, SensorStateClass
from homeassistant.const import ATTR_ENTITY_ID
from homeassistant.const import ATTR_ENTITY_ID, STATE_UNKNOWN
from homeassistant.core import HomeAssistant
from homeassistant.setup import async_setup_component
from homeassistant.util.unit_system import US_CUSTOMARY_SYSTEM
@@ -105,3 +107,40 @@ async def test_manual_update_entity(
blocking=True,
)
assert aioclient_mock.call_count == call_count + 3
@pytest.mark.parametrize("device_info_response", [225, 212, 220], indirect=True)
@pytest.mark.usefixtures("aioclient_mock_fixture")
async def test_water_temperature_placeholder_is_not_published(
hass: HomeAssistant, config_entry: MockConfigEntry
) -> None:
"""A valve with no temperature sensor reports a placeholder, not a reading."""
hass.config.units = US_CUSTOMARY_SYSTEM
config_entry.add_to_hass(hass)
assert await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done()
assert (
hass.states.get("sensor.smart_water_shutoff_water_temperature").state
== STATE_UNKNOWN
)
# The detector measures ambient air and is unaffected.
assert hass.states.get("sensor.kitchen_sink_temperature").state == "61"
@pytest.mark.parametrize("device_info_response", [211.9, 70], indirect=True)
@pytest.mark.usefixtures("aioclient_mock_fixture")
async def test_water_temperature_below_threshold_is_published(
hass: HomeAssistant, config_entry: MockConfigEntry, device_info_response: str
) -> None:
"""Anything below boiling is a real reading and is published."""
hass.config.units = US_CUSTOMARY_SYSTEM
config_entry.add_to_hass(hass)
assert await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done()
expected = json.loads(device_info_response)["telemetry"]["current"]["tempF"]
assert hass.states.get("sensor.smart_water_shutoff_water_temperature").state == str(
round(expected, 1)
)