diff --git a/homeassistant/components/rainmachine/__init__.py b/homeassistant/components/rainmachine/__init__.py index 411691ca9f50..5c3ff18f71c5 100644 --- a/homeassistant/components/rainmachine/__init__.py +++ b/homeassistant/components/rainmachine/__init__.py @@ -38,6 +38,7 @@ from homeassistant.util.network import is_ip_address from .config_flow import get_client_controller from .const import ( + CONF_ALLOW_INACTIVE_ZONES_TO_RUN, CONF_DEFAULT_ZONE_RUN_TIME, CONF_DURATION, CONF_USE_APP_RUN_TIMES, @@ -48,6 +49,7 @@ from .const import ( DATA_RESTRICTIONS_CURRENT, DATA_RESTRICTIONS_UNIVERSAL, DATA_ZONES, + DEFAULT_ZONE_RUN, DOMAIN, LOGGER, ) @@ -249,8 +251,13 @@ async def async_setup_entry( # noqa: C901 **entry.options, CONF_DEFAULT_ZONE_RUN_TIME: data.pop(CONF_DEFAULT_ZONE_RUN_TIME), } + entry_updates["options"] = {**entry.options} if CONF_USE_APP_RUN_TIMES not in entry.options: - entry_updates["options"] = {**entry.options, CONF_USE_APP_RUN_TIMES: False} + entry_updates["options"][CONF_USE_APP_RUN_TIMES] = False + if CONF_DEFAULT_ZONE_RUN_TIME not in entry.options: + entry_updates["options"][CONF_DEFAULT_ZONE_RUN_TIME] = DEFAULT_ZONE_RUN + if CONF_ALLOW_INACTIVE_ZONES_TO_RUN not in entry.options: + entry_updates["options"][CONF_ALLOW_INACTIVE_ZONES_TO_RUN] = False if entry_updates: hass.config_entries.async_update_entry(entry, **entry_updates) diff --git a/homeassistant/components/rainmachine/config_flow.py b/homeassistant/components/rainmachine/config_flow.py index 1ad97de7d0b4..1d73ef3dd881 100644 --- a/homeassistant/components/rainmachine/config_flow.py +++ b/homeassistant/components/rainmachine/config_flow.py @@ -17,6 +17,7 @@ from homeassistant.data_entry_flow import FlowResult from homeassistant.helpers import aiohttp_client, config_validation as cv from .const import ( + CONF_ALLOW_INACTIVE_ZONES_TO_RUN, CONF_DEFAULT_ZONE_RUN_TIME, CONF_USE_APP_RUN_TIMES, DEFAULT_PORT, @@ -188,6 +189,12 @@ class RainMachineOptionsFlowHandler(config_entries.OptionsFlow): CONF_USE_APP_RUN_TIMES, default=self.config_entry.options.get(CONF_USE_APP_RUN_TIMES), ): bool, + vol.Optional( + CONF_ALLOW_INACTIVE_ZONES_TO_RUN, + default=self.config_entry.options.get( + CONF_ALLOW_INACTIVE_ZONES_TO_RUN + ), + ): bool, } ), ) diff --git a/homeassistant/components/rainmachine/const.py b/homeassistant/components/rainmachine/const.py index 00af0bd0b75b..e28b2326b790 100644 --- a/homeassistant/components/rainmachine/const.py +++ b/homeassistant/components/rainmachine/const.py @@ -8,6 +8,7 @@ DOMAIN = "rainmachine" CONF_DURATION = "duration" CONF_DEFAULT_ZONE_RUN_TIME = "zone_run_time" CONF_USE_APP_RUN_TIMES = "use_app_run_times" +CONF_ALLOW_INACTIVE_ZONES_TO_RUN = "allow_inactive_zones_to_run" DATA_API_VERSIONS = "api.versions" DATA_MACHINE_FIRMWARE_UPDATE_STATUS = "machine.firmware_update_status" diff --git a/homeassistant/components/rainmachine/strings.json b/homeassistant/components/rainmachine/strings.json index ac2b86754e5d..a564d33e777d 100644 --- a/homeassistant/components/rainmachine/strings.json +++ b/homeassistant/components/rainmachine/strings.json @@ -24,7 +24,8 @@ "title": "Configure RainMachine", "data": { "zone_run_time": "Default zone run time (in seconds)", - "use_app_run_times": "Use zone run times from RainMachine app" + "use_app_run_times": "Use zone run times from the RainMachine app", + "allow_inactive_zones_to_run": "Allow disabled zones to be run manually" } } } diff --git a/homeassistant/components/rainmachine/switch.py b/homeassistant/components/rainmachine/switch.py index 0150f4cb6000..b47396bc9e52 100644 --- a/homeassistant/components/rainmachine/switch.py +++ b/homeassistant/components/rainmachine/switch.py @@ -20,6 +20,7 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback from . import RainMachineData, RainMachineEntity, async_update_programs_and_zones from .const import ( + CONF_ALLOW_INACTIVE_ZONES_TO_RUN, CONF_DEFAULT_ZONE_RUN_TIME, CONF_DURATION, CONF_USE_APP_RUN_TIMES, @@ -300,7 +301,10 @@ class RainMachineActivitySwitch(RainMachineBaseSwitch): The only way this could occur is if someone rapidly turns a disabled activity off right after turning it on. """ - if not self.coordinator.data[self.entity_description.uid]["active"]: + if ( + not self._entry.options[CONF_ALLOW_INACTIVE_ZONES_TO_RUN] + and not self.coordinator.data[self.entity_description.uid]["active"] + ): raise HomeAssistantError( f"Cannot turn off an inactive program/zone: {self.name}" ) @@ -314,7 +318,10 @@ class RainMachineActivitySwitch(RainMachineBaseSwitch): async def async_turn_on(self, **kwargs: Any) -> None: """Turn the switch on.""" - if not self.coordinator.data[self.entity_description.uid]["active"]: + if ( + not self._entry.options[CONF_ALLOW_INACTIVE_ZONES_TO_RUN] + and not self.coordinator.data[self.entity_description.uid]["active"] + ): self._attr_is_on = False self.async_write_ha_state() raise HomeAssistantError( diff --git a/tests/components/rainmachine/test_config_flow.py b/tests/components/rainmachine/test_config_flow.py index 5fa457bf771a..631f1d5a3f87 100644 --- a/tests/components/rainmachine/test_config_flow.py +++ b/tests/components/rainmachine/test_config_flow.py @@ -8,6 +8,7 @@ from regenmaschine.errors import RainMachineError from homeassistant import config_entries, data_entry_flow, setup from homeassistant.components import zeroconf from homeassistant.components.rainmachine import ( + CONF_ALLOW_INACTIVE_ZONES_TO_RUN, CONF_DEFAULT_ZONE_RUN_TIME, CONF_USE_APP_RUN_TIMES, DOMAIN, @@ -106,12 +107,17 @@ async def test_options_flow(hass: HomeAssistant, config, config_entry) -> None: result = await hass.config_entries.options.async_configure( result["flow_id"], - user_input={CONF_DEFAULT_ZONE_RUN_TIME: 600, CONF_USE_APP_RUN_TIMES: False}, + user_input={ + CONF_DEFAULT_ZONE_RUN_TIME: 600, + CONF_USE_APP_RUN_TIMES: False, + CONF_ALLOW_INACTIVE_ZONES_TO_RUN: False, + }, ) assert result["type"] == data_entry_flow.FlowResultType.CREATE_ENTRY assert config_entry.options == { CONF_DEFAULT_ZONE_RUN_TIME: 600, CONF_USE_APP_RUN_TIMES: False, + CONF_ALLOW_INACTIVE_ZONES_TO_RUN: False, } diff --git a/tests/components/rainmachine/test_diagnostics.py b/tests/components/rainmachine/test_diagnostics.py index 47cb32020262..2180bf2a20e0 100644 --- a/tests/components/rainmachine/test_diagnostics.py +++ b/tests/components/rainmachine/test_diagnostics.py @@ -2,6 +2,7 @@ from regenmaschine.errors import RainMachineError from homeassistant.components.diagnostics import REDACTED +from homeassistant.components.rainmachine.const import DEFAULT_ZONE_RUN from homeassistant.core import HomeAssistant from tests.components.diagnostics import get_diagnostics_for_config_entry @@ -28,7 +29,11 @@ async def test_entry_diagnostics( "port": 8080, "ssl": True, }, - "options": {"use_app_run_times": False}, + "options": { + "zone_run_time": DEFAULT_ZONE_RUN, + "use_app_run_times": False, + "allow_inactive_zones_to_run": False, + }, "pref_disable_new_entities": False, "pref_disable_polling": False, "source": "user", @@ -655,7 +660,11 @@ async def test_entry_diagnostics_failed_controller_diagnostics( "port": 8080, "ssl": True, }, - "options": {"use_app_run_times": False}, + "options": { + "zone_run_time": DEFAULT_ZONE_RUN, + "use_app_run_times": False, + "allow_inactive_zones_to_run": False, + }, "pref_disable_new_entities": False, "pref_disable_polling": False, "source": "user",