Skip to content

Commit

Permalink
Fix restored temperature values in Shelly climate platform (home-assi…
Browse files Browse the repository at this point in the history
…stant#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
  • Loading branch information
bieniu authored Dec 7, 2022
1 parent fa98685 commit e11917b
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 3 deletions.
33 changes: 30 additions & 3 deletions homeassistant/components/shelly/climate.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
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
Expand Down Expand Up @@ -126,7 +128,14 @@ def __init__(
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}"
Expand Down Expand Up @@ -157,14 +166,32 @@ def target_temperature(self) -> float | None:
"""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:
Expand Down
1 change: 1 addition & 0 deletions homeassistant/components/shelly/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@
"min": 4,
"max": 31,
"step": 0.5,
"default": 20.0,
}

# Kelvin value for colorTemp
Expand Down
48 changes: 48 additions & 0 deletions tests/components/shelly/test_climate.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
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

Expand Down Expand Up @@ -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
):
Expand Down

0 comments on commit e11917b

Please sign in to comment.