Use dataclass properties in dlna_dmr discovery (#60693)

Co-authored-by: epenet <epenet@users.noreply.github.com>
This commit is contained in:
epenet 2021-12-01 19:59:12 +01:00 committed by GitHub
parent d7bf8a7ac3
commit e95914cf60
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 153 additions and 108 deletions

View File

@ -216,7 +216,7 @@ class DlnaDmrFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
# Abort if the device doesn't support all services required for a DmrDevice. # Abort if the device doesn't support all services required for a DmrDevice.
# Use the discovery_info instead of DmrDevice.is_profile_device to avoid # Use the discovery_info instead of DmrDevice.is_profile_device to avoid
# contacting the device again. # contacting the device again.
discovery_service_list = discovery_info.get(ssdp.ATTR_UPNP_SERVICE_LIST) discovery_service_list = discovery_info.upnp.get(ssdp.ATTR_UPNP_SERVICE_LIST)
if not discovery_service_list: if not discovery_service_list:
return self.async_abort(reason="not_dmr") return self.async_abort(reason="not_dmr")
discovery_service_ids = { discovery_service_ids = {
@ -334,15 +334,15 @@ class DlnaDmrFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
"""Set information required for a config entry from the SSDP discovery.""" """Set information required for a config entry from the SSDP discovery."""
LOGGER.debug( LOGGER.debug(
"_async_set_info_from_discovery: location: %s, UDN: %s", "_async_set_info_from_discovery: location: %s, UDN: %s",
discovery_info[ssdp.ATTR_SSDP_LOCATION], discovery_info.ssdp_location,
discovery_info[ssdp.ATTR_SSDP_UDN], discovery_info.ssdp_udn,
) )
if not self._location: if not self._location:
self._location = discovery_info[ssdp.ATTR_SSDP_LOCATION] self._location = discovery_info.ssdp_location
assert isinstance(self._location, str) assert isinstance(self._location, str)
self._udn = discovery_info[ssdp.ATTR_SSDP_UDN] self._udn = discovery_info.ssdp_udn
await self.async_set_unique_id(self._udn) await self.async_set_unique_id(self._udn)
if abort_if_configured: if abort_if_configured:
@ -351,11 +351,9 @@ class DlnaDmrFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
updates={CONF_URL: self._location}, reload_on_update=False updates={CONF_URL: self._location}, reload_on_update=False
) )
self._device_type = ( self._device_type = discovery_info.ssdp_nt or discovery_info.ssdp_st
discovery_info.get(ssdp.ATTR_SSDP_NT) or discovery_info[ssdp.ATTR_SSDP_ST]
)
self._name = ( self._name = (
discovery_info.get(ssdp.ATTR_UPNP_FRIENDLY_NAME) discovery_info.upnp.get(ssdp.ATTR_UPNP_FRIENDLY_NAME)
or urlparse(self._location).hostname or urlparse(self._location).hostname
or DEFAULT_NAME or DEFAULT_NAME
) )
@ -461,22 +459,25 @@ def _is_ignored_device(discovery_info: ssdp.SsdpServiceInfo) -> bool:
flow, which will list all discovered but unconfigured devices. flow, which will list all discovered but unconfigured devices.
""" """
# Did the discovery trigger more than just this flow? # Did the discovery trigger more than just this flow?
if len(discovery_info.get(ssdp.ATTR_HA_MATCHING_DOMAINS, set())) > 1: if len(discovery_info.x_homeassistant_matching_domains) > 1:
LOGGER.debug( LOGGER.debug(
"Ignoring device supported by multiple integrations: %s", "Ignoring device supported by multiple integrations: %s",
discovery_info[ssdp.ATTR_HA_MATCHING_DOMAINS], discovery_info.x_homeassistant_matching_domains,
) )
return True return True
# Is the root device not a DMR? # Is the root device not a DMR?
if discovery_info.get(ssdp.ATTR_UPNP_DEVICE_TYPE) not in DmrDevice.DEVICE_TYPES: if (
discovery_info.upnp.get(ssdp.ATTR_UPNP_DEVICE_TYPE)
not in DmrDevice.DEVICE_TYPES
):
return True return True
# Special cases for devices with other discovery methods (e.g. mDNS), or # Special cases for devices with other discovery methods (e.g. mDNS), or
# that advertise multiple unrelated (sent in separate discovery packets) # that advertise multiple unrelated (sent in separate discovery packets)
# UPnP devices. # UPnP devices.
manufacturer = discovery_info.get(ssdp.ATTR_UPNP_MANUFACTURER, "").lower() manufacturer = discovery_info.upnp.get(ssdp.ATTR_UPNP_MANUFACTURER, "").lower()
model = discovery_info.get(ssdp.ATTR_UPNP_MODEL_NAME, "").lower() model = discovery_info.upnp.get(ssdp.ATTR_UPNP_MODEL_NAME, "").lower()
if manufacturer.startswith("xbmc") or model == "kodi": if manufacturer.startswith("xbmc") or model == "kodi":
# kodi # kodi

View File

@ -247,12 +247,12 @@ class DlnaDmrEntity(MediaPlayerEntity):
_LOGGER.debug( _LOGGER.debug(
"SSDP %s notification of device %s at %s", "SSDP %s notification of device %s at %s",
change, change,
info[ssdp.ATTR_SSDP_USN], info.ssdp_usn,
info.get(ssdp.ATTR_SSDP_LOCATION), info.ssdp_location,
) )
try: try:
bootid_str = info[ssdp.ATTR_SSDP_BOOTID] bootid_str = info.ssdp_headers[ssdp.ATTR_SSDP_BOOTID]
bootid: int | None = int(bootid_str, 10) bootid: int | None = int(bootid_str, 10)
except (KeyError, ValueError): except (KeyError, ValueError):
bootid = None bootid = None
@ -263,7 +263,7 @@ class DlnaDmrEntity(MediaPlayerEntity):
# Store the new value (because our old value matches) so that we # Store the new value (because our old value matches) so that we
# can ignore subsequent ssdp:alive messages # can ignore subsequent ssdp:alive messages
with contextlib.suppress(KeyError, ValueError): with contextlib.suppress(KeyError, ValueError):
next_bootid_str = info[ssdp.ATTR_SSDP_NEXTBOOTID] next_bootid_str = info.ssdp_headers[ssdp.ATTR_SSDP_NEXTBOOTID]
self._bootid = int(next_bootid_str, 10) self._bootid = int(next_bootid_str, 10)
# Nothing left to do until ssdp:alive comes through # Nothing left to do until ssdp:alive comes through
return return
@ -278,7 +278,7 @@ class DlnaDmrEntity(MediaPlayerEntity):
await self._device_disconnect() await self._device_disconnect()
if change == ssdp.SsdpChange.ALIVE and not self._device: if change == ssdp.SsdpChange.ALIVE and not self._device:
location = info[ssdp.ATTR_SSDP_LOCATION] location = info.ssdp_location or ""
try: try:
await self._device_connect(location) await self._device_connect(location)
except UpnpError as err: except UpnpError as err:

View File

@ -51,6 +51,8 @@ from .conftest import (
from tests.common import MockConfigEntry from tests.common import MockConfigEntry
MOCK_DEVICE_ST = "mock_st"
# Auto-use the domain_data_mock fixture for every test in this module # Auto-use the domain_data_mock fixture for every test in this module
pytestmark = pytest.mark.usefixtures("domain_data_mock") pytestmark = pytest.mark.usefixtures("domain_data_mock")
@ -1052,10 +1054,12 @@ async def test_become_available(
# Send an SSDP notification from the now alive device # Send an SSDP notification from the now alive device
ssdp_callback = ssdp_scanner_mock.async_register_callback.call_args.args[0] ssdp_callback = ssdp_scanner_mock.async_register_callback.call_args.args[0]
await ssdp_callback( await ssdp_callback(
{ ssdp.SsdpServiceInfo(
ssdp.ATTR_SSDP_USN: MOCK_DEVICE_USN, ssdp_usn=MOCK_DEVICE_USN,
ssdp.ATTR_SSDP_LOCATION: NEW_DEVICE_LOCATION, ssdp_location=NEW_DEVICE_LOCATION,
}, ssdp_st=MOCK_DEVICE_ST,
upnp={},
),
ssdp.SsdpChange.ALIVE, ssdp.SsdpChange.ALIVE,
) )
await hass.async_block_till_done() await hass.async_block_till_done()
@ -1114,10 +1118,12 @@ async def test_alive_but_gone(
# Send an SSDP notification from the still missing device # Send an SSDP notification from the still missing device
ssdp_callback = ssdp_scanner_mock.async_register_callback.call_args.args[0] ssdp_callback = ssdp_scanner_mock.async_register_callback.call_args.args[0]
await ssdp_callback( await ssdp_callback(
{ ssdp.SsdpServiceInfo(
ssdp.ATTR_SSDP_USN: MOCK_DEVICE_USN, ssdp_usn=MOCK_DEVICE_USN,
ssdp.ATTR_SSDP_LOCATION: NEW_DEVICE_LOCATION, ssdp_location=NEW_DEVICE_LOCATION,
}, ssdp_st=MOCK_DEVICE_ST,
upnp={},
),
ssdp.SsdpChange.ALIVE, ssdp.SsdpChange.ALIVE,
) )
await hass.async_block_till_done() await hass.async_block_till_done()
@ -1153,17 +1159,21 @@ async def test_multiple_ssdp_alive(
# Send two SSDP notifications with the new device URL # Send two SSDP notifications with the new device URL
ssdp_callback = ssdp_scanner_mock.async_register_callback.call_args.args[0] ssdp_callback = ssdp_scanner_mock.async_register_callback.call_args.args[0]
await ssdp_callback( await ssdp_callback(
{ ssdp.SsdpServiceInfo(
ssdp.ATTR_SSDP_USN: MOCK_DEVICE_USN, ssdp_usn=MOCK_DEVICE_USN,
ssdp.ATTR_SSDP_LOCATION: NEW_DEVICE_LOCATION, ssdp_location=NEW_DEVICE_LOCATION,
}, ssdp_st=MOCK_DEVICE_ST,
upnp={},
),
ssdp.SsdpChange.ALIVE, ssdp.SsdpChange.ALIVE,
) )
await ssdp_callback( await ssdp_callback(
{ ssdp.SsdpServiceInfo(
ssdp.ATTR_SSDP_USN: MOCK_DEVICE_USN, ssdp_usn=MOCK_DEVICE_USN,
ssdp.ATTR_SSDP_LOCATION: NEW_DEVICE_LOCATION, ssdp_location=NEW_DEVICE_LOCATION,
}, ssdp_st=MOCK_DEVICE_ST,
upnp={},
),
ssdp.SsdpChange.ALIVE, ssdp.SsdpChange.ALIVE,
) )
await hass.async_block_till_done() await hass.async_block_till_done()
@ -1189,11 +1199,13 @@ async def test_ssdp_byebye(
# First byebye will cause a disconnect # First byebye will cause a disconnect
ssdp_callback = ssdp_scanner_mock.async_register_callback.call_args.args[0] ssdp_callback = ssdp_scanner_mock.async_register_callback.call_args.args[0]
await ssdp_callback( await ssdp_callback(
{ ssdp.SsdpServiceInfo(
ssdp.ATTR_SSDP_USN: MOCK_DEVICE_USN, ssdp_usn=MOCK_DEVICE_USN,
"_udn": MOCK_DEVICE_UDN, ssdp_udn=MOCK_DEVICE_UDN,
"NTS": "ssdp:byebye", ssdp_headers={"NTS": "ssdp:byebye"},
}, ssdp_st=MOCK_DEVICE_ST,
upnp={},
),
ssdp.SsdpChange.BYEBYE, ssdp.SsdpChange.BYEBYE,
) )
@ -1206,11 +1218,13 @@ async def test_ssdp_byebye(
# Second byebye will do nothing # Second byebye will do nothing
await ssdp_callback( await ssdp_callback(
{ ssdp.SsdpServiceInfo(
ssdp.ATTR_SSDP_USN: MOCK_DEVICE_USN, ssdp_usn=MOCK_DEVICE_USN,
"_udn": MOCK_DEVICE_UDN, ssdp_udn=MOCK_DEVICE_UDN,
"NTS": "ssdp:byebye", ssdp_headers={"NTS": "ssdp:byebye"},
}, ssdp_st=MOCK_DEVICE_ST,
upnp={},
),
ssdp.SsdpChange.BYEBYE, ssdp.SsdpChange.BYEBYE,
) )
@ -1237,24 +1251,30 @@ async def test_ssdp_update_seen_bootid(
# Send SSDP alive with boot ID # Send SSDP alive with boot ID
ssdp_callback = ssdp_scanner_mock.async_register_callback.call_args.args[0] ssdp_callback = ssdp_scanner_mock.async_register_callback.call_args.args[0]
await ssdp_callback( await ssdp_callback(
{ ssdp.SsdpServiceInfo(
ssdp.ATTR_SSDP_USN: MOCK_DEVICE_USN, ssdp_usn=MOCK_DEVICE_USN,
ssdp.ATTR_SSDP_LOCATION: MOCK_DEVICE_LOCATION, ssdp_location=MOCK_DEVICE_LOCATION,
ssdp.ATTR_SSDP_BOOTID: "1", ssdp_headers={ssdp.ATTR_SSDP_BOOTID: "1"},
}, ssdp_st=MOCK_DEVICE_ST,
upnp={},
),
ssdp.SsdpChange.ALIVE, ssdp.SsdpChange.ALIVE,
) )
await hass.async_block_till_done() await hass.async_block_till_done()
# Send SSDP update with next boot ID # Send SSDP update with next boot ID
await ssdp_callback( await ssdp_callback(
{ ssdp.SsdpServiceInfo(
ssdp.ATTR_SSDP_USN: MOCK_DEVICE_USN, ssdp_usn=MOCK_DEVICE_USN,
"_udn": MOCK_DEVICE_UDN, ssdp_udn=MOCK_DEVICE_UDN,
"NTS": "ssdp:update", ssdp_headers={
ssdp.ATTR_SSDP_BOOTID: "1", "NTS": "ssdp:update",
ssdp.ATTR_SSDP_NEXTBOOTID: "2", ssdp.ATTR_SSDP_BOOTID: "1",
}, ssdp.ATTR_SSDP_NEXTBOOTID: "2",
},
ssdp_st=MOCK_DEVICE_ST,
upnp={},
),
ssdp.SsdpChange.UPDATE, ssdp.SsdpChange.UPDATE,
) )
await hass.async_block_till_done() await hass.async_block_till_done()
@ -1269,13 +1289,17 @@ async def test_ssdp_update_seen_bootid(
# Send SSDP update with same next boot ID, again # Send SSDP update with same next boot ID, again
await ssdp_callback( await ssdp_callback(
{ ssdp.SsdpServiceInfo(
ssdp.ATTR_SSDP_USN: MOCK_DEVICE_USN, ssdp_usn=MOCK_DEVICE_USN,
"_udn": MOCK_DEVICE_UDN, ssdp_udn=MOCK_DEVICE_UDN,
"NTS": "ssdp:update", ssdp_headers={
ssdp.ATTR_SSDP_BOOTID: "1", "NTS": "ssdp:update",
ssdp.ATTR_SSDP_NEXTBOOTID: "2", ssdp.ATTR_SSDP_BOOTID: "1",
}, ssdp.ATTR_SSDP_NEXTBOOTID: "2",
},
ssdp_st=MOCK_DEVICE_ST,
upnp={},
),
ssdp.SsdpChange.UPDATE, ssdp.SsdpChange.UPDATE,
) )
await hass.async_block_till_done() await hass.async_block_till_done()
@ -1290,13 +1314,17 @@ async def test_ssdp_update_seen_bootid(
# Send SSDP update with bad next boot ID # Send SSDP update with bad next boot ID
await ssdp_callback( await ssdp_callback(
{ ssdp.SsdpServiceInfo(
ssdp.ATTR_SSDP_USN: MOCK_DEVICE_USN, ssdp_usn=MOCK_DEVICE_USN,
"_udn": MOCK_DEVICE_UDN, ssdp_udn=MOCK_DEVICE_UDN,
"NTS": "ssdp:update", ssdp_headers={
ssdp.ATTR_SSDP_BOOTID: "2", "NTS": "ssdp:update",
ssdp.ATTR_SSDP_NEXTBOOTID: "7c848375-a106-4bd1-ac3c-8e50427c8e4f", ssdp.ATTR_SSDP_BOOTID: "2",
}, ssdp.ATTR_SSDP_NEXTBOOTID: "7c848375-a106-4bd1-ac3c-8e50427c8e4f",
},
ssdp_st=MOCK_DEVICE_ST,
upnp={},
),
ssdp.SsdpChange.UPDATE, ssdp.SsdpChange.UPDATE,
) )
await hass.async_block_till_done() await hass.async_block_till_done()
@ -1311,11 +1339,13 @@ async def test_ssdp_update_seen_bootid(
# Send a new SSDP alive with the new boot ID, device should not reconnect # Send a new SSDP alive with the new boot ID, device should not reconnect
await ssdp_callback( await ssdp_callback(
{ ssdp.SsdpServiceInfo(
ssdp.ATTR_SSDP_USN: MOCK_DEVICE_USN, ssdp_usn=MOCK_DEVICE_USN,
ssdp.ATTR_SSDP_LOCATION: MOCK_DEVICE_LOCATION, ssdp_location=MOCK_DEVICE_LOCATION,
ssdp.ATTR_SSDP_BOOTID: "2", ssdp_headers={ssdp.ATTR_SSDP_BOOTID: "2"},
}, ssdp_st=MOCK_DEVICE_ST,
upnp={},
),
ssdp.SsdpChange.ALIVE, ssdp.SsdpChange.ALIVE,
) )
await hass.async_block_till_done() await hass.async_block_till_done()
@ -1348,24 +1378,30 @@ async def test_ssdp_update_missed_bootid(
# Send SSDP alive with boot ID # Send SSDP alive with boot ID
ssdp_callback = ssdp_scanner_mock.async_register_callback.call_args.args[0] ssdp_callback = ssdp_scanner_mock.async_register_callback.call_args.args[0]
await ssdp_callback( await ssdp_callback(
{ ssdp.SsdpServiceInfo(
ssdp.ATTR_SSDP_USN: MOCK_DEVICE_USN, ssdp_usn=MOCK_DEVICE_USN,
ssdp.ATTR_SSDP_LOCATION: MOCK_DEVICE_LOCATION, ssdp_location=MOCK_DEVICE_LOCATION,
ssdp.ATTR_SSDP_BOOTID: "1", ssdp_headers={ssdp.ATTR_SSDP_BOOTID: "1"},
}, ssdp_st=MOCK_DEVICE_ST,
upnp={},
),
ssdp.SsdpChange.ALIVE, ssdp.SsdpChange.ALIVE,
) )
await hass.async_block_till_done() await hass.async_block_till_done()
# Send SSDP update with skipped boot ID (not previously seen) # Send SSDP update with skipped boot ID (not previously seen)
await ssdp_callback( await ssdp_callback(
{ ssdp.SsdpServiceInfo(
ssdp.ATTR_SSDP_USN: MOCK_DEVICE_USN, ssdp_usn=MOCK_DEVICE_USN,
"_udn": MOCK_DEVICE_UDN, ssdp_udn=MOCK_DEVICE_UDN,
"NTS": "ssdp:update", ssdp_headers={
ssdp.ATTR_SSDP_BOOTID: "2", "NTS": "ssdp:update",
ssdp.ATTR_SSDP_NEXTBOOTID: "3", ssdp.ATTR_SSDP_BOOTID: "2",
}, ssdp.ATTR_SSDP_NEXTBOOTID: "3",
},
ssdp_st=MOCK_DEVICE_ST,
upnp={},
),
ssdp.SsdpChange.UPDATE, ssdp.SsdpChange.UPDATE,
) )
await hass.async_block_till_done() await hass.async_block_till_done()
@ -1380,11 +1416,13 @@ async def test_ssdp_update_missed_bootid(
# Send a new SSDP alive with the new boot ID, device should reconnect # Send a new SSDP alive with the new boot ID, device should reconnect
await ssdp_callback( await ssdp_callback(
{ ssdp.SsdpServiceInfo(
ssdp.ATTR_SSDP_USN: MOCK_DEVICE_USN, ssdp_usn=MOCK_DEVICE_USN,
ssdp.ATTR_SSDP_LOCATION: MOCK_DEVICE_LOCATION, ssdp_location=MOCK_DEVICE_LOCATION,
ssdp.ATTR_SSDP_BOOTID: "3", ssdp_headers={ssdp.ATTR_SSDP_BOOTID: "3"},
}, ssdp_st=MOCK_DEVICE_ST,
upnp={},
),
ssdp.SsdpChange.ALIVE, ssdp.SsdpChange.ALIVE,
) )
await hass.async_block_till_done() await hass.async_block_till_done()
@ -1417,11 +1455,13 @@ async def test_ssdp_bootid(
# Send SSDP alive with boot ID # Send SSDP alive with boot ID
ssdp_callback = ssdp_scanner_mock.async_register_callback.call_args.args[0] ssdp_callback = ssdp_scanner_mock.async_register_callback.call_args.args[0]
await ssdp_callback( await ssdp_callback(
{ ssdp.SsdpServiceInfo(
ssdp.ATTR_SSDP_USN: MOCK_DEVICE_USN, ssdp_usn=MOCK_DEVICE_USN,
ssdp.ATTR_SSDP_LOCATION: MOCK_DEVICE_LOCATION, ssdp_location=MOCK_DEVICE_LOCATION,
ssdp.ATTR_SSDP_BOOTID: "1", ssdp_headers={ssdp.ATTR_SSDP_BOOTID: "1"},
}, ssdp_st=MOCK_DEVICE_ST,
upnp={},
),
ssdp.SsdpChange.ALIVE, ssdp.SsdpChange.ALIVE,
) )
await hass.async_block_till_done() await hass.async_block_till_done()
@ -1435,11 +1475,13 @@ async def test_ssdp_bootid(
# Send SSDP alive with same boot ID, nothing should happen # Send SSDP alive with same boot ID, nothing should happen
await ssdp_callback( await ssdp_callback(
{ ssdp.SsdpServiceInfo(
ssdp.ATTR_SSDP_USN: MOCK_DEVICE_USN, ssdp_usn=MOCK_DEVICE_USN,
ssdp.ATTR_SSDP_LOCATION: MOCK_DEVICE_LOCATION, ssdp_location=MOCK_DEVICE_LOCATION,
ssdp.ATTR_SSDP_BOOTID: "1", ssdp_headers={ssdp.ATTR_SSDP_BOOTID: "1"},
}, ssdp_st=MOCK_DEVICE_ST,
upnp={},
),
ssdp.SsdpChange.ALIVE, ssdp.SsdpChange.ALIVE,
) )
await hass.async_block_till_done() await hass.async_block_till_done()
@ -1453,11 +1495,13 @@ async def test_ssdp_bootid(
# Send a new SSDP alive with an incremented boot ID, device should be dis/reconnected # Send a new SSDP alive with an incremented boot ID, device should be dis/reconnected
await ssdp_callback( await ssdp_callback(
{ ssdp.SsdpServiceInfo(
ssdp.ATTR_SSDP_USN: MOCK_DEVICE_USN, ssdp_usn=MOCK_DEVICE_USN,
ssdp.ATTR_SSDP_LOCATION: MOCK_DEVICE_LOCATION, ssdp_location=MOCK_DEVICE_LOCATION,
ssdp.ATTR_SSDP_BOOTID: "2", ssdp_headers={ssdp.ATTR_SSDP_BOOTID: "2"},
}, ssdp_st=MOCK_DEVICE_ST,
upnp={},
),
ssdp.SsdpChange.ALIVE, ssdp.SsdpChange.ALIVE,
) )
await hass.async_block_till_done() await hass.async_block_till_done()