diff --git a/homeassistant/components/daikin/config_flow.py b/homeassistant/components/daikin/config_flow.py index 8dc491ac868..cd5be5cef29 100644 --- a/homeassistant/components/daikin/config_flow.py +++ b/homeassistant/components/daikin/config_flow.py @@ -15,14 +15,6 @@ from .const import CONF_KEY, CONF_UUID, KEY_IP, KEY_MAC, TIMEOUT _LOGGER = logging.getLogger(__name__) -DATA_SCHEMA = vol.Schema( - { - vol.Required(CONF_HOST): str, - vol.Optional(CONF_KEY): str, - vol.Optional(CONF_PASSWORD): str, - } -) - @config_entries.HANDLERS.register("daikin") class FlowHandler(config_entries.ConfigFlow): @@ -31,12 +23,26 @@ class FlowHandler(config_entries.ConfigFlow): VERSION = 1 CONNECTION_CLASS = config_entries.CONN_CLASS_LOCAL_POLL - def _create_entry(self, host, mac, key=None, uuid=None, password=None): + def __init__(self): + """Initialize the Daikin config flow.""" + self.host = None + + @property + def schema(self): + """Return current schema.""" + return vol.Schema( + { + vol.Required(CONF_HOST, default=self.host): str, + vol.Optional(CONF_KEY): str, + vol.Optional(CONF_PASSWORD): str, + } + ) + + async def _create_entry(self, host, mac, key=None, uuid=None, password=None): """Register new entry.""" # Check if mac already is registered - for entry in self._async_current_entries(): - if entry.data[KEY_MAC] == mac: - return self.async_abort(reason="already_configured") + await self.async_set_unique_id(mac) + self._abort_if_unique_id_configured() return self.async_create_entry( title=host, @@ -73,31 +79,31 @@ class FlowHandler(config_entries.ConfigFlow): except asyncio.TimeoutError: return self.async_show_form( step_id="user", - data_schema=DATA_SCHEMA, + data_schema=self.schema, errors={"base": "device_timeout"}, ) except web_exceptions.HTTPForbidden: return self.async_show_form( - step_id="user", data_schema=DATA_SCHEMA, errors={"base": "forbidden"}, + step_id="user", data_schema=self.schema, errors={"base": "forbidden"}, ) except ClientError: _LOGGER.exception("ClientError") return self.async_show_form( - step_id="user", data_schema=DATA_SCHEMA, errors={"base": "device_fail"}, + step_id="user", data_schema=self.schema, errors={"base": "device_fail"}, ) except Exception: # pylint: disable=broad-except _LOGGER.exception("Unexpected error creating device") return self.async_show_form( - step_id="user", data_schema=DATA_SCHEMA, errors={"base": "device_fail"}, + step_id="user", data_schema=self.schema, errors={"base": "device_fail"}, ) mac = device.mac - return self._create_entry(host, mac, key, uuid, password) + return await self._create_entry(host, mac, key, uuid, password) async def async_step_user(self, user_input=None): """User initiated config flow.""" if user_input is None: - return self.async_show_form(step_id="user", data_schema=DATA_SCHEMA,) + return self.async_show_form(step_id="user", data_schema=self.schema) return await self._create_device( user_input[CONF_HOST], user_input.get(CONF_KEY), @@ -111,7 +117,10 @@ class FlowHandler(config_entries.ConfigFlow): return await self.async_step_user() return await self._create_device(host) - async def async_step_discovery(self, user_input): + async def async_step_discovery(self, discovery_info): """Initialize step from discovery.""" - _LOGGER.info("Discovered device: %s", user_input) - return self._create_entry(user_input[KEY_IP], user_input[KEY_MAC]) + _LOGGER.debug("Discovered device: %s", discovery_info) + await self.async_set_unique_id(discovery_info[KEY_MAC]) + self._abort_if_unique_id_configured() + self.host = discovery_info[KEY_IP] + return await self.async_step_user() diff --git a/homeassistant/components/daikin/manifest.json b/homeassistant/components/daikin/manifest.json index c554e882b48..9732962de5a 100644 --- a/homeassistant/components/daikin/manifest.json +++ b/homeassistant/components/daikin/manifest.json @@ -3,7 +3,7 @@ "name": "Daikin AC", "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/daikin", - "requirements": ["pydaikin==2.0.1"], + "requirements": ["pydaikin==2.0.2"], "codeowners": ["@fredrike"], "quality_scale": "platinum" } diff --git a/homeassistant/components/daikin/strings.json b/homeassistant/components/daikin/strings.json index 0286ca00c32..c60163577a6 100644 --- a/homeassistant/components/daikin/strings.json +++ b/homeassistant/components/daikin/strings.json @@ -3,7 +3,7 @@ "step": { "user": { "title": "Configure Daikin AC", - "description": "Enter IP address of your Daikin AC.", + "description": "Enter IP address of your Daikin AC.\n\nNote that [%key:common::config_flow::data::api_key%] and [%key:common::config_flow::data::password%] are used by BRP072Cxx and SKYFi devices respectively.", "data": { "host": "[%key:common::config_flow::data::host%]", "key": "[%key:common::config_flow::data::api_key%]", diff --git a/requirements_all.txt b/requirements_all.txt index f488e6c94f5..a1196251b0f 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1263,7 +1263,7 @@ pycsspeechtts==1.0.3 # pycups==1.9.73 # homeassistant.components.daikin -pydaikin==2.0.1 +pydaikin==2.0.2 # homeassistant.components.danfoss_air pydanfossair==0.1.0 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 4dde6361d6c..b3afbc47a9d 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -539,7 +539,7 @@ pychromecast==5.2.0 pycoolmasternet==0.0.4 # homeassistant.components.daikin -pydaikin==2.0.1 +pydaikin==2.0.2 # homeassistant.components.deconz pydeconz==70 diff --git a/tests/components/daikin/test_config_flow.py b/tests/components/daikin/test_config_flow.py index 83e13047f80..25fc8ba26f2 100644 --- a/tests/components/daikin/test_config_flow.py +++ b/tests/components/daikin/test_config_flow.py @@ -6,8 +6,8 @@ from aiohttp import ClientError from aiohttp.web_exceptions import HTTPForbidden import pytest -from homeassistant.components.daikin import config_flow from homeassistant.components.daikin.const import KEY_IP, KEY_MAC +from homeassistant.config_entries import SOURCE_DISCOVERY, SOURCE_IMPORT, SOURCE_USER from homeassistant.const import CONF_HOST from homeassistant.data_entry_flow import ( RESULT_TYPE_ABORT, @@ -22,13 +22,6 @@ MAC = "AABBCCDDEEFF" HOST = "127.0.0.1" -def init_config_flow(hass): - """Init a configuration flow.""" - flow = config_flow.FlowHandler() - flow.hass = hass - return flow - - @pytest.fixture def mock_daikin(): """Mock pydaikin.""" @@ -45,13 +38,16 @@ def mock_daikin(): async def test_user(hass, mock_daikin): """Test user config.""" - flow = init_config_flow(hass) + result = await hass.config_entries.flow.async_init( + "daikin", context={"source": SOURCE_USER}, + ) - result = await flow.async_step_user() assert result["type"] == RESULT_TYPE_FORM assert result["step_id"] == "user" - result = await flow.async_step_user({CONF_HOST: HOST}) + result = await hass.config_entries.flow.async_init( + "daikin", context={"source": SOURCE_USER}, data={CONF_HOST: HOST}, + ) assert result["type"] == RESULT_TYPE_CREATE_ENTRY assert result["title"] == HOST assert result["data"][CONF_HOST] == HOST @@ -60,34 +56,26 @@ async def test_user(hass, mock_daikin): async def test_abort_if_already_setup(hass, mock_daikin): """Test we abort if Daikin is already setup.""" - flow = init_config_flow(hass) - MockConfigEntry(domain="daikin", data={KEY_MAC: MAC}).add_to_hass(hass) + MockConfigEntry(domain="daikin", unique_id=MAC).add_to_hass(hass) + result = await hass.config_entries.flow.async_init( + "daikin", context={"source": SOURCE_USER}, data={CONF_HOST: HOST, KEY_MAC: MAC}, + ) - result = await flow.async_step_user({CONF_HOST: HOST}) assert result["type"] == RESULT_TYPE_ABORT assert result["reason"] == "already_configured" async def test_import(hass, mock_daikin): """Test import step.""" - flow = init_config_flow(hass) - - result = await flow.async_step_import({}) + result = await hass.config_entries.flow.async_init( + "daikin", context={"source": SOURCE_IMPORT}, data={}, + ) assert result["type"] == RESULT_TYPE_FORM assert result["step_id"] == "user" - result = await flow.async_step_import({CONF_HOST: HOST}) - assert result["type"] == RESULT_TYPE_CREATE_ENTRY - assert result["title"] == HOST - assert result["data"][CONF_HOST] == HOST - assert result["data"][KEY_MAC] == MAC - - -async def test_discovery(hass, mock_daikin): - """Test discovery step.""" - flow = init_config_flow(hass) - - result = await flow.async_step_discovery({KEY_IP: HOST, KEY_MAC: MAC}) + result = await hass.config_entries.flow.async_init( + "daikin", context={"source": SOURCE_IMPORT}, data={CONF_HOST: HOST}, + ) assert result["type"] == RESULT_TYPE_CREATE_ENTRY assert result["title"] == HOST assert result["data"][CONF_HOST] == HOST @@ -105,10 +93,31 @@ async def test_discovery(hass, mock_daikin): ) async def test_device_abort(hass, mock_daikin, s_effect, reason): """Test device abort.""" - flow = init_config_flow(hass) mock_daikin.factory.side_effect = s_effect - result = await flow.async_step_user({CONF_HOST: HOST}) + result = await hass.config_entries.flow.async_init( + "daikin", context={"source": SOURCE_USER}, data={CONF_HOST: HOST, KEY_MAC: MAC}, + ) assert result["type"] == RESULT_TYPE_FORM assert result["errors"] == {"base": reason} assert result["step_id"] == "user" + + +@pytest.mark.parametrize( + "source, data, unique_id", [(SOURCE_DISCOVERY, {KEY_IP: HOST, KEY_MAC: MAC}, MAC)], +) +async def test_discovery(hass, mock_daikin, source, data, unique_id): + """Test discovery/zeroconf step.""" + result = await hass.config_entries.flow.async_init( + "daikin", context={"source": source}, data=data, + ) + assert result["type"] == RESULT_TYPE_FORM + assert result["step_id"] == "user" + + MockConfigEntry(domain="daikin", unique_id=unique_id).add_to_hass(hass) + result = await hass.config_entries.flow.async_init( + "daikin", context={"source": source}, data=data, + ) + + assert result["type"] == RESULT_TYPE_ABORT + assert result["reason"] == "already_in_progress"