Risco code review follow ups (#39143)
parent
45401d4308
commit
e3ce699d75
|
@ -4,19 +4,14 @@ import logging
|
||||||
from homeassistant.components.alarm_control_panel import AlarmControlPanelEntity
|
from homeassistant.components.alarm_control_panel import AlarmControlPanelEntity
|
||||||
from homeassistant.components.alarm_control_panel.const import (
|
from homeassistant.components.alarm_control_panel.const import (
|
||||||
SUPPORT_ALARM_ARM_AWAY,
|
SUPPORT_ALARM_ARM_AWAY,
|
||||||
SUPPORT_ALARM_ARM_CUSTOM_BYPASS,
|
|
||||||
SUPPORT_ALARM_ARM_HOME,
|
SUPPORT_ALARM_ARM_HOME,
|
||||||
SUPPORT_ALARM_ARM_NIGHT,
|
|
||||||
)
|
)
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
STATE_ALARM_ARMED_AWAY,
|
STATE_ALARM_ARMED_AWAY,
|
||||||
STATE_ALARM_ARMED_CUSTOM_BYPASS,
|
|
||||||
STATE_ALARM_ARMED_HOME,
|
STATE_ALARM_ARMED_HOME,
|
||||||
STATE_ALARM_ARMED_NIGHT,
|
|
||||||
STATE_ALARM_ARMING,
|
STATE_ALARM_ARMING,
|
||||||
STATE_ALARM_DISARMED,
|
STATE_ALARM_DISARMED,
|
||||||
STATE_ALARM_TRIGGERED,
|
STATE_ALARM_TRIGGERED,
|
||||||
STATE_UNKNOWN,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
from .const import DATA_COORDINATOR, DOMAIN
|
from .const import DATA_COORDINATOR, DOMAIN
|
||||||
|
@ -27,8 +22,6 @@ SUPPORTED_STATES = [
|
||||||
STATE_ALARM_DISARMED,
|
STATE_ALARM_DISARMED,
|
||||||
STATE_ALARM_ARMED_AWAY,
|
STATE_ALARM_ARMED_AWAY,
|
||||||
STATE_ALARM_ARMED_HOME,
|
STATE_ALARM_ARMED_HOME,
|
||||||
STATE_ALARM_ARMED_NIGHT,
|
|
||||||
STATE_ALARM_ARMED_CUSTOM_BYPASS,
|
|
||||||
STATE_ALARM_TRIGGERED,
|
STATE_ALARM_TRIGGERED,
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -37,8 +30,8 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
|
||||||
"""Set up the Risco alarm control panel."""
|
"""Set up the Risco alarm control panel."""
|
||||||
coordinator = hass.data[DOMAIN][config_entry.entry_id][DATA_COORDINATOR]
|
coordinator = hass.data[DOMAIN][config_entry.entry_id][DATA_COORDINATOR]
|
||||||
entities = [
|
entities = [
|
||||||
RiscoAlarm(hass, coordinator, partition_id)
|
RiscoAlarm(coordinator, partition_id)
|
||||||
for partition_id in coordinator.data.partitions.keys()
|
for partition_id in coordinator.data.partitions
|
||||||
]
|
]
|
||||||
|
|
||||||
async_add_entities(entities, False)
|
async_add_entities(entities, False)
|
||||||
|
@ -47,9 +40,8 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
|
||||||
class RiscoAlarm(AlarmControlPanelEntity):
|
class RiscoAlarm(AlarmControlPanelEntity):
|
||||||
"""Representation of a Risco partition."""
|
"""Representation of a Risco partition."""
|
||||||
|
|
||||||
def __init__(self, hass, coordinator, partition_id):
|
def __init__(self, coordinator, partition_id):
|
||||||
"""Init the partition."""
|
"""Init the partition."""
|
||||||
self._hass = hass
|
|
||||||
self._coordinator = coordinator
|
self._coordinator = coordinator
|
||||||
self._partition_id = partition_id
|
self._partition_id = partition_id
|
||||||
self._partition = self._coordinator.data.partitions[self._partition_id]
|
self._partition = self._coordinator.data.partitions[self._partition_id]
|
||||||
|
@ -112,17 +104,12 @@ class RiscoAlarm(AlarmControlPanelEntity):
|
||||||
if self._partition.disarmed:
|
if self._partition.disarmed:
|
||||||
return STATE_ALARM_DISARMED
|
return STATE_ALARM_DISARMED
|
||||||
|
|
||||||
return STATE_UNKNOWN
|
return None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def supported_features(self):
|
def supported_features(self):
|
||||||
"""Return the list of supported features."""
|
"""Return the list of supported features."""
|
||||||
return (
|
return SUPPORT_ALARM_ARM_HOME | SUPPORT_ALARM_ARM_AWAY
|
||||||
SUPPORT_ALARM_ARM_HOME
|
|
||||||
| SUPPORT_ALARM_ARM_AWAY
|
|
||||||
| SUPPORT_ALARM_ARM_NIGHT
|
|
||||||
| SUPPORT_ALARM_ARM_CUSTOM_BYPASS
|
|
||||||
)
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def code_arm_required(self):
|
def code_arm_required(self):
|
||||||
|
@ -137,14 +124,6 @@ class RiscoAlarm(AlarmControlPanelEntity):
|
||||||
"""Send arm home command."""
|
"""Send arm home command."""
|
||||||
await self._call_alarm_method("partial_arm")
|
await self._call_alarm_method("partial_arm")
|
||||||
|
|
||||||
async def async_alarm_arm_night(self, code=None):
|
|
||||||
"""Send arm night command."""
|
|
||||||
await self._call_alarm_method("partial_arm")
|
|
||||||
|
|
||||||
async def async_alarm_arm_custom_bypass(self, code=None):
|
|
||||||
"""Send arm custom bypass command."""
|
|
||||||
await self._call_alarm_method("partial_arm")
|
|
||||||
|
|
||||||
async def async_alarm_arm_away(self, code=None):
|
async def async_alarm_arm_away(self, code=None):
|
||||||
"""Send arm away command."""
|
"""Send arm away command."""
|
||||||
await self._call_alarm_method("arm")
|
await self._call_alarm_method("arm")
|
||||||
|
|
|
@ -41,10 +41,11 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
||||||
"""Handle the initial step."""
|
"""Handle the initial step."""
|
||||||
errors = {}
|
errors = {}
|
||||||
if user_input is not None:
|
if user_input is not None:
|
||||||
|
await self.async_set_unique_id(user_input[CONF_USERNAME])
|
||||||
|
self._abort_if_unique_id_configured()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
info = await validate_input(self.hass, user_input)
|
info = await validate_input(self.hass, user_input)
|
||||||
|
|
||||||
return self.async_create_entry(title=info["title"], data=user_input)
|
|
||||||
except CannotConnectError:
|
except CannotConnectError:
|
||||||
errors["base"] = "cannot_connect"
|
errors["base"] = "cannot_connect"
|
||||||
except UnauthorizedError:
|
except UnauthorizedError:
|
||||||
|
@ -52,6 +53,8 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
||||||
except Exception: # pylint: disable=broad-except
|
except Exception: # pylint: disable=broad-except
|
||||||
_LOGGER.exception("Unexpected exception")
|
_LOGGER.exception("Unexpected exception")
|
||||||
errors["base"] = "unknown"
|
errors["base"] = "unknown"
|
||||||
|
else:
|
||||||
|
return self.async_create_entry(title=info["title"], data=user_input)
|
||||||
|
|
||||||
return self.async_show_form(
|
return self.async_show_form(
|
||||||
step_id="user", data_schema=DATA_SCHEMA, errors=errors
|
step_id="user", data_schema=DATA_SCHEMA, errors=errors
|
||||||
|
|
|
@ -9,9 +9,7 @@ from homeassistant.const import (
|
||||||
CONF_PIN,
|
CONF_PIN,
|
||||||
CONF_USERNAME,
|
CONF_USERNAME,
|
||||||
SERVICE_ALARM_ARM_AWAY,
|
SERVICE_ALARM_ARM_AWAY,
|
||||||
SERVICE_ALARM_ARM_CUSTOM_BYPASS,
|
|
||||||
SERVICE_ALARM_ARM_HOME,
|
SERVICE_ALARM_ARM_HOME,
|
||||||
SERVICE_ALARM_ARM_NIGHT,
|
|
||||||
SERVICE_ALARM_DISARM,
|
SERVICE_ALARM_DISARM,
|
||||||
STATE_ALARM_ARMED_AWAY,
|
STATE_ALARM_ARMED_AWAY,
|
||||||
STATE_ALARM_ARMED_HOME,
|
STATE_ALARM_ARMED_HOME,
|
||||||
|
@ -22,7 +20,7 @@ from homeassistant.const import (
|
||||||
)
|
)
|
||||||
from homeassistant.helpers.entity_component import async_update_entity
|
from homeassistant.helpers.entity_component import async_update_entity
|
||||||
|
|
||||||
from tests.async_mock import AsyncMock, MagicMock, PropertyMock, patch
|
from tests.async_mock import MagicMock, PropertyMock, patch
|
||||||
from tests.common import MockConfigEntry
|
from tests.common import MockConfigEntry
|
||||||
|
|
||||||
TEST_CONFIG = {
|
TEST_CONFIG = {
|
||||||
|
@ -60,14 +58,15 @@ def two_part_alarm():
|
||||||
"partitions",
|
"partitions",
|
||||||
new_callable=PropertyMock(return_value=partition_mocks),
|
new_callable=PropertyMock(return_value=partition_mocks),
|
||||||
), patch(
|
), patch(
|
||||||
"homeassistant.components.risco.RiscoAPI.get_state",
|
"homeassistant.components.risco.RiscoAPI.get_state", return_value=alarm_mock,
|
||||||
AsyncMock(return_value=alarm_mock),
|
|
||||||
):
|
):
|
||||||
yield alarm_mock
|
yield alarm_mock
|
||||||
|
|
||||||
|
|
||||||
async def _setup_risco(hass, alarm=MagicMock()):
|
async def _setup_risco(hass, alarm=MagicMock()):
|
||||||
config_entry = MockConfigEntry(domain=DOMAIN, data=TEST_CONFIG)
|
config_entry = MockConfigEntry(domain=DOMAIN, data=TEST_CONFIG)
|
||||||
|
config_entry.add_to_hass(hass)
|
||||||
|
|
||||||
with patch(
|
with patch(
|
||||||
"homeassistant.components.risco.RiscoAPI.login", return_value=True,
|
"homeassistant.components.risco.RiscoAPI.login", return_value=True,
|
||||||
), patch(
|
), patch(
|
||||||
|
@ -77,9 +76,8 @@ async def _setup_risco(hass, alarm=MagicMock()):
|
||||||
"homeassistant.components.risco.RiscoAPI.site_name",
|
"homeassistant.components.risco.RiscoAPI.site_name",
|
||||||
new_callable=PropertyMock(return_value=TEST_SITE_NAME),
|
new_callable=PropertyMock(return_value=TEST_SITE_NAME),
|
||||||
), patch(
|
), patch(
|
||||||
"homeassistant.components.risco.RiscoAPI.close", AsyncMock()
|
"homeassistant.components.risco.RiscoAPI.close"
|
||||||
):
|
):
|
||||||
config_entry.add_to_hass(hass)
|
|
||||||
await hass.config_entries.async_setup(config_entry.entry_id)
|
await hass.config_entries.async_setup(config_entry.entry_id)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
@ -194,9 +192,7 @@ async def test_states(hass, two_part_alarm):
|
||||||
|
|
||||||
|
|
||||||
async def _test_servie_call(hass, service, method, entity_id, partition_id):
|
async def _test_servie_call(hass, service, method, entity_id, partition_id):
|
||||||
with patch(
|
with patch("homeassistant.components.risco.RiscoAPI." + method) as set_mock:
|
||||||
"homeassistant.components.risco.RiscoAPI." + method, AsyncMock()
|
|
||||||
) as set_mock:
|
|
||||||
await _call_alarm_service(hass, service, entity_id)
|
await _call_alarm_service(hass, service, entity_id)
|
||||||
set_mock.assert_awaited_once_with(partition_id)
|
set_mock.assert_awaited_once_with(partition_id)
|
||||||
|
|
||||||
|
@ -223,15 +219,3 @@ async def test_sets(hass, two_part_alarm):
|
||||||
await _test_servie_call(
|
await _test_servie_call(
|
||||||
hass, SERVICE_ALARM_ARM_HOME, "partial_arm", SECOND_ENTITY_ID, 1
|
hass, SERVICE_ALARM_ARM_HOME, "partial_arm", SECOND_ENTITY_ID, 1
|
||||||
)
|
)
|
||||||
await _test_servie_call(
|
|
||||||
hass, SERVICE_ALARM_ARM_NIGHT, "partial_arm", FIRST_ENTITY_ID, 0
|
|
||||||
)
|
|
||||||
await _test_servie_call(
|
|
||||||
hass, SERVICE_ALARM_ARM_NIGHT, "partial_arm", SECOND_ENTITY_ID, 1
|
|
||||||
)
|
|
||||||
await _test_servie_call(
|
|
||||||
hass, SERVICE_ALARM_ARM_CUSTOM_BYPASS, "partial_arm", FIRST_ENTITY_ID, 0
|
|
||||||
)
|
|
||||||
await _test_servie_call(
|
|
||||||
hass, SERVICE_ALARM_ARM_CUSTOM_BYPASS, "partial_arm", SECOND_ENTITY_ID, 1
|
|
||||||
)
|
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
"""Test the Risco config flow."""
|
"""Test the Risco config flow."""
|
||||||
from homeassistant import config_entries, setup
|
from homeassistant import config_entries
|
||||||
from homeassistant.components.risco.config_flow import (
|
from homeassistant.components.risco.config_flow import (
|
||||||
CannotConnectError,
|
CannotConnectError,
|
||||||
UnauthorizedError,
|
UnauthorizedError,
|
||||||
)
|
)
|
||||||
from homeassistant.components.risco.const import DOMAIN
|
from homeassistant.components.risco.const import DOMAIN
|
||||||
|
|
||||||
from tests.async_mock import AsyncMock, PropertyMock, patch
|
from tests.async_mock import PropertyMock, patch
|
||||||
|
from tests.common import MockConfigEntry
|
||||||
|
|
||||||
TEST_SITE_NAME = "test-site-name"
|
TEST_SITE_NAME = "test-site-name"
|
||||||
TEST_DATA = {
|
TEST_DATA = {
|
||||||
|
@ -18,7 +19,6 @@ TEST_DATA = {
|
||||||
|
|
||||||
async def test_form(hass):
|
async def test_form(hass):
|
||||||
"""Test we get the form."""
|
"""Test we get the form."""
|
||||||
await setup.async_setup_component(hass, "persistent_notification", {})
|
|
||||||
result = await hass.config_entries.flow.async_init(
|
result = await hass.config_entries.flow.async_init(
|
||||||
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
||||||
)
|
)
|
||||||
|
@ -31,7 +31,7 @@ async def test_form(hass):
|
||||||
"homeassistant.components.risco.config_flow.RiscoAPI.site_name",
|
"homeassistant.components.risco.config_flow.RiscoAPI.site_name",
|
||||||
new_callable=PropertyMock(return_value=TEST_SITE_NAME),
|
new_callable=PropertyMock(return_value=TEST_SITE_NAME),
|
||||||
), patch(
|
), patch(
|
||||||
"homeassistant.components.risco.config_flow.RiscoAPI.close", AsyncMock()
|
"homeassistant.components.risco.config_flow.RiscoAPI.close"
|
||||||
) as mock_close, patch(
|
) as mock_close, patch(
|
||||||
"homeassistant.components.risco.async_setup", return_value=True
|
"homeassistant.components.risco.async_setup", return_value=True
|
||||||
) as mock_setup, patch(
|
) as mock_setup, patch(
|
||||||
|
@ -59,9 +59,7 @@ async def test_form_invalid_auth(hass):
|
||||||
with patch(
|
with patch(
|
||||||
"homeassistant.components.risco.config_flow.RiscoAPI.login",
|
"homeassistant.components.risco.config_flow.RiscoAPI.login",
|
||||||
side_effect=UnauthorizedError,
|
side_effect=UnauthorizedError,
|
||||||
), patch(
|
), patch("homeassistant.components.risco.config_flow.RiscoAPI.close") as mock_close:
|
||||||
"homeassistant.components.risco.config_flow.RiscoAPI.close", AsyncMock()
|
|
||||||
) as mock_close:
|
|
||||||
result2 = await hass.config_entries.flow.async_configure(
|
result2 = await hass.config_entries.flow.async_configure(
|
||||||
result["flow_id"], TEST_DATA
|
result["flow_id"], TEST_DATA
|
||||||
)
|
)
|
||||||
|
@ -80,9 +78,7 @@ async def test_form_cannot_connect(hass):
|
||||||
with patch(
|
with patch(
|
||||||
"homeassistant.components.risco.config_flow.RiscoAPI.login",
|
"homeassistant.components.risco.config_flow.RiscoAPI.login",
|
||||||
side_effect=CannotConnectError,
|
side_effect=CannotConnectError,
|
||||||
), patch(
|
), patch("homeassistant.components.risco.config_flow.RiscoAPI.close") as mock_close:
|
||||||
"homeassistant.components.risco.config_flow.RiscoAPI.close", AsyncMock()
|
|
||||||
) as mock_close:
|
|
||||||
result2 = await hass.config_entries.flow.async_configure(
|
result2 = await hass.config_entries.flow.async_configure(
|
||||||
result["flow_id"], TEST_DATA
|
result["flow_id"], TEST_DATA
|
||||||
)
|
)
|
||||||
|
@ -101,9 +97,7 @@ async def test_form_exception(hass):
|
||||||
with patch(
|
with patch(
|
||||||
"homeassistant.components.risco.config_flow.RiscoAPI.login",
|
"homeassistant.components.risco.config_flow.RiscoAPI.login",
|
||||||
side_effect=Exception,
|
side_effect=Exception,
|
||||||
), patch(
|
), patch("homeassistant.components.risco.config_flow.RiscoAPI.close") as mock_close:
|
||||||
"homeassistant.components.risco.config_flow.RiscoAPI.close", AsyncMock()
|
|
||||||
) as mock_close:
|
|
||||||
result2 = await hass.config_entries.flow.async_configure(
|
result2 = await hass.config_entries.flow.async_configure(
|
||||||
result["flow_id"], TEST_DATA
|
result["flow_id"], TEST_DATA
|
||||||
)
|
)
|
||||||
|
@ -111,3 +105,24 @@ async def test_form_exception(hass):
|
||||||
assert result2["type"] == "form"
|
assert result2["type"] == "form"
|
||||||
assert result2["errors"] == {"base": "unknown"}
|
assert result2["errors"] == {"base": "unknown"}
|
||||||
mock_close.assert_awaited_once()
|
mock_close.assert_awaited_once()
|
||||||
|
|
||||||
|
|
||||||
|
async def test_form_already_exists(hass):
|
||||||
|
"""Test that a flow with an existing username aborts."""
|
||||||
|
entry = MockConfigEntry(
|
||||||
|
domain=DOMAIN, unique_id=TEST_DATA["username"], data=TEST_DATA,
|
||||||
|
)
|
||||||
|
|
||||||
|
entry.add_to_hass(hass)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
result = await hass.config_entries.flow.async_init(
|
||||||
|
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
||||||
|
)
|
||||||
|
|
||||||
|
result2 = await hass.config_entries.flow.async_configure(
|
||||||
|
result["flow_id"], TEST_DATA
|
||||||
|
)
|
||||||
|
|
||||||
|
assert result2["type"] == "abort"
|
||||||
|
assert result2["reason"] == "already_configured"
|
||||||
|
|
Loading…
Reference in New Issue