Skip to content
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 27 additions & 9 deletions homeassistant/components/risco/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,12 @@
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,
)

Expand Down Expand Up @@ -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()
Comment thread
FredericMa marked this conversation as resolved.
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)
Expand Down
32 changes: 27 additions & 5 deletions homeassistant/components/risco/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,12 @@
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,
)
Expand Down Expand Up @@ -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):
Expand Down Expand Up @@ -170,7 +187,12 @@ async def async_step_local(self, user_input=None):
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(
Expand Down
3 changes: 3 additions & 0 deletions homeassistant/components/risco/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,13 @@

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"
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/risco/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@
"iot_class": "local_push",
"loggers": ["pyrisco"],
"quality_scale": "platinum",
"requirements": ["pyrisco==0.5.7"]
"requirements": ["pyrisco==0.5.8"]
}
2 changes: 1 addition & 1 deletion requirements_all.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion requirements_test_all.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
10 changes: 10 additions & 0 deletions tests/components/risco/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -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."""
Expand Down
7 changes: 5 additions & 2 deletions tests/components/risco/test_config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
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
Expand Down Expand Up @@ -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
Expand Down
21 changes: 21 additions & 0 deletions tests/components/risco/test_connect.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
"""Tests for the Risco connect logic."""
Comment thread
FredericMa marked this conversation as resolved.
Outdated
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