Remove deprecated yaml import from Ecovacs (#123605)
This commit is contained in:
parent
6343a086e4
commit
401e36b885
5 changed files with 8 additions and 311 deletions
|
@ -1,31 +1,13 @@
|
|||
"""Support for Ecovacs Deebot vacuums."""
|
||||
|
||||
from sucks import VacBot
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry
|
||||
from homeassistant.const import CONF_COUNTRY, CONF_PASSWORD, CONF_USERNAME, Platform
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import Platform
|
||||
from homeassistant.core import HomeAssistant
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.helpers.typing import ConfigType
|
||||
|
||||
from .const import CONF_CONTINENT, DOMAIN
|
||||
from .controller import EcovacsController
|
||||
|
||||
CONFIG_SCHEMA = vol.Schema(
|
||||
{
|
||||
DOMAIN: vol.Schema(
|
||||
{
|
||||
vol.Required(CONF_USERNAME): cv.string,
|
||||
vol.Required(CONF_PASSWORD): cv.string,
|
||||
vol.Required(CONF_COUNTRY): vol.All(vol.Lower, cv.string),
|
||||
vol.Required(CONF_CONTINENT): vol.All(vol.Lower, cv.string),
|
||||
}
|
||||
)
|
||||
},
|
||||
extra=vol.ALLOW_EXTRA,
|
||||
)
|
||||
|
||||
PLATFORMS = [
|
||||
Platform.BINARY_SENSOR,
|
||||
Platform.BUTTON,
|
||||
|
@ -41,17 +23,6 @@ PLATFORMS = [
|
|||
type EcovacsConfigEntry = ConfigEntry[EcovacsController]
|
||||
|
||||
|
||||
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
||||
"""Set up the Ecovacs component."""
|
||||
if DOMAIN in config:
|
||||
hass.async_create_task(
|
||||
hass.config_entries.flow.async_init(
|
||||
DOMAIN, context={"source": SOURCE_IMPORT}, data=config[DOMAIN]
|
||||
)
|
||||
)
|
||||
return True
|
||||
|
||||
|
||||
async def async_setup_entry(hass: HomeAssistant, entry: EcovacsConfigEntry) -> bool:
|
||||
"""Set up this integration using UI."""
|
||||
controller = EcovacsController(hass, entry.data)
|
||||
|
|
|
@ -4,7 +4,7 @@ from __future__ import annotations
|
|||
|
||||
import logging
|
||||
import ssl
|
||||
from typing import Any, cast
|
||||
from typing import Any
|
||||
from urllib.parse import urlparse
|
||||
|
||||
from aiohttp import ClientError
|
||||
|
@ -13,21 +13,16 @@ from deebot_client.const import UNDEFINED, UndefinedType
|
|||
from deebot_client.exceptions import InvalidAuthenticationError, MqttError
|
||||
from deebot_client.mqtt_client import MqttClient, create_mqtt_config
|
||||
from deebot_client.util import md5
|
||||
from deebot_client.util.continents import COUNTRIES_TO_CONTINENTS, get_continent
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.config_entries import ConfigFlow, ConfigFlowResult
|
||||
from homeassistant.const import CONF_COUNTRY, CONF_MODE, CONF_PASSWORD, CONF_USERNAME
|
||||
from homeassistant.core import DOMAIN as HOMEASSISTANT_DOMAIN, HomeAssistant
|
||||
from homeassistant.data_entry_flow import AbortFlow
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import aiohttp_client, selector
|
||||
from homeassistant.helpers.issue_registry import IssueSeverity, async_create_issue
|
||||
from homeassistant.helpers.typing import VolDictType
|
||||
from homeassistant.loader import async_get_issue_tracker
|
||||
from homeassistant.util.ssl import get_default_no_verify_context
|
||||
|
||||
from .const import (
|
||||
CONF_CONTINENT,
|
||||
CONF_OVERRIDE_MQTT_URL,
|
||||
CONF_OVERRIDE_REST_URL,
|
||||
CONF_VERIFY_MQTT_CERTIFICATE,
|
||||
|
@ -218,98 +213,3 @@ class EcovacsConfigFlow(ConfigFlow, domain=DOMAIN):
|
|||
errors=errors,
|
||||
last_step=True,
|
||||
)
|
||||
|
||||
async def async_step_import(self, user_input: dict[str, Any]) -> ConfigFlowResult:
|
||||
"""Import configuration from yaml."""
|
||||
|
||||
def create_repair(
|
||||
error: str | None = None, placeholders: dict[str, Any] | None = None
|
||||
) -> None:
|
||||
if placeholders is None:
|
||||
placeholders = {}
|
||||
if error:
|
||||
async_create_issue(
|
||||
self.hass,
|
||||
DOMAIN,
|
||||
f"deprecated_yaml_import_issue_{error}",
|
||||
breaks_in_ha_version="2024.8.0",
|
||||
is_fixable=False,
|
||||
issue_domain=DOMAIN,
|
||||
severity=IssueSeverity.WARNING,
|
||||
translation_key=f"deprecated_yaml_import_issue_{error}",
|
||||
translation_placeholders=placeholders
|
||||
| {"url": "/config/integrations/dashboard/add?domain=ecovacs"},
|
||||
)
|
||||
else:
|
||||
async_create_issue(
|
||||
self.hass,
|
||||
HOMEASSISTANT_DOMAIN,
|
||||
f"deprecated_yaml_{DOMAIN}",
|
||||
breaks_in_ha_version="2024.8.0",
|
||||
is_fixable=False,
|
||||
issue_domain=DOMAIN,
|
||||
severity=IssueSeverity.WARNING,
|
||||
translation_key="deprecated_yaml",
|
||||
translation_placeholders=placeholders
|
||||
| {
|
||||
"domain": DOMAIN,
|
||||
"integration_title": "Ecovacs",
|
||||
},
|
||||
)
|
||||
|
||||
# We need to validate the imported country and continent
|
||||
# as the YAML configuration allows any string for them.
|
||||
# The config flow allows only valid alpha-2 country codes
|
||||
# through the CountrySelector.
|
||||
# The continent will be calculated with the function get_continent
|
||||
# from the country code and there is no need to specify the continent anymore.
|
||||
# As the YAML configuration includes the continent,
|
||||
# we check if both the entered continent and the calculated continent match.
|
||||
# If not we will inform the user about the mismatch.
|
||||
error = None
|
||||
placeholders = None
|
||||
|
||||
# Convert the country to upper case as ISO 3166-1 alpha-2 country codes are upper case
|
||||
user_input[CONF_COUNTRY] = user_input[CONF_COUNTRY].upper()
|
||||
|
||||
if len(user_input[CONF_COUNTRY]) != 2:
|
||||
error = "invalid_country_length"
|
||||
placeholders = {"countries_url": "https://www.iso.org/obp/ui/#search/code/"}
|
||||
elif len(user_input[CONF_CONTINENT]) != 2:
|
||||
error = "invalid_continent_length"
|
||||
placeholders = {
|
||||
"continent_list": ",".join(
|
||||
sorted(set(COUNTRIES_TO_CONTINENTS.values()))
|
||||
)
|
||||
}
|
||||
elif user_input[CONF_CONTINENT].lower() != (
|
||||
continent := get_continent(user_input[CONF_COUNTRY])
|
||||
):
|
||||
error = "continent_not_match"
|
||||
placeholders = {
|
||||
"continent": continent,
|
||||
"github_issue_url": cast(
|
||||
str, async_get_issue_tracker(self.hass, integration_domain=DOMAIN)
|
||||
),
|
||||
}
|
||||
|
||||
if error:
|
||||
create_repair(error, placeholders)
|
||||
return self.async_abort(reason=error)
|
||||
|
||||
# Remove the continent from the user input as it is not needed anymore
|
||||
user_input.pop(CONF_CONTINENT)
|
||||
try:
|
||||
result = await self.async_step_auth(user_input)
|
||||
except AbortFlow as ex:
|
||||
if ex.reason == "already_configured":
|
||||
create_repair()
|
||||
raise
|
||||
|
||||
if errors := result.get("errors"):
|
||||
error = errors["base"]
|
||||
create_repair(error)
|
||||
return self.async_abort(reason=error)
|
||||
|
||||
create_repair()
|
||||
return result
|
||||
|
|
|
@ -237,32 +237,6 @@
|
|||
"message": "Getting the positions of the chargers and the device itself is not supported"
|
||||
}
|
||||
},
|
||||
"issues": {
|
||||
"deprecated_yaml_import_issue_cannot_connect": {
|
||||
"title": "The Ecovacs YAML configuration import failed",
|
||||
"description": "Configuring Ecovacs using YAML is being removed but there was a connection error when trying to import the YAML configuration.\n\nPlease verify that you have a stable internet connection and restart Home Assistant to try again or remove the Ecovacs YAML configuration from your configuration.yaml file and continue to [set up the integration]({url}) manually."
|
||||
},
|
||||
"deprecated_yaml_import_issue_invalid_auth": {
|
||||
"title": "The Ecovacs YAML configuration import failed",
|
||||
"description": "Configuring Ecovacs using YAML is being removed but there was an authentication error when trying to import the YAML configuration.\n\nCorrect the YAML configuration and restart Home Assistant to try again or remove the Ecovacs YAML configuration from your configuration.yaml file and continue to [set up the integration]({url}) manually."
|
||||
},
|
||||
"deprecated_yaml_import_issue_unknown": {
|
||||
"title": "The Ecovacs YAML configuration import failed",
|
||||
"description": "Configuring Ecovacs using YAML is being removed but there was an unknown error when trying to import the YAML configuration.\n\nEnsure the YAML configuration is correct and restart Home Assistant to try again or remove the Ecovacs YAML configuration from your configuration.yaml file and continue to [set up the integration]({url}) manually."
|
||||
},
|
||||
"deprecated_yaml_import_issue_invalid_country_length": {
|
||||
"title": "The Ecovacs YAML configuration import failed",
|
||||
"description": "Configuring Ecovacs using YAML is being removed but there is an invalid country specified in the YAML configuration.\n\nPlease change the country to the [Alpha-2 code of your country]({countries_url}) and restart Home Assistant to try again or remove the Ecovacs YAML configuration from your configuration.yaml file and continue to [set up the integration]({url}) manually."
|
||||
},
|
||||
"deprecated_yaml_import_issue_invalid_continent_length": {
|
||||
"title": "The Ecovacs YAML configuration import failed",
|
||||
"description": "Configuring Ecovacs using YAML is being removed but there is an invalid continent specified in the YAML configuration.\n\nPlease correct the continent to be one of {continent_list} and restart Home Assistant to try again or remove the Ecovacs YAML configuration from your configuration.yaml file and continue to [set up the integration]({url}) manually."
|
||||
},
|
||||
"deprecated_yaml_import_issue_continent_not_match": {
|
||||
"title": "The Ecovacs YAML configuration import failed",
|
||||
"description": "Configuring Ecovacs using YAML is being removed but there is an unexpected continent specified in the YAML configuration.\n\nFrom the given country, the continent \"{continent}\" is expected. Change the continent and restart Home Assistant to try again or remove the Ecovacs YAML configuration from your configuration.yaml file and continue to [set up the integration]({url}) manually.\n\nIf the contintent \"{continent}\" is not applicable, please open an issue on [GitHub]({github_issue_url})."
|
||||
}
|
||||
},
|
||||
"selector": {
|
||||
"installation_mode": {
|
||||
"options": {
|
||||
|
|
|
@ -11,28 +11,23 @@ from deebot_client.mqtt_client import create_mqtt_config
|
|||
import pytest
|
||||
|
||||
from homeassistant.components.ecovacs.const import (
|
||||
CONF_CONTINENT,
|
||||
CONF_OVERRIDE_MQTT_URL,
|
||||
CONF_OVERRIDE_REST_URL,
|
||||
CONF_VERIFY_MQTT_CERTIFICATE,
|
||||
DOMAIN,
|
||||
InstanceMode,
|
||||
)
|
||||
from homeassistant.config_entries import SOURCE_IMPORT, SOURCE_USER
|
||||
from homeassistant.const import CONF_COUNTRY, CONF_MODE, CONF_USERNAME
|
||||
from homeassistant.core import DOMAIN as HOMEASSISTANT_DOMAIN, HomeAssistant
|
||||
from homeassistant.config_entries import SOURCE_USER
|
||||
from homeassistant.const import CONF_MODE, CONF_USERNAME
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.data_entry_flow import FlowResultType
|
||||
from homeassistant.helpers import issue_registry as ir
|
||||
|
||||
from .const import (
|
||||
IMPORT_DATA,
|
||||
VALID_ENTRY_DATA_CLOUD,
|
||||
VALID_ENTRY_DATA_SELF_HOSTED,
|
||||
VALID_ENTRY_DATA_SELF_HOSTED_WITH_VALIDATE_CERT,
|
||||
)
|
||||
|
||||
from tests.common import MockConfigEntry
|
||||
|
||||
_USER_STEP_SELF_HOSTED = {CONF_MODE: InstanceMode.SELF_HOSTED}
|
||||
|
||||
_TEST_FN_AUTH_ARG = "user_input_auth"
|
||||
|
@ -303,116 +298,3 @@ async def test_user_flow_self_hosted_error(
|
|||
mock_setup_entry.assert_called()
|
||||
mock_authenticator_authenticate.assert_called()
|
||||
mock_mqtt_client.verify_config.assert_called()
|
||||
|
||||
|
||||
async def test_import_flow(
|
||||
hass: HomeAssistant,
|
||||
issue_registry: ir.IssueRegistry,
|
||||
mock_setup_entry: AsyncMock,
|
||||
mock_authenticator_authenticate: AsyncMock,
|
||||
mock_mqtt_client: Mock,
|
||||
) -> None:
|
||||
"""Test importing yaml config."""
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN,
|
||||
context={"source": SOURCE_IMPORT},
|
||||
data=IMPORT_DATA.copy(),
|
||||
)
|
||||
mock_authenticator_authenticate.assert_called()
|
||||
|
||||
assert result["type"] is FlowResultType.CREATE_ENTRY
|
||||
assert result["title"] == VALID_ENTRY_DATA_CLOUD[CONF_USERNAME]
|
||||
assert result["data"] == VALID_ENTRY_DATA_CLOUD
|
||||
assert (HOMEASSISTANT_DOMAIN, f"deprecated_yaml_{DOMAIN}") in issue_registry.issues
|
||||
mock_setup_entry.assert_called()
|
||||
mock_mqtt_client.verify_config.assert_called()
|
||||
|
||||
|
||||
async def test_import_flow_already_configured(
|
||||
hass: HomeAssistant, issue_registry: ir.IssueRegistry
|
||||
) -> None:
|
||||
"""Test importing yaml config where entry already configured."""
|
||||
entry = MockConfigEntry(domain=DOMAIN, data=VALID_ENTRY_DATA_CLOUD)
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN,
|
||||
context={"source": SOURCE_IMPORT},
|
||||
data=IMPORT_DATA.copy(),
|
||||
)
|
||||
assert result["type"] is FlowResultType.ABORT
|
||||
assert result["reason"] == "already_configured"
|
||||
assert (HOMEASSISTANT_DOMAIN, f"deprecated_yaml_{DOMAIN}") in issue_registry.issues
|
||||
|
||||
|
||||
@pytest.mark.parametrize("show_advanced_options", [True, False])
|
||||
@pytest.mark.parametrize(
|
||||
("side_effect", "reason"),
|
||||
[
|
||||
(ClientError, "cannot_connect"),
|
||||
(InvalidAuthenticationError, "invalid_auth"),
|
||||
(Exception, "unknown"),
|
||||
],
|
||||
)
|
||||
async def test_import_flow_error(
|
||||
hass: HomeAssistant,
|
||||
issue_registry: ir.IssueRegistry,
|
||||
mock_authenticator_authenticate: AsyncMock,
|
||||
mock_mqtt_client: Mock,
|
||||
side_effect: Exception,
|
||||
reason: str,
|
||||
show_advanced_options: bool,
|
||||
) -> None:
|
||||
"""Test handling invalid connection."""
|
||||
mock_authenticator_authenticate.side_effect = side_effect
|
||||
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN,
|
||||
context={
|
||||
"source": SOURCE_IMPORT,
|
||||
"show_advanced_options": show_advanced_options,
|
||||
},
|
||||
data=IMPORT_DATA.copy(),
|
||||
)
|
||||
assert result["type"] is FlowResultType.ABORT
|
||||
assert result["reason"] == reason
|
||||
assert (
|
||||
DOMAIN,
|
||||
f"deprecated_yaml_import_issue_{reason}",
|
||||
) in issue_registry.issues
|
||||
mock_authenticator_authenticate.assert_called()
|
||||
|
||||
|
||||
@pytest.mark.parametrize("show_advanced_options", [True, False])
|
||||
@pytest.mark.parametrize(
|
||||
("reason", "user_input"),
|
||||
[
|
||||
("invalid_country_length", IMPORT_DATA | {CONF_COUNTRY: "too_long"}),
|
||||
("invalid_country_length", IMPORT_DATA | {CONF_COUNTRY: "a"}), # too short
|
||||
("invalid_continent_length", IMPORT_DATA | {CONF_CONTINENT: "too_long"}),
|
||||
("invalid_continent_length", IMPORT_DATA | {CONF_CONTINENT: "a"}), # too short
|
||||
("continent_not_match", IMPORT_DATA | {CONF_CONTINENT: "AA"}),
|
||||
],
|
||||
)
|
||||
async def test_import_flow_invalid_data(
|
||||
hass: HomeAssistant,
|
||||
issue_registry: ir.IssueRegistry,
|
||||
reason: str,
|
||||
user_input: dict[str, Any],
|
||||
show_advanced_options: bool,
|
||||
) -> None:
|
||||
"""Test handling invalid connection."""
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN,
|
||||
context={
|
||||
"source": SOURCE_IMPORT,
|
||||
"show_advanced_options": show_advanced_options,
|
||||
},
|
||||
data=user_input,
|
||||
)
|
||||
assert result["type"] is FlowResultType.ABORT
|
||||
assert result["reason"] == reason
|
||||
assert (
|
||||
DOMAIN,
|
||||
f"deprecated_yaml_import_issue_{reason}",
|
||||
) in issue_registry.issues
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
"""Test init of ecovacs."""
|
||||
|
||||
from typing import Any
|
||||
from unittest.mock import AsyncMock, Mock, patch
|
||||
from unittest.mock import Mock, patch
|
||||
|
||||
from deebot_client.exceptions import DeebotError, InvalidAuthenticationError
|
||||
import pytest
|
||||
|
@ -12,9 +11,6 @@ from homeassistant.components.ecovacs.controller import EcovacsController
|
|||
from homeassistant.config_entries import ConfigEntryState
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import device_registry as dr
|
||||
from homeassistant.setup import async_setup_component
|
||||
|
||||
from .const import IMPORT_DATA
|
||||
|
||||
from tests.common import MockConfigEntry
|
||||
|
||||
|
@ -88,32 +84,6 @@ async def test_invalid_auth(
|
|||
assert mock_config_entry.state is ConfigEntryState.SETUP_ERROR
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("config", "config_entries_expected"),
|
||||
[
|
||||
({}, 0),
|
||||
({DOMAIN: IMPORT_DATA.copy()}, 1),
|
||||
],
|
||||
ids=["no_config", "import_config"],
|
||||
)
|
||||
async def test_async_setup_import(
|
||||
hass: HomeAssistant,
|
||||
config: dict[str, Any],
|
||||
config_entries_expected: int,
|
||||
mock_setup_entry: AsyncMock,
|
||||
mock_authenticator_authenticate: AsyncMock,
|
||||
mock_mqtt_client: Mock,
|
||||
) -> None:
|
||||
"""Test async_setup config import."""
|
||||
assert len(hass.config_entries.async_entries(DOMAIN)) == 0
|
||||
assert await async_setup_component(hass, DOMAIN, config)
|
||||
await hass.async_block_till_done()
|
||||
assert len(hass.config_entries.async_entries(DOMAIN)) == config_entries_expected
|
||||
assert mock_setup_entry.call_count == config_entries_expected
|
||||
assert mock_authenticator_authenticate.call_count == config_entries_expected
|
||||
assert mock_mqtt_client.verify_config.call_count == config_entries_expected
|
||||
|
||||
|
||||
async def test_devices_in_dr(
|
||||
device_registry: dr.DeviceRegistry,
|
||||
controller: EcovacsController,
|
||||
|
|
Loading…
Add table
Reference in a new issue