From a852a38d24fd251b961720d02d54d45d28fa46da Mon Sep 17 00:00:00 2001 From: On Freund Date: Tue, 9 Apr 2024 10:59:27 +0300 Subject: [PATCH] Configurable maximum concurrency in Risco local (#115226) * Configurable maximum concurrency in Risco local * Show advanced Risco options in advanced mode --- homeassistant/components/risco/__init__.py | 7 ++- homeassistant/components/risco/config_flow.py | 20 +++++-- homeassistant/components/risco/const.py | 8 ++- homeassistant/components/risco/strings.json | 3 +- tests/components/risco/test_config_flow.py | 53 ++++++++++++++++++- 5 files changed, 83 insertions(+), 8 deletions(-) diff --git a/homeassistant/components/risco/__init__.py b/homeassistant/components/risco/__init__.py index 531cd982a1e..7ca18ea77c5 100644 --- a/homeassistant/components/risco/__init__.py +++ b/homeassistant/components/risco/__init__.py @@ -38,7 +38,9 @@ from homeassistant.helpers.storage import Store from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed from .const import ( + CONF_CONCURRENCY, DATA_COORDINATOR, + DEFAULT_CONCURRENCY, DEFAULT_SCAN_INTERVAL, DOMAIN, EVENTS_COORDINATOR, @@ -85,7 +87,10 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: async def _async_setup_local_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: data = entry.data - risco = RiscoLocal(data[CONF_HOST], data[CONF_PORT], data[CONF_PIN]) + concurrency = entry.options.get(CONF_CONCURRENCY, DEFAULT_CONCURRENCY) + risco = RiscoLocal( + data[CONF_HOST], data[CONF_PORT], data[CONF_PIN], concurrency=concurrency + ) try: await risco.connect() diff --git a/homeassistant/components/risco/config_flow.py b/homeassistant/components/risco/config_flow.py index ab372be3a14..21761e23d09 100644 --- a/homeassistant/components/risco/config_flow.py +++ b/homeassistant/components/risco/config_flow.py @@ -35,8 +35,10 @@ from .const import ( CONF_CODE_ARM_REQUIRED, CONF_CODE_DISARM_REQUIRED, CONF_COMMUNICATION_DELAY, + CONF_CONCURRENCY, CONF_HA_STATES_TO_RISCO, CONF_RISCO_STATES_TO_HA, + DEFAULT_ADVANCED_OPTIONS, DEFAULT_OPTIONS, DOMAIN, MAX_COMMUNICATION_DELAY, @@ -225,11 +227,8 @@ class RiscoOptionsFlowHandler(OptionsFlow): self._data = {**DEFAULT_OPTIONS, **config_entry.options} def _options_schema(self) -> vol.Schema: - return vol.Schema( + schema = vol.Schema( { - vol.Required( - CONF_SCAN_INTERVAL, default=self._data[CONF_SCAN_INTERVAL] - ): int, vol.Required( CONF_CODE_ARM_REQUIRED, default=self._data[CONF_CODE_ARM_REQUIRED] ): bool, @@ -239,6 +238,19 @@ class RiscoOptionsFlowHandler(OptionsFlow): ): bool, } ) + if self.show_advanced_options: + self._data = {**DEFAULT_ADVANCED_OPTIONS, **self._data} + schema = schema.extend( + { + vol.Required( + CONF_SCAN_INTERVAL, default=self._data[CONF_SCAN_INTERVAL] + ): int, + vol.Required( + CONF_CONCURRENCY, default=self._data[CONF_CONCURRENCY] + ): int, + } + ) + return schema async def async_step_init( self, user_input: dict[str, Any] | None = None diff --git a/homeassistant/components/risco/const.py b/homeassistant/components/risco/const.py index a27aeae4bf0..f1240a704de 100644 --- a/homeassistant/components/risco/const.py +++ b/homeassistant/components/risco/const.py @@ -14,6 +14,7 @@ DATA_COORDINATOR = "risco" EVENTS_COORDINATOR = "risco_events" DEFAULT_SCAN_INTERVAL = 30 +DEFAULT_CONCURRENCY = 4 TYPE_LOCAL = "local" @@ -25,6 +26,7 @@ CONF_CODE_DISARM_REQUIRED = "code_disarm_required" CONF_RISCO_STATES_TO_HA = "risco_states_to_ha" CONF_HA_STATES_TO_RISCO = "ha_states_to_risco" CONF_COMMUNICATION_DELAY = "communication_delay" +CONF_CONCURRENCY = "concurrency" RISCO_GROUPS = ["A", "B", "C", "D"] RISCO_ARM = "arm" @@ -44,9 +46,13 @@ DEFAULT_HA_STATES_TO_RISCO = { } DEFAULT_OPTIONS = { - CONF_SCAN_INTERVAL: DEFAULT_SCAN_INTERVAL, CONF_CODE_ARM_REQUIRED: False, CONF_CODE_DISARM_REQUIRED: False, CONF_RISCO_STATES_TO_HA: DEFAULT_RISCO_STATES_TO_HA, CONF_HA_STATES_TO_RISCO: DEFAULT_HA_STATES_TO_RISCO, } + +DEFAULT_ADVANCED_OPTIONS = { + CONF_SCAN_INTERVAL: DEFAULT_SCAN_INTERVAL, + CONF_CONCURRENCY: DEFAULT_CONCURRENCY, +} diff --git a/homeassistant/components/risco/strings.json b/homeassistant/components/risco/strings.json index 69d7e571f43..e35b13394cb 100644 --- a/homeassistant/components/risco/strings.json +++ b/homeassistant/components/risco/strings.json @@ -36,7 +36,8 @@ "init": { "title": "Configure options", "data": { - "scan_interval": "How often to poll Risco (in seconds)", + "scan_interval": "How often to poll Risco Cloud (in seconds)", + "concurrency": "Maximum concurrent requests in Risco local", "code_arm_required": "Require PIN to arm", "code_disarm_required": "Require PIN to disarm" } diff --git a/tests/components/risco/test_config_flow.py b/tests/components/risco/test_config_flow.py index 7589bc0ae14..9fade18ea96 100644 --- a/tests/components/risco/test_config_flow.py +++ b/tests/components/risco/test_config_flow.py @@ -46,11 +46,15 @@ TEST_HA_TO_RISCO = { } TEST_OPTIONS = { - "scan_interval": 10, "code_arm_required": True, "code_disarm_required": True, } +TEST_ADVANCED_OPTIONS = { + "scan_interval": 10, + "concurrency": 3, +} + async def test_cloud_form(hass: HomeAssistant) -> None: """Test we get the cloud form.""" @@ -387,6 +391,53 @@ async def test_options_flow(hass: HomeAssistant) -> None: } +async def test_advanced_options_flow(hass: HomeAssistant) -> None: + """Test options flow.""" + entry = MockConfigEntry( + domain=DOMAIN, + unique_id=TEST_CLOUD_DATA["username"], + data=TEST_CLOUD_DATA, + ) + + entry.add_to_hass(hass) + + result = await hass.config_entries.options.async_init( + entry.entry_id, context={"show_advanced_options": True} + ) + + assert result["type"] is FlowResultType.FORM + assert result["step_id"] == "init" + assert "concurrency" in result["data_schema"].schema + assert "scan_interval" in result["data_schema"].schema + result = await hass.config_entries.options.async_configure( + result["flow_id"], user_input={**TEST_OPTIONS, **TEST_ADVANCED_OPTIONS} + ) + assert result["type"] is FlowResultType.FORM + assert result["step_id"] == "risco_to_ha" + + result = await hass.config_entries.options.async_configure( + result["flow_id"], + user_input=TEST_RISCO_TO_HA, + ) + + assert result["type"] is FlowResultType.FORM + assert result["step_id"] == "ha_to_risco" + + with patch("homeassistant.components.risco.async_setup_entry", return_value=True): + result = await hass.config_entries.options.async_configure( + result["flow_id"], + user_input=TEST_HA_TO_RISCO, + ) + + assert result["type"] is FlowResultType.CREATE_ENTRY + assert entry.options == { + **TEST_OPTIONS, + **TEST_ADVANCED_OPTIONS, + "risco_states_to_ha": TEST_RISCO_TO_HA, + "ha_states_to_risco": TEST_HA_TO_RISCO, + } + + async def test_ha_to_risco_schema(hass: HomeAssistant) -> None: """Test that the schema for the ha-to-risco mapping step is generated properly.""" entry = MockConfigEntry(