Fix check on non numeric custom sensor device classes (#89052)

* Custom device classes are not numeric

* Update homeassistant/components/sensor/__init__.py

Co-authored-by: Paulus Schoutsen <paulus@home-assistant.io>

* Add test

* Update homeassistant/components/sensor/__init__.py

Co-authored-by: epenet <6771947+epenet@users.noreply.github.com>

---------

Co-authored-by: Paulus Schoutsen <paulus@home-assistant.io>
Co-authored-by: epenet <6771947+epenet@users.noreply.github.com>
This commit is contained in:
Jan Bouwhuis 2023-03-02 20:20:26 +01:00 committed by Paulus Schoutsen
parent d0b195516b
commit b1ee6e304e
2 changed files with 49 additions and 3 deletions

View File

@ -271,15 +271,20 @@ class SensorEntity(Entity):
@property
def _numeric_state_expected(self) -> bool:
"""Return true if the sensor must be numeric."""
# Note: the order of the checks needs to be kept aligned
# with the checks in `state` property.
device_class = try_parse_enum(SensorDeviceClass, self.device_class)
if device_class in NON_NUMERIC_DEVICE_CLASSES:
return False
if (
self.state_class is not None
or self.native_unit_of_measurement is not None
or self.suggested_display_precision is not None
):
return True
# Sensors with custom device classes are not considered numeric
device_class = try_parse_enum(SensorDeviceClass, self.device_class)
return device_class not in {None, *NON_NUMERIC_DEVICE_CLASSES}
# Sensors with custom device classes will have the device class
# converted to None and are not considered numeric
return device_class is not None
@property
def options(self) -> list[str] | None:

View File

@ -205,6 +205,47 @@ async def test_datetime_conversion(
assert state.state == test_timestamp.isoformat()
async def test_a_sensor_with_a_non_numeric_device_class(
hass: HomeAssistant,
caplog: pytest.LogCaptureFixture,
enable_custom_integrations: None,
) -> None:
"""Test that a sensor with a non numeric device class will be non numeric.
A non numeric sensor with a valid device class should never be
handled as numeric because it has a device class.
"""
test_timestamp = datetime(2017, 12, 19, 18, 29, 42, tzinfo=timezone.utc)
test_local_timestamp = test_timestamp.astimezone(
dt_util.get_time_zone("Europe/Amsterdam")
)
platform = getattr(hass.components, "test.sensor")
platform.init(empty=True)
platform.ENTITIES["0"] = platform.MockSensor(
name="Test",
native_value=test_local_timestamp,
native_unit_of_measurement="",
device_class=SensorDeviceClass.TIMESTAMP,
)
platform.ENTITIES["1"] = platform.MockSensor(
name="Test",
native_value=test_local_timestamp,
state_class="",
device_class=SensorDeviceClass.TIMESTAMP,
)
assert await async_setup_component(hass, "sensor", {"sensor": {"platform": "test"}})
await hass.async_block_till_done()
state = hass.states.get(platform.ENTITIES["0"].entity_id)
assert state.state == test_timestamp.isoformat()
state = hass.states.get(platform.ENTITIES["1"].entity_id)
assert state.state == test_timestamp.isoformat()
@pytest.mark.parametrize(
("device_class", "state_value", "provides"),
[