mirror of
https://github.com/home-assistant/core.git
synced 2025-07-29 08:07:45 +00:00
cover
This commit is contained in:
parent
2d9faa3e71
commit
1f32e6361a
@ -284,13 +284,13 @@ class EsphomeFlowHandler(ConfigFlow, domain=DOMAIN):
|
||||
await self._async_validate_mac_abort_configured(
|
||||
mac_address, self._host, self._port
|
||||
)
|
||||
|
||||
return await self.async_step_discovery_confirm()
|
||||
|
||||
async def _async_validate_mac_abort_configured(
|
||||
self, formatted_mac: str, host: str, port: int | None
|
||||
) -> None:
|
||||
"""Validate if the MAC address is already configured."""
|
||||
assert self.unique_id is not None
|
||||
if not (
|
||||
entry := self.hass.config_entries.async_entry_for_domain_unique_id(
|
||||
self.handler, formatted_mac
|
||||
@ -459,11 +459,12 @@ class EsphomeFlowHandler(ConfigFlow, domain=DOMAIN):
|
||||
|
||||
async def async_step_validated_connection(self) -> ConfigFlowResult:
|
||||
"""Handle validated connection."""
|
||||
if self.source == SOURCE_RECONFIGURE:
|
||||
assert self.unique_id is not None
|
||||
assert self._reconfig_entry.unique_id is not None
|
||||
assert self._host is not None
|
||||
assert self._device_name is not None
|
||||
|
||||
if self.source == SOURCE_RECONFIGURE:
|
||||
assert self._reconfig_entry.unique_id is not None
|
||||
placeholders = {
|
||||
"name": self._reconfig_entry.data.get(
|
||||
CONF_DEVICE_NAME, self._reconfig_entry.title
|
||||
@ -500,6 +501,22 @@ class EsphomeFlowHandler(ConfigFlow, domain=DOMAIN):
|
||||
data=self._reconfig_entry.data | self._async_make_config_data(),
|
||||
)
|
||||
if self.source == SOURCE_REAUTH:
|
||||
if self.unique_id != self._reauth_entry.unique_id:
|
||||
await self._async_validate_mac_abort_configured(
|
||||
format_mac(self.unique_id), self._host, self._port
|
||||
)
|
||||
return self.async_abort(
|
||||
reason="reauth_unique_id_changed",
|
||||
description_placeholders={
|
||||
"name": self._reauth_entry.data.get(
|
||||
CONF_DEVICE_NAME, self._reauth_entry.title
|
||||
),
|
||||
"host": self._host,
|
||||
"expected_mac": format_mac(self._reauth_entry.unique_id),
|
||||
"unexpected_mac": format_mac(self.unique_id),
|
||||
"unexpected_device_name": self._device_name,
|
||||
},
|
||||
)
|
||||
return self.async_update_reload_and_abort(
|
||||
self._reauth_entry,
|
||||
data=self._reauth_entry.data | self._async_make_config_data(),
|
||||
@ -563,7 +580,6 @@ class EsphomeFlowHandler(ConfigFlow, domain=DOMAIN):
|
||||
zeroconf_instance=zeroconf_instance,
|
||||
noise_psk=noise_psk,
|
||||
)
|
||||
|
||||
try:
|
||||
await cli.connect()
|
||||
self._device_info = await cli.device_info()
|
||||
|
@ -12,6 +12,7 @@
|
||||
"mqtt_missing_payload": "Missing MQTT Payload.",
|
||||
"name_conflict_migrated": "The configuration for `{name}` has been migrated to a new device with MAC address `{mac}` from `{existing_mac}`.",
|
||||
"reconfigure_successful": "[%key:common::config_flow::abort::reconfigure_successful%]",
|
||||
"reauth_unique_id_changed": "**Re-authentication of `{name}` was aborted** because the address `{host}` points to a different device: `{unexpected_device_name}` (MAC: `{unexpected_mac}`) instead of the expected one (MAC: `{expected_mac}`).",
|
||||
"reconfigure_name_conflict": "**Reconfiguration of `{name}` was aborted** because the address `{host}` points to a device named `{name}` (MAC: `{expected_mac}`), which is already in use by another configuration entry: `{existing_title}`.",
|
||||
"reconfigure_unique_id_changed": "**Reconfiguration of `{name}` was aborted** because the address `{host}` points to a different device: `{unexpected_device_name}` (MAC: `{unexpected_mac}`) instead of the expected one (MAC: `{expected_mac}`)."
|
||||
},
|
||||
|
@ -813,12 +813,15 @@ async def test_reauth_confirm_valid(
|
||||
entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
data={CONF_HOST: "127.0.0.1", CONF_PORT: 6053, CONF_PASSWORD: ""},
|
||||
unique_id="11:22:33:44:55:aa",
|
||||
)
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
result = await entry.start_reauth_flow(hass)
|
||||
|
||||
mock_client.device_info.return_value = DeviceInfo(uses_password=False, name="test")
|
||||
mock_client.device_info.return_value = DeviceInfo(
|
||||
uses_password=False, name="test", mac_address="11:22:33:44:55:aa"
|
||||
)
|
||||
result = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"], user_input={CONF_NOISE_PSK: VALID_NOISE_PSK}
|
||||
)
|
||||
@ -828,6 +831,41 @@ async def test_reauth_confirm_valid(
|
||||
assert entry.data[CONF_NOISE_PSK] == VALID_NOISE_PSK
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("mock_zeroconf", "mock_setup_entry")
|
||||
async def test_reauth_attempt_to_change_mac_aborts(
|
||||
hass: HomeAssistant, mock_client: APIClient
|
||||
) -> None:
|
||||
"""Test reauth initiation with valid PSK attempting to change mac.
|
||||
|
||||
This can happen if reauth starts, but they don't finish it before
|
||||
a new device takes the place of the old one at the same IP.
|
||||
"""
|
||||
entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
data={
|
||||
CONF_HOST: "127.0.0.1",
|
||||
CONF_PORT: 6053,
|
||||
CONF_PASSWORD: "",
|
||||
CONF_DEVICE_NAME: "test",
|
||||
},
|
||||
unique_id="11:22:33:44:55:aa",
|
||||
)
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
result = await entry.start_reauth_flow(hass)
|
||||
|
||||
mock_client.device_info.return_value = DeviceInfo(
|
||||
uses_password=False, name="test", mac_address="11:22:33:44:55:bb"
|
||||
)
|
||||
result = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"], user_input={CONF_NOISE_PSK: VALID_NOISE_PSK}
|
||||
)
|
||||
|
||||
assert result["type"] is FlowResultType.ABORT
|
||||
assert result["reason"] == "reauth_unique_id_changed"
|
||||
assert CONF_NOISE_PSK not in entry.data
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("mock_zeroconf")
|
||||
async def test_reauth_fixed_via_dashboard(
|
||||
hass: HomeAssistant,
|
||||
@ -845,10 +883,13 @@ async def test_reauth_fixed_via_dashboard(
|
||||
CONF_PASSWORD: "",
|
||||
CONF_DEVICE_NAME: "test",
|
||||
},
|
||||
unique_id="11:22:33:44:55:aa",
|
||||
)
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
mock_client.device_info.return_value = DeviceInfo(uses_password=False, name="test")
|
||||
mock_client.device_info.return_value = DeviceInfo(
|
||||
uses_password=False, name="test", mac_address="11:22:33:44:55:aa"
|
||||
)
|
||||
|
||||
mock_dashboard["configured"].append(
|
||||
{
|
||||
@ -883,7 +924,7 @@ async def test_reauth_fixed_via_dashboard_add_encryption_remove_password(
|
||||
"""Test reauth fixed automatically via dashboard with password removed."""
|
||||
mock_client.device_info.side_effect = (
|
||||
InvalidAuthAPIError,
|
||||
DeviceInfo(uses_password=False, name="test"),
|
||||
DeviceInfo(uses_password=False, name="test", mac_address="11:22:33:44:55:aa"),
|
||||
)
|
||||
|
||||
mock_dashboard["configured"].append(
|
||||
@ -917,7 +958,9 @@ async def test_reauth_fixed_via_remove_password(
|
||||
mock_setup_entry: None,
|
||||
) -> None:
|
||||
"""Test reauth fixed automatically by seeing password removed."""
|
||||
mock_client.device_info.return_value = DeviceInfo(uses_password=False, name="test")
|
||||
mock_client.device_info.return_value = DeviceInfo(
|
||||
uses_password=False, name="test", mac_address="11:22:33:44:55:aa"
|
||||
)
|
||||
|
||||
result = await mock_config_entry.start_reauth_flow(hass)
|
||||
|
||||
@ -943,10 +986,13 @@ async def test_reauth_fixed_via_dashboard_at_confirm(
|
||||
CONF_PASSWORD: "",
|
||||
CONF_DEVICE_NAME: "test",
|
||||
},
|
||||
unique_id="11:22:33:44:55:aa",
|
||||
)
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
mock_client.device_info.return_value = DeviceInfo(uses_password=False, name="test")
|
||||
mock_client.device_info.return_value = DeviceInfo(
|
||||
uses_password=False, name="test", mac_address="11:22:33:44:55:aa"
|
||||
)
|
||||
|
||||
result = await entry.start_reauth_flow(hass)
|
||||
|
||||
@ -984,6 +1030,7 @@ async def test_reauth_confirm_invalid(
|
||||
entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
data={CONF_HOST: "127.0.0.1", CONF_PORT: 6053, CONF_PASSWORD: ""},
|
||||
unique_id="11:22:33:44:55:aa",
|
||||
)
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
@ -1000,7 +1047,9 @@ async def test_reauth_confirm_invalid(
|
||||
assert result["errors"]["base"] == "invalid_psk"
|
||||
|
||||
mock_client.device_info = AsyncMock(
|
||||
return_value=DeviceInfo(uses_password=False, name="test")
|
||||
return_value=DeviceInfo(
|
||||
uses_password=False, name="test", mac_address="11:22:33:44:55:aa"
|
||||
)
|
||||
)
|
||||
result = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"], user_input={CONF_NOISE_PSK: VALID_NOISE_PSK}
|
||||
@ -1019,7 +1068,7 @@ async def test_reauth_confirm_invalid_with_unique_id(
|
||||
entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
data={CONF_HOST: "127.0.0.1", CONF_PORT: 6053, CONF_PASSWORD: ""},
|
||||
unique_id="test",
|
||||
unique_id="11:22:33:44:55:aa",
|
||||
)
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
@ -1036,7 +1085,9 @@ async def test_reauth_confirm_invalid_with_unique_id(
|
||||
assert result["errors"]["base"] == "invalid_psk"
|
||||
|
||||
mock_client.device_info = AsyncMock(
|
||||
return_value=DeviceInfo(uses_password=False, name="test")
|
||||
return_value=DeviceInfo(
|
||||
uses_password=False, name="test", mac_address="11:22:33:44:55:aa"
|
||||
)
|
||||
)
|
||||
result = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"], user_input={CONF_NOISE_PSK: VALID_NOISE_PSK}
|
||||
@ -1049,7 +1100,7 @@ async def test_reauth_confirm_invalid_with_unique_id(
|
||||
|
||||
@pytest.mark.usefixtures("mock_zeroconf")
|
||||
async def test_reauth_encryption_key_removed(
|
||||
hass: HomeAssistant, mock_client, mock_setup_entry: None
|
||||
hass: HomeAssistant, mock_client: APIClient, mock_setup_entry: None
|
||||
) -> None:
|
||||
"""Test reauth when the encryption key was removed."""
|
||||
entry = MockConfigEntry(
|
||||
@ -1060,7 +1111,7 @@ async def test_reauth_encryption_key_removed(
|
||||
CONF_PASSWORD: "",
|
||||
CONF_NOISE_PSK: VALID_NOISE_PSK,
|
||||
},
|
||||
unique_id="test",
|
||||
unique_id="11:22:33:44:55:aa",
|
||||
)
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
@ -1715,3 +1766,129 @@ async def test_user_flow_name_conflict_overwrite(
|
||||
CONF_DEVICE_NAME: "test",
|
||||
}
|
||||
assert result["context"]["unique_id"] == "11:22:33:44:55:aa"
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("mock_zeroconf", "mock_setup_entry")
|
||||
async def test_reconfig_attempt_to_change_mac_aborts(
|
||||
hass: HomeAssistant, mock_client: APIClient
|
||||
) -> None:
|
||||
"""Test reconfig initiation with valid PSK attempting to change mac."""
|
||||
entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
data={
|
||||
CONF_HOST: "127.0.0.1",
|
||||
CONF_PORT: 6053,
|
||||
CONF_PASSWORD: "",
|
||||
CONF_DEVICE_NAME: "test",
|
||||
},
|
||||
unique_id="11:22:33:44:55:aa",
|
||||
)
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
result = await entry.start_reconfigure_flow(hass)
|
||||
|
||||
mock_client.device_info.return_value = DeviceInfo(
|
||||
uses_password=False, name="other", mac_address="11:22:33:44:55:bb"
|
||||
)
|
||||
result = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"], user_input={CONF_HOST: "127.0.0.2", CONF_PORT: 6053}
|
||||
)
|
||||
|
||||
assert result["type"] is FlowResultType.ABORT
|
||||
assert result["reason"] == "reconfigure_unique_id_changed"
|
||||
assert CONF_NOISE_PSK not in entry.data
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("mock_zeroconf", "mock_setup_entry")
|
||||
async def test_reconfig_name_conflict_migrate(
|
||||
hass: HomeAssistant, mock_client: APIClient
|
||||
) -> None:
|
||||
"""Test reconfig initiation when device has been replaced."""
|
||||
entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
data={
|
||||
CONF_HOST: "127.0.0.1",
|
||||
CONF_PORT: 6053,
|
||||
CONF_PASSWORD: "",
|
||||
CONF_DEVICE_NAME: "test",
|
||||
},
|
||||
unique_id="11:22:33:44:55:aa",
|
||||
)
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
result = await entry.start_reconfigure_flow(hass)
|
||||
|
||||
mock_client.device_info.return_value = DeviceInfo(
|
||||
uses_password=False, name="test", mac_address="11:22:33:44:55:bb"
|
||||
)
|
||||
result = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"], user_input={CONF_HOST: "127.0.0.2", CONF_PORT: 6053}
|
||||
)
|
||||
|
||||
assert result["type"] is FlowResultType.MENU
|
||||
assert result["step_id"] == "name_conflict"
|
||||
|
||||
result = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"], user_input={"next_step_id": "name_conflict_migrate"}
|
||||
)
|
||||
assert result["type"] is FlowResultType.ABORT
|
||||
assert result["reason"] == "name_conflict_migrated"
|
||||
|
||||
assert entry.data == {
|
||||
CONF_HOST: "127.0.0.2",
|
||||
CONF_PORT: 6053,
|
||||
CONF_PASSWORD: "",
|
||||
CONF_NOISE_PSK: "",
|
||||
CONF_DEVICE_NAME: "test",
|
||||
}
|
||||
assert entry.unique_id == "11:22:33:44:55:bb"
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("mock_zeroconf", "mock_setup_entry")
|
||||
async def test_reconfig_name_conflict_overwrite(
|
||||
hass: HomeAssistant, mock_client: APIClient
|
||||
) -> None:
|
||||
"""Test reconfig initiation when device has been replaced."""
|
||||
entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
data={
|
||||
CONF_HOST: "127.0.0.1",
|
||||
CONF_PORT: 6053,
|
||||
CONF_PASSWORD: "",
|
||||
CONF_DEVICE_NAME: "test",
|
||||
},
|
||||
unique_id="11:22:33:44:55:aa",
|
||||
)
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
result = await entry.start_reconfigure_flow(hass)
|
||||
|
||||
mock_client.device_info.return_value = DeviceInfo(
|
||||
uses_password=False, name="test", mac_address="11:22:33:44:55:bb"
|
||||
)
|
||||
result = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"], user_input={CONF_HOST: "127.0.0.2", CONF_PORT: 6053}
|
||||
)
|
||||
|
||||
assert result["type"] is FlowResultType.MENU
|
||||
assert result["step_id"] == "name_conflict"
|
||||
|
||||
result = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"], user_input={"next_step_id": "name_conflict_overwrite"}
|
||||
)
|
||||
assert result["type"] is FlowResultType.CREATE_ENTRY
|
||||
|
||||
assert result["data"] == {
|
||||
CONF_HOST: "127.0.0.2",
|
||||
CONF_PORT: 6053,
|
||||
CONF_PASSWORD: "",
|
||||
CONF_NOISE_PSK: "",
|
||||
CONF_DEVICE_NAME: "test",
|
||||
}
|
||||
assert result["context"]["unique_id"] == "11:22:33:44:55:bb"
|
||||
assert (
|
||||
hass.config_entries.async_entry_for_domain_unique_id(
|
||||
DOMAIN, "11:22:33:44:55:aa"
|
||||
)
|
||||
is None
|
||||
)
|
||||
|
Loading…
x
Reference in New Issue
Block a user