Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 15 additions & 5 deletions homeassistant/components/fritzbox/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@
import voluptuous as vol

from homeassistant import config_entries
from homeassistant.components.ssdp import ATTR_SSDP_LOCATION, ATTR_UPNP_FRIENDLY_NAME
from homeassistant.components.ssdp import (
ATTR_SSDP_LOCATION,
ATTR_UPNP_FRIENDLY_NAME,
ATTR_UPNP_UDN,
)
from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_USERNAME

# pylint:disable=unused-import
Expand Down Expand Up @@ -82,10 +86,6 @@ async def async_step_user(self, user_input=None):

for entry in self.hass.config_entries.async_entries(DOMAIN):
if entry.data[CONF_HOST] == user_input[CONF_HOST]:
if entry.data != user_input:
self.hass.config_entries.async_update_entry(
entry, data=user_input
)
return self.async_abort(reason="already_configured")

self._host = user_input[CONF_HOST]
Expand All @@ -110,12 +110,22 @@ async def async_step_ssdp(self, user_input):
host = urlparse(user_input[ATTR_SSDP_LOCATION]).hostname
self.context[CONF_HOST] = host

uuid = user_input.get(ATTR_UPNP_UDN)
if uuid:
if uuid.startswith("uuid:"):
uuid = uuid[5:]
await self.async_set_unique_id(uuid)
Comment thread
balloob marked this conversation as resolved.
self._abort_if_unique_id_configured({CONF_HOST: host})

for progress in self._async_in_progress():
if progress.get("context", {}).get(CONF_HOST) == host:
return self.async_abort(reason="already_in_progress")

# update old and user-configured config entries
for entry in self.hass.config_entries.async_entries(DOMAIN):
Comment thread
escoand marked this conversation as resolved.
if entry.data[CONF_HOST] == host:
if uuid and not entry.unique_id:
self.hass.config_entries.async_update_entry(entry, unique_id=uuid)
return self.async_abort(reason="already_configured")

self._host = host
Expand Down
32 changes: 30 additions & 2 deletions tests/components/fritzbox/test_config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@
import pytest

from homeassistant.components.fritzbox.const import DOMAIN
from homeassistant.components.ssdp import ATTR_SSDP_LOCATION, ATTR_UPNP_FRIENDLY_NAME
from homeassistant.components.ssdp import (
ATTR_SSDP_LOCATION,
ATTR_UPNP_FRIENDLY_NAME,
ATTR_UPNP_UDN,
)
from homeassistant.const import CONF_DEVICES, CONF_HOST, CONF_PASSWORD, CONF_USERNAME
from homeassistant.helpers.typing import HomeAssistantType

Expand All @@ -16,6 +20,7 @@
MOCK_SSDP_DATA = {
ATTR_SSDP_LOCATION: "https://fake_host:12345/test",
ATTR_UPNP_FRIENDLY_NAME: "fake_name",
ATTR_UPNP_UDN: "uuid:only-a-test",
}


Expand All @@ -42,6 +47,7 @@ async def test_user(hass: HomeAssistantType, fritz: Mock):
assert result["data"][CONF_HOST] == "fake_host"
assert result["data"][CONF_PASSWORD] == "fake_pass"
assert result["data"][CONF_USERNAME] == "fake_user"
assert not result["result"].unique_id


async def test_user_auth_failed(hass: HomeAssistantType, fritz: Mock):
Expand Down Expand Up @@ -73,6 +79,7 @@ async def test_user_already_configured(hass: HomeAssistantType, fritz: Mock):
DOMAIN, context={"source": "user"}, data=MOCK_USER_DATA
)
assert result["type"] == "create_entry"
assert not result["result"].unique_id

result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": "user"}, data=MOCK_USER_DATA
Expand All @@ -91,6 +98,7 @@ async def test_import(hass: HomeAssistantType, fritz: Mock):
assert result["data"][CONF_HOST] == "fake_host"
assert result["data"][CONF_PASSWORD] == "fake_pass"
assert result["data"][CONF_USERNAME] == "fake_user"
assert not result["result"].unique_id


async def test_ssdp(hass: HomeAssistantType, fritz: Mock):
Expand All @@ -110,6 +118,7 @@ async def test_ssdp(hass: HomeAssistantType, fritz: Mock):
assert result["data"][CONF_HOST] == "fake_host"
assert result["data"][CONF_PASSWORD] == "fake_pass"
assert result["data"][CONF_USERNAME] == "fake_user"
assert result["result"].unique_id == "only-a-test"


async def test_ssdp_auth_failed(hass: HomeAssistantType, fritz: Mock):
Expand Down Expand Up @@ -150,7 +159,7 @@ async def test_ssdp_not_successful(hass: HomeAssistantType, fritz: Mock):
assert result["reason"] == "not_found"


async def test_ssdp_already_in_progress(hass: HomeAssistantType, fritz: Mock):
async def test_ssdp_already_in_progress_unique_id(hass: HomeAssistantType, fritz: Mock):
"""Test starting a flow from discovery twice."""
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": "ssdp"}, data=MOCK_SSDP_DATA
Expand All @@ -165,15 +174,34 @@ async def test_ssdp_already_in_progress(hass: HomeAssistantType, fritz: Mock):
assert result["reason"] == "already_in_progress"


async def test_ssdp_already_in_progress_host(hass: HomeAssistantType, fritz: Mock):
"""Test starting a flow from discovery twice."""
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": "ssdp"}, data=MOCK_SSDP_DATA
)
assert result["type"] == "form"
assert result["step_id"] == "confirm"

MOCK_NO_UNIQUE_ID = MOCK_SSDP_DATA.copy()
del MOCK_NO_UNIQUE_ID[ATTR_UPNP_UDN]
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": "ssdp"}, data=MOCK_NO_UNIQUE_ID
)
assert result["type"] == "abort"
assert result["reason"] == "already_in_progress"


async def test_ssdp_already_configured(hass: HomeAssistantType, fritz: Mock):
"""Test starting a flow from discovery when already configured."""
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": "user"}, data=MOCK_USER_DATA
)
assert result["type"] == "create_entry"
assert not result["result"].unique_id

result2 = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": "ssdp"}, data=MOCK_SSDP_DATA
)
assert result2["type"] == "abort"
assert result2["reason"] == "already_configured"
assert result["result"].unique_id == "only-a-test"