Rework config flow in AVM Fritz!Tools ()

pull/68875/head
Michael 2022-03-30 01:53:53 +02:00 committed by GitHub
parent 603601b32e
commit 94c5dbfd16
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 60 additions and 66 deletions
homeassistant/components/fritz
tests/components/fritz

View File

@ -1,7 +1,7 @@
"""Support for AVM Fritz!Box functions."""
import logging
from fritzconnection.core.exceptions import FritzSecurityError
from fritzconnection.core.exceptions import FritzConnectionException
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_PORT, CONF_USERNAME
@ -28,10 +28,10 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
try:
await avm_wrapper.async_setup(entry.options)
except FritzSecurityError as ex:
raise ConfigEntryAuthFailed from ex
except FRITZ_EXCEPTIONS as ex:
raise ConfigEntryNotReady from ex
except FritzConnectionException as ex:
raise ConfigEntryAuthFailed from ex
if (
"X_AVM-DE_UPnP1" in avm_wrapper.connection.services

View File

@ -6,6 +6,7 @@ import socket
from typing import Any
from urllib.parse import ParseResult, urlparse
from fritzconnection import FritzConnection
from fritzconnection.core.exceptions import FritzConnectionException, FritzSecurityError
import voluptuous as vol
@ -19,7 +20,6 @@ from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_PORT, CONF_USERNA
from homeassistant.core import callback
from homeassistant.data_entry_flow import FlowResult
from .common import AvmWrapper
from .const import (
CONF_OLD_DISCOVERY,
DEFAULT_CONF_OLD_DISCOVERY,
@ -49,29 +49,25 @@ class FritzBoxToolsFlowHandler(ConfigFlow, domain=DOMAIN):
def __init__(self) -> None:
"""Initialize FRITZ!Box Tools flow."""
self._host: str | None = None
self._entry: ConfigEntry
self._name: str
self._password: str
self._entry: ConfigEntry | None = None
self._name: str = ""
self._password: str = ""
self._port: int | None = None
self._username: str
self.avm_wrapper: AvmWrapper
self._username: str = ""
self._model: str = ""
async def fritz_tools_init(self) -> str | None:
def fritz_tools_init(self) -> str | None:
"""Initialize FRITZ!Box Tools class."""
if not self._host or not self._port:
return None
self.avm_wrapper = AvmWrapper(
hass=self.hass,
host=self._host,
port=self._port,
username=self._username,
password=self._password,
)
try:
await self.avm_wrapper.async_setup()
connection = FritzConnection(
address=self._host,
port=self._port,
user=self._username,
password=self._password,
timeout=60.0,
pool_maxsize=30,
)
except FritzSecurityError:
return ERROR_AUTH_INVALID
except FritzConnectionException:
@ -80,9 +76,11 @@ class FritzBoxToolsFlowHandler(ConfigFlow, domain=DOMAIN):
_LOGGER.exception("Unexpected exception")
return ERROR_UNKNOWN
self._model = connection.call_action("DeviceInfo:1", "GetInfo")["NewModelName"]
if (
"X_AVM-DE_UPnP1" in self.avm_wrapper.connection.services
and not (await self.avm_wrapper.async_get_upnp_configuration())["NewEnable"]
"X_AVM-DE_UPnP1" in connection.services
and not connection.call_action("X_AVM-DE_UPnP1", "GetInfo")["NewEnable"]
):
return ERROR_UPNP_NOT_CONFIGURED
@ -109,10 +107,10 @@ class FritzBoxToolsFlowHandler(ConfigFlow, domain=DOMAIN):
return self.async_create_entry(
title=self._name,
data={
CONF_HOST: self.avm_wrapper.host,
CONF_PASSWORD: self.avm_wrapper.password,
CONF_PORT: self.avm_wrapper.port,
CONF_USERNAME: self.avm_wrapper.username,
CONF_HOST: self._host,
CONF_PASSWORD: self._password,
CONF_PORT: self._port,
CONF_USERNAME: self._username,
},
options={
CONF_CONSIDER_HOME: DEFAULT_CONSIDER_HOME.total_seconds(),
@ -163,7 +161,7 @@ class FritzBoxToolsFlowHandler(ConfigFlow, domain=DOMAIN):
self._username = user_input[CONF_USERNAME]
self._password = user_input[CONF_PASSWORD]
error = await self.fritz_tools_init()
error = await self.hass.async_add_executor_job(self.fritz_tools_init)
if error:
errors["base"] = error
@ -213,8 +211,8 @@ class FritzBoxToolsFlowHandler(ConfigFlow, domain=DOMAIN):
self._username = user_input[CONF_USERNAME]
self._password = user_input[CONF_PASSWORD]
if not (error := await self.fritz_tools_init()):
self._name = self.avm_wrapper.model
if not (error := await self.hass.async_add_executor_job(self.fritz_tools_init)):
self._name = self._model
if await self.async_check_configured_entry():
error = "already_configured"
@ -226,10 +224,7 @@ class FritzBoxToolsFlowHandler(ConfigFlow, domain=DOMAIN):
async def async_step_reauth(self, data: dict[str, Any]) -> FlowResult:
"""Handle flow upon an API authentication error."""
if cfg_entry := self.hass.config_entries.async_get_entry(
self.context["entry_id"]
):
self._entry = cfg_entry
self._entry = self.hass.config_entries.async_get_entry(self.context["entry_id"])
self._host = data[CONF_HOST]
self._port = data[CONF_PORT]
self._username = data[CONF_USERNAME]
@ -265,11 +260,12 @@ class FritzBoxToolsFlowHandler(ConfigFlow, domain=DOMAIN):
self._username = user_input[CONF_USERNAME]
self._password = user_input[CONF_PASSWORD]
if error := await self.fritz_tools_init():
if error := await self.hass.async_add_executor_job(self.fritz_tools_init):
return self._show_setup_form_reauth_confirm(
user_input=user_input, errors={"base": error}
)
assert isinstance(self._entry, ConfigEntry)
self.hass.config_entries.async_update_entry(
self._entry,
data={

View File

@ -38,9 +38,9 @@ from tests.common import MockConfigEntry
async def test_user(hass: HomeAssistant, fc_class_mock, mock_get_source_ip):
"""Test starting a flow by user."""
with patch(
"homeassistant.components.fritz.common.FritzConnection",
"homeassistant.components.fritz.config_flow.FritzConnection",
side_effect=fc_class_mock,
), patch("homeassistant.components.fritz.common.FritzStatus"), patch(
), patch(
"homeassistant.components.fritz.common.FritzBoxTools._update_device_info",
return_value=MOCK_FIRMWARE_INFO,
), patch(
@ -91,9 +91,9 @@ async def test_user_already_configured(
mock_config.add_to_hass(hass)
with patch(
"homeassistant.components.fritz.common.FritzConnection",
"homeassistant.components.fritz.config_flow.FritzConnection",
side_effect=fc_class_mock,
), patch("homeassistant.components.fritz.common.FritzStatus"), patch(
), patch(
"homeassistant.components.fritz.common.FritzBoxTools._update_device_info",
return_value=MOCK_FIRMWARE_INFO,
), patch(
@ -134,9 +134,9 @@ async def test_exception_security(hass: HomeAssistant, mock_get_source_ip):
assert result["step_id"] == "user"
with patch(
"homeassistant.components.fritz.common.FritzConnection",
"homeassistant.components.fritz.config_flow.FritzConnection",
side_effect=FritzSecurityError,
), patch("homeassistant.components.fritz.common.FritzStatus"):
):
result = await hass.config_entries.flow.async_configure(
result["flow_id"], user_input=MOCK_USER_DATA
@ -157,9 +157,9 @@ async def test_exception_connection(hass: HomeAssistant, mock_get_source_ip):
assert result["step_id"] == "user"
with patch(
"homeassistant.components.fritz.common.FritzConnection",
"homeassistant.components.fritz.config_flow.FritzConnection",
side_effect=FritzConnectionException,
), patch("homeassistant.components.fritz.common.FritzStatus"):
):
result = await hass.config_entries.flow.async_configure(
result["flow_id"], user_input=MOCK_USER_DATA
@ -180,9 +180,9 @@ async def test_exception_unknown(hass: HomeAssistant, mock_get_source_ip):
assert result["step_id"] == "user"
with patch(
"homeassistant.components.fritz.common.FritzConnection",
"homeassistant.components.fritz.config_flow.FritzConnection",
side_effect=OSError,
), patch("homeassistant.components.fritz.common.FritzStatus"):
):
result = await hass.config_entries.flow.async_configure(
result["flow_id"], user_input=MOCK_USER_DATA
@ -202,9 +202,9 @@ async def test_reauth_successful(
mock_config.add_to_hass(hass)
with patch(
"homeassistant.components.fritz.common.FritzConnection",
"homeassistant.components.fritz.config_flow.FritzConnection",
side_effect=fc_class_mock,
), patch("homeassistant.components.fritz.common.FritzStatus"), patch(
), patch(
"homeassistant.components.fritz.common.FritzBoxTools._update_device_info",
return_value=MOCK_FIRMWARE_INFO,
), patch(
@ -252,9 +252,9 @@ async def test_reauth_not_successful(
mock_config.add_to_hass(hass)
with patch(
"homeassistant.components.fritz.common.FritzConnection",
"homeassistant.components.fritz.config_flow.FritzConnection",
side_effect=FritzConnectionException,
), patch("homeassistant.components.fritz.common.FritzStatus"):
):
result = await hass.config_entries.flow.async_init(
DOMAIN,
@ -291,9 +291,9 @@ async def test_ssdp_already_configured(
mock_config.add_to_hass(hass)
with patch(
"homeassistant.components.fritz.common.FritzConnection",
"homeassistant.components.fritz.config_flow.FritzConnection",
side_effect=fc_class_mock,
), patch("homeassistant.components.fritz.common.FritzStatus"), patch(
), patch(
"homeassistant.components.fritz.config_flow.socket.gethostbyname",
return_value=MOCK_IPS["fritz.box"],
):
@ -318,9 +318,9 @@ async def test_ssdp_already_configured_host(
mock_config.add_to_hass(hass)
with patch(
"homeassistant.components.fritz.common.FritzConnection",
"homeassistant.components.fritz.config_flow.FritzConnection",
side_effect=fc_class_mock,
), patch("homeassistant.components.fritz.common.FritzStatus"), patch(
), patch(
"homeassistant.components.fritz.config_flow.socket.gethostbyname",
return_value=MOCK_IPS["fritz.box"],
):
@ -345,9 +345,9 @@ async def test_ssdp_already_configured_host_uuid(
mock_config.add_to_hass(hass)
with patch(
"homeassistant.components.fritz.common.FritzConnection",
"homeassistant.components.fritz.config_flow.FritzConnection",
side_effect=fc_class_mock,
), patch("homeassistant.components.fritz.common.FritzStatus"), patch(
), patch(
"homeassistant.components.fritz.config_flow.socket.gethostbyname",
return_value=MOCK_IPS["fritz.box"],
):
@ -364,9 +364,9 @@ async def test_ssdp_already_in_progress_host(
):
"""Test starting a flow from discovery twice."""
with patch(
"homeassistant.components.fritz.common.FritzConnection",
"homeassistant.components.fritz.config_flow.FritzConnection",
side_effect=fc_class_mock,
), patch("homeassistant.components.fritz.common.FritzStatus"):
):
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_SSDP}, data=MOCK_SSDP_DATA
@ -387,9 +387,9 @@ async def test_ssdp_already_in_progress_host(
async def test_ssdp(hass: HomeAssistant, fc_class_mock, mock_get_source_ip):
"""Test starting a flow from discovery."""
with patch(
"homeassistant.components.fritz.common.FritzConnection",
"homeassistant.components.fritz.config_flow.FritzConnection",
side_effect=fc_class_mock,
), patch("homeassistant.components.fritz.common.FritzStatus"), patch(
), patch(
"homeassistant.components.fritz.common.FritzBoxTools._update_device_info",
return_value=MOCK_FIRMWARE_INFO,
), patch(
@ -430,9 +430,9 @@ async def test_ssdp(hass: HomeAssistant, fc_class_mock, mock_get_source_ip):
async def test_ssdp_exception(hass: HomeAssistant, mock_get_source_ip):
"""Test starting a flow from discovery but no device found."""
with patch(
"homeassistant.components.fritz.common.FritzConnection",
"homeassistant.components.fritz.config_flow.FritzConnection",
side_effect=FritzConnectionException,
), patch("homeassistant.components.fritz.common.FritzStatus"):
):
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_SSDP}, data=MOCK_SSDP_DATA
@ -459,11 +459,9 @@ async def test_options_flow(hass: HomeAssistant, fc_class_mock, mock_get_source_
mock_config.add_to_hass(hass)
with patch(
"homeassistant.components.fritz.common.FritzConnection",
"homeassistant.components.fritz.config_flow.FritzConnection",
side_effect=fc_class_mock,
), patch("homeassistant.components.fritz.common.FritzStatus"), patch(
"homeassistant.components.fritz.common.FritzBoxTools"
):
), patch("homeassistant.components.fritz.common.FritzBoxTools"):
result = await hass.config_entries.options.async_init(mock_config.entry_id)
assert result["type"] == RESULT_TYPE_FORM
assert result["step_id"] == "init"