mirror of
https://github.com/home-assistant/core.git
synced 2025-07-20 19:57:07 +00:00
Fix check for locked device in AVM Fritz!SmartHome (#141697)
* feat: raise execption on hvac mode while device is locked * fix: test for setting hvac mode while device is locked. * feat: update translation * feat: add separate translations for HVAC and temperature * fix: test cases * fix: test cases for test_set_preset_mode_boost * rev: code review * rev: exception string * feat: updated error message and added helper function * Update homeassistant/components/fritzbox/strings.json Co-authored-by: Michael <35783820+mib1185@users.noreply.github.com> * fix: translation key * remove check_active_or_lock_mode from async_set_preset_mode --------- Co-authored-by: Michael <35783820+mib1185@users.noreply.github.com>
This commit is contained in:
parent
debec3bfbc
commit
aea5760424
@ -144,6 +144,7 @@ class FritzboxThermostat(FritzBoxDeviceEntity, ClimateEntity):
|
|||||||
|
|
||||||
async def async_set_temperature(self, **kwargs: Any) -> None:
|
async def async_set_temperature(self, **kwargs: Any) -> None:
|
||||||
"""Set new target temperature."""
|
"""Set new target temperature."""
|
||||||
|
self.check_active_or_lock_mode()
|
||||||
if kwargs.get(ATTR_HVAC_MODE) is HVACMode.OFF:
|
if kwargs.get(ATTR_HVAC_MODE) is HVACMode.OFF:
|
||||||
await self.async_set_hkr_state("off")
|
await self.async_set_hkr_state("off")
|
||||||
elif (target_temp := kwargs.get(ATTR_TEMPERATURE)) is not None:
|
elif (target_temp := kwargs.get(ATTR_TEMPERATURE)) is not None:
|
||||||
@ -168,11 +169,7 @@ class FritzboxThermostat(FritzBoxDeviceEntity, ClimateEntity):
|
|||||||
|
|
||||||
async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None:
|
async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None:
|
||||||
"""Set new operation mode."""
|
"""Set new operation mode."""
|
||||||
if self.data.holiday_active or self.data.summer_active:
|
self.check_active_or_lock_mode()
|
||||||
raise HomeAssistantError(
|
|
||||||
translation_domain=DOMAIN,
|
|
||||||
translation_key="change_hvac_while_active_mode",
|
|
||||||
)
|
|
||||||
if self.hvac_mode is hvac_mode:
|
if self.hvac_mode is hvac_mode:
|
||||||
LOGGER.debug(
|
LOGGER.debug(
|
||||||
"%s is already in requested hvac mode %s", self.name, hvac_mode
|
"%s is already in requested hvac mode %s", self.name, hvac_mode
|
||||||
@ -204,11 +201,7 @@ class FritzboxThermostat(FritzBoxDeviceEntity, ClimateEntity):
|
|||||||
|
|
||||||
async def async_set_preset_mode(self, preset_mode: str) -> None:
|
async def async_set_preset_mode(self, preset_mode: str) -> None:
|
||||||
"""Set preset mode."""
|
"""Set preset mode."""
|
||||||
if self.data.holiday_active or self.data.summer_active:
|
self.check_active_or_lock_mode()
|
||||||
raise HomeAssistantError(
|
|
||||||
translation_domain=DOMAIN,
|
|
||||||
translation_key="change_preset_while_active_mode",
|
|
||||||
)
|
|
||||||
await self.async_set_hkr_state(PRESET_API_HKR_STATE_MAPPING[preset_mode])
|
await self.async_set_hkr_state(PRESET_API_HKR_STATE_MAPPING[preset_mode])
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@ -230,3 +223,17 @@ class FritzboxThermostat(FritzBoxDeviceEntity, ClimateEntity):
|
|||||||
attrs[ATTR_STATE_WINDOW_OPEN] = self.data.window_open
|
attrs[ATTR_STATE_WINDOW_OPEN] = self.data.window_open
|
||||||
|
|
||||||
return attrs
|
return attrs
|
||||||
|
|
||||||
|
def check_active_or_lock_mode(self) -> None:
|
||||||
|
"""Check if in summer/vacation mode or lock enabled."""
|
||||||
|
if self.data.holiday_active or self.data.summer_active:
|
||||||
|
raise HomeAssistantError(
|
||||||
|
translation_domain=DOMAIN,
|
||||||
|
translation_key="change_settings_while_active_mode",
|
||||||
|
)
|
||||||
|
|
||||||
|
if self.data.lock:
|
||||||
|
raise HomeAssistantError(
|
||||||
|
translation_domain=DOMAIN,
|
||||||
|
translation_key="change_settings_while_lock_enabled",
|
||||||
|
)
|
||||||
|
@ -88,11 +88,11 @@
|
|||||||
"manual_switching_disabled": {
|
"manual_switching_disabled": {
|
||||||
"message": "Can't toggle switch while manual switching is disabled for the device."
|
"message": "Can't toggle switch while manual switching is disabled for the device."
|
||||||
},
|
},
|
||||||
"change_preset_while_active_mode": {
|
"change_settings_while_lock_enabled": {
|
||||||
"message": "Can't change preset while holiday or summer mode is active on the device."
|
"message": "Can't change settings while manual access for telephone, app, or user interface is disabled on the device"
|
||||||
},
|
},
|
||||||
"change_hvac_while_active_mode": {
|
"change_settings_while_active_mode": {
|
||||||
"message": "Can't change HVAC mode while holiday or summer mode is active on the device."
|
"message": "Can't change settings while holiday or summer mode is active on the device."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -211,6 +211,8 @@ async def test_set_temperature(
|
|||||||
) -> None:
|
) -> None:
|
||||||
"""Test setting temperature."""
|
"""Test setting temperature."""
|
||||||
device = FritzDeviceClimateMock()
|
device = FritzDeviceClimateMock()
|
||||||
|
device.lock = False
|
||||||
|
|
||||||
await setup_config_entry(
|
await setup_config_entry(
|
||||||
hass, MOCK_CONFIG[FB_DOMAIN][CONF_DEVICES][0], ENTITY_ID, device, fritz
|
hass, MOCK_CONFIG[FB_DOMAIN][CONF_DEVICES][0], ENTITY_ID, device, fritz
|
||||||
)
|
)
|
||||||
@ -288,6 +290,8 @@ async def test_set_hvac_mode(
|
|||||||
) -> None:
|
) -> None:
|
||||||
"""Test setting hvac mode."""
|
"""Test setting hvac mode."""
|
||||||
device = FritzDeviceClimateMock()
|
device = FritzDeviceClimateMock()
|
||||||
|
|
||||||
|
device.lock = False
|
||||||
device.target_temperature = target_temperature
|
device.target_temperature = target_temperature
|
||||||
|
|
||||||
if current_preset is PRESET_COMFORT:
|
if current_preset is PRESET_COMFORT:
|
||||||
@ -335,6 +339,8 @@ async def test_set_preset_mode_comfort(
|
|||||||
) -> None:
|
) -> None:
|
||||||
"""Test setting preset mode."""
|
"""Test setting preset mode."""
|
||||||
device = FritzDeviceClimateMock()
|
device = FritzDeviceClimateMock()
|
||||||
|
|
||||||
|
device.lock = False
|
||||||
device.comfort_temperature = comfort_temperature
|
device.comfort_temperature = comfort_temperature
|
||||||
await setup_config_entry(
|
await setup_config_entry(
|
||||||
hass, MOCK_CONFIG[FB_DOMAIN][CONF_DEVICES][0], ENTITY_ID, device, fritz
|
hass, MOCK_CONFIG[FB_DOMAIN][CONF_DEVICES][0], ENTITY_ID, device, fritz
|
||||||
@ -366,6 +372,8 @@ async def test_set_preset_mode_eco(
|
|||||||
) -> None:
|
) -> None:
|
||||||
"""Test setting preset mode."""
|
"""Test setting preset mode."""
|
||||||
device = FritzDeviceClimateMock()
|
device = FritzDeviceClimateMock()
|
||||||
|
|
||||||
|
device.lock = False
|
||||||
device.eco_temperature = eco_temperature
|
device.eco_temperature = eco_temperature
|
||||||
await setup_config_entry(
|
await setup_config_entry(
|
||||||
hass, MOCK_CONFIG[FB_DOMAIN][CONF_DEVICES][0], ENTITY_ID, device, fritz
|
hass, MOCK_CONFIG[FB_DOMAIN][CONF_DEVICES][0], ENTITY_ID, device, fritz
|
||||||
@ -387,6 +395,8 @@ async def test_set_preset_mode_boost(
|
|||||||
) -> None:
|
) -> None:
|
||||||
"""Test setting preset mode."""
|
"""Test setting preset mode."""
|
||||||
device = FritzDeviceClimateMock()
|
device = FritzDeviceClimateMock()
|
||||||
|
device.lock = False
|
||||||
|
|
||||||
await setup_config_entry(
|
await setup_config_entry(
|
||||||
hass, MOCK_CONFIG[FB_DOMAIN][CONF_DEVICES][0], ENTITY_ID, device, fritz
|
hass, MOCK_CONFIG[FB_DOMAIN][CONF_DEVICES][0], ENTITY_ID, device, fritz
|
||||||
)
|
)
|
||||||
@ -471,11 +481,106 @@ async def test_discover_new_device(hass: HomeAssistant, fritz: Mock) -> None:
|
|||||||
assert state
|
assert state
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"service_data",
|
||||||
|
[
|
||||||
|
{ATTR_TEMPERATURE: 23},
|
||||||
|
{
|
||||||
|
ATTR_HVAC_MODE: HVACMode.HEAT,
|
||||||
|
ATTR_TEMPERATURE: 25,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
)
|
||||||
|
async def test_set_temperature_lock(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
fritz: Mock,
|
||||||
|
service_data: dict,
|
||||||
|
) -> None:
|
||||||
|
"""Test setting temperature while device is locked."""
|
||||||
|
device = FritzDeviceClimateMock()
|
||||||
|
|
||||||
|
device.lock = True
|
||||||
|
assert await setup_config_entry(
|
||||||
|
hass, MOCK_CONFIG[FB_DOMAIN][CONF_DEVICES][0], ENTITY_ID, device, fritz
|
||||||
|
)
|
||||||
|
|
||||||
|
with pytest.raises(
|
||||||
|
HomeAssistantError,
|
||||||
|
match="Can't change settings while manual access for telephone, app, or user interface is disabled on the device",
|
||||||
|
):
|
||||||
|
await hass.services.async_call(
|
||||||
|
CLIMATE_DOMAIN,
|
||||||
|
SERVICE_SET_TEMPERATURE,
|
||||||
|
{ATTR_ENTITY_ID: ENTITY_ID, **service_data},
|
||||||
|
True,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
("service_data", "target_temperature", "current_preset", "expected_call_args"),
|
||||||
|
[
|
||||||
|
# mode off always sets target temperature to 0
|
||||||
|
({ATTR_HVAC_MODE: HVACMode.OFF}, 22, PRESET_COMFORT, [call(0, True)]),
|
||||||
|
({ATTR_HVAC_MODE: HVACMode.OFF}, 16, PRESET_ECO, [call(0, True)]),
|
||||||
|
({ATTR_HVAC_MODE: HVACMode.OFF}, 16, None, [call(0, True)]),
|
||||||
|
# mode heat sets target temperature based on current scheduled preset,
|
||||||
|
# when not already in mode heat
|
||||||
|
({ATTR_HVAC_MODE: HVACMode.HEAT}, 0.0, PRESET_COMFORT, [call(22, True)]),
|
||||||
|
({ATTR_HVAC_MODE: HVACMode.HEAT}, 0.0, PRESET_ECO, [call(16, True)]),
|
||||||
|
({ATTR_HVAC_MODE: HVACMode.HEAT}, 0.0, None, [call(22, True)]),
|
||||||
|
# mode heat does not set target temperature, when already in mode heat
|
||||||
|
({ATTR_HVAC_MODE: HVACMode.HEAT}, 16, PRESET_COMFORT, []),
|
||||||
|
({ATTR_HVAC_MODE: HVACMode.HEAT}, 16, PRESET_ECO, []),
|
||||||
|
({ATTR_HVAC_MODE: HVACMode.HEAT}, 16, None, []),
|
||||||
|
({ATTR_HVAC_MODE: HVACMode.HEAT}, 22, PRESET_COMFORT, []),
|
||||||
|
({ATTR_HVAC_MODE: HVACMode.HEAT}, 22, PRESET_ECO, []),
|
||||||
|
({ATTR_HVAC_MODE: HVACMode.HEAT}, 22, None, []),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
async def test_set_hvac_mode_lock(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
fritz: Mock,
|
||||||
|
service_data: dict,
|
||||||
|
target_temperature: float,
|
||||||
|
current_preset: str,
|
||||||
|
expected_call_args: list[_Call],
|
||||||
|
) -> None:
|
||||||
|
"""Test setting hvac mode while device is locked."""
|
||||||
|
device = FritzDeviceClimateMock()
|
||||||
|
|
||||||
|
device.lock = True
|
||||||
|
device.target_temperature = target_temperature
|
||||||
|
|
||||||
|
if current_preset is PRESET_COMFORT:
|
||||||
|
device.nextchange_temperature = device.eco_temperature
|
||||||
|
elif current_preset is PRESET_ECO:
|
||||||
|
device.nextchange_temperature = device.comfort_temperature
|
||||||
|
else:
|
||||||
|
device.nextchange_endperiod = 0
|
||||||
|
|
||||||
|
assert await setup_config_entry(
|
||||||
|
hass, MOCK_CONFIG[FB_DOMAIN][CONF_DEVICES][0], ENTITY_ID, device, fritz
|
||||||
|
)
|
||||||
|
|
||||||
|
with pytest.raises(
|
||||||
|
HomeAssistantError,
|
||||||
|
match="Can't change settings while manual access for telephone, app, or user interface is disabled on the device",
|
||||||
|
):
|
||||||
|
await hass.services.async_call(
|
||||||
|
CLIMATE_DOMAIN,
|
||||||
|
SERVICE_SET_HVAC_MODE,
|
||||||
|
{ATTR_ENTITY_ID: ENTITY_ID, **service_data},
|
||||||
|
True,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
async def test_holidy_summer_mode(
|
async def test_holidy_summer_mode(
|
||||||
hass: HomeAssistant, freezer: FrozenDateTimeFactory, fritz: Mock
|
hass: HomeAssistant, freezer: FrozenDateTimeFactory, fritz: Mock
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test holiday and summer mode."""
|
"""Test holiday and summer mode."""
|
||||||
device = FritzDeviceClimateMock()
|
device = FritzDeviceClimateMock()
|
||||||
|
device.lock = False
|
||||||
|
|
||||||
await setup_config_entry(
|
await setup_config_entry(
|
||||||
hass, MOCK_CONFIG[FB_DOMAIN][CONF_DEVICES][0], ENTITY_ID, device, fritz
|
hass, MOCK_CONFIG[FB_DOMAIN][CONF_DEVICES][0], ENTITY_ID, device, fritz
|
||||||
)
|
)
|
||||||
@ -510,7 +615,7 @@ async def test_holidy_summer_mode(
|
|||||||
|
|
||||||
with pytest.raises(
|
with pytest.raises(
|
||||||
HomeAssistantError,
|
HomeAssistantError,
|
||||||
match="Can't change HVAC mode while holiday or summer mode is active on the device",
|
match="Can't change settings while holiday or summer mode is active on the device",
|
||||||
):
|
):
|
||||||
await hass.services.async_call(
|
await hass.services.async_call(
|
||||||
"climate",
|
"climate",
|
||||||
@ -520,7 +625,7 @@ async def test_holidy_summer_mode(
|
|||||||
)
|
)
|
||||||
with pytest.raises(
|
with pytest.raises(
|
||||||
HomeAssistantError,
|
HomeAssistantError,
|
||||||
match="Can't change preset while holiday or summer mode is active on the device",
|
match="Can't change settings while holiday or summer mode is active on the device",
|
||||||
):
|
):
|
||||||
await hass.services.async_call(
|
await hass.services.async_call(
|
||||||
"climate",
|
"climate",
|
||||||
@ -546,7 +651,7 @@ async def test_holidy_summer_mode(
|
|||||||
|
|
||||||
with pytest.raises(
|
with pytest.raises(
|
||||||
HomeAssistantError,
|
HomeAssistantError,
|
||||||
match="Can't change HVAC mode while holiday or summer mode is active on the device",
|
match="Can't change settings while holiday or summer mode is active on the device",
|
||||||
):
|
):
|
||||||
await hass.services.async_call(
|
await hass.services.async_call(
|
||||||
"climate",
|
"climate",
|
||||||
@ -556,7 +661,7 @@ async def test_holidy_summer_mode(
|
|||||||
)
|
)
|
||||||
with pytest.raises(
|
with pytest.raises(
|
||||||
HomeAssistantError,
|
HomeAssistantError,
|
||||||
match="Can't change preset while holiday or summer mode is active on the device",
|
match="Can't change settings while holiday or summer mode is active on the device",
|
||||||
):
|
):
|
||||||
await hass.services.async_call(
|
await hass.services.async_call(
|
||||||
"climate",
|
"climate",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user