diff --git a/homeassistant/components/fritzbox/strings.json b/homeassistant/components/fritzbox/strings.json index cee0afa26c1..d4f59fd1c08 100644 --- a/homeassistant/components/fritzbox/strings.json +++ b/homeassistant/components/fritzbox/strings.json @@ -81,6 +81,9 @@ } }, "exceptions": { + "manual_switching_disabled": { + "message": "Can't toggle switch while manual switching is disabled for the device." + }, "change_preset_while_active_mode": { "message": "Can't change preset while holiday or summer mode is active on the device." }, diff --git a/homeassistant/components/fritzbox/switch.py b/homeassistant/components/fritzbox/switch.py index 0bdf7a9f944..d13f21e1c14 100644 --- a/homeassistant/components/fritzbox/switch.py +++ b/homeassistant/components/fritzbox/switch.py @@ -6,9 +6,11 @@ from typing import Any from homeassistant.components.switch import SwitchEntity from homeassistant.core import HomeAssistant, callback +from homeassistant.exceptions import HomeAssistantError from homeassistant.helpers.entity_platform import AddEntitiesCallback from . import FritzBoxDeviceEntity +from .const import DOMAIN from .coordinator import FritzboxConfigEntry @@ -48,10 +50,20 @@ class FritzboxSwitch(FritzBoxDeviceEntity, SwitchEntity): async def async_turn_on(self, **kwargs: Any) -> None: """Turn the switch on.""" + self.check_lock_state() await self.hass.async_add_executor_job(self.data.set_switch_state_on) await self.coordinator.async_refresh() async def async_turn_off(self, **kwargs: Any) -> None: """Turn the switch off.""" + self.check_lock_state() await self.hass.async_add_executor_job(self.data.set_switch_state_off) await self.coordinator.async_refresh() + + def check_lock_state(self) -> None: + """Raise an Error if manual switching via FRITZ!Box user interface is disabled.""" + if self.data.lock: + raise HomeAssistantError( + translation_domain=DOMAIN, + translation_key="manual_switching_disabled", + ) diff --git a/tests/components/fritzbox/__init__.py b/tests/components/fritzbox/__init__.py index 2bd8f26d73b..61312805e91 100644 --- a/tests/components/fritzbox/__init__.py +++ b/tests/components/fritzbox/__init__.py @@ -151,7 +151,7 @@ class FritzDeviceSwitchMock(FritzEntityBaseMock): has_thermostat = False has_blind = False switch_state = "fake_state" - lock = "fake_locked" + lock = False power = 5678 present = True temperature = 1.23 diff --git a/tests/components/fritzbox/test_switch.py b/tests/components/fritzbox/test_switch.py index 417b355b396..ba3b1de9b2f 100644 --- a/tests/components/fritzbox/test_switch.py +++ b/tests/components/fritzbox/test_switch.py @@ -3,6 +3,7 @@ from datetime import timedelta from unittest.mock import Mock +import pytest from requests.exceptions import HTTPError from homeassistant.components.fritzbox.const import DOMAIN as FB_DOMAIN @@ -29,6 +30,7 @@ from homeassistant.const import ( UnitOfTemperature, ) from homeassistant.core import HomeAssistant +from homeassistant.exceptions import HomeAssistantError from homeassistant.helpers import entity_registry as er import homeassistant.util.dt as dt_util @@ -130,6 +132,7 @@ async def test_turn_on(hass: HomeAssistant, fritz: Mock) -> None: async def test_turn_off(hass: HomeAssistant, fritz: Mock) -> None: """Test turn device off.""" device = FritzDeviceSwitchMock() + assert await setup_config_entry( hass, MOCK_CONFIG[FB_DOMAIN][CONF_DEVICES][0], ENTITY_ID, device, fritz ) @@ -137,9 +140,36 @@ async def test_turn_off(hass: HomeAssistant, fritz: Mock) -> None: await hass.services.async_call( DOMAIN, SERVICE_TURN_OFF, {ATTR_ENTITY_ID: ENTITY_ID}, True ) + assert device.set_switch_state_off.call_count == 1 +async def test_toggle_while_locked(hass: HomeAssistant, fritz: Mock) -> None: + """Test toggling while device is locked.""" + device = FritzDeviceSwitchMock() + 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 toggle switch while manual switching is disabled for the device", + ): + await hass.services.async_call( + DOMAIN, SERVICE_TURN_OFF, {ATTR_ENTITY_ID: ENTITY_ID}, True + ) + + with pytest.raises( + HomeAssistantError, + match="Can't toggle switch while manual switching is disabled for the device", + ): + await hass.services.async_call( + DOMAIN, SERVICE_TURN_ON, {ATTR_ENTITY_ID: ENTITY_ID}, True + ) + + async def test_update(hass: HomeAssistant, fritz: Mock) -> None: """Test update without error.""" device = FritzDeviceSwitchMock()