Remove deprecated yaml config from dlna_dmr (#62344)

pull/62391/head
Robert Hillis 2021-12-20 07:56:45 -05:00 committed by GitHub
parent b5de2c38b3
commit e689afc0b3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 4 additions and 388 deletions

View File

@ -14,13 +14,7 @@ import voluptuous as vol
from homeassistant import config_entries
from homeassistant.components import ssdp
from homeassistant.const import (
CONF_DEVICE_ID,
CONF_HOST,
CONF_NAME,
CONF_TYPE,
CONF_URL,
)
from homeassistant.const import CONF_DEVICE_ID, CONF_HOST, CONF_TYPE, CONF_URL
from homeassistant.core import callback
from homeassistant.data_entry_flow import FlowResult
from homeassistant.exceptions import IntegrationError
@ -125,85 +119,6 @@ class DlnaDmrFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
step_id="manual", data_schema=data_schema, errors=errors
)
async def async_step_import(self, import_data: FlowInput = None) -> FlowResult:
"""Import a new DLNA DMR device from a config entry.
This flow is triggered by `async_setup_platform`. If the device has not
been migrated, and can be connected to, automatically import it. If it
cannot be connected to, prompt the user to turn it on. If it has already
been migrated, do nothing.
"""
LOGGER.debug("async_step_import: import_data: %s", import_data)
if not import_data or CONF_URL not in import_data:
LOGGER.debug("Entry not imported: incomplete_config")
return self.async_abort(reason="incomplete_config")
self._location = import_data[CONF_URL]
self._async_abort_entries_match({CONF_URL: self._location})
# Use the location as this config flow's unique ID until UDN is known
await self.async_set_unique_id(self._location)
# Set options from the import_data, except listen_ip which is no longer used
self._options[CONF_LISTEN_PORT] = import_data.get(CONF_LISTEN_PORT)
self._options[CONF_CALLBACK_URL_OVERRIDE] = import_data.get(
CONF_CALLBACK_URL_OVERRIDE
)
# Override device name if it's set in the YAML
self._name = import_data.get(CONF_NAME)
discoveries = await self._async_get_discoveries()
# Find the device in the list of unconfigured devices
for discovery in discoveries:
if discovery.ssdp_location == self._location:
# Device found via SSDP, it shouldn't need polling
self._options[CONF_POLL_AVAILABILITY] = False
# Discovery info has everything required to create config entry
await self._async_set_info_from_discovery(discovery)
LOGGER.debug(
"Entry %s found via SSDP, with UDN %s",
self._location,
self._udn,
)
return self._create_entry()
# This device will need to be polled
self._options[CONF_POLL_AVAILABILITY] = True
# Device was not found via SSDP, connect directly for configuration
try:
await self._async_connect()
except ConnectError as err:
# This will require user action
LOGGER.debug("Entry %s not imported yet: %s", self._location, err.args[0])
return await self.async_step_import_turn_on()
LOGGER.debug("Entry %s ready for import", self._location)
return self._create_entry()
async def async_step_import_turn_on(
self, user_input: FlowInput = None
) -> FlowResult:
"""Request the user to turn on the device so that import can finish."""
LOGGER.debug("async_step_import_turn_on: %s", user_input)
self.context["title_placeholders"] = {"name": self._name or self._location}
errors = {}
if user_input is not None:
try:
await self._async_connect()
except ConnectError as err:
errors["base"] = err.args[0]
else:
return self._create_entry()
self._set_confirm_only()
return self.async_show_form(step_id="import_turn_on", errors=errors)
async def async_step_ssdp(self, discovery_info: ssdp.SsdpServiceInfo) -> FlowResult:
"""Handle a flow initialized by SSDP discovery."""
LOGGER.debug("async_step_ssdp: discovery_info %s", pformat(discovery_info))

View File

@ -13,11 +13,10 @@ from async_upnp_client.const import NotificationSubType
from async_upnp_client.exceptions import UpnpError, UpnpResponseError
from async_upnp_client.profiles.dlna import DmrDevice, PlayMode, TransportState
from async_upnp_client.utils import async_get_local_ip
import voluptuous as vol
from homeassistant import config_entries
from homeassistant.components import ssdp
from homeassistant.components.media_player import PLATFORM_SCHEMA, MediaPlayerEntity
from homeassistant.components.media_player import MediaPlayerEntity
from homeassistant.components.media_player.const import (
ATTR_MEDIA_EXTRA,
REPEAT_MODE_ALL,
@ -38,7 +37,6 @@ from homeassistant.components.media_player.const import (
)
from homeassistant.const import (
CONF_DEVICE_ID,
CONF_NAME,
CONF_TYPE,
CONF_URL,
STATE_IDLE,
@ -49,9 +47,7 @@ from homeassistant.const import (
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers import device_registry, entity_registry
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
from .const import (
CONF_CALLBACK_URL_OVERRIDE,
@ -69,25 +65,6 @@ from .data import EventListenAddr, get_domain_data
PARALLEL_UPDATES = 0
# Configuration via YAML is deprecated in favour of config flow
CONF_LISTEN_IP = "listen_ip"
PLATFORM_SCHEMA = vol.All(
cv.deprecated(CONF_URL),
cv.deprecated(CONF_LISTEN_IP),
cv.deprecated(CONF_LISTEN_PORT),
cv.deprecated(CONF_NAME),
cv.deprecated(CONF_CALLBACK_URL_OVERRIDE),
PLATFORM_SCHEMA.extend(
{
vol.Required(CONF_URL): cv.string,
vol.Optional(CONF_LISTEN_IP): cv.string,
vol.Optional(CONF_LISTEN_PORT): cv.port,
vol.Optional(CONF_NAME): cv.string,
vol.Optional(CONF_CALLBACK_URL_OVERRIDE): cv.url,
}
),
)
Func = TypeVar("Func", bound=Callable[..., Any])
@ -111,29 +88,6 @@ def catch_request_errors(func: Func) -> Func:
return cast(Func, wrapper)
async def async_setup_platform(
hass: HomeAssistant,
config: ConfigType,
async_add_entities: AddEntitiesCallback,
discovery_info: DiscoveryInfoType | None = None,
) -> None:
"""Set up DLNA media_player platform."""
hass.async_create_task(
hass.config_entries.flow.async_init(
DOMAIN,
context={"source": config_entries.SOURCE_IMPORT},
data=config,
)
)
_LOGGER.warning(
"Configuring dlna_dmr via yaml is deprecated; the configuration for"
" %s will be migrated to a config entry and can be safely removed when"
"migration is complete",
config.get(CONF_URL),
)
async def async_setup_entry(
hass: HomeAssistant,
entry: config_entries.ConfigEntry,

View File

@ -15,14 +15,7 @@ from homeassistant.components.dlna_dmr.const import (
CONF_POLL_AVAILABILITY,
DOMAIN as DLNA_DOMAIN,
)
from homeassistant.const import (
CONF_DEVICE_ID,
CONF_HOST,
CONF_NAME,
CONF_PLATFORM,
CONF_TYPE,
CONF_URL,
)
from homeassistant.const import CONF_DEVICE_ID, CONF_HOST, CONF_TYPE, CONF_URL
from homeassistant.core import HomeAssistant
from .conftest import (
@ -43,13 +36,6 @@ pytestmark = [
WRONG_DEVICE_TYPE = "urn:schemas-upnp-org:device:InternetGatewayDevice:1"
IMPORTED_DEVICE_NAME = "Imported DMR device"
MOCK_CONFIG_IMPORT_DATA = {
CONF_PLATFORM: DLNA_DOMAIN,
CONF_URL: MOCK_DEVICE_LOCATION,
}
MOCK_ROOT_DEVICE_UDN = "ROOT_DEVICE"
MOCK_DISCOVERY = ssdp.SsdpServiceInfo(
@ -276,212 +262,6 @@ async def test_user_flow_wrong_st(hass: HomeAssistant, domain_data_mock: Mock) -
assert result["step_id"] == "manual"
async def test_import_flow_invalid(hass: HomeAssistant, domain_data_mock: Mock) -> None:
"""Test import flow of invalid YAML config."""
# Missing CONF_URL
result = await hass.config_entries.flow.async_init(
DLNA_DOMAIN,
context={"source": config_entries.SOURCE_IMPORT},
data={CONF_PLATFORM: DLNA_DOMAIN},
)
assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT
assert result["reason"] == "incomplete_config"
async def test_import_flow_ssdp_discovered(
hass: HomeAssistant, ssdp_scanner_mock: Mock
) -> None:
"""Test import of YAML config with a device also found via SSDP."""
ssdp_scanner_mock.async_get_discovery_info_by_st.side_effect = [
[MOCK_DISCOVERY],
[],
[],
]
result = await hass.config_entries.flow.async_init(
DLNA_DOMAIN,
context={"source": config_entries.SOURCE_IMPORT},
data=MOCK_CONFIG_IMPORT_DATA,
)
await hass.async_block_till_done()
assert ssdp_scanner_mock.async_get_discovery_info_by_st.call_count >= 1
assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
assert result["title"] == MOCK_DEVICE_NAME
assert result["data"] == {
CONF_URL: MOCK_DEVICE_LOCATION,
CONF_DEVICE_ID: MOCK_DEVICE_UDN,
CONF_TYPE: MOCK_DEVICE_TYPE,
}
assert result["options"] == {
CONF_LISTEN_PORT: None,
CONF_CALLBACK_URL_OVERRIDE: None,
CONF_POLL_AVAILABILITY: False,
}
# The config entry should not be duplicated when dlna_dmr is restarted
ssdp_scanner_mock.async_get_discovery_info_by_st.side_effect = [
[MOCK_DISCOVERY],
[],
[],
]
result = await hass.config_entries.flow.async_init(
DLNA_DOMAIN,
context={"source": config_entries.SOURCE_IMPORT},
data=MOCK_CONFIG_IMPORT_DATA,
)
assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT
assert result["reason"] == "already_configured"
# Wait for platform to be fully setup
await hass.async_block_till_done()
async def test_import_flow_direct_connect(
hass: HomeAssistant, ssdp_scanner_mock: Mock
) -> None:
"""Test import of YAML config with a device *not found* via SSDP."""
ssdp_scanner_mock.async_get_discovery_info_by_st.return_value = []
result = await hass.config_entries.flow.async_init(
DLNA_DOMAIN,
context={"source": config_entries.SOURCE_IMPORT},
data=MOCK_CONFIG_IMPORT_DATA,
)
await hass.async_block_till_done()
assert ssdp_scanner_mock.async_get_discovery_info_by_st.call_count >= 1
assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
assert result["title"] == MOCK_DEVICE_NAME
assert result["data"] == {
CONF_URL: MOCK_DEVICE_LOCATION,
CONF_DEVICE_ID: MOCK_DEVICE_UDN,
CONF_TYPE: MOCK_DEVICE_TYPE,
}
assert result["options"] == {
CONF_LISTEN_PORT: None,
CONF_CALLBACK_URL_OVERRIDE: None,
CONF_POLL_AVAILABILITY: True,
}
# The config entry should not be duplicated when dlna_dmr is restarted
result = await hass.config_entries.flow.async_init(
DLNA_DOMAIN,
context={"source": config_entries.SOURCE_IMPORT},
data=MOCK_CONFIG_IMPORT_DATA,
)
assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT
assert result["reason"] == "already_configured"
async def test_import_flow_offline(
hass: HomeAssistant, domain_data_mock: Mock, ssdp_scanner_mock: Mock
) -> None:
"""Test import flow of offline device."""
# Device is not yet contactable
domain_data_mock.upnp_factory.async_create_device.side_effect = UpnpError
result = await hass.config_entries.flow.async_init(
DLNA_DOMAIN,
context={"source": config_entries.SOURCE_IMPORT},
data={
CONF_PLATFORM: DLNA_DOMAIN,
CONF_URL: MOCK_DEVICE_LOCATION,
CONF_NAME: IMPORTED_DEVICE_NAME,
CONF_CALLBACK_URL_OVERRIDE: "http://override/callback",
CONF_LISTEN_PORT: 2222,
},
)
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
assert result["errors"] == {}
assert result["step_id"] == "import_turn_on"
import_flow_id = result["flow_id"]
# User clicks submit, same form is displayed with an error
result = await hass.config_entries.flow.async_configure(
import_flow_id, user_input={}
)
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
assert result["errors"] == {"base": "cannot_connect"}
assert result["step_id"] == "import_turn_on"
# Device is discovered via SSDP, new flow should not be initialized
ssdp_scanner_mock.async_get_discovery_info_by_st.side_effect = [
[MOCK_DISCOVERY],
[],
[],
]
domain_data_mock.upnp_factory.async_create_device.side_effect = None
result = await hass.config_entries.flow.async_init(
DLNA_DOMAIN,
context={"source": config_entries.SOURCE_SSDP},
data=MOCK_DISCOVERY,
)
assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT
assert result["reason"] == "already_in_progress"
# User clicks submit, config entry should be created
result = await hass.config_entries.flow.async_configure(
import_flow_id, user_input={}
)
assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
assert result["title"] == IMPORTED_DEVICE_NAME
assert result["data"] == {
CONF_URL: MOCK_DEVICE_LOCATION,
CONF_DEVICE_ID: MOCK_DEVICE_UDN,
CONF_TYPE: MOCK_DEVICE_TYPE,
}
# Options should be retained
assert result["options"] == {
CONF_LISTEN_PORT: 2222,
CONF_CALLBACK_URL_OVERRIDE: "http://override/callback",
CONF_POLL_AVAILABILITY: True,
}
# Wait for platform to be fully setup
await hass.async_block_till_done()
async def test_import_flow_options(
hass: HomeAssistant, ssdp_scanner_mock: Mock
) -> None:
"""Test import of YAML config with options set."""
ssdp_scanner_mock.async_get_discovery_info_by_st.return_value = []
result = await hass.config_entries.flow.async_init(
DLNA_DOMAIN,
context={"source": config_entries.SOURCE_IMPORT},
data={
CONF_PLATFORM: DLNA_DOMAIN,
CONF_URL: MOCK_DEVICE_LOCATION,
CONF_NAME: IMPORTED_DEVICE_NAME,
CONF_LISTEN_PORT: 2222,
CONF_CALLBACK_URL_OVERRIDE: "http://override/callback",
},
)
await hass.async_block_till_done()
assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
assert result["title"] == IMPORTED_DEVICE_NAME
assert result["data"] == {
CONF_URL: MOCK_DEVICE_LOCATION,
CONF_DEVICE_ID: MOCK_DEVICE_UDN,
CONF_TYPE: MOCK_DEVICE_TYPE,
}
assert result["options"] == {
CONF_LISTEN_PORT: 2222,
CONF_CALLBACK_URL_OVERRIDE: "http://override/callback",
CONF_POLL_AVAILABILITY: True,
}
# Wait for platform to be fully setup
await hass.async_block_till_done()
async def test_ssdp_flow_success(hass: HomeAssistant) -> None:
"""Test that SSDP discovery with an available device works."""
result = await hass.config_entries.flow.async_init(

View File

@ -29,7 +29,7 @@ from homeassistant.components.dlna_dmr.const import (
from homeassistant.components.dlna_dmr.data import EventListenAddr
from homeassistant.components.media_player import ATTR_TO_PROPERTY, const as mp_const
from homeassistant.components.media_player.const import DOMAIN as MP_DOMAIN
from homeassistant.const import ATTR_ENTITY_ID, CONF_PLATFORM, CONF_URL
from homeassistant.const import ATTR_ENTITY_ID
from homeassistant.core import HomeAssistant
from homeassistant.helpers.device_registry import async_get as async_get_dr
from homeassistant.helpers.entity_component import async_update_entity
@ -37,7 +37,6 @@ from homeassistant.helpers.entity_registry import (
async_entries_for_config_entry,
async_get as async_get_er,
)
from homeassistant.helpers.typing import ConfigType
from homeassistant.setup import async_setup_component
from .conftest import (
@ -183,38 +182,6 @@ async def mock_disconnected_entity_id(
assert dmr_device_mock.on_event is None
async def test_setup_platform_import_flow_started(
hass: HomeAssistant, domain_data_mock: Mock
) -> None:
"""Test import flow of YAML config is started if there's config data."""
# Cause connection attempts to fail
domain_data_mock.upnp_factory.async_create_device.side_effect = UpnpConnectionError
# Run the setup
mock_config: ConfigType = {
MP_DOMAIN: [
{
CONF_PLATFORM: DLNA_DOMAIN,
CONF_URL: MOCK_DEVICE_LOCATION,
CONF_LISTEN_PORT: 1234,
}
]
}
await async_setup_component(hass, MP_DOMAIN, mock_config)
await hass.async_block_till_done()
# Check config_flow has started
flows = hass.config_entries.flow.async_progress(include_uninitialized=True)
assert len(flows) == 1
# It should be paused, waiting for the user to turn on the device
flow = flows[0]
assert flow["handler"] == "dlna_dmr"
assert flow["step_id"] == "import_turn_on"
assert flow["context"].get("unique_id") == MOCK_DEVICE_LOCATION
async def test_setup_entry_no_options(
hass: HomeAssistant,
domain_data_mock: Mock,