diff --git a/homeassistant/components/qbittorrent/config_flow.py b/homeassistant/components/qbittorrent/config_flow.py index ac41d03e998a4..54c47c53895ad 100644 --- a/homeassistant/components/qbittorrent/config_flow.py +++ b/homeassistant/components/qbittorrent/config_flow.py @@ -1,6 +1,7 @@ """Config flow for qBittorrent.""" from __future__ import annotations +import logging from typing import Any from qbittorrent.client import LoginRequired @@ -8,12 +9,20 @@ import voluptuous as vol from homeassistant.config_entries import ConfigFlow -from homeassistant.const import CONF_PASSWORD, CONF_URL, CONF_USERNAME, CONF_VERIFY_SSL +from homeassistant.const import ( + CONF_NAME, + CONF_PASSWORD, + CONF_URL, + CONF_USERNAME, + CONF_VERIFY_SSL, +) from homeassistant.data_entry_flow import FlowResult from .const import DEFAULT_NAME, DEFAULT_URL, DOMAIN from .helpers import setup_client +_LOGGER = logging.getLogger(__name__) + USER_DATA_SCHEMA = vol.Schema( { vol.Required(CONF_URL, default=DEFAULT_URL): str, @@ -52,3 +61,16 @@ async def async_step_user( schema = self.add_suggested_values_to_schema(USER_DATA_SCHEMA, user_input) return self.async_show_form(step_id="user", data_schema=schema, errors=errors) + + async def async_step_import(self, config: dict[str, Any]) -> FlowResult: + """Import a config entry from configuration.yaml.""" + self._async_abort_entries_match({CONF_URL: config[CONF_URL]}) + return self.async_create_entry( + title=config.get(CONF_NAME, DEFAULT_NAME), + data={ + CONF_URL: config[CONF_URL], + CONF_USERNAME: config[CONF_USERNAME], + CONF_PASSWORD: config[CONF_PASSWORD], + CONF_VERIFY_SSL: True, + }, + ) diff --git a/homeassistant/components/qbittorrent/sensor.py b/homeassistant/components/qbittorrent/sensor.py index b6d9fe63e4ba3..15a634cf7a987 100644 --- a/homeassistant/components/qbittorrent/sensor.py +++ b/homeassistant/components/qbittorrent/sensor.py @@ -14,7 +14,7 @@ SensorEntityDescription, SensorStateClass, ) -from homeassistant.config_entries import ConfigEntry +from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry from homeassistant.const import ( CONF_NAME, CONF_PASSWORD, @@ -24,8 +24,10 @@ UnitOfDataRate, ) from homeassistant.core import HomeAssistant +from homeassistant.helpers import issue_registry as ir import homeassistant.helpers.config_validation as cv from homeassistant.helpers.entity_platform import AddEntitiesCallback +from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType from .const import DEFAULT_NAME, DOMAIN @@ -68,6 +70,29 @@ ) +async def async_setup_platform( + hass: HomeAssistant, + config: ConfigType, + async_add_entities: AddEntitiesCallback, + discovery_info: DiscoveryInfoType | None = None, +) -> None: + """Set up the qBittorrent platform.""" + hass.async_create_task( + hass.config_entries.flow.async_init( + DOMAIN, context={"source": SOURCE_IMPORT}, data=config + ) + ) + ir.async_create_issue( + hass, + DOMAIN, + "deprecated_yaml", + breaks_in_ha_version="2023.11.0", + is_fixable=False, + severity=ir.IssueSeverity.WARNING, + translation_key="deprecated_yaml", + ) + + async def async_setup_entry( hass: HomeAssistant, config_entry: ConfigEntry, diff --git a/homeassistant/components/qbittorrent/strings.json b/homeassistant/components/qbittorrent/strings.json index 66c9430911e74..24d1885a9177a 100644 --- a/homeassistant/components/qbittorrent/strings.json +++ b/homeassistant/components/qbittorrent/strings.json @@ -17,5 +17,11 @@ "abort": { "already_configured": "[%key:common::config_flow::abort::already_configured_device%]" } + }, + "issues": { + "deprecated_yaml": { + "title": "The qBittorrent YAML configuration is being removed", + "description": "Configuring qBittorrent using YAML is being removed.\n\nYour existing YAML configuration has been imported into the UI automatically.\n\nRemove the qBittorrent YAML configuration from your configuration.yaml file and restart Home Assistant to fix this issue." + } } } diff --git a/tests/components/qbittorrent/test_config_flow.py b/tests/components/qbittorrent/test_config_flow.py index bbfeee20d8a6f..b7244ccef8d74 100644 --- a/tests/components/qbittorrent/test_config_flow.py +++ b/tests/components/qbittorrent/test_config_flow.py @@ -4,7 +4,7 @@ import requests_mock from homeassistant.components.qbittorrent.const import DOMAIN -from homeassistant.config_entries import SOURCE_USER +from homeassistant.config_entries import SOURCE_IMPORT, SOURCE_USER from homeassistant.const import ( CONF_PASSWORD, CONF_SOURCE, @@ -26,6 +26,12 @@ CONF_VERIFY_SSL: True, } +YAML_IMPORT = { + CONF_URL: "http://localhost:8080", + CONF_USERNAME: "user", + CONF_PASSWORD: "pass", +} + async def test_flow_user(hass: HomeAssistant, mock_api: requests_mock.Mocker) -> None: """Test the user flow.""" @@ -98,3 +104,33 @@ async def test_flow_user_already_configured(hass: HomeAssistant) -> None: ) assert result["type"] == FlowResultType.ABORT assert result["reason"] == "already_configured" + + +async def test_flow_import(hass: HomeAssistant) -> None: + """Test import step.""" + result = await hass.config_entries.flow.async_init( + DOMAIN, + context={CONF_SOURCE: SOURCE_IMPORT}, + data=YAML_IMPORT, + ) + assert result["type"] == FlowResultType.CREATE_ENTRY + assert result["data"] == { + CONF_URL: "http://localhost:8080", + CONF_USERNAME: "user", + CONF_PASSWORD: "pass", + CONF_VERIFY_SSL: True, + } + + +async def test_flow_import_already_configured(hass: HomeAssistant) -> None: + """Test import step already configured.""" + entry = MockConfigEntry(domain=DOMAIN, data=USER_INPUT) + entry.add_to_hass(hass) + + result = await hass.config_entries.flow.async_init( + DOMAIN, + context={CONF_SOURCE: SOURCE_IMPORT}, + data=YAML_IMPORT, + ) + assert result["type"] == FlowResultType.ABORT + assert result["reason"] == "already_configured"