Skip to content
Snippets Groups Projects
Unverified Commit d4c5a93b authored by FredericMa's avatar FredericMa Committed by GitHub
Browse files

Add Risco communication delay (#101349)

* Add optional communication delay in case a panel responds slow.

* Add migration test

* Connect by increasing the communication delay

* Update init to use option instead of config

* Updated strings

* Fix migration and tests

* Review changes

* Update connect strategy

* Update tests

* Changes after review

* Change typing from object to Any.

* Add test to validate communication delay update.

* Move test to separate file

* Change filename.
parent 92b3c0c9
No related branches found
No related tags found
No related merge requests found
......@@ -35,10 +35,12 @@ from homeassistant.helpers.storage import Store
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
from .const import (
CONF_COMMUNICATION_DELAY,
DATA_COORDINATOR,
DEFAULT_SCAN_INTERVAL,
DOMAIN,
EVENTS_COORDINATOR,
MAX_COMMUNICATION_DELAY,
TYPE_LOCAL,
)
......@@ -81,15 +83,31 @@ 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])
try:
await risco.connect()
except CannotConnectError as error:
raise ConfigEntryNotReady() from error
except UnauthorizedError:
_LOGGER.exception("Failed to login to Risco cloud")
return False
comm_delay = initial_delay = data.get(CONF_COMMUNICATION_DELAY, 0)
while True:
risco = RiscoLocal(
data[CONF_HOST],
data[CONF_PORT],
data[CONF_PIN],
communication_delay=comm_delay,
)
try:
await risco.connect()
except CannotConnectError as error:
if comm_delay >= MAX_COMMUNICATION_DELAY:
raise ConfigEntryNotReady() from error
comm_delay += 1
except UnauthorizedError:
_LOGGER.exception("Failed to login to Risco cloud")
return False
else:
break
if comm_delay > initial_delay:
new_data = data.copy()
new_data[CONF_COMMUNICATION_DELAY] = comm_delay
hass.config_entries.async_update_entry(entry, data=new_data)
async def _error(error: Exception) -> None:
_LOGGER.error("Error in Risco library: %s", error)
......
......@@ -28,10 +28,12 @@ from homeassistant.helpers.aiohttp_client import async_get_clientsession
from .const import (
CONF_CODE_ARM_REQUIRED,
CONF_CODE_DISARM_REQUIRED,
CONF_COMMUNICATION_DELAY,
CONF_HA_STATES_TO_RISCO,
CONF_RISCO_STATES_TO_HA,
DEFAULT_OPTIONS,
DOMAIN,
MAX_COMMUNICATION_DELAY,
RISCO_STATES,
TYPE_LOCAL,
)
......@@ -78,16 +80,31 @@ async def validate_cloud_input(hass: core.HomeAssistant, data) -> dict[str, str]
async def validate_local_input(
hass: core.HomeAssistant, data: Mapping[str, str]
) -> dict[str, str]:
) -> dict[str, Any]:
"""Validate the user input allows us to connect to a local panel.
Data has the keys from LOCAL_SCHEMA with values provided by the user.
"""
risco = RiscoLocal(data[CONF_HOST], data[CONF_PORT], data[CONF_PIN])
await risco.connect()
comm_delay = 0
while True:
risco = RiscoLocal(
data[CONF_HOST],
data[CONF_PORT],
data[CONF_PIN],
communication_delay=comm_delay,
)
try:
await risco.connect()
except CannotConnectError as e:
if comm_delay >= MAX_COMMUNICATION_DELAY:
raise e
comm_delay += 1
else:
break
site_id = risco.id
await risco.disconnect()
return {"title": site_id}
return {"title": site_id, "comm_delay": comm_delay}
class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
......@@ -170,7 +187,12 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
self._abort_if_unique_id_configured()
return self.async_create_entry(
title=info["title"], data={**user_input, **{CONF_TYPE: TYPE_LOCAL}}
title=info["title"],
data={
**user_input,
**{CONF_TYPE: TYPE_LOCAL},
**{CONF_COMMUNICATION_DELAY: info["comm_delay"]},
},
)
return self.async_show_form(
......
......@@ -17,10 +17,13 @@ DEFAULT_SCAN_INTERVAL = 30
TYPE_LOCAL = "local"
MAX_COMMUNICATION_DELAY = 3
CONF_CODE_ARM_REQUIRED = "code_arm_required"
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"
RISCO_GROUPS = ["A", "B", "C", "D"]
RISCO_ARM = "arm"
......
......@@ -7,5 +7,5 @@
"iot_class": "local_push",
"loggers": ["pyrisco"],
"quality_scale": "platinum",
"requirements": ["pyrisco==0.5.7"]
"requirements": ["pyrisco==0.5.8"]
}
......@@ -2001,7 +2001,7 @@ pyrecswitch==1.0.2
pyrepetierng==0.1.0
# homeassistant.components.risco
pyrisco==0.5.7
pyrisco==0.5.8
# homeassistant.components.rituals_perfume_genie
pyrituals==0.0.6
......
......@@ -1508,7 +1508,7 @@ pyqwikswitch==0.93
pyrainbird==4.0.0
# homeassistant.components.risco
pyrisco==0.5.7
pyrisco==0.5.8
# homeassistant.components.rituals_perfume_genie
pyrituals==0.0.6
......
......@@ -171,6 +171,16 @@ def connect_with_error(exception):
yield
@pytest.fixture
def connect_with_single_error(exception):
"""Fixture to simulate error on connect."""
with patch(
"homeassistant.components.risco.RiscoLocal.connect",
side_effect=[exception, None],
):
yield
@pytest.fixture
async def setup_risco_local(hass, local_config_entry):
"""Set up a local Risco integration for testing."""
......
......@@ -9,7 +9,7 @@ from homeassistant.components.risco.config_flow import (
CannotConnectError,
UnauthorizedError,
)
from homeassistant.components.risco.const import DOMAIN
from homeassistant.components.risco.const import CONF_COMMUNICATION_DELAY, DOMAIN
from homeassistant.const import CONF_PASSWORD, CONF_USERNAME
from homeassistant.core import HomeAssistant
from homeassistant.data_entry_flow import FlowResultType
......@@ -246,7 +246,10 @@ async def test_local_form(hass: HomeAssistant) -> None:
)
await hass.async_block_till_done()
expected_data = {**TEST_LOCAL_DATA, **{"type": "local"}}
expected_data = {
**TEST_LOCAL_DATA,
**{"type": "local", CONF_COMMUNICATION_DELAY: 0},
}
assert result3["type"] == FlowResultType.CREATE_ENTRY
assert result3["title"] == TEST_SITE_NAME
assert result3["data"] == expected_data
......
"""Tests for the Risco initialization."""
import pytest
from homeassistant.components.risco import CannotConnectError
from homeassistant.components.risco.const import CONF_COMMUNICATION_DELAY
from homeassistant.core import HomeAssistant
@pytest.mark.parametrize("exception", [CannotConnectError])
async def test_single_error_on_connect(
hass: HomeAssistant, connect_with_single_error, local_config_entry
) -> None:
"""Test single error on connect to validate communication delay update from 0 (default) to 1."""
expected_data = {
**local_config_entry.data,
**{"type": "local", CONF_COMMUNICATION_DELAY: 1},
}
await hass.config_entries.async_setup(local_config_entry.entry_id)
await hass.async_block_till_done()
assert local_config_entry.data == expected_data
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment