mirror of
https://github.com/home-assistant/core.git
synced 2025-07-19 19:27:45 +00:00
Add intellifire UDP discovery at configuration start (#67002)
Co-authored-by: J. Nick Koston <nick@koston.org>
This commit is contained in:
parent
8e76948297
commit
cea21a00b3
@ -4,29 +4,31 @@ from __future__ import annotations
|
|||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from aiohttp import ClientConnectionError
|
from aiohttp import ClientConnectionError
|
||||||
from intellifire4py import IntellifireAsync
|
from intellifire4py import AsyncUDPFireplaceFinder, IntellifireAsync
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
from homeassistant import config_entries
|
from homeassistant import config_entries
|
||||||
from homeassistant.const import CONF_HOST
|
from homeassistant.const import CONF_HOST
|
||||||
from homeassistant.core import HomeAssistant
|
|
||||||
from homeassistant.data_entry_flow import FlowResult
|
from homeassistant.data_entry_flow import FlowResult
|
||||||
|
|
||||||
from .const import DOMAIN
|
from .const import DOMAIN, LOGGER
|
||||||
|
|
||||||
STEP_USER_DATA_SCHEMA = vol.Schema({vol.Required(CONF_HOST): str})
|
STEP_USER_DATA_SCHEMA = vol.Schema({vol.Required(CONF_HOST): str})
|
||||||
|
|
||||||
|
MANUAL_ENTRY_STRING = "IP Address" # Simplified so it does not have to be translated
|
||||||
|
|
||||||
async def validate_input(hass: HomeAssistant, host: str) -> str:
|
|
||||||
|
async def validate_host_input(host: str) -> str:
|
||||||
"""Validate the user input allows us to connect.
|
"""Validate the user input allows us to connect.
|
||||||
|
|
||||||
Data has the keys from STEP_USER_DATA_SCHEMA with values provided by the user.
|
Data has the keys from STEP_USER_DATA_SCHEMA with values provided by the user.
|
||||||
"""
|
"""
|
||||||
api = IntellifireAsync(host)
|
api = IntellifireAsync(host)
|
||||||
await api.poll()
|
await api.poll()
|
||||||
|
serial = api.data.serial
|
||||||
|
LOGGER.debug("Found a fireplace: %s", serial)
|
||||||
# Return the serial number which will be used to calculate a unique ID for the device/sensors
|
# Return the serial number which will be used to calculate a unique ID for the device/sensors
|
||||||
return api.data.serial
|
return serial
|
||||||
|
|
||||||
|
|
||||||
class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
||||||
@ -34,30 +36,94 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
|||||||
|
|
||||||
VERSION = 1
|
VERSION = 1
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
"""Initialize the Config Flow Handler."""
|
||||||
|
self._config_context = {}
|
||||||
|
self._not_configured_hosts: list[str] = []
|
||||||
|
|
||||||
|
async def _find_fireplaces(self):
|
||||||
|
"""Perform UDP discovery."""
|
||||||
|
fireplace_finder = AsyncUDPFireplaceFinder()
|
||||||
|
discovered_hosts = await fireplace_finder.search_fireplace(timeout=1)
|
||||||
|
configured_hosts = {
|
||||||
|
entry.data[CONF_HOST]
|
||||||
|
for entry in self._async_current_entries(include_ignore=False)
|
||||||
|
if CONF_HOST in entry.data # CONF_HOST will be missing for ignored entries
|
||||||
|
}
|
||||||
|
|
||||||
|
self._not_configured_hosts = [
|
||||||
|
ip for ip in discovered_hosts if ip not in configured_hosts
|
||||||
|
]
|
||||||
|
LOGGER.debug("Discovered Hosts: %s", discovered_hosts)
|
||||||
|
LOGGER.debug("Configured Hosts: %s", configured_hosts)
|
||||||
|
LOGGER.debug("Not Configured Hosts: %s", self._not_configured_hosts)
|
||||||
|
|
||||||
|
async def _async_validate_and_create_entry(self, host: str) -> FlowResult:
|
||||||
|
"""Validate and create the entry."""
|
||||||
|
self._async_abort_entries_match({CONF_HOST: host})
|
||||||
|
serial = await validate_host_input(host)
|
||||||
|
await self.async_set_unique_id(serial)
|
||||||
|
self._abort_if_unique_id_configured(updates={CONF_HOST: host})
|
||||||
|
return self.async_create_entry(
|
||||||
|
title=f"Fireplace {serial}",
|
||||||
|
data={CONF_HOST: host},
|
||||||
|
)
|
||||||
|
|
||||||
|
async def async_step_manual_device_entry(self, user_input=None):
|
||||||
|
"""Handle manual input of local IP configuration."""
|
||||||
|
errors = {}
|
||||||
|
host = user_input.get(CONF_HOST) if user_input else None
|
||||||
|
if user_input is not None:
|
||||||
|
try:
|
||||||
|
return await self._async_validate_and_create_entry(host)
|
||||||
|
except (ConnectionError, ClientConnectionError):
|
||||||
|
errors["base"] = "cannot_connect"
|
||||||
|
|
||||||
|
return self.async_show_form(
|
||||||
|
step_id="manual_device_entry",
|
||||||
|
errors=errors,
|
||||||
|
data_schema=vol.Schema({vol.Required(CONF_HOST, default=host): str}),
|
||||||
|
)
|
||||||
|
|
||||||
|
async def async_step_pick_device(
|
||||||
|
self, user_input: dict[str, Any] | None = None
|
||||||
|
) -> FlowResult:
|
||||||
|
"""Pick which device to configure."""
|
||||||
|
errors = {}
|
||||||
|
|
||||||
|
if user_input is not None:
|
||||||
|
if user_input[CONF_HOST] == MANUAL_ENTRY_STRING:
|
||||||
|
return await self.async_step_manual_device_entry()
|
||||||
|
|
||||||
|
try:
|
||||||
|
return await self._async_validate_and_create_entry(
|
||||||
|
user_input[CONF_HOST]
|
||||||
|
)
|
||||||
|
except (ConnectionError, ClientConnectionError):
|
||||||
|
errors["base"] = "cannot_connect"
|
||||||
|
|
||||||
|
return self.async_show_form(
|
||||||
|
step_id="pick_device",
|
||||||
|
errors=errors,
|
||||||
|
data_schema=vol.Schema(
|
||||||
|
{
|
||||||
|
vol.Required(CONF_HOST): vol.In(
|
||||||
|
self._not_configured_hosts + [MANUAL_ENTRY_STRING]
|
||||||
|
)
|
||||||
|
}
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
async def async_step_user(
|
async def async_step_user(
|
||||||
self, user_input: dict[str, Any] | None = None
|
self, user_input: dict[str, Any] | None = None
|
||||||
) -> FlowResult:
|
) -> FlowResult:
|
||||||
"""Handle the initial step."""
|
"""Start the user flow."""
|
||||||
if user_input is None:
|
|
||||||
return self.async_show_form(
|
|
||||||
step_id="user", data_schema=STEP_USER_DATA_SCHEMA
|
|
||||||
)
|
|
||||||
errors = {}
|
|
||||||
|
|
||||||
try:
|
# Launch fireplaces discovery
|
||||||
serial = await validate_input(self.hass, user_input[CONF_HOST])
|
await self._find_fireplaces()
|
||||||
except (ConnectionError, ClientConnectionError):
|
|
||||||
errors["base"] = "cannot_connect"
|
|
||||||
else:
|
|
||||||
await self.async_set_unique_id(serial)
|
|
||||||
self._abort_if_unique_id_configured(
|
|
||||||
updates={CONF_HOST: user_input[CONF_HOST]}
|
|
||||||
)
|
|
||||||
|
|
||||||
return self.async_create_entry(
|
if self._not_configured_hosts:
|
||||||
title="Fireplace",
|
LOGGER.debug("Running Step: pick_device")
|
||||||
data={CONF_HOST: user_input[CONF_HOST]},
|
return await self.async_step_pick_device()
|
||||||
)
|
LOGGER.debug("Running Step: manual_device_entry")
|
||||||
return self.async_show_form(
|
return await self.async_step_manual_device_entry()
|
||||||
step_id="user", data_schema=STEP_USER_DATA_SCHEMA, errors=errors
|
|
||||||
)
|
|
||||||
|
@ -1,7 +1,13 @@
|
|||||||
{
|
{
|
||||||
"config": {
|
"config": {
|
||||||
"step": {
|
"step": {
|
||||||
"user": {
|
"manual_device_entry": {
|
||||||
|
"description": "Local Configuration",
|
||||||
|
"data": {
|
||||||
|
"host": "[%key:common::config_flow::data::host%]"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"pick_device": {
|
||||||
"data": {
|
"data": {
|
||||||
"host": "[%key:common::config_flow::data::host%]"
|
"host": "[%key:common::config_flow::data::host%]"
|
||||||
}
|
}
|
||||||
@ -15,3 +21,4 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,18 +1,27 @@
|
|||||||
{
|
{
|
||||||
"config": {
|
"config": {
|
||||||
"abort": {
|
"abort": {
|
||||||
"already_configured": "Device is already configured"
|
"already_configured": "Device is already configured"
|
||||||
|
},
|
||||||
|
"error": {
|
||||||
|
"cannot_connect": "Could not connect to a fireplace endpoint at url: http://{host}/poll\nVerify IP address and try again"
|
||||||
|
},
|
||||||
|
"step": {
|
||||||
|
"manual_device_entry": {
|
||||||
|
"title": "IntelliFire - Local Config",
|
||||||
|
"description": "Enter the IP address of the IntelliFire unit on your local network.",
|
||||||
|
"data": {
|
||||||
|
"host": "Host (IP Address)"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"error": {
|
"user": {
|
||||||
"cannot_connect": "Failed to connect",
|
"description": "Username and password are the same information used in your IntelliFire Android/iOS application.",
|
||||||
"unknown": "Unexpected error"
|
"title": "IntelliFire Config"
|
||||||
},
|
},
|
||||||
"step": {
|
"pick_device": {
|
||||||
"user": {
|
"title": "Device Selection",
|
||||||
"data": {
|
"description": "The following IntelliFire devices were discovered. Please select which you wish to configure."
|
||||||
"host": "Host"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -14,6 +14,28 @@ def mock_setup_entry() -> Generator[AsyncMock, None, None]:
|
|||||||
yield mock_setup
|
yield mock_setup
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture()
|
||||||
|
def mock_fireplace_finder_none() -> Generator[None, MagicMock, None]:
|
||||||
|
"""Mock fireplace finder."""
|
||||||
|
mock_found_fireplaces = Mock()
|
||||||
|
mock_found_fireplaces.ips = []
|
||||||
|
with patch(
|
||||||
|
"homeassistant.components.intellifire.config_flow.AsyncUDPFireplaceFinder.search_fireplace"
|
||||||
|
):
|
||||||
|
yield mock_found_fireplaces
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture()
|
||||||
|
def mock_fireplace_finder_single() -> Generator[None, MagicMock, None]:
|
||||||
|
"""Mock fireplace finder."""
|
||||||
|
mock_found_fireplaces = Mock()
|
||||||
|
mock_found_fireplaces.ips = ["192.168.1.69"]
|
||||||
|
with patch(
|
||||||
|
"homeassistant.components.intellifire.config_flow.AsyncUDPFireplaceFinder.search_fireplace"
|
||||||
|
):
|
||||||
|
yield mock_found_fireplaces
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def mock_intellifire_config_flow() -> Generator[None, MagicMock, None]:
|
def mock_intellifire_config_flow() -> Generator[None, MagicMock, None]:
|
||||||
"""Return a mocked IntelliFire client."""
|
"""Return a mocked IntelliFire client."""
|
||||||
|
@ -1,41 +1,152 @@
|
|||||||
"""Test the IntelliFire config flow."""
|
"""Test the IntelliFire config flow."""
|
||||||
from unittest.mock import AsyncMock, MagicMock
|
from unittest.mock import AsyncMock, MagicMock, patch
|
||||||
|
|
||||||
from homeassistant import config_entries
|
from homeassistant import config_entries
|
||||||
|
from homeassistant.components.intellifire.config_flow import MANUAL_ENTRY_STRING
|
||||||
from homeassistant.components.intellifire.const import DOMAIN
|
from homeassistant.components.intellifire.const import DOMAIN
|
||||||
|
from homeassistant.const import CONF_HOST
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.data_entry_flow import RESULT_TYPE_CREATE_ENTRY, RESULT_TYPE_FORM
|
from homeassistant.data_entry_flow import RESULT_TYPE_CREATE_ENTRY, RESULT_TYPE_FORM
|
||||||
|
|
||||||
|
from tests.common import MockConfigEntry
|
||||||
|
|
||||||
async def test_form(
|
|
||||||
|
async def test_no_discovery(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
mock_setup_entry: AsyncMock,
|
mock_setup_entry: AsyncMock,
|
||||||
mock_intellifire_config_flow: MagicMock,
|
mock_intellifire_config_flow: MagicMock,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test we get the form."""
|
"""Test we should get the manual discovery form - because no discovered fireplaces."""
|
||||||
result = await hass.config_entries.flow.async_init(
|
with patch(
|
||||||
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
"homeassistant.components.intellifire.config_flow.AsyncUDPFireplaceFinder.search_fireplace",
|
||||||
)
|
return_value=[],
|
||||||
|
):
|
||||||
|
result = await hass.config_entries.flow.async_init(
|
||||||
|
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
||||||
|
)
|
||||||
assert result["type"] == RESULT_TYPE_FORM
|
assert result["type"] == RESULT_TYPE_FORM
|
||||||
assert result["errors"] is None
|
assert result["errors"] == {}
|
||||||
|
assert result["step_id"] == "manual_device_entry"
|
||||||
|
|
||||||
result2 = await hass.config_entries.flow.async_configure(
|
result2 = await hass.config_entries.flow.async_configure(
|
||||||
result["flow_id"],
|
result["flow_id"],
|
||||||
{
|
{
|
||||||
"host": "1.1.1.1",
|
CONF_HOST: "1.1.1.1",
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
assert result2["type"] == RESULT_TYPE_CREATE_ENTRY
|
assert result2["type"] == RESULT_TYPE_CREATE_ENTRY
|
||||||
assert result2["title"] == "Fireplace"
|
assert result2["title"] == "Fireplace 12345"
|
||||||
assert result2["data"] == {"host": "1.1.1.1"}
|
assert result2["data"] == {CONF_HOST: "1.1.1.1"}
|
||||||
|
|
||||||
assert len(mock_setup_entry.mock_calls) == 1
|
assert len(mock_setup_entry.mock_calls) == 1
|
||||||
|
|
||||||
|
|
||||||
async def test_form_cannot_connect(
|
async def test_single_discovery(
|
||||||
hass: HomeAssistant, mock_intellifire_config_flow: MagicMock
|
hass: HomeAssistant,
|
||||||
|
mock_setup_entry: AsyncMock,
|
||||||
|
mock_intellifire_config_flow: MagicMock,
|
||||||
|
) -> None:
|
||||||
|
"""Test single fireplace UDP discovery."""
|
||||||
|
with patch(
|
||||||
|
"homeassistant.components.intellifire.config_flow.AsyncUDPFireplaceFinder.search_fireplace",
|
||||||
|
return_value=["192.168.1.69"],
|
||||||
|
):
|
||||||
|
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"], {CONF_HOST: "192.168.1.69"}
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
print("Result:", result)
|
||||||
|
|
||||||
|
assert result2["type"] == RESULT_TYPE_CREATE_ENTRY
|
||||||
|
assert result2["title"] == "Fireplace 12345"
|
||||||
|
assert result2["data"] == {CONF_HOST: "192.168.1.69"}
|
||||||
|
assert len(mock_setup_entry.mock_calls) == 1
|
||||||
|
|
||||||
|
|
||||||
|
async def test_manual_entry(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
mock_setup_entry: AsyncMock,
|
||||||
|
mock_intellifire_config_flow: MagicMock,
|
||||||
|
) -> None:
|
||||||
|
"""Test for multiple firepalce discovery - involing a pick_device step."""
|
||||||
|
with patch(
|
||||||
|
"homeassistant.components.intellifire.config_flow.AsyncUDPFireplaceFinder.search_fireplace",
|
||||||
|
return_value=["192.168.1.69", "192.168.1.33", "192.168.169"],
|
||||||
|
):
|
||||||
|
|
||||||
|
result = await hass.config_entries.flow.async_init(
|
||||||
|
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
||||||
|
)
|
||||||
|
|
||||||
|
assert result["step_id"] == "pick_device"
|
||||||
|
result2 = await hass.config_entries.flow.async_configure(
|
||||||
|
result["flow_id"], user_input={CONF_HOST: MANUAL_ENTRY_STRING}
|
||||||
|
)
|
||||||
|
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert result2["step_id"] == "manual_device_entry"
|
||||||
|
|
||||||
|
|
||||||
|
async def test_multi_discovery(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
mock_setup_entry: AsyncMock,
|
||||||
|
mock_intellifire_config_flow: MagicMock,
|
||||||
|
) -> None:
|
||||||
|
"""Test for multiple fireplace discovery - involving a pick_device step."""
|
||||||
|
with patch(
|
||||||
|
"homeassistant.components.intellifire.config_flow.AsyncUDPFireplaceFinder.search_fireplace",
|
||||||
|
return_value=["192.168.1.69", "192.168.1.33", "192.168.169"],
|
||||||
|
):
|
||||||
|
result = await hass.config_entries.flow.async_init(
|
||||||
|
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
||||||
|
)
|
||||||
|
|
||||||
|
assert result["step_id"] == "pick_device"
|
||||||
|
|
||||||
|
result2 = await hass.config_entries.flow.async_configure(
|
||||||
|
result["flow_id"], user_input={CONF_HOST: "192.168.1.33"}
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert result["step_id"] == "pick_device"
|
||||||
|
|
||||||
|
assert result2["type"] == RESULT_TYPE_CREATE_ENTRY
|
||||||
|
|
||||||
|
|
||||||
|
async def test_multi_discovery_cannot_connect(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
mock_setup_entry: AsyncMock,
|
||||||
|
mock_intellifire_config_flow: MagicMock,
|
||||||
|
) -> None:
|
||||||
|
"""Test for multiple fireplace discovery - involving a pick_device step."""
|
||||||
|
with patch(
|
||||||
|
"homeassistant.components.intellifire.config_flow.AsyncUDPFireplaceFinder.search_fireplace",
|
||||||
|
return_value=["192.168.1.69", "192.168.1.33", "192.168.169"],
|
||||||
|
):
|
||||||
|
|
||||||
|
mock_intellifire_config_flow.poll.side_effect = ConnectionError
|
||||||
|
|
||||||
|
result = await hass.config_entries.flow.async_init(
|
||||||
|
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
||||||
|
)
|
||||||
|
assert result["type"] == RESULT_TYPE_FORM
|
||||||
|
assert result["step_id"] == "pick_device"
|
||||||
|
|
||||||
|
result2 = await hass.config_entries.flow.async_configure(
|
||||||
|
result["flow_id"], user_input={CONF_HOST: "192.168.1.33"}
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert result2["type"] == RESULT_TYPE_FORM
|
||||||
|
assert result2["errors"] == {"base": "cannot_connect"}
|
||||||
|
|
||||||
|
|
||||||
|
async def test_form_cannot_connect_manual_entry(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
mock_intellifire_config_flow: MagicMock,
|
||||||
|
mock_fireplace_finder_single: AsyncMock,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test we handle cannot connect error."""
|
"""Test we handle cannot connect error."""
|
||||||
mock_intellifire_config_flow.poll.side_effect = ConnectionError
|
mock_intellifire_config_flow.poll.side_effect = ConnectionError
|
||||||
@ -43,13 +154,52 @@ async def test_form_cannot_connect(
|
|||||||
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}
|
||||||
)
|
)
|
||||||
|
assert result["type"] == RESULT_TYPE_FORM
|
||||||
|
assert result["step_id"] == "manual_device_entry"
|
||||||
|
|
||||||
result2 = await hass.config_entries.flow.async_configure(
|
result2 = await hass.config_entries.flow.async_configure(
|
||||||
result["flow_id"],
|
result["flow_id"],
|
||||||
{
|
{
|
||||||
"host": "1.1.1.1",
|
CONF_HOST: "1.1.1.1",
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
assert result2["type"] == RESULT_TYPE_FORM
|
assert result2["type"] == RESULT_TYPE_FORM
|
||||||
assert result2["errors"] == {"base": "cannot_connect"}
|
assert result2["errors"] == {"base": "cannot_connect"}
|
||||||
|
|
||||||
|
|
||||||
|
async def test_picker_already_discovered(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
mock_setup_entry: AsyncMock,
|
||||||
|
mock_intellifire_config_flow: MagicMock,
|
||||||
|
) -> None:
|
||||||
|
"""Test single fireplace UDP discovery."""
|
||||||
|
|
||||||
|
entry = MockConfigEntry(
|
||||||
|
domain=DOMAIN,
|
||||||
|
data={
|
||||||
|
"host": "192.168.1.3",
|
||||||
|
},
|
||||||
|
title="Fireplace",
|
||||||
|
unique_id=44444,
|
||||||
|
)
|
||||||
|
entry.add_to_hass(hass)
|
||||||
|
with patch(
|
||||||
|
"homeassistant.components.intellifire.config_flow.AsyncUDPFireplaceFinder.search_fireplace",
|
||||||
|
return_value=["192.168.1.3"],
|
||||||
|
):
|
||||||
|
result = await hass.config_entries.flow.async_init(
|
||||||
|
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
result2 = await hass.config_entries.flow.async_configure(
|
||||||
|
result["flow_id"],
|
||||||
|
{
|
||||||
|
CONF_HOST: "192.168.1.4",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
assert result2["type"] == RESULT_TYPE_CREATE_ENTRY
|
||||||
|
assert result2["title"] == "Fireplace 12345"
|
||||||
|
assert result2["data"] == {CONF_HOST: "192.168.1.4"}
|
||||||
|
assert len(mock_setup_entry.mock_calls) == 2
|
||||||
|
Loading…
x
Reference in New Issue
Block a user