From e11917b7cbdd21a93424f801dce0be3802c8cb89 Mon Sep 17 00:00:00 2001 From: Maciej Bieniek Date: Wed, 7 Dec 2022 08:11:18 +0100 Subject: [PATCH] Fix restored temperature values in Shelly climate platform (#83428) * Set last_target_temp value according the unit system * Convert restored temperature values * Add test * Improve comments * Move _last_target_temp value to constants --- homeassistant/components/shelly/climate.py | 33 +++++++++++++-- homeassistant/components/shelly/const.py | 1 + tests/components/shelly/test_climate.py | 48 ++++++++++++++++++++++ 3 files changed, 79 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/shelly/climate.py b/homeassistant/components/shelly/climate.py index 28ecf0f231c..a624ba341af 100644 --- a/homeassistant/components/shelly/climate.py +++ b/homeassistant/components/shelly/climate.py @@ -24,6 +24,8 @@ from homeassistant.helpers.entity import DeviceInfo from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.restore_state import RestoreEntity from homeassistant.helpers.update_coordinator import CoordinatorEntity +from homeassistant.util.unit_conversion import TemperatureConverter +from homeassistant.util.unit_system import US_CUSTOMARY_SYSTEM from .const import LOGGER, SHTRV_01_TEMPERATURE_SETTINGS from .coordinator import ShellyBlockCoordinator, get_entry_data @@ -126,7 +128,14 @@ class BlockSleepingClimate( self.last_state: State | None = None self.last_state_attributes: Mapping[str, Any] self._preset_modes: list[str] = [] - self._last_target_temp = 20.0 + if coordinator.hass.config.units is US_CUSTOMARY_SYSTEM: + self._last_target_temp = TemperatureConverter.convert( + SHTRV_01_TEMPERATURE_SETTINGS["default"], + UnitOfTemperature.CELSIUS, + UnitOfTemperature.FAHRENHEIT, + ) + else: + self._last_target_temp = SHTRV_01_TEMPERATURE_SETTINGS["default"] if self.block is not None and self.device_block is not None: self._unique_id = f"{self.coordinator.mac}-{self.block.description}" @@ -157,14 +166,32 @@ class BlockSleepingClimate( """Set target temperature.""" if self.block is not None: return cast(float, self.block.targetTemp) - return self.last_state_attributes.get("temperature") + # The restored value can be in Fahrenheit so we have to convert it to Celsius + # because we use this unit internally in integration. + target_temp = self.last_state_attributes.get("temperature") + if self.hass.config.units is US_CUSTOMARY_SYSTEM and target_temp: + return TemperatureConverter.convert( + cast(float, target_temp), + UnitOfTemperature.FAHRENHEIT, + UnitOfTemperature.CELSIUS, + ) + return target_temp @property def current_temperature(self) -> float | None: """Return current temperature.""" if self.block is not None: return cast(float, self.block.temp) - return self.last_state_attributes.get("current_temperature") + # The restored value can be in Fahrenheit so we have to convert it to Celsius + # because we use this unit internally in integration. + current_temp = self.last_state_attributes.get("current_temperature") + if self.hass.config.units is US_CUSTOMARY_SYSTEM and current_temp: + return TemperatureConverter.convert( + cast(float, current_temp), + UnitOfTemperature.FAHRENHEIT, + UnitOfTemperature.CELSIUS, + ) + return current_temp @property def available(self) -> bool: diff --git a/homeassistant/components/shelly/const.py b/homeassistant/components/shelly/const.py index 81d4bfd7b14..41656bbcd6f 100644 --- a/homeassistant/components/shelly/const.py +++ b/homeassistant/components/shelly/const.py @@ -147,6 +147,7 @@ SHTRV_01_TEMPERATURE_SETTINGS: Final = { "min": 4, "max": 31, "step": 0.5, + "default": 20.0, } # Kelvin value for colorTemp diff --git a/tests/components/shelly/test_climate.py b/tests/components/shelly/test_climate.py index 56effa156e6..0d43ae118cf 100644 --- a/tests/components/shelly/test_climate.py +++ b/tests/components/shelly/test_climate.py @@ -21,6 +21,7 @@ from homeassistant.config_entries import SOURCE_REAUTH, ConfigEntryState from homeassistant.const import ATTR_ENTITY_ID, ATTR_TEMPERATURE, STATE_UNAVAILABLE from homeassistant.core import State from homeassistant.exceptions import HomeAssistantError +from homeassistant.util.unit_system import US_CUSTOMARY_SYSTEM from . import init_integration, register_device, register_entity @@ -212,6 +213,53 @@ async def test_block_restored_climate(hass, mock_block_device, device_reg, monke assert hass.states.get(entity_id).state == HVACMode.OFF +async def test_block_restored_climate_us_customery( + hass, mock_block_device, device_reg, monkeypatch +): + """Test block restored climate with US CUSTOMATY unit system.""" + hass.config.units = US_CUSTOMARY_SYSTEM + monkeypatch.delattr(mock_block_device.blocks[DEVICE_BLOCK_ID], "targetTemp") + monkeypatch.setattr(mock_block_device.blocks[DEVICE_BLOCK_ID], "valveError", 0) + entry = await init_integration(hass, 1, sleep_period=1000, skip_setup=True) + register_device(device_reg, entry) + entity_id = register_entity( + hass, + CLIMATE_DOMAIN, + "test_name", + "sensor_0", + entry, + ) + attrs = {"current_temperature": 67, "temperature": 68} + mock_restore_cache(hass, [State(entity_id, HVACMode.HEAT, attributes=attrs)]) + + monkeypatch.setattr(mock_block_device, "initialized", False) + await hass.config_entries.async_setup(entry.entry_id) + await hass.async_block_till_done() + + assert hass.states.get(entity_id).state == HVACMode.HEAT + assert hass.states.get(entity_id).attributes.get("temperature") == 68 + assert hass.states.get(entity_id).attributes.get("current_temperature") == 67 + + # Partial update, should not change state + mock_block_device.mock_update() + await hass.async_block_till_done() + + assert hass.states.get(entity_id).state == HVACMode.HEAT + assert hass.states.get(entity_id).attributes.get("temperature") == 68 + assert hass.states.get(entity_id).attributes.get("current_temperature") == 67 + + # Make device online + monkeypatch.setattr(mock_block_device, "initialized", True) + monkeypatch.setattr(mock_block_device.blocks[SENSOR_BLOCK_ID], "targetTemp", 19.7) + monkeypatch.setattr(mock_block_device.blocks[SENSOR_BLOCK_ID], "temp", 18.2) + mock_block_device.mock_update() + await hass.async_block_till_done() + + assert hass.states.get(entity_id).state == HVACMode.HEAT + assert hass.states.get(entity_id).attributes.get("temperature") == 67 + assert hass.states.get(entity_id).attributes.get("current_temperature") == 65 + + async def test_block_restored_climate_unavailable( hass, mock_block_device, device_reg, monkeypatch ):