diff --git a/homeassistant/components/simplisafe/.translations/en.json b/homeassistant/components/simplisafe/.translations/en.json index b000335af8f..7e9c26291f7 100644 --- a/homeassistant/components/simplisafe/.translations/en.json +++ b/homeassistant/components/simplisafe/.translations/en.json @@ -1,5 +1,8 @@ { "config": { + "abort": { + "already_configured": "This SimpliSafe account is already in use." + }, "error": { "identifier_exists": "Account already registered", "invalid_credentials": "Invalid credentials" diff --git a/homeassistant/components/simplisafe/config_flow.py b/homeassistant/components/simplisafe/config_flow.py index 9c93cd18626..5c7c6d7d450 100644 --- a/homeassistant/components/simplisafe/config_flow.py +++ b/homeassistant/components/simplisafe/config_flow.py @@ -1,6 +1,4 @@ """Config flow to configure the SimpliSafe component.""" -from collections import OrderedDict - from simplipy import API from simplipy.errors import SimplipyError import voluptuous as vol @@ -21,8 +19,7 @@ def configured_instances(hass): ) -@config_entries.HANDLERS.register(DOMAIN) -class SimpliSafeFlowHandler(config_entries.ConfigFlow): +class SimpliSafeFlowHandler(config_entries.ConfigFlow, domain=DOMAIN): """Handle a SimpliSafe config flow.""" VERSION = 1 @@ -30,16 +27,19 @@ class SimpliSafeFlowHandler(config_entries.ConfigFlow): def __init__(self): """Initialize the config flow.""" - self.data_schema = OrderedDict() - self.data_schema[vol.Required(CONF_USERNAME)] = str - self.data_schema[vol.Required(CONF_PASSWORD)] = str - self.data_schema[vol.Optional(CONF_CODE)] = str + self.data_schema = vol.Schema( + { + vol.Required(CONF_USERNAME): str, + vol.Required(CONF_PASSWORD): str, + vol.Optional(CONF_CODE): str, + } + ) async def _show_form(self, errors=None): """Show the form to the user.""" return self.async_show_form( step_id="user", - data_schema=vol.Schema(self.data_schema), + data_schema=self.data_schema, errors=errors if errors else {}, ) @@ -49,12 +49,11 @@ class SimpliSafeFlowHandler(config_entries.ConfigFlow): async def async_step_user(self, user_input=None): """Handle the start of the config flow.""" - if not user_input: return await self._show_form() - if user_input[CONF_USERNAME] in configured_instances(self.hass): - return await self._show_form({CONF_USERNAME: "identifier_exists"}) + await self.async_set_unique_id(user_input[CONF_USERNAME]) + self._abort_if_unique_id_configured() username = user_input[CONF_USERNAME] websession = aiohttp_client.async_get_clientsession(self.hass) @@ -64,7 +63,7 @@ class SimpliSafeFlowHandler(config_entries.ConfigFlow): username, user_input[CONF_PASSWORD], websession ) except SimplipyError: - return await self._show_form({"base": "invalid_credentials"}) + return await self._show_form(errors={"base": "invalid_credentials"}) return self.async_create_entry( title=user_input[CONF_USERNAME], diff --git a/homeassistant/components/simplisafe/strings.json b/homeassistant/components/simplisafe/strings.json index 5df0cf400d4..3043bd79104 100644 --- a/homeassistant/components/simplisafe/strings.json +++ b/homeassistant/components/simplisafe/strings.json @@ -14,6 +14,9 @@ "error": { "identifier_exists": "Account already registered", "invalid_credentials": "Invalid credentials" + }, + "abort": { + "already_configured": "This SimpliSafe account is already in use." } } } diff --git a/tests/components/simplisafe/test_config_flow.py b/tests/components/simplisafe/test_config_flow.py index 2d40495215a..eebb437d137 100644 --- a/tests/components/simplisafe/test_config_flow.py +++ b/tests/components/simplisafe/test_config_flow.py @@ -4,6 +4,7 @@ from unittest.mock import MagicMock, PropertyMock, mock_open, patch from homeassistant import data_entry_flow from homeassistant.components.simplisafe import DOMAIN, config_flow +from homeassistant.config_entries import SOURCE_USER from homeassistant.const import CONF_PASSWORD, CONF_TOKEN, CONF_USERNAME from tests.common import MockConfigEntry, mock_coro @@ -20,12 +21,27 @@ async def test_duplicate_error(hass): """Test that errors are shown when duplicates are added.""" conf = {CONF_USERNAME: "user@email.com", CONF_PASSWORD: "password"} - MockConfigEntry(domain=DOMAIN, data=conf).add_to_hass(hass) - flow = config_flow.SimpliSafeFlowHandler() - flow.hass = hass + MockConfigEntry(domain=DOMAIN, unique_id="user@email.com", data=conf).add_to_hass( + hass + ) - result = await flow.async_step_user(user_input=conf) - assert result["errors"] == {CONF_USERNAME: "identifier_exists"} + result = await hass.config_entries.flow.async_init( + DOMAIN, context={"source": SOURCE_USER}, data=conf + ) + + assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT + assert result["reason"] == "already_configured" + + +async def test_get_configured_instances(hass): + """Test retrieving all configured instances.""" + conf = {CONF_USERNAME: "user@email.com", CONF_PASSWORD: "password"} + + MockConfigEntry(domain=DOMAIN, unique_id="user@email.com", data=conf).add_to_hass( + hass + ) + + assert len(config_flow.configured_instances(hass)) == 1 async def test_invalid_credentials(hass): @@ -36,6 +52,7 @@ async def test_invalid_credentials(hass): flow = config_flow.SimpliSafeFlowHandler() flow.hass = hass + flow.context = {"source": SOURCE_USER} with patch( "simplipy.API.login_via_credentials", @@ -49,6 +66,7 @@ async def test_show_form(hass): """Test that the form is served with no input.""" flow = config_flow.SimpliSafeFlowHandler() flow.hass = hass + flow.context = {"source": SOURCE_USER} result = await flow.async_step_user(user_input=None) @@ -62,6 +80,7 @@ async def test_step_import(hass): flow = config_flow.SimpliSafeFlowHandler() flow.hass = hass + flow.context = {"source": SOURCE_USER} mop = mock_open(read_data=json.dumps({"refresh_token": "12345"})) @@ -91,6 +110,7 @@ async def test_step_user(hass): flow = config_flow.SimpliSafeFlowHandler() flow.hass = hass + flow.context = {"source": SOURCE_USER} mop = mock_open(read_data=json.dumps({"refresh_token": "12345"}))