diff --git a/homeassistant/components/satel_integra/strings.json b/homeassistant/components/satel_integra/strings.json index 0440665956b..3cd2f74eafa 100644 --- a/homeassistant/components/satel_integra/strings.json +++ b/homeassistant/components/satel_integra/strings.json @@ -162,6 +162,11 @@ } } }, + "exceptions": { + "missing_output_access_code": { + "message": "Cannot control switchable outputs because no user code is configured for this Satel Integra entry. Configure a code in the integration options to enable output control." + } + }, "issues": { "deprecated_yaml_import_issue_cannot_connect": { "description": "Configuring {integration_title} using YAML is being removed but there was an connection error importing your existing configuration.\n\nEnsure connection to {integration_title} works and restart Home Assistant to try again or remove the `{domain}` YAML configuration from your configuration.yaml file and add the {integration_title} integration manually.", diff --git a/homeassistant/components/satel_integra/switch.py b/homeassistant/components/satel_integra/switch.py index 1c53ce7ee9e..4b33f7d4ef2 100644 --- a/homeassistant/components/satel_integra/switch.py +++ b/homeassistant/components/satel_integra/switch.py @@ -8,9 +8,14 @@ from homeassistant.components.switch import SwitchEntity from homeassistant.config_entries import ConfigSubentry from homeassistant.const import CONF_CODE from homeassistant.core import HomeAssistant, callback +from homeassistant.exceptions import ServiceValidationError from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback -from .const import CONF_SWITCHABLE_OUTPUT_NUMBER, SUBENTRY_TYPE_SWITCHABLE_OUTPUT +from .const import ( + CONF_SWITCHABLE_OUTPUT_NUMBER, + DOMAIN, + SUBENTRY_TYPE_SWITCHABLE_OUTPUT, +) from .coordinator import SatelConfigEntry, SatelIntegraOutputsCoordinator from .entity import SatelIntegraEntity @@ -83,12 +88,24 @@ class SatelIntegraSwitch( async def async_turn_on(self, **kwargs: Any) -> None: """Turn the device on.""" + if self._code is None: + raise ServiceValidationError( + translation_domain=DOMAIN, + translation_key="missing_output_access_code", + ) + await self._controller.set_output(self._code, self._device_number, True) self._attr_is_on = True self.async_write_ha_state() async def async_turn_off(self, **kwargs: Any) -> None: """Turn the device off.""" + if self._code is None: + raise ServiceValidationError( + translation_domain=DOMAIN, + translation_key="missing_output_access_code", + ) + await self._controller.set_output(self._code, self._device_number, False) self._attr_is_on = False self.async_write_ha_state() diff --git a/tests/components/satel_integra/test_switch.py b/tests/components/satel_integra/test_switch.py index 8a6a3bedc83..ec74103624f 100644 --- a/tests/components/satel_integra/test_switch.py +++ b/tests/components/satel_integra/test_switch.py @@ -15,12 +15,14 @@ from homeassistant.components.switch import ( ) from homeassistant.const import ( ATTR_ENTITY_ID, + CONF_CODE, STATE_OFF, STATE_ON, STATE_UNKNOWN, Platform, ) from homeassistant.core import HomeAssistant +from homeassistant.exceptions import ServiceValidationError from homeassistant.helpers.device_registry import DeviceRegistry from homeassistant.helpers.entity_registry import EntityRegistry @@ -176,3 +178,35 @@ async def test_switch_last_reported( assert first_reported != hass.states.get("switch.switchable_output").last_reported assert len(events) == 1 # last_reported shall not fire state_changed + + +async def test_switch_actions_require_code( + hass: HomeAssistant, + mock_satel: AsyncMock, + mock_config_entry_with_subentries: MockConfigEntry, +) -> None: + """Test switch actions fail when access code is missing.""" + + await setup_integration(hass, mock_config_entry_with_subentries) + + hass.config_entries.async_update_entry( + mock_config_entry_with_subentries, options={CONF_CODE: None} + ) + await hass.async_block_till_done() + + # Turning the device on or off should raise ServiceValidationError. + with pytest.raises(ServiceValidationError): + await hass.services.async_call( + SWITCH_DOMAIN, + SERVICE_TURN_ON, + {ATTR_ENTITY_ID: "switch.switchable_output"}, + blocking=True, + ) + + with pytest.raises(ServiceValidationError): + await hass.services.async_call( + SWITCH_DOMAIN, + SERVICE_TURN_OFF, + {ATTR_ENTITY_ID: "switch.switchable_output"}, + blocking=True, + )