mirror of
https://github.com/home-assistant/core.git
synced 2025-07-14 00:37:13 +00:00
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
@ -484,10 +484,19 @@ class SensorEntity(Entity):
|
|||||||
platform: EntityPlatform,
|
platform: EntityPlatform,
|
||||||
parallel_updates: asyncio.Semaphore | None,
|
parallel_updates: asyncio.Semaphore | None,
|
||||||
) -> 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)
|
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
|
return
|
||||||
registry = er.async_get(self.hass)
|
registry = er.async_get(self.hass)
|
||||||
if not (
|
if not (
|
||||||
@ -499,23 +508,35 @@ class SensorEntity(Entity):
|
|||||||
registry_entry = registry.async_get(entity_id)
|
registry_entry = registry.async_get(entity_id)
|
||||||
assert registry_entry
|
assert registry_entry
|
||||||
|
|
||||||
# Store unit override according to automatic unit conversion rules if:
|
# If the sensor has 'unit_of_measurement' in its sensor options, the user has
|
||||||
# - no unit override is stored in the entity registry
|
# overridden the unit.
|
||||||
# - units have changed
|
# If the sensor has 'sensor.private' in its entity options, it was added after
|
||||||
# - the unit stored in the registry matches automatic unit conversion rules
|
# automatic unit conversion was implemented.
|
||||||
# This allows integrations to drop custom unit conversion and rely on automatic
|
|
||||||
# conversion.
|
|
||||||
registry_unit = registry_entry.unit_of_measurement
|
registry_unit = registry_entry.unit_of_measurement
|
||||||
if (
|
if (
|
||||||
DOMAIN not in registry_entry.options
|
(
|
||||||
and f"{DOMAIN}.private" not in registry_entry.options
|
(sensor_options := registry_entry.options.get(DOMAIN))
|
||||||
and self.unit_of_measurement != registry_unit
|
and CONF_UNIT_OF_MEASUREMENT in sensor_options
|
||||||
and (suggested_unit := self._get_initial_suggested_unit()) == registry_unit
|
)
|
||||||
|
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(
|
registry.async_update_entity_options(
|
||||||
entity_id,
|
entity_id,
|
||||||
f"{DOMAIN}.private",
|
f"{DOMAIN}.private",
|
||||||
{"suggested_unit_of_measurement": suggested_unit},
|
{"suggested_unit_of_measurement": registry_unit},
|
||||||
)
|
)
|
||||||
|
|
||||||
async def async_internal_added_to_hass(self) -> None:
|
async def async_internal_added_to_hass(self) -> None:
|
||||||
@ -572,8 +593,12 @@ class SensorEntity(Entity):
|
|||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def _get_initial_suggested_unit(self) -> str | None:
|
def get_initial_entity_options(self) -> er.EntityOptionsType | None:
|
||||||
"""Return initial suggested unit of measurement."""
|
"""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
|
# Unit suggested by the integration
|
||||||
suggested_unit_of_measurement = self.suggested_unit_of_measurement
|
suggested_unit_of_measurement = self.suggested_unit_of_measurement
|
||||||
|
|
||||||
@ -583,15 +608,6 @@ class SensorEntity(Entity):
|
|||||||
self.device_class, self.native_unit_of_measurement
|
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:
|
if suggested_unit_of_measurement is None:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@ -889,6 +889,14 @@ async def test_unit_conversion_priority_suggested_unit_change(
|
|||||||
621,
|
621,
|
||||||
SensorDeviceClass.DISTANCE,
|
SensorDeviceClass.DISTANCE,
|
||||||
),
|
),
|
||||||
|
(
|
||||||
|
US_CUSTOMARY_SYSTEM,
|
||||||
|
LENGTH_METERS,
|
||||||
|
LENGTH_MILES,
|
||||||
|
1000000,
|
||||||
|
621.371,
|
||||||
|
SensorDeviceClass.DISTANCE,
|
||||||
|
),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
async def test_unit_conversion_priority_legacy_conversion_removed(
|
async def test_unit_conversion_priority_legacy_conversion_removed(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user