mirror of
https://github.com/home-assistant/core.git
synced 2025-07-19 11:17:21 +00:00
Fix daikin discovery flow (#35767)
This commit is contained in:
parent
50105eed74
commit
d0e8880e48
@ -15,14 +15,6 @@ from .const import CONF_KEY, CONF_UUID, KEY_IP, KEY_MAC, TIMEOUT
|
|||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_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")
|
@config_entries.HANDLERS.register("daikin")
|
||||||
class FlowHandler(config_entries.ConfigFlow):
|
class FlowHandler(config_entries.ConfigFlow):
|
||||||
@ -31,12 +23,26 @@ class FlowHandler(config_entries.ConfigFlow):
|
|||||||
VERSION = 1
|
VERSION = 1
|
||||||
CONNECTION_CLASS = config_entries.CONN_CLASS_LOCAL_POLL
|
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."""
|
"""Register new entry."""
|
||||||
# Check if mac already is registered
|
# Check if mac already is registered
|
||||||
for entry in self._async_current_entries():
|
await self.async_set_unique_id(mac)
|
||||||
if entry.data[KEY_MAC] == mac:
|
self._abort_if_unique_id_configured()
|
||||||
return self.async_abort(reason="already_configured")
|
|
||||||
|
|
||||||
return self.async_create_entry(
|
return self.async_create_entry(
|
||||||
title=host,
|
title=host,
|
||||||
@ -73,31 +79,31 @@ class FlowHandler(config_entries.ConfigFlow):
|
|||||||
except asyncio.TimeoutError:
|
except asyncio.TimeoutError:
|
||||||
return self.async_show_form(
|
return self.async_show_form(
|
||||||
step_id="user",
|
step_id="user",
|
||||||
data_schema=DATA_SCHEMA,
|
data_schema=self.schema,
|
||||||
errors={"base": "device_timeout"},
|
errors={"base": "device_timeout"},
|
||||||
)
|
)
|
||||||
except web_exceptions.HTTPForbidden:
|
except web_exceptions.HTTPForbidden:
|
||||||
return self.async_show_form(
|
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:
|
except ClientError:
|
||||||
_LOGGER.exception("ClientError")
|
_LOGGER.exception("ClientError")
|
||||||
return self.async_show_form(
|
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
|
except Exception: # pylint: disable=broad-except
|
||||||
_LOGGER.exception("Unexpected error creating device")
|
_LOGGER.exception("Unexpected error creating device")
|
||||||
return self.async_show_form(
|
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
|
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):
|
async def async_step_user(self, user_input=None):
|
||||||
"""User initiated config flow."""
|
"""User initiated config flow."""
|
||||||
if user_input is None:
|
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(
|
return await self._create_device(
|
||||||
user_input[CONF_HOST],
|
user_input[CONF_HOST],
|
||||||
user_input.get(CONF_KEY),
|
user_input.get(CONF_KEY),
|
||||||
@ -111,7 +117,10 @@ class FlowHandler(config_entries.ConfigFlow):
|
|||||||
return await self.async_step_user()
|
return await self.async_step_user()
|
||||||
return await self._create_device(host)
|
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."""
|
"""Initialize step from discovery."""
|
||||||
_LOGGER.info("Discovered device: %s", user_input)
|
_LOGGER.debug("Discovered device: %s", discovery_info)
|
||||||
return self._create_entry(user_input[KEY_IP], user_input[KEY_MAC])
|
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()
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
"name": "Daikin AC",
|
"name": "Daikin AC",
|
||||||
"config_flow": true,
|
"config_flow": true,
|
||||||
"documentation": "https://www.home-assistant.io/integrations/daikin",
|
"documentation": "https://www.home-assistant.io/integrations/daikin",
|
||||||
"requirements": ["pydaikin==2.0.1"],
|
"requirements": ["pydaikin==2.0.2"],
|
||||||
"codeowners": ["@fredrike"],
|
"codeowners": ["@fredrike"],
|
||||||
"quality_scale": "platinum"
|
"quality_scale": "platinum"
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
"step": {
|
"step": {
|
||||||
"user": {
|
"user": {
|
||||||
"title": "Configure Daikin AC",
|
"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": {
|
"data": {
|
||||||
"host": "[%key:common::config_flow::data::host%]",
|
"host": "[%key:common::config_flow::data::host%]",
|
||||||
"key": "[%key:common::config_flow::data::api_key%]",
|
"key": "[%key:common::config_flow::data::api_key%]",
|
||||||
|
@ -1263,7 +1263,7 @@ pycsspeechtts==1.0.3
|
|||||||
# pycups==1.9.73
|
# pycups==1.9.73
|
||||||
|
|
||||||
# homeassistant.components.daikin
|
# homeassistant.components.daikin
|
||||||
pydaikin==2.0.1
|
pydaikin==2.0.2
|
||||||
|
|
||||||
# homeassistant.components.danfoss_air
|
# homeassistant.components.danfoss_air
|
||||||
pydanfossair==0.1.0
|
pydanfossair==0.1.0
|
||||||
|
@ -539,7 +539,7 @@ pychromecast==5.2.0
|
|||||||
pycoolmasternet==0.0.4
|
pycoolmasternet==0.0.4
|
||||||
|
|
||||||
# homeassistant.components.daikin
|
# homeassistant.components.daikin
|
||||||
pydaikin==2.0.1
|
pydaikin==2.0.2
|
||||||
|
|
||||||
# homeassistant.components.deconz
|
# homeassistant.components.deconz
|
||||||
pydeconz==70
|
pydeconz==70
|
||||||
|
@ -6,8 +6,8 @@ from aiohttp import ClientError
|
|||||||
from aiohttp.web_exceptions import HTTPForbidden
|
from aiohttp.web_exceptions import HTTPForbidden
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from homeassistant.components.daikin import config_flow
|
|
||||||
from homeassistant.components.daikin.const import KEY_IP, KEY_MAC
|
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.const import CONF_HOST
|
||||||
from homeassistant.data_entry_flow import (
|
from homeassistant.data_entry_flow import (
|
||||||
RESULT_TYPE_ABORT,
|
RESULT_TYPE_ABORT,
|
||||||
@ -22,13 +22,6 @@ MAC = "AABBCCDDEEFF"
|
|||||||
HOST = "127.0.0.1"
|
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
|
@pytest.fixture
|
||||||
def mock_daikin():
|
def mock_daikin():
|
||||||
"""Mock pydaikin."""
|
"""Mock pydaikin."""
|
||||||
@ -45,13 +38,16 @@ def mock_daikin():
|
|||||||
|
|
||||||
async def test_user(hass, mock_daikin):
|
async def test_user(hass, mock_daikin):
|
||||||
"""Test user config."""
|
"""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["type"] == RESULT_TYPE_FORM
|
||||||
assert result["step_id"] == "user"
|
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["type"] == RESULT_TYPE_CREATE_ENTRY
|
||||||
assert result["title"] == HOST
|
assert result["title"] == HOST
|
||||||
assert result["data"][CONF_HOST] == 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):
|
async def test_abort_if_already_setup(hass, mock_daikin):
|
||||||
"""Test we abort if Daikin is already setup."""
|
"""Test we abort if Daikin is already setup."""
|
||||||
flow = init_config_flow(hass)
|
MockConfigEntry(domain="daikin", unique_id=MAC).add_to_hass(hass)
|
||||||
MockConfigEntry(domain="daikin", data={KEY_MAC: 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["type"] == RESULT_TYPE_ABORT
|
||||||
assert result["reason"] == "already_configured"
|
assert result["reason"] == "already_configured"
|
||||||
|
|
||||||
|
|
||||||
async def test_import(hass, mock_daikin):
|
async def test_import(hass, mock_daikin):
|
||||||
"""Test import step."""
|
"""Test import step."""
|
||||||
flow = init_config_flow(hass)
|
result = await hass.config_entries.flow.async_init(
|
||||||
|
"daikin", context={"source": SOURCE_IMPORT}, data={},
|
||||||
result = await flow.async_step_import({})
|
)
|
||||||
assert result["type"] == RESULT_TYPE_FORM
|
assert result["type"] == RESULT_TYPE_FORM
|
||||||
assert result["step_id"] == "user"
|
assert result["step_id"] == "user"
|
||||||
|
|
||||||
result = await flow.async_step_import({CONF_HOST: HOST})
|
result = await hass.config_entries.flow.async_init(
|
||||||
assert result["type"] == RESULT_TYPE_CREATE_ENTRY
|
"daikin", context={"source": SOURCE_IMPORT}, data={CONF_HOST: HOST},
|
||||||
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})
|
|
||||||
assert result["type"] == RESULT_TYPE_CREATE_ENTRY
|
assert result["type"] == RESULT_TYPE_CREATE_ENTRY
|
||||||
assert result["title"] == HOST
|
assert result["title"] == HOST
|
||||||
assert result["data"][CONF_HOST] == 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):
|
async def test_device_abort(hass, mock_daikin, s_effect, reason):
|
||||||
"""Test device abort."""
|
"""Test device abort."""
|
||||||
flow = init_config_flow(hass)
|
|
||||||
mock_daikin.factory.side_effect = s_effect
|
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["type"] == RESULT_TYPE_FORM
|
||||||
assert result["errors"] == {"base": reason}
|
assert result["errors"] == {"base": reason}
|
||||||
assert result["step_id"] == "user"
|
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"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user