diff --git a/homeassistant/helpers/entity.py b/homeassistant/helpers/entity.py index f6ff8c73bf5..75ac1e0c1b8 100644 --- a/homeassistant/helpers/entity.py +++ b/homeassistant/helpers/entity.py @@ -295,6 +295,9 @@ class Entity(ABC): # If we reported this entity is updated while disabled _disabled_reported = False + # If we reported this entity is relying on deprecated temperature conversion + _temperature_reported = False + # Protect for multiple updates _update_staged = False @@ -642,23 +645,57 @@ class Entity(ABC): if DATA_CUSTOMIZE in self.hass.data: attr.update(self.hass.data[DATA_CUSTOMIZE].get(self.entity_id)) - # Convert temperature if we detect one - try: + def _convert_temperature(state: str, attr: dict) -> str: + # Convert temperature if we detect one + # pylint: disable-next=import-outside-toplevel + from homeassistant.components.sensor import SensorEntity + unit_of_measure = attr.get(ATTR_UNIT_OF_MEASUREMENT) units = self.hass.config.units - domain = split_entity_id(self.entity_id)[0] - if ( - unit_of_measure in (TEMP_CELSIUS, TEMP_FAHRENHEIT) - and unit_of_measure != units.temperature_unit - and domain != "sensor" + if unit_of_measure == units.temperature_unit or unit_of_measure not in ( + TEMP_CELSIUS, + TEMP_FAHRENHEIT, ): + return state + + domain = split_entity_id(self.entity_id)[0] + if domain != "sensor": + if not self._temperature_reported: + self._temperature_reported = True + report_issue = self._suggest_report_issue() + _LOGGER.warning( + "Entity %s (%s) relies on automatic temperature conversion, this will " + "be unsupported in Home Assistant Core 2022.7. Please %s", + self.entity_id, + type(self), + report_issue, + ) + elif not isinstance(self, SensorEntity): + if not self._temperature_reported: + self._temperature_reported = True + report_issue = self._suggest_report_issue() + _LOGGER.warning( + "Temperature sensor %s (%s) does not inherit SensorEntity, " + "this will be unsupported in Home Assistant Core 2022.7." + "Please %s", + self.entity_id, + type(self), + report_issue, + ) + else: + return state + + try: prec = len(state) - state.index(".") - 1 if "." in state else 0 temp = units.temperature(float(state), unit_of_measure) state = str(round(temp) if prec == 0 else round(temp, prec)) attr[ATTR_UNIT_OF_MEASUREMENT] = units.temperature_unit - except ValueError: - # Could not convert state to float - pass + except ValueError: + # Could not convert state to float + pass + return state + + state = _convert_temperature(state, attr) if ( self._context_set is not None diff --git a/tests/helpers/test_entity.py b/tests/helpers/test_entity.py index afc0887371e..9130de04e0f 100644 --- a/tests/helpers/test_entity.py +++ b/tests/helpers/test_entity.py @@ -13,6 +13,7 @@ from homeassistant.const import ( ATTR_DEVICE_CLASS, STATE_UNAVAILABLE, STATE_UNKNOWN, + TEMP_FAHRENHEIT, ) from homeassistant.core import Context, HomeAssistantError from homeassistant.helpers import entity, entity_registry @@ -814,6 +815,64 @@ async def test_float_conversion(hass): assert state.state == "3.6" +async def test_temperature_conversion(hass, caplog): + """Test conversion of temperatures.""" + # Non sensor entity reporting a temperature + with patch.object( + entity.Entity, "state", PropertyMock(return_value=100) + ), patch.object( + entity.Entity, "unit_of_measurement", PropertyMock(return_value=TEMP_FAHRENHEIT) + ): + ent = entity.Entity() + ent.hass = hass + ent.entity_id = "hello.world" + ent.async_write_ha_state() + + state = hass.states.get("hello.world") + assert state is not None + assert state.state == "38" + assert ( + "Entity hello.world () relies on automatic " + "temperature conversion, this will be unsupported in Home Assistant Core 2022.7. " + "Please create a bug report" in caplog.text + ) + + # Sensor entity, not extending SensorEntity, reporting a temperature + with patch.object( + entity.Entity, "state", PropertyMock(return_value=100) + ), patch.object( + entity.Entity, "unit_of_measurement", PropertyMock(return_value=TEMP_FAHRENHEIT) + ): + ent = entity.Entity() + ent.hass = hass + ent.entity_id = "sensor.temp" + ent.async_write_ha_state() + + state = hass.states.get("sensor.temp") + assert state is not None + assert state.state == "38" + assert ( + "Temperature sensor sensor.temp () " + "does not inherit SensorEntity, this will be unsupported in Home Assistant Core " + "2022.7.Please create a bug report" in caplog.text + ) + + # Sensor entity, not extending SensorEntity, not reporting a number + with patch.object( + entity.Entity, "state", PropertyMock(return_value="really warm") + ), patch.object( + entity.Entity, "unit_of_measurement", PropertyMock(return_value=TEMP_FAHRENHEIT) + ): + ent = entity.Entity() + ent.hass = hass + ent.entity_id = "sensor.temp" + ent.async_write_ha_state() + + state = hass.states.get("sensor.temp") + assert state is not None + assert state.state == "really warm" + + async def test_attribution_attribute(hass): """Test attribution attribute.""" mock_entity = entity.Entity()