From b980ed3eacc35273d48476895e935c64634cf99f Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sun, 22 Oct 2023 11:55:13 -1000 Subject: [PATCH] Avoid more device_class lookups for number entities when writing state (#102381) --- homeassistant/components/number/__init__.py | 26 +++++++++++++++------ tests/components/number/test_init.py | 25 ++++++++++++++++++++ 2 files changed, 44 insertions(+), 7 deletions(-) diff --git a/homeassistant/components/number/__init__.py b/homeassistant/components/number/__init__.py index 97221aaca90..201fa8fedb6 100644 --- a/homeassistant/components/number/__init__.py +++ b/homeassistant/components/number/__init__.py @@ -218,8 +218,13 @@ class NumberEntity(Entity): @property def capability_attributes(self) -> dict[str, Any]: """Return capability attributes.""" - min_value = self.min_value - max_value = self.max_value + device_class = self.device_class + min_value = self._convert_to_state_value( + self.native_min_value, floor_decimal, device_class + ) + max_value = self._convert_to_state_value( + self.native_max_value, ceil_decimal, device_class + ) return { ATTR_MIN: min_value, ATTR_MAX: max_value, @@ -259,7 +264,9 @@ class NumberEntity(Entity): @final def min_value(self) -> float: """Return the minimum value.""" - return self._convert_to_state_value(self.native_min_value, floor_decimal) + return self._convert_to_state_value( + self.native_min_value, floor_decimal, self.device_class + ) @property def native_max_value(self) -> float: @@ -277,7 +284,9 @@ class NumberEntity(Entity): @final def max_value(self) -> float: """Return the maximum value.""" - return self._convert_to_state_value(self.native_max_value, ceil_decimal) + return self._convert_to_state_value( + self.native_max_value, ceil_decimal, self.device_class + ) @property def native_step(self) -> float | None: @@ -365,7 +374,7 @@ class NumberEntity(Entity): """Return the entity value to represent the entity state.""" if (native_value := self.native_value) is None: return native_value - return self._convert_to_state_value(native_value, round) + return self._convert_to_state_value(native_value, round, self.device_class) def set_native_value(self, value: float) -> None: """Set new value.""" @@ -386,12 +395,15 @@ class NumberEntity(Entity): await self.hass.async_add_executor_job(self.set_value, value) def _convert_to_state_value( - self, value: float, method: Callable[[float, int], float] + self, + value: float, + method: Callable[[float, int], float], + device_class: NumberDeviceClass | None, ) -> float: """Convert a value in the number's native unit to the configured unit.""" # device_class is checked first since most of the time we can avoid # the unit conversion - if (device_class := self.device_class) not in UNIT_CONVERTERS: + if device_class not in UNIT_CONVERTERS: return value native_unit_of_measurement = self.native_unit_of_measurement diff --git a/tests/components/number/test_init.py b/tests/components/number/test_init.py index 3f612c421c8..601a34d4271 100644 --- a/tests/components/number/test_init.py +++ b/tests/components/number/test_init.py @@ -8,6 +8,7 @@ import pytest from homeassistant.components.number import ( ATTR_MAX, ATTR_MIN, + ATTR_MODE, ATTR_STEP, ATTR_VALUE, DOMAIN, @@ -227,6 +228,12 @@ async def test_attributes(hass: HomeAssistant) -> None: assert number.step == 1.0 assert number.unit_of_measurement is None assert number.value == 0.5 + assert number.capability_attributes == { + ATTR_MAX: 100.0, + ATTR_MIN: 0.0, + ATTR_MODE: NumberMode.AUTO, + ATTR_STEP: 1.0, + } number_2 = MockNumberEntity() number_2.hass = hass @@ -235,6 +242,12 @@ async def test_attributes(hass: HomeAssistant) -> None: assert number_2.step == 0.1 assert number_2.unit_of_measurement == "native_cats" assert number_2.value == 0.5 + assert number_2.capability_attributes == { + ATTR_MAX: 0.5, + ATTR_MIN: -0.5, + ATTR_MODE: NumberMode.AUTO, + ATTR_STEP: 0.1, + } number_3 = MockNumberEntityAttr() number_3.hass = hass @@ -243,6 +256,12 @@ async def test_attributes(hass: HomeAssistant) -> None: assert number_3.step == 100.0 assert number_3.unit_of_measurement == "native_dogs" assert number_3.value == 500.0 + assert number_3.capability_attributes == { + ATTR_MAX: 1000.0, + ATTR_MIN: -1000.0, + ATTR_MODE: NumberMode.AUTO, + ATTR_STEP: 100.0, + } number_4 = MockNumberEntityDescr() number_4.hass = hass @@ -251,6 +270,12 @@ async def test_attributes(hass: HomeAssistant) -> None: assert number_4.step == 2.0 assert number_4.unit_of_measurement == "native_rabbits" assert number_4.value is None + assert number_4.capability_attributes == { + ATTR_MAX: 10.0, + ATTR_MIN: -10.0, + ATTR_MODE: NumberMode.AUTO, + ATTR_STEP: 2.0, + } async def test_sync_set_value(hass: HomeAssistant) -> None: