diff --git a/homeassistant/components/sensor/__init__.py b/homeassistant/components/sensor/__init__.py index c00d20d51ef..b8151256519 100644 --- a/homeassistant/components/sensor/__init__.py +++ b/homeassistant/components/sensor/__init__.py @@ -8,7 +8,7 @@ from dataclasses import dataclass from datetime import UTC, date, datetime, timedelta from decimal import Decimal, InvalidOperation as DecimalInvalidOperation import logging -from math import ceil, floor, log10 +from math import ceil, floor, isfinite, log10 from typing import Any, Final, Self, cast, final from homeassistant.config_entries import ConfigEntry @@ -582,7 +582,11 @@ class SensorEntity(Entity): if not isinstance(value, (int, float, Decimal)): try: if isinstance(value, str) and "." not in value and "e" not in value: - numerical_value = int(value) + try: + numerical_value = int(value) + except ValueError: + # Handle nan, inf + numerical_value = float(value) else: numerical_value = float(value) # type:ignore[arg-type] except (TypeError, ValueError) as err: @@ -596,6 +600,15 @@ class SensorEntity(Entity): else: numerical_value = value + if not isfinite(numerical_value): + raise ValueError( + f"Sensor {self.entity_id} has device class '{device_class}', " + f"state class '{state_class}' unit '{unit_of_measurement}' and " + f"suggested precision '{suggested_precision}' thus indicating it " + f"has a numeric value; however, it has the non-finite value: " + f"'{numerical_value}'" + ) + if native_unit_of_measurement != unit_of_measurement and ( converter := UNIT_CONVERTERS.get(device_class) ): diff --git a/tests/components/sensor/test_init.py b/tests/components/sensor/test_init.py index 530e8cb4209..1f836ad9095 100644 --- a/tests/components/sensor/test_init.py +++ b/tests/components/sensor/test_init.py @@ -1861,13 +1861,17 @@ async def test_device_classes_with_invalid_unit_of_measurement( ], ) @pytest.mark.parametrize( - "native_value", + ("native_value", "problem"), [ - "", - "abc", - "13.7.1", - datetime(2012, 11, 10, 7, 35, 1), - date(2012, 11, 10), + ("", "non-numeric"), + ("abc", "non-numeric"), + ("13.7.1", "non-numeric"), + (datetime(2012, 11, 10, 7, 35, 1), "non-numeric"), + (date(2012, 11, 10), "non-numeric"), + ("inf", "non-finite"), + (float("inf"), "non-finite"), + ("nan", "non-finite"), + (float("nan"), "non-finite"), ], ) async def test_non_numeric_validation_error( @@ -1875,6 +1879,7 @@ async def test_non_numeric_validation_error( caplog: pytest.LogCaptureFixture, enable_custom_integrations: None, native_value: Any, + problem: str, device_class: SensorDeviceClass | None, state_class: SensorStateClass | None, unit: str | None, @@ -1899,7 +1904,7 @@ async def test_non_numeric_validation_error( assert ( "thus indicating it has a numeric value; " - f"however, it has the non-numeric value: '{native_value}'" + f"however, it has the {problem} value: '{native_value}'" ) in caplog.text