Fix sensor unit conversion (#87978)

This commit is contained in:
Erik Montnemery 2023-02-13 10:08:07 +01:00 committed by GitHub
parent b68f502769
commit 3f910b49ae
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 146 additions and 1 deletions

View File

@ -623,6 +623,8 @@ class SensorEntity(Entity):
# This can be replaced with adding the z option when we drop support for
# Python 3.10
value = NEGATIVE_ZERO_PATTERN.sub(r"\1", value)
else:
value = converted_numerical_value
# Validate unit of measurement used for sensors with a device class
if (

View File

@ -788,7 +788,9 @@ async def test_custom_unit_change(
@pytest.mark.parametrize(
"unit_system, native_unit, automatic_unit, suggested_unit, custom_unit, native_value, native_state, automatic_state, suggested_state, custom_state, device_class",
"unit_system, native_unit, automatic_unit, suggested_unit, custom_unit,"
"native_value, native_state, automatic_state, suggested_state, custom_state,"
"device_class",
[
# Distance
(
@ -918,6 +920,147 @@ async def test_unit_conversion_priority(
assert state.attributes[ATTR_UNIT_OF_MEASUREMENT] == custom_unit
@pytest.mark.parametrize(
"unit_system, native_unit, automatic_unit, suggested_unit, custom_unit,"
"suggested_precision, native_value, native_state, automatic_state, suggested_state,"
"custom_state, device_class",
[
# Distance
(
US_CUSTOMARY_SYSTEM,
UnitOfLength.KILOMETERS,
UnitOfLength.MILES,
UnitOfLength.METERS,
UnitOfLength.YARDS,
2,
1000,
"1000",
621.371,
1000000,
1093613,
SensorDeviceClass.DISTANCE,
),
],
)
async def test_unit_conversion_priority_precision(
hass,
enable_custom_integrations,
unit_system,
native_unit,
automatic_unit,
suggested_unit,
custom_unit,
suggested_precision,
native_value,
native_state,
automatic_state,
suggested_state,
custom_state,
device_class,
):
"""Test priority of unit conversion for sensors with suggested_display_precision."""
hass.config.units = unit_system
entity_registry = er.async_get(hass)
platform = getattr(hass.components, "test.sensor")
platform.init(empty=True)
platform.ENTITIES["0"] = platform.MockSensor(
name="Test",
device_class=device_class,
native_unit_of_measurement=native_unit,
native_value=str(native_value),
suggested_display_precision=suggested_precision,
unique_id="very_unique",
)
entity0 = platform.ENTITIES["0"]
platform.ENTITIES["1"] = platform.MockSensor(
name="Test",
device_class=device_class,
native_unit_of_measurement=native_unit,
native_value=str(native_value),
suggested_display_precision=suggested_precision,
)
entity1 = platform.ENTITIES["1"]
platform.ENTITIES["2"] = platform.MockSensor(
name="Test",
device_class=device_class,
native_unit_of_measurement=native_unit,
native_value=str(native_value),
suggested_display_precision=suggested_precision,
suggested_unit_of_measurement=suggested_unit,
unique_id="very_unique_2",
)
entity2 = platform.ENTITIES["2"]
platform.ENTITIES["3"] = platform.MockSensor(
name="Test",
device_class=device_class,
native_unit_of_measurement=native_unit,
native_value=str(native_value),
suggested_display_precision=suggested_precision,
suggested_unit_of_measurement=suggested_unit,
)
entity3 = platform.ENTITIES["3"]
assert await async_setup_component(hass, "sensor", {"sensor": {"platform": "test"}})
await hass.async_block_till_done()
# Registered entity -> Follow automatic unit conversion
state = hass.states.get(entity0.entity_id)
assert float(state.state) == pytest.approx(automatic_state)
assert state.attributes[ATTR_UNIT_OF_MEASUREMENT] == automatic_unit
# Assert the automatic unit conversion is stored in the registry
entry = entity_registry.async_get(entity0.entity_id)
assert entry.options == {
"sensor": {"suggested_display_precision": 2},
"sensor.private": {"suggested_unit_of_measurement": automatic_unit},
}
# Unregistered entity -> Follow native unit
state = hass.states.get(entity1.entity_id)
assert state.state == native_state
assert state.attributes[ATTR_UNIT_OF_MEASUREMENT] == native_unit
# Registered entity with suggested unit
state = hass.states.get(entity2.entity_id)
assert float(state.state) == pytest.approx(suggested_state)
assert state.attributes[ATTR_UNIT_OF_MEASUREMENT] == suggested_unit
# Assert the suggested unit is stored in the registry
entry = entity_registry.async_get(entity2.entity_id)
assert entry.options == {
"sensor": {"suggested_display_precision": 2},
"sensor.private": {"suggested_unit_of_measurement": suggested_unit},
}
# Unregistered entity with suggested unit
state = hass.states.get(entity3.entity_id)
assert float(state.state) == pytest.approx(suggested_state)
assert state.attributes[ATTR_UNIT_OF_MEASUREMENT] == suggested_unit
# Set a custom unit, this should have priority over the automatic unit conversion
entity_registry.async_update_entity_options(
entity0.entity_id, "sensor", {"unit_of_measurement": custom_unit}
)
await hass.async_block_till_done()
state = hass.states.get(entity0.entity_id)
assert float(state.state) == pytest.approx(custom_state)
assert state.attributes[ATTR_UNIT_OF_MEASUREMENT] == custom_unit
entity_registry.async_update_entity_options(
entity2.entity_id, "sensor", {"unit_of_measurement": custom_unit}
)
await hass.async_block_till_done()
state = hass.states.get(entity2.entity_id)
assert float(state.state) == pytest.approx(custom_state)
assert state.attributes[ATTR_UNIT_OF_MEASUREMENT] == custom_unit
@pytest.mark.parametrize(
"unit_system, native_unit, original_unit, suggested_unit, native_value, original_value, device_class",
[