Improve mysensors config flow (#75122)

* Improve mysensors config flow

* Improve form input order

* Update flow tests
pull/76372/head
Martin Hjelmare 2022-08-07 01:22:50 +02:00 committed by GitHub
parent 1aa0e64354
commit e864b82c03
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 113 additions and 137 deletions

View File

@ -20,13 +20,13 @@ from homeassistant.components.mqtt import (
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
from homeassistant.core import callback from homeassistant.core import callback
from homeassistant.data_entry_flow import FlowResult from homeassistant.data_entry_flow import FlowResult
from homeassistant.helpers import selector
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
from .const import ( from .const import (
CONF_BAUD_RATE, CONF_BAUD_RATE,
CONF_DEVICE, CONF_DEVICE,
CONF_GATEWAY_TYPE, CONF_GATEWAY_TYPE,
CONF_GATEWAY_TYPE_ALL,
CONF_GATEWAY_TYPE_MQTT, CONF_GATEWAY_TYPE_MQTT,
CONF_GATEWAY_TYPE_SERIAL, CONF_GATEWAY_TYPE_SERIAL,
CONF_GATEWAY_TYPE_TCP, CONF_GATEWAY_TYPE_TCP,
@ -45,6 +45,15 @@ DEFAULT_BAUD_RATE = 115200
DEFAULT_TCP_PORT = 5003 DEFAULT_TCP_PORT = 5003
DEFAULT_VERSION = "1.4" DEFAULT_VERSION = "1.4"
_PORT_SELECTOR = vol.All(
selector.NumberSelector(
selector.NumberSelectorConfig(
min=1, max=65535, mode=selector.NumberSelectorMode.BOX
),
),
vol.Coerce(int),
)
def is_persistence_file(value: str) -> str: def is_persistence_file(value: str) -> str:
"""Validate that persistence file path ends in either .pickle or .json.""" """Validate that persistence file path ends in either .pickle or .json."""
@ -119,51 +128,34 @@ class MySensorsConfigFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
self, user_input: dict[str, str] | None = None self, user_input: dict[str, str] | None = None
) -> FlowResult: ) -> FlowResult:
"""Create a config entry from frontend user input.""" """Create a config entry from frontend user input."""
schema = {vol.Required(CONF_GATEWAY_TYPE): vol.In(CONF_GATEWAY_TYPE_ALL)} return self.async_show_menu(
schema = vol.Schema(schema) step_id="select_gateway_type",
errors = {} menu_options=["gw_serial", "gw_tcp", "gw_mqtt"],
)
if user_input is not None:
gw_type = self._gw_type = user_input[CONF_GATEWAY_TYPE]
input_pass = user_input if CONF_DEVICE in user_input else None
if gw_type == CONF_GATEWAY_TYPE_MQTT:
# Naive check that doesn't consider config entry state.
if MQTT_DOMAIN in self.hass.config.components:
return await self.async_step_gw_mqtt(input_pass)
errors["base"] = "mqtt_required"
if gw_type == CONF_GATEWAY_TYPE_TCP:
return await self.async_step_gw_tcp(input_pass)
if gw_type == CONF_GATEWAY_TYPE_SERIAL:
return await self.async_step_gw_serial(input_pass)
return self.async_show_form(step_id="user", data_schema=schema, errors=errors)
async def async_step_gw_serial( async def async_step_gw_serial(
self, user_input: dict[str, Any] | None = None self, user_input: dict[str, Any] | None = None
) -> FlowResult: ) -> FlowResult:
"""Create config entry for a serial gateway.""" """Create config entry for a serial gateway."""
gw_type = self._gw_type = CONF_GATEWAY_TYPE_SERIAL
errors: dict[str, str] = {} errors: dict[str, str] = {}
if user_input is not None: if user_input is not None:
errors.update( errors.update(await self.validate_common(gw_type, errors, user_input))
await self.validate_common(CONF_GATEWAY_TYPE_SERIAL, errors, user_input)
)
if not errors: if not errors:
return self._async_create_entry(user_input) return self._async_create_entry(user_input)
user_input = user_input or {} user_input = user_input or {}
schema = _get_schema_common(user_input) schema = {
schema[ vol.Required(
CONF_DEVICE, default=user_input.get(CONF_DEVICE, "/dev/ttyACM0")
): str,
vol.Required( vol.Required(
CONF_BAUD_RATE, CONF_BAUD_RATE,
default=user_input.get(CONF_BAUD_RATE, DEFAULT_BAUD_RATE), default=user_input.get(CONF_BAUD_RATE, DEFAULT_BAUD_RATE),
) ): cv.positive_int,
] = cv.positive_int }
schema[ schema.update(_get_schema_common(user_input))
vol.Required(
CONF_DEVICE, default=user_input.get(CONF_DEVICE, "/dev/ttyACM0")
)
] = str
schema = vol.Schema(schema) schema = vol.Schema(schema)
return self.async_show_form( return self.async_show_form(
@ -174,30 +166,24 @@ class MySensorsConfigFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
self, user_input: dict[str, Any] | None = None self, user_input: dict[str, Any] | None = None
) -> FlowResult: ) -> FlowResult:
"""Create a config entry for a tcp gateway.""" """Create a config entry for a tcp gateway."""
errors = {} gw_type = self._gw_type = CONF_GATEWAY_TYPE_TCP
if user_input is not None: errors: dict[str, str] = {}
if CONF_TCP_PORT in user_input:
port: int = user_input[CONF_TCP_PORT]
if not (0 < port <= 65535):
errors[CONF_TCP_PORT] = "port_out_of_range"
errors.update( if user_input is not None:
await self.validate_common(CONF_GATEWAY_TYPE_TCP, errors, user_input) errors.update(await self.validate_common(gw_type, errors, user_input))
)
if not errors: if not errors:
return self._async_create_entry(user_input) return self._async_create_entry(user_input)
user_input = user_input or {} user_input = user_input or {}
schema = _get_schema_common(user_input) schema = {
schema[ vol.Required(
vol.Required(CONF_DEVICE, default=user_input.get(CONF_DEVICE, "127.0.0.1")) CONF_DEVICE, default=user_input.get(CONF_DEVICE, "127.0.0.1")
] = str ): str,
# Don't use cv.port as that would show a slider *facepalm*
schema[
vol.Optional( vol.Optional(
CONF_TCP_PORT, default=user_input.get(CONF_TCP_PORT, DEFAULT_TCP_PORT) CONF_TCP_PORT, default=user_input.get(CONF_TCP_PORT, DEFAULT_TCP_PORT)
) ): _PORT_SELECTOR,
] = vol.Coerce(int) }
schema.update(_get_schema_common(user_input))
schema = vol.Schema(schema) schema = vol.Schema(schema)
return self.async_show_form(step_id="gw_tcp", data_schema=schema, errors=errors) return self.async_show_form(step_id="gw_tcp", data_schema=schema, errors=errors)
@ -214,7 +200,13 @@ class MySensorsConfigFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
self, user_input: dict[str, Any] | None = None self, user_input: dict[str, Any] | None = None
) -> FlowResult: ) -> FlowResult:
"""Create a config entry for a mqtt gateway.""" """Create a config entry for a mqtt gateway."""
errors = {} # Naive check that doesn't consider config entry state.
if MQTT_DOMAIN not in self.hass.config.components:
return self.async_abort(reason="mqtt_required")
gw_type = self._gw_type = CONF_GATEWAY_TYPE_MQTT
errors: dict[str, str] = {}
if user_input is not None: if user_input is not None:
user_input[CONF_DEVICE] = MQTT_COMPONENT user_input[CONF_DEVICE] = MQTT_COMPONENT
@ -239,27 +231,21 @@ class MySensorsConfigFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
elif self._check_topic_exists(user_input[CONF_TOPIC_OUT_PREFIX]): elif self._check_topic_exists(user_input[CONF_TOPIC_OUT_PREFIX]):
errors[CONF_TOPIC_OUT_PREFIX] = "duplicate_topic" errors[CONF_TOPIC_OUT_PREFIX] = "duplicate_topic"
errors.update( errors.update(await self.validate_common(gw_type, errors, user_input))
await self.validate_common(CONF_GATEWAY_TYPE_MQTT, errors, user_input)
)
if not errors: if not errors:
return self._async_create_entry(user_input) return self._async_create_entry(user_input)
user_input = user_input or {} user_input = user_input or {}
schema = _get_schema_common(user_input) schema = {
schema[
vol.Required(CONF_RETAIN, default=user_input.get(CONF_RETAIN, True))
] = bool
schema[
vol.Required( vol.Required(
CONF_TOPIC_IN_PREFIX, default=user_input.get(CONF_TOPIC_IN_PREFIX, "") CONF_TOPIC_IN_PREFIX, default=user_input.get(CONF_TOPIC_IN_PREFIX, "")
) ): str,
] = str
schema[
vol.Required( vol.Required(
CONF_TOPIC_OUT_PREFIX, default=user_input.get(CONF_TOPIC_OUT_PREFIX, "") CONF_TOPIC_OUT_PREFIX, default=user_input.get(CONF_TOPIC_OUT_PREFIX, "")
) ): str,
] = str vol.Required(CONF_RETAIN, default=user_input.get(CONF_RETAIN, True)): bool,
}
schema.update(_get_schema_common(user_input))
schema = vol.Schema(schema) schema = vol.Schema(schema)
return self.async_show_form( return self.async_show_form(

View File

@ -22,11 +22,6 @@ ConfGatewayType = Literal["Serial", "TCP", "MQTT"]
CONF_GATEWAY_TYPE_SERIAL: ConfGatewayType = "Serial" CONF_GATEWAY_TYPE_SERIAL: ConfGatewayType = "Serial"
CONF_GATEWAY_TYPE_TCP: ConfGatewayType = "TCP" CONF_GATEWAY_TYPE_TCP: ConfGatewayType = "TCP"
CONF_GATEWAY_TYPE_MQTT: ConfGatewayType = "MQTT" CONF_GATEWAY_TYPE_MQTT: ConfGatewayType = "MQTT"
CONF_GATEWAY_TYPE_ALL: list[str] = [
CONF_GATEWAY_TYPE_MQTT,
CONF_GATEWAY_TYPE_SERIAL,
CONF_GATEWAY_TYPE_TCP,
]
DOMAIN: Final = "mysensors" DOMAIN: Final = "mysensors"
MYSENSORS_GATEWAY_START_TASK: str = "mysensors_gateway_start_task_{}" MYSENSORS_GATEWAY_START_TASK: str = "mysensors_gateway_start_task_{}"

View File

@ -7,6 +7,14 @@
}, },
"description": "Choose connection method to the gateway" "description": "Choose connection method to the gateway"
}, },
"select_gateway_type": {
"description": "Select which gateway to configure.",
"menu_options": {
"gw_mqtt": "Configure an MQTT gateway",
"gw_serial": "Configure a serial gateway",
"gw_tcp": "Configure a TCP gateway"
}
},
"gw_tcp": { "gw_tcp": {
"description": "Ethernet gateway setup", "description": "Ethernet gateway setup",
"data": { "data": {
@ -51,7 +59,6 @@
"invalid_serial": "Invalid serial port", "invalid_serial": "Invalid serial port",
"invalid_device": "Invalid device", "invalid_device": "Invalid device",
"invalid_version": "Invalid MySensors version", "invalid_version": "Invalid MySensors version",
"mqtt_required": "The MQTT integration is not set up",
"not_a_number": "Please enter a number", "not_a_number": "Please enter a number",
"port_out_of_range": "Port number must be at least 1 and at most 65535", "port_out_of_range": "Port number must be at least 1 and at most 65535",
"unknown": "[%key:common::config_flow::error::unknown%]" "unknown": "[%key:common::config_flow::error::unknown%]"
@ -71,6 +78,7 @@
"invalid_serial": "Invalid serial port", "invalid_serial": "Invalid serial port",
"invalid_device": "Invalid device", "invalid_device": "Invalid device",
"invalid_version": "Invalid MySensors version", "invalid_version": "Invalid MySensors version",
"mqtt_required": "The MQTT integration is not set up",
"not_a_number": "Please enter a number", "not_a_number": "Please enter a number",
"port_out_of_range": "Port number must be at least 1 and at most 65535", "port_out_of_range": "Port number must be at least 1 and at most 65535",
"unknown": "[%key:common::config_flow::error::unknown%]" "unknown": "[%key:common::config_flow::error::unknown%]"

View File

@ -14,6 +14,7 @@
"invalid_serial": "Invalid serial port", "invalid_serial": "Invalid serial port",
"invalid_subscribe_topic": "Invalid subscribe topic", "invalid_subscribe_topic": "Invalid subscribe topic",
"invalid_version": "Invalid MySensors version", "invalid_version": "Invalid MySensors version",
"mqtt_required": "The MQTT integration is not set up",
"not_a_number": "Please enter a number", "not_a_number": "Please enter a number",
"port_out_of_range": "Port number must be at least 1 and at most 65535", "port_out_of_range": "Port number must be at least 1 and at most 65535",
"same_topic": "Subscribe and publish topics are the same", "same_topic": "Subscribe and publish topics are the same",
@ -33,7 +34,6 @@
"invalid_serial": "Invalid serial port", "invalid_serial": "Invalid serial port",
"invalid_subscribe_topic": "Invalid subscribe topic", "invalid_subscribe_topic": "Invalid subscribe topic",
"invalid_version": "Invalid MySensors version", "invalid_version": "Invalid MySensors version",
"mqtt_required": "The MQTT integration is not set up",
"not_a_number": "Please enter a number", "not_a_number": "Please enter a number",
"port_out_of_range": "Port number must be at least 1 and at most 65535", "port_out_of_range": "Port number must be at least 1 and at most 65535",
"same_topic": "Subscribe and publish topics are the same", "same_topic": "Subscribe and publish topics are the same",
@ -68,6 +68,14 @@
}, },
"description": "Ethernet gateway setup" "description": "Ethernet gateway setup"
}, },
"select_gateway_type": {
"description": "Select which gateway to configure.",
"menu_options": {
"gw_mqtt": "Configure an MQTT gateway",
"gw_serial": "Configure a serial gateway",
"gw_tcp": "Configure a TCP gateway"
}
},
"user": { "user": {
"data": { "data": {
"gateway_type": "Gateway type" "gateway_type": "Gateway type"

View File

@ -24,28 +24,32 @@ from homeassistant.components.mysensors.const import (
ConfGatewayType, ConfGatewayType,
) )
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.data_entry_flow import FlowResult from homeassistant.data_entry_flow import FlowResult, FlowResultType
from tests.common import MockConfigEntry from tests.common import MockConfigEntry
GATEWAY_TYPE_TO_STEP = {
CONF_GATEWAY_TYPE_TCP: "gw_tcp",
CONF_GATEWAY_TYPE_SERIAL: "gw_serial",
CONF_GATEWAY_TYPE_MQTT: "gw_mqtt",
}
async def get_form( async def get_form(
hass: HomeAssistant, gatway_type: ConfGatewayType, expected_step_id: str hass: HomeAssistant, gateway_type: ConfGatewayType, expected_step_id: str
) -> FlowResult: ) -> FlowResult:
"""Get a form for the given gateway type.""" """Get a form for the given gateway type."""
stepuser = 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 stepuser["type"] == "form" assert result["type"] == FlowResultType.MENU
assert not stepuser["errors"]
result = await hass.config_entries.flow.async_configure( result = await hass.config_entries.flow.async_configure(
stepuser["flow_id"], result["flow_id"], {"next_step_id": GATEWAY_TYPE_TO_STEP[gateway_type]}
{CONF_GATEWAY_TYPE: gatway_type},
) )
await hass.async_block_till_done() await hass.async_block_till_done()
assert result["type"] == "form" assert result["type"] == FlowResultType.FORM
assert result["step_id"] == expected_step_id assert result["step_id"] == expected_step_id
return result return result
@ -62,7 +66,7 @@ async def test_config_mqtt(hass: HomeAssistant, mqtt: None) -> None:
"homeassistant.components.mysensors.async_setup_entry", "homeassistant.components.mysensors.async_setup_entry",
return_value=True, return_value=True,
) as mock_setup_entry: ) as mock_setup_entry:
result2 = await hass.config_entries.flow.async_configure( result = await hass.config_entries.flow.async_configure(
flow_id, flow_id,
{ {
CONF_RETAIN: True, CONF_RETAIN: True,
@ -73,11 +77,11 @@ async def test_config_mqtt(hass: HomeAssistant, mqtt: None) -> None:
) )
await hass.async_block_till_done() await hass.async_block_till_done()
if "errors" in result2: if "errors" in result:
assert not result2["errors"] assert not result["errors"]
assert result2["type"] == "create_entry" assert result["type"] == FlowResultType.CREATE_ENTRY
assert result2["title"] == "mqtt" assert result["title"] == "mqtt"
assert result2["data"] == { assert result["data"] == {
CONF_DEVICE: "mqtt", CONF_DEVICE: "mqtt",
CONF_RETAIN: True, CONF_RETAIN: True,
CONF_TOPIC_IN_PREFIX: "bla", CONF_TOPIC_IN_PREFIX: "bla",
@ -91,20 +95,19 @@ async def test_config_mqtt(hass: HomeAssistant, mqtt: None) -> None:
async def test_missing_mqtt(hass: HomeAssistant) -> None: async def test_missing_mqtt(hass: HomeAssistant) -> None:
"""Test configuring a mqtt gateway without mqtt integration setup.""" """Test configuring a mqtt gateway without mqtt integration setup."""
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"] == "form" assert result["type"] == FlowResultType.MENU
assert not result["errors"]
result = await hass.config_entries.flow.async_configure( result = await hass.config_entries.flow.async_configure(
result["flow_id"], result["flow_id"],
{CONF_GATEWAY_TYPE: CONF_GATEWAY_TYPE_MQTT}, {"next_step_id": GATEWAY_TYPE_TO_STEP[CONF_GATEWAY_TYPE_MQTT]},
) )
assert result["step_id"] == "user" await hass.async_block_till_done()
assert result["type"] == "form"
assert result["errors"] == {"base": "mqtt_required"} assert result["type"] == FlowResultType.ABORT
assert result["reason"] == "mqtt_required"
async def test_config_serial(hass: HomeAssistant) -> None: async def test_config_serial(hass: HomeAssistant) -> None:
@ -123,7 +126,7 @@ async def test_config_serial(hass: HomeAssistant) -> None:
"homeassistant.components.mysensors.async_setup_entry", "homeassistant.components.mysensors.async_setup_entry",
return_value=True, return_value=True,
) as mock_setup_entry: ) as mock_setup_entry:
result2 = await hass.config_entries.flow.async_configure( result = await hass.config_entries.flow.async_configure(
flow_id, flow_id,
{ {
CONF_BAUD_RATE: 115200, CONF_BAUD_RATE: 115200,
@ -133,11 +136,11 @@ async def test_config_serial(hass: HomeAssistant) -> None:
) )
await hass.async_block_till_done() await hass.async_block_till_done()
if "errors" in result2: if "errors" in result:
assert not result2["errors"] assert not result["errors"]
assert result2["type"] == "create_entry" assert result["type"] == FlowResultType.CREATE_ENTRY
assert result2["title"] == "/dev/ttyACM0" assert result["title"] == "/dev/ttyACM0"
assert result2["data"] == { assert result["data"] == {
CONF_DEVICE: "/dev/ttyACM0", CONF_DEVICE: "/dev/ttyACM0",
CONF_BAUD_RATE: 115200, CONF_BAUD_RATE: 115200,
CONF_VERSION: "2.4", CONF_VERSION: "2.4",
@ -160,7 +163,7 @@ async def test_config_tcp(hass: HomeAssistant) -> None:
"homeassistant.components.mysensors.async_setup_entry", "homeassistant.components.mysensors.async_setup_entry",
return_value=True, return_value=True,
) as mock_setup_entry: ) as mock_setup_entry:
result2 = await hass.config_entries.flow.async_configure( result = await hass.config_entries.flow.async_configure(
flow_id, flow_id,
{ {
CONF_TCP_PORT: 5003, CONF_TCP_PORT: 5003,
@ -170,11 +173,11 @@ async def test_config_tcp(hass: HomeAssistant) -> None:
) )
await hass.async_block_till_done() await hass.async_block_till_done()
if "errors" in result2: if "errors" in result:
assert not result2["errors"] assert not result["errors"]
assert result2["type"] == "create_entry" assert result["type"] == FlowResultType.CREATE_ENTRY
assert result2["title"] == "127.0.0.1" assert result["title"] == "127.0.0.1"
assert result2["data"] == { assert result["data"] == {
CONF_DEVICE: "127.0.0.1", CONF_DEVICE: "127.0.0.1",
CONF_TCP_PORT: 5003, CONF_TCP_PORT: 5003,
CONF_VERSION: "2.4", CONF_VERSION: "2.4",
@ -197,7 +200,7 @@ async def test_fail_to_connect(hass: HomeAssistant) -> None:
"homeassistant.components.mysensors.async_setup_entry", "homeassistant.components.mysensors.async_setup_entry",
return_value=True, return_value=True,
) as mock_setup_entry: ) as mock_setup_entry:
result2 = await hass.config_entries.flow.async_configure( result = await hass.config_entries.flow.async_configure(
flow_id, flow_id,
{ {
CONF_TCP_PORT: 5003, CONF_TCP_PORT: 5003,
@ -207,9 +210,9 @@ async def test_fail_to_connect(hass: HomeAssistant) -> None:
) )
await hass.async_block_till_done() await hass.async_block_till_done()
assert result2["type"] == "form" assert result["type"] == FlowResultType.FORM
assert "errors" in result2 assert "errors" in result
errors = result2["errors"] errors = result["errors"]
assert errors assert errors
assert errors.get("base") == "cannot_connect" assert errors.get("base") == "cannot_connect"
assert len(mock_setup.mock_calls) == 0 assert len(mock_setup.mock_calls) == 0
@ -219,28 +222,6 @@ async def test_fail_to_connect(hass: HomeAssistant) -> None:
@pytest.mark.parametrize( @pytest.mark.parametrize(
"gateway_type, expected_step_id, user_input, err_field, err_string", "gateway_type, expected_step_id, user_input, err_field, err_string",
[ [
(
CONF_GATEWAY_TYPE_TCP,
"gw_tcp",
{
CONF_TCP_PORT: 600_000,
CONF_DEVICE: "127.0.0.1",
CONF_VERSION: "2.4",
},
CONF_TCP_PORT,
"port_out_of_range",
),
(
CONF_GATEWAY_TYPE_TCP,
"gw_tcp",
{
CONF_TCP_PORT: 0,
CONF_DEVICE: "127.0.0.1",
CONF_VERSION: "2.4",
},
CONF_TCP_PORT,
"port_out_of_range",
),
( (
CONF_GATEWAY_TYPE_TCP, CONF_GATEWAY_TYPE_TCP,
"gw_tcp", "gw_tcp",
@ -382,15 +363,15 @@ async def test_config_invalid(
"homeassistant.components.mysensors.async_setup_entry", "homeassistant.components.mysensors.async_setup_entry",
return_value=True, return_value=True,
) as mock_setup_entry: ) as mock_setup_entry:
result2 = await hass.config_entries.flow.async_configure( result = await hass.config_entries.flow.async_configure(
flow_id, flow_id,
user_input, user_input,
) )
await hass.async_block_till_done() await hass.async_block_till_done()
assert result2["type"] == "form" assert result["type"] == FlowResultType.FORM
assert "errors" in result2 assert "errors" in result
errors = result2["errors"] errors = result["errors"]
assert errors assert errors
assert err_field in errors assert err_field in errors
assert errors[err_field] == err_string assert errors[err_field] == err_string
@ -681,10 +662,8 @@ async def test_duplicate(
MockConfigEntry(domain=DOMAIN, data=first_input).add_to_hass(hass) MockConfigEntry(domain=DOMAIN, data=first_input).add_to_hass(hass)
second_gateway_type = second_input.pop(CONF_GATEWAY_TYPE) second_gateway_type = second_input.pop(CONF_GATEWAY_TYPE)
result = await hass.config_entries.flow.async_init( result = await get_form(
DOMAIN, hass, second_gateway_type, GATEWAY_TYPE_TO_STEP[second_gateway_type]
data={CONF_GATEWAY_TYPE: second_gateway_type},
context={"source": config_entries.SOURCE_USER},
) )
result = await hass.config_entries.flow.async_configure( result = await hass.config_entries.flow.async_configure(
result["flow_id"], result["flow_id"],