1
0
mirror of https://github.com/home-assistant/core.git synced 2026-02-15 07:36:16 +00:00

Ensure numeric template sensors only use numbers in _attr_native_state (#162878)

Co-authored-by: Erik Montnemery <erik@montnemery.com>
This commit is contained in:
Petro31
2026-02-13 08:14:28 -05:00
committed by GitHub
parent d3d916566a
commit 4e71a38e31
3 changed files with 45 additions and 12 deletions

View File

@@ -256,6 +256,9 @@ class AbstractTemplateSensor(AbstractTemplateEntity, RestoreSensor):
self, result: Any
) -> StateType | date | datetime | Decimal | None:
"""Validate the state."""
if self._numeric_state_expected:
return template_validators.number(self, CONF_STATE)(result)
if result is None or self.device_class not in (
SensorDeviceClass.DATE,
SensorDeviceClass.TIMESTAMP,

View File

@@ -1306,7 +1306,7 @@ async def test_config_flow_preview_template_error(
[
(
"sensor",
"{{ states('sensor.one') }}",
"{{ 1.0 / states('sensor.one') | float(0.0) }}",
{"unit_of_measurement": "°C"},
),
],
@@ -1350,14 +1350,7 @@ async def test_config_flow_preview_bad_state(
assert msg["result"] is None
msg = await client.receive_json()
assert msg["event"] == {
"error": (
"Sensor None has device class 'None', state class 'None' unit '°C' "
"and suggested precision 'None' thus indicating it has a numeric "
"value; however, it has the non-numeric value: 'unknown' (<class "
"'str'>)"
),
}
assert msg["event"] == {"error": "ZeroDivisionError: division by zero"}
@pytest.mark.parametrize(

View File

@@ -692,7 +692,7 @@ async def test_sun_renders_once_per_sensor(hass: HomeAssistant) -> None:
hass.states.async_set("sun.sun", {"elevation": 50, "next_rising": later})
await hass.async_block_till_done()
assert hass.states.get("sensor.solar_angle").state == "75"
assert hass.states.get("sensor.solar_angle").state == "75.0"
assert hass.states.get("sensor.sunrise").state == "75"
assert len(async_render_calls) == 2
@@ -1524,7 +1524,7 @@ async def test_last_reset(hass: HomeAssistant, expected: str) -> None:
state = hass.states.get(TEST_SENSOR.entity_id)
assert state is not None
assert state.state == "0"
assert state.state == "0.0"
assert state.attributes["state_class"] == "total"
assert state.attributes["last_reset"] == expected
@@ -1553,7 +1553,7 @@ async def test_invalid_last_reset(
state = hass.states.get(TEST_SENSOR.entity_id)
assert state is not None
assert state.state == "0"
assert state.state == "0.0"
assert state.attributes.get("last_reset") is None
err = "Received invalid sensor last_reset: not a datetime for entity"
@@ -1956,3 +1956,40 @@ async def test_flow_preview(
)
assert state["state"] == "0.0"
@pytest.mark.parametrize(
("count", "config", "state_template"),
[
(
1,
{
"device_class": "temperature",
"state_class": "measurement",
"unit_of_measurement": "°C",
},
"{{ states('sensor.test_state') }}",
)
],
)
@pytest.mark.parametrize(
"style", [ConfigurationStyle.MODERN, ConfigurationStyle.TRIGGER]
)
@pytest.mark.usefixtures("setup_state_sensor")
async def test_numeric_sensor_recovers_from_exception(hass: HomeAssistant) -> None:
"""Test template."""
assert hass.states.get(TEST_SENSOR.entity_id).state == STATE_UNKNOWN
for set_state, expected_state in (
("0.0", "0.0"),
("unavailable", STATE_UNKNOWN),
("1.0", "1.0"),
("unknown", STATE_UNKNOWN),
("2.0", "2.0"),
("kjfdah", STATE_UNKNOWN),
("3.0", "3.0"),
("3.x", STATE_UNKNOWN),
("4.0", "4.0"),
):
await async_trigger(hass, TEST_STATE_SENSOR, set_state)
assert hass.states.get(TEST_SENSOR.entity_id).state == expected_state