Fix handling of min/max temperature presets in AVM Fritz!SmartHome (#138954)

pull/139012/head
Michael 2025-02-20 22:38:43 +01:00 committed by Franck Nijhof
parent dc7cba60bd
commit 266612e4d9
No known key found for this signature in database
GPG Key ID: D62583BA8AB11CA3
2 changed files with 50 additions and 21 deletions

View File

@ -85,6 +85,8 @@ async def async_setup_entry(
class FritzboxThermostat(FritzBoxDeviceEntity, ClimateEntity):
"""The thermostat class for FRITZ!SmartHome thermostats."""
_attr_max_temp = MAX_TEMPERATURE
_attr_min_temp = MIN_TEMPERATURE
_attr_precision = PRECISION_HALVES
_attr_temperature_unit = UnitOfTemperature.CELSIUS
_attr_translation_key = "thermostat"
@ -135,11 +137,13 @@ class FritzboxThermostat(FritzBoxDeviceEntity, ClimateEntity):
async def async_set_temperature(self, **kwargs: Any) -> None:
"""Set new target temperature."""
target_temp = kwargs.get(ATTR_TEMPERATURE)
hvac_mode = kwargs.get(ATTR_HVAC_MODE)
if hvac_mode == HVACMode.OFF:
if (hvac_mode := kwargs.get(ATTR_HVAC_MODE)) is HVACMode.OFF:
await self.async_set_hvac_mode(hvac_mode)
elif target_temp is not None:
elif (target_temp := kwargs.get(ATTR_TEMPERATURE)) is not None:
if target_temp == OFF_API_TEMPERATURE:
target_temp = OFF_REPORT_SET_TEMPERATURE
elif target_temp == ON_API_TEMPERATURE:
target_temp = ON_REPORT_SET_TEMPERATURE
await self.hass.async_add_executor_job(
self.data.set_target_temperature, target_temp, True
)
@ -169,12 +173,12 @@ class FritzboxThermostat(FritzBoxDeviceEntity, ClimateEntity):
translation_domain=DOMAIN,
translation_key="change_hvac_while_active_mode",
)
if self.hvac_mode == hvac_mode:
if self.hvac_mode is hvac_mode:
LOGGER.debug(
"%s is already in requested hvac mode %s", self.name, hvac_mode
)
return
if hvac_mode == HVACMode.OFF:
if hvac_mode is HVACMode.OFF:
await self.async_set_temperature(temperature=OFF_REPORT_SET_TEMPERATURE)
else:
if value_scheduled_preset(self.data) == PRESET_ECO:
@ -208,16 +212,6 @@ class FritzboxThermostat(FritzBoxDeviceEntity, ClimateEntity):
elif preset_mode == PRESET_ECO:
await self.async_set_temperature(temperature=self.data.eco_temperature)
@property
def min_temp(self) -> int:
"""Return the minimum temperature."""
return MIN_TEMPERATURE
@property
def max_temp(self) -> int:
"""Return the maximum temperature."""
return MAX_TEMPERATURE
@property
def extra_state_attributes(self) -> ClimateExtraAttributes:
"""Return the device specific state attributes."""

View File

@ -23,7 +23,12 @@ from homeassistant.components.climate import (
SERVICE_SET_TEMPERATURE,
HVACMode,
)
from homeassistant.components.fritzbox.climate import PRESET_HOLIDAY, PRESET_SUMMER
from homeassistant.components.fritzbox.climate import (
OFF_API_TEMPERATURE,
ON_API_TEMPERATURE,
PRESET_HOLIDAY,
PRESET_SUMMER,
)
from homeassistant.components.fritzbox.const import (
ATTR_STATE_BATTERY_LOW,
ATTR_STATE_HOLIDAY_MODE,
@ -367,9 +372,23 @@ async def test_set_hvac_mode(
assert device.set_target_temperature.call_args_list == expected_call_args
async def test_set_preset_mode_comfort(hass: HomeAssistant, fritz: Mock) -> None:
@pytest.mark.parametrize(
("comfort_temperature", "expected_call_args"),
[
(20, [call(20, True)]),
(28, [call(28, True)]),
(ON_API_TEMPERATURE, [call(30, True)]),
],
)
async def test_set_preset_mode_comfort(
hass: HomeAssistant,
fritz: Mock,
comfort_temperature: int,
expected_call_args: list[_Call],
) -> None:
"""Test setting preset mode."""
device = FritzDeviceClimateMock()
device.comfort_temperature = comfort_temperature
assert await setup_config_entry(
hass, MOCK_CONFIG[FB_DOMAIN][CONF_DEVICES][0], ENTITY_ID, device, fritz
)
@ -380,12 +399,27 @@ async def test_set_preset_mode_comfort(hass: HomeAssistant, fritz: Mock) -> None
{ATTR_ENTITY_ID: ENTITY_ID, ATTR_PRESET_MODE: PRESET_COMFORT},
True,
)
assert device.set_target_temperature.call_args_list == [call(22, True)]
assert device.set_target_temperature.call_count == len(expected_call_args)
assert device.set_target_temperature.call_args_list == expected_call_args
async def test_set_preset_mode_eco(hass: HomeAssistant, fritz: Mock) -> None:
@pytest.mark.parametrize(
("eco_temperature", "expected_call_args"),
[
(20, [call(20, True)]),
(16, [call(16, True)]),
(OFF_API_TEMPERATURE, [call(0, True)]),
],
)
async def test_set_preset_mode_eco(
hass: HomeAssistant,
fritz: Mock,
eco_temperature: int,
expected_call_args: list[_Call],
) -> None:
"""Test setting preset mode."""
device = FritzDeviceClimateMock()
device.eco_temperature = eco_temperature
assert await setup_config_entry(
hass, MOCK_CONFIG[FB_DOMAIN][CONF_DEVICES][0], ENTITY_ID, device, fritz
)
@ -396,7 +430,8 @@ async def test_set_preset_mode_eco(hass: HomeAssistant, fritz: Mock) -> None:
{ATTR_ENTITY_ID: ENTITY_ID, ATTR_PRESET_MODE: PRESET_ECO},
True,
)
assert device.set_target_temperature.call_args_list == [call(16, True)]
assert device.set_target_temperature.call_count == len(expected_call_args)
assert device.set_target_temperature.call_args_list == expected_call_args
async def test_preset_mode_update(hass: HomeAssistant, fritz: Mock) -> None: