Refactor support for integrations to drop custom unit conversion (#83228)
* Refactor support for integrations to drop custom unit conversion * Fix lying comment * Address review comment
This commit is contained in:
parent
1f7a7d5cb5
commit
67875b99a3
2 changed files with 52 additions and 28 deletions
|
@ -484,10 +484,19 @@ class SensorEntity(Entity):
|
|||
platform: EntityPlatform,
|
||||
parallel_updates: asyncio.Semaphore | None,
|
||||
) -> None:
|
||||
"""Start adding an entity to a platform."""
|
||||
"""Start adding an entity to a platform.
|
||||
|
||||
Allows integrations to remove legacy custom unit conversion which is no longer
|
||||
needed without breaking existing sensors. Only works for sensors which are in
|
||||
the entity registry.
|
||||
|
||||
This can be removed once core integrations have dropped unneeded custom unit
|
||||
conversion.
|
||||
"""
|
||||
super().add_to_platform_start(hass, platform, parallel_updates)
|
||||
|
||||
if self.unique_id is None:
|
||||
# Bail out if the sensor doesn't have a unique_id or a device class
|
||||
if self.unique_id is None or self.device_class is None:
|
||||
return
|
||||
registry = er.async_get(self.hass)
|
||||
if not (
|
||||
|
@ -499,24 +508,36 @@ class SensorEntity(Entity):
|
|||
registry_entry = registry.async_get(entity_id)
|
||||
assert registry_entry
|
||||
|
||||
# Store unit override according to automatic unit conversion rules if:
|
||||
# - no unit override is stored in the entity registry
|
||||
# - units have changed
|
||||
# - the unit stored in the registry matches automatic unit conversion rules
|
||||
# This allows integrations to drop custom unit conversion and rely on automatic
|
||||
# conversion.
|
||||
# If the sensor has 'unit_of_measurement' in its sensor options, the user has
|
||||
# overridden the unit.
|
||||
# If the sensor has 'sensor.private' in its entity options, it was added after
|
||||
# automatic unit conversion was implemented.
|
||||
registry_unit = registry_entry.unit_of_measurement
|
||||
if (
|
||||
DOMAIN not in registry_entry.options
|
||||
and f"{DOMAIN}.private" not in registry_entry.options
|
||||
and self.unit_of_measurement != registry_unit
|
||||
and (suggested_unit := self._get_initial_suggested_unit()) == registry_unit
|
||||
):
|
||||
registry.async_update_entity_options(
|
||||
entity_id,
|
||||
f"{DOMAIN}.private",
|
||||
{"suggested_unit_of_measurement": suggested_unit},
|
||||
(
|
||||
(sensor_options := registry_entry.options.get(DOMAIN))
|
||||
and CONF_UNIT_OF_MEASUREMENT in sensor_options
|
||||
)
|
||||
or f"{DOMAIN}.private" in registry_entry.options
|
||||
or self.unit_of_measurement == registry_unit
|
||||
):
|
||||
return
|
||||
|
||||
# Make sure we can convert the units
|
||||
if (
|
||||
(unit_converter := UNIT_CONVERTERS.get(self.device_class)) is None
|
||||
or registry_unit not in unit_converter.VALID_UNITS
|
||||
or self.unit_of_measurement not in unit_converter.VALID_UNITS
|
||||
):
|
||||
return
|
||||
|
||||
# Set suggested_unit_of_measurement to the old unit to enable automatic
|
||||
# conversion
|
||||
registry.async_update_entity_options(
|
||||
entity_id,
|
||||
f"{DOMAIN}.private",
|
||||
{"suggested_unit_of_measurement": registry_unit},
|
||||
)
|
||||
|
||||
async def async_internal_added_to_hass(self) -> None:
|
||||
"""Call when the sensor entity is added to hass."""
|
||||
|
@ -572,8 +593,12 @@ class SensorEntity(Entity):
|
|||
|
||||
return None
|
||||
|
||||
def _get_initial_suggested_unit(self) -> str | None:
|
||||
"""Return initial suggested unit of measurement."""
|
||||
def get_initial_entity_options(self) -> er.EntityOptionsType | None:
|
||||
"""Return initial entity options.
|
||||
|
||||
These will be stored in the entity registry the first time the entity is seen,
|
||||
and then never updated.
|
||||
"""
|
||||
# Unit suggested by the integration
|
||||
suggested_unit_of_measurement = self.suggested_unit_of_measurement
|
||||
|
||||
|
@ -583,15 +608,6 @@ class SensorEntity(Entity):
|
|||
self.device_class, self.native_unit_of_measurement
|
||||
)
|
||||
|
||||
return suggested_unit_of_measurement
|
||||
|
||||
def get_initial_entity_options(self) -> er.EntityOptionsType | None:
|
||||
"""Return initial entity options.
|
||||
|
||||
These will be stored in the entity registry the first time the entity is seen,
|
||||
and then never updated.
|
||||
"""
|
||||
suggested_unit_of_measurement = self._get_initial_suggested_unit()
|
||||
if suggested_unit_of_measurement is None:
|
||||
return None
|
||||
|
||||
|
|
|
@ -889,6 +889,14 @@ async def test_unit_conversion_priority_suggested_unit_change(
|
|||
621,
|
||||
SensorDeviceClass.DISTANCE,
|
||||
),
|
||||
(
|
||||
US_CUSTOMARY_SYSTEM,
|
||||
LENGTH_METERS,
|
||||
LENGTH_MILES,
|
||||
1000000,
|
||||
621.371,
|
||||
SensorDeviceClass.DISTANCE,
|
||||
),
|
||||
],
|
||||
)
|
||||
async def test_unit_conversion_priority_legacy_conversion_removed(
|
||||
|
|
Loading…
Add table
Reference in a new issue