Skip to content

Commit 29309d1

Browse files
Add reconfigure flow to Satel Integra (#164938)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent 130e0db commit 29309d1

File tree

3 files changed

+176
-17
lines changed

3 files changed

+176
-17
lines changed

homeassistant/components/satel_integra/config_flow.py

Lines changed: 60 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,9 @@
4444
{
4545
vol.Required(CONF_HOST): str,
4646
vol.Required(CONF_PORT, default=DEFAULT_PORT): cv.port,
47-
vol.Optional(CONF_CODE): cv.string,
4847
}
4948
)
5049

51-
5250
CODE_SCHEMA = vol.Schema(
5351
{
5452
vol.Optional(CONF_CODE): cv.string,
@@ -86,6 +84,11 @@
8684
class SatelConfigFlow(ConfigFlow, domain=DOMAIN):
8785
"""Handle a Satel Integra config flow."""
8886

87+
def __init__(self) -> None:
88+
"""Initialize the config flow."""
89+
super().__init__()
90+
self.connection_data: dict[str, Any] = {}
91+
8992
VERSION = 2
9093
MINOR_VERSION = 1
9194

@@ -119,24 +122,71 @@ async def async_step_user(
119122
if user_input is not None:
120123
self._async_abort_entries_match({CONF_HOST: user_input[CONF_HOST]})
121124

122-
valid = await self.test_connection(
123-
user_input[CONF_HOST], user_input[CONF_PORT]
125+
if await self.test_connection(user_input[CONF_HOST], user_input[CONF_PORT]):
126+
self.connection_data = {
127+
CONF_HOST: user_input[CONF_HOST],
128+
CONF_PORT: user_input[CONF_PORT],
129+
}
130+
return await self.async_step_code()
131+
132+
errors["base"] = "cannot_connect"
133+
134+
return self.async_show_form(
135+
step_id="user",
136+
data_schema=CONNECTION_SCHEMA,
137+
errors=errors,
138+
)
139+
140+
async def async_step_code(
141+
self, user_input: dict[str, Any] | None = None
142+
) -> ConfigFlowResult:
143+
"""Handle code configuration."""
144+
if user_input is not None:
145+
return self.async_create_entry(
146+
title=self.connection_data[CONF_HOST],
147+
data=self.connection_data,
148+
options={CONF_CODE: user_input.get(CONF_CODE)},
124149
)
125150

126-
if valid:
127-
return self.async_create_entry(
128-
title=user_input[CONF_HOST],
129-
data={
151+
return self.async_show_form(
152+
step_id="code",
153+
data_schema=CODE_SCHEMA,
154+
)
155+
156+
async def async_step_reconfigure(
157+
self, user_input: dict[str, Any] | None = None
158+
) -> ConfigFlowResult:
159+
"""Handle reconfiguration."""
160+
errors: dict[str, str] = {}
161+
reconfigure_entry = self._get_reconfigure_entry()
162+
163+
if user_input is not None:
164+
self._async_abort_entries_match({CONF_HOST: user_input[CONF_HOST]})
165+
166+
if await self.test_connection(user_input[CONF_HOST], user_input[CONF_PORT]):
167+
return self.async_update_reload_and_abort(
168+
reconfigure_entry,
169+
data_updates={
130170
CONF_HOST: user_input[CONF_HOST],
131171
CONF_PORT: user_input[CONF_PORT],
132172
},
133-
options={CONF_CODE: user_input.get(CONF_CODE)},
173+
title=user_input[CONF_HOST],
174+
reload_even_if_entry_is_unchanged=False,
134175
)
135176

136177
errors["base"] = "cannot_connect"
137178

179+
suggested_values: dict[str, Any] = {
180+
**reconfigure_entry.data,
181+
**(user_input or {}),
182+
}
183+
138184
return self.async_show_form(
139-
step_id="user", data_schema=CONNECTION_SCHEMA, errors=errors
185+
step_id="reconfigure",
186+
data_schema=self.add_suggested_values_to_schema(
187+
CONNECTION_SCHEMA, suggested_values
188+
),
189+
errors=errors,
140190
)
141191

142192
async def test_connection(self, host: str, port: int) -> bool:

homeassistant/components/satel_integra/strings.json

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,37 @@
55
},
66
"config": {
77
"abort": {
8-
"already_configured": "[%key:common::config_flow::abort::already_configured_device%]"
8+
"already_configured": "[%key:common::config_flow::abort::already_configured_device%]",
9+
"reconfigure_successful": "[%key:common::config_flow::abort::reconfigure_successful%]"
910
},
1011
"error": {
1112
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]"
1213
},
1314
"step": {
15+
"code": {
16+
"data": {
17+
"code": "[%key:component::satel_integra::common::code%]"
18+
},
19+
"data_description": {
20+
"code": "[%key:component::satel_integra::common::code_input_description%]"
21+
}
22+
},
23+
"reconfigure": {
24+
"data": {
25+
"host": "[%key:common::config_flow::data::host%]",
26+
"port": "[%key:common::config_flow::data::port%]"
27+
},
28+
"data_description": {
29+
"host": "[%key:component::satel_integra::config::step::user::data_description::host%]",
30+
"port": "[%key:component::satel_integra::config::step::user::data_description::port%]"
31+
}
32+
},
1433
"user": {
1534
"data": {
16-
"code": "[%key:component::satel_integra::common::code%]",
1735
"host": "[%key:common::config_flow::data::host%]",
1836
"port": "[%key:common::config_flow::data::port%]"
1937
},
2038
"data_description": {
21-
"code": "[%key:component::satel_integra::common::code_input_description%]",
2239
"host": "The IP address of the alarm panel",
2340
"port": "The port of the alarm panel"
2441
}

tests/components/satel_integra/test_config_flow.py

Lines changed: 96 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,15 +35,17 @@
3535

3636

3737
@pytest.mark.parametrize(
38-
("user_input", "entry_data", "entry_options"),
38+
("user_input_connection", "user_input_code", "entry_data", "entry_options"),
3939
[
4040
(
41-
{**MOCK_CONFIG_DATA, **MOCK_CONFIG_OPTIONS},
41+
MOCK_CONFIG_DATA,
42+
MOCK_CONFIG_OPTIONS,
4243
MOCK_CONFIG_DATA,
4344
MOCK_CONFIG_OPTIONS,
4445
),
4546
(
4647
{CONF_HOST: MOCK_CONFIG_DATA[CONF_HOST]},
48+
{},
4749
{CONF_HOST: MOCK_CONFIG_DATA[CONF_HOST], CONF_PORT: DEFAULT_PORT},
4850
{CONF_CODE: None},
4951
),
@@ -53,7 +55,8 @@ async def test_setup_flow(
5355
hass: HomeAssistant,
5456
mock_satel: AsyncMock,
5557
mock_setup_entry: AsyncMock,
56-
user_input: dict[str, Any],
58+
user_input_connection: dict[str, Any],
59+
user_input_code: dict[str, Any],
5760
entry_data: dict[str, Any],
5861
entry_options: dict[str, Any],
5962
) -> None:
@@ -68,7 +71,14 @@ async def test_setup_flow(
6871

6972
result = await hass.config_entries.flow.async_configure(
7073
result["flow_id"],
71-
user_input,
74+
user_input_connection,
75+
)
76+
assert result["type"] is FlowResultType.FORM
77+
assert result["step_id"] == "code"
78+
79+
result = await hass.config_entries.flow.async_configure(
80+
result["flow_id"],
81+
user_input_code,
7282
)
7383
assert result["type"] is FlowResultType.CREATE_ENTRY
7484
assert result["title"] == MOCK_CONFIG_DATA[CONF_HOST]
@@ -105,6 +115,14 @@ async def test_setup_connection_failed(
105115
user_input,
106116
)
107117

118+
assert result["type"] is FlowResultType.FORM
119+
assert result["step_id"] == "code"
120+
121+
result = await hass.config_entries.flow.async_configure(
122+
result["flow_id"],
123+
{},
124+
)
125+
108126
assert result["type"] is FlowResultType.CREATE_ENTRY
109127
assert len(mock_setup_entry.mock_calls) == 1
110128

@@ -311,6 +329,80 @@ async def test_cannot_create_same_subentry(
311329
assert len(mock_setup_entry.mock_calls) == 0
312330

313331

332+
async def test_reconfigure_flow_success(
333+
hass: HomeAssistant,
334+
mock_satel: AsyncMock,
335+
mock_setup_entry: AsyncMock,
336+
mock_config_entry: MockConfigEntry,
337+
) -> None:
338+
"""Test that reconfigure updates host/port."""
339+
mock_config_entry.add_to_hass(hass)
340+
341+
result = await mock_config_entry.start_reconfigure_flow(hass)
342+
343+
assert result["type"] is FlowResultType.FORM
344+
assert result["step_id"] == "reconfigure"
345+
346+
result = await hass.config_entries.flow.async_configure(
347+
result["flow_id"],
348+
{
349+
CONF_HOST: "10.0.0.2",
350+
CONF_PORT: 4321,
351+
},
352+
)
353+
354+
assert result["type"] is FlowResultType.ABORT
355+
assert result["reason"] == "reconfigure_successful"
356+
357+
assert mock_config_entry.data == {
358+
CONF_HOST: "10.0.0.2",
359+
CONF_PORT: 4321,
360+
}
361+
362+
await hass.async_block_till_done()
363+
assert mock_setup_entry.call_count == 1
364+
365+
366+
async def test_reconfigure_connection_failed(
367+
hass: HomeAssistant,
368+
mock_satel: AsyncMock,
369+
mock_config_entry: MockConfigEntry,
370+
) -> None:
371+
"""Failure path for the reconfigure flow."""
372+
mock_satel.connect.return_value = False
373+
374+
mock_config_entry.add_to_hass(hass)
375+
376+
result = await mock_config_entry.start_reconfigure_flow(hass)
377+
378+
assert result["type"] is FlowResultType.FORM
379+
assert result["step_id"] == "reconfigure"
380+
381+
result = await hass.config_entries.flow.async_configure(
382+
result["flow_id"],
383+
{CONF_HOST: "1.2.3.4", CONF_PORT: 1234},
384+
)
385+
386+
assert result["type"] is FlowResultType.FORM
387+
assert result["step_id"] == "reconfigure"
388+
assert result["errors"] == {"base": "cannot_connect"}
389+
390+
mock_satel.connect.return_value = True
391+
392+
result = await hass.config_entries.flow.async_configure(
393+
result["flow_id"],
394+
{CONF_HOST: "1.2.3.4", CONF_PORT: 1234},
395+
)
396+
397+
assert result["type"] is FlowResultType.ABORT
398+
assert result["reason"] == "reconfigure_successful"
399+
400+
assert mock_config_entry.data == {
401+
CONF_HOST: "1.2.3.4",
402+
CONF_PORT: 1234,
403+
}
404+
405+
314406
async def test_same_host_config_disallowed(
315407
hass: HomeAssistant, mock_config_entry: MockConfigEntry
316408
) -> None:

0 commit comments

Comments
 (0)