Include all SSDP data in discovery info (#28197)

* Include all SSDP data in discovery info

* Use UPnP device description as discovery info, inject some SSDP attrs

* Clean up attribute names

* Adapt existing SSDP flows to changed attribute names

* Prefix all SSDP UPnP attribute name constants with ATTR_UPNP, tweak a bit
pull/30101/head
Ville Skyttä 2019-12-19 19:28:03 +02:00 committed by GitHub
parent 0cb468d7b0
commit d236a19139
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 128 additions and 125 deletions

View File

@ -1,5 +1,6 @@
"""Config flow to configure deCONZ component."""
import asyncio
from urllib.parse import urlparse
import async_timeout
from pydeconz.errors import RequestError, ResponseError
@ -7,7 +8,7 @@ from pydeconz.utils import async_discovery, async_get_api_key, async_get_gateway
import voluptuous as vol
from homeassistant import config_entries
from homeassistant.components.ssdp import ATTR_MANUFACTURERURL, ATTR_SERIAL
from homeassistant.components import ssdp
from homeassistant.const import CONF_API_KEY, CONF_HOST, CONF_PORT
from homeassistant.core import callback
from homeassistant.helpers import aiohttp_client
@ -26,7 +27,6 @@ from .const import (
DECONZ_MANUFACTURERURL = "http://www.dresden-elektronik.de"
CONF_SERIAL = "serial"
ATTR_UUID = "udn"
@callback
@ -170,18 +170,20 @@ class DeconzFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
async def async_step_ssdp(self, discovery_info):
"""Handle a discovered deCONZ bridge."""
if discovery_info[ATTR_MANUFACTURERURL] != DECONZ_MANUFACTURERURL:
if discovery_info[ssdp.ATTR_UPNP_MANUFACTURER_URL] != DECONZ_MANUFACTURERURL:
return self.async_abort(reason="not_deconz_bridge")
uuid = discovery_info[ATTR_UUID].replace("uuid:", "")
uuid = discovery_info[ssdp.ATTR_UPNP_UDN].replace("uuid:", "")
_LOGGER.debug("deCONZ gateway discovered (%s)", uuid)
parsed_url = urlparse(discovery_info[ssdp.ATTR_SSDP_LOCATION])
for entry in self.hass.config_entries.async_entries(DOMAIN):
if uuid == entry.data.get(CONF_UUID):
return await self._update_entry(entry, discovery_info[CONF_HOST])
return await self._update_entry(entry, parsed_url.hostname)
bridgeid = discovery_info[ATTR_SERIAL]
bridgeid = discovery_info[ssdp.ATTR_UPNP_SERIAL]
if any(
bridgeid == flow["context"][CONF_BRIDGEID]
for flow in self._async_in_progress()
@ -190,11 +192,11 @@ class DeconzFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
# pylint: disable=no-member # https://github.com/PyCQA/pylint/issues/3167
self.context[CONF_BRIDGEID] = bridgeid
self.context["title_placeholders"] = {"host": discovery_info[CONF_HOST]}
self.context["title_placeholders"] = {"host": parsed_url.hostname}
self.deconz_config = {
CONF_HOST: discovery_info[CONF_HOST],
CONF_PORT: discovery_info[CONF_PORT],
CONF_HOST: parsed_url.hostname,
CONF_PORT: parsed_url.port,
}
return await self.async_step_link()

View File

@ -1,9 +1,12 @@
"""Config flow to configure Heos."""
from urllib.parse import urlparse
from pyheos import Heos, HeosError
import voluptuous as vol
from homeassistant import config_entries
from homeassistant.const import CONF_HOST, CONF_NAME
from homeassistant.components import ssdp
from homeassistant.const import CONF_HOST
from .const import DATA_DISCOVERED_HOSTS, DOMAIN
@ -23,11 +26,12 @@ class HeosFlowHandler(config_entries.ConfigFlow):
async def async_step_ssdp(self, discovery_info):
"""Handle a discovered Heos device."""
# Store discovered host
hostname = urlparse(discovery_info[ssdp.ATTR_SSDP_LOCATION]).hostname
friendly_name = "{} ({})".format(
discovery_info[CONF_NAME], discovery_info[CONF_HOST]
discovery_info[ssdp.ATTR_UPNP_FRIENDLY_NAME], hostname
)
self.hass.data.setdefault(DATA_DISCOVERED_HOSTS, {})
self.hass.data[DATA_DISCOVERED_HOSTS][friendly_name] = discovery_info[CONF_HOST]
self.hass.data[DATA_DISCOVERED_HOSTS][friendly_name] = hostname
# Abort if other flows in progress or an entry already exists
if self._async_in_progress() or self._async_current_entries():
return self.async_abort(reason="already_setup")

View File

@ -3,6 +3,7 @@
from collections import OrderedDict
import logging
from typing import Optional
from urllib.parse import urlparse
from huawei_lte_api.AuthorizedConnection import AuthorizedConnection
from huawei_lte_api.Client import Client
@ -19,7 +20,7 @@ from url_normalize import url_normalize
import voluptuous as vol
from homeassistant import config_entries
from homeassistant.components.ssdp import ATTR_HOST, ATTR_NAME, ATTR_PRESENTATIONURL
from homeassistant.components import ssdp
from homeassistant.const import CONF_PASSWORD, CONF_RECIPIENT, CONF_URL, CONF_USERNAME
from homeassistant.core import callback
@ -208,13 +209,14 @@ class ConfigFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
"""Handle SSDP initiated config flow."""
# Attempt to distinguish from other non-LTE Huawei router devices, at least
# some ones we are interested in have "Mobile Wi-Fi" friendlyName.
if "mobile" not in discovery_info.get(ATTR_NAME, "").lower():
if "mobile" not in discovery_info.get(ssdp.ATTR_UPNP_FRIENDLY_NAME, "").lower():
return self.async_abort(reason="not_huawei_lte")
# https://github.com/PyCQA/pylint/issues/3167
url = self.context[CONF_URL] = url_normalize( # pylint: disable=no-member
discovery_info.get(
ATTR_PRESENTATIONURL, f"http://{discovery_info[ATTR_HOST]}/"
ssdp.ATTR_UPNP_PRESENTATION_URL,
f"http://{urlparse(discovery_info[ssdp.ATTR_SSDP_LOCATION]).hostname}/",
)
)

View File

@ -1,6 +1,7 @@
"""Config flow to configure Philips Hue."""
import asyncio
from typing import Dict, Optional
from urllib.parse import urlparse
import aiohue
from aiohue.discovery import discover_nupnp, normalize_bridge_id
@ -8,7 +9,7 @@ import async_timeout
import voluptuous as vol
from homeassistant import config_entries, core
from homeassistant.components.ssdp import ATTR_MANUFACTURERURL, ATTR_NAME
from homeassistant.components import ssdp
from homeassistant.helpers import aiohttp_client
from .bridge import authenticate_bridge
@ -147,22 +148,25 @@ class HueFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
host is already configured and delegate to the import step if not.
"""
# Filter out non-Hue bridges #1
if discovery_info[ATTR_MANUFACTURERURL] != HUE_MANUFACTURERURL:
if discovery_info[ssdp.ATTR_UPNP_MANUFACTURER_URL] != HUE_MANUFACTURERURL:
return self.async_abort(reason="not_hue_bridge")
# Filter out non-Hue bridges #2
if any(
name in discovery_info.get(ATTR_NAME, "")
name in discovery_info.get(ssdp.ATTR_UPNP_FRIENDLY_NAME, "")
for name in HUE_IGNORED_BRIDGE_NAMES
):
return self.async_abort(reason="not_hue_bridge")
if "host" not in discovery_info or "serial" not in discovery_info:
if (
ssdp.ATTR_SSDP_LOCATION not in discovery_info
or ssdp.ATTR_UPNP_SERIAL not in discovery_info
):
return self.async_abort(reason="not_hue_bridge")
bridge = self._async_get_bridge(
discovery_info["host"], discovery_info["serial"]
)
host = urlparse(discovery_info[ssdp.ATTR_SSDP_LOCATION]).hostname
bridge = self._async_get_bridge(host, discovery_info[ssdp.ATTR_UPNP_SERIAL])
await self.async_set_unique_id(bridge.id)
self._abort_if_unique_id_configured()

View File

@ -2,7 +2,6 @@
import asyncio
from datetime import timedelta
import logging
from urllib.parse import urlparse
import aiohttp
from defusedxml import ElementTree
@ -14,19 +13,19 @@ from homeassistant.helpers.event import async_track_time_interval
DOMAIN = "ssdp"
SCAN_INTERVAL = timedelta(seconds=60)
ATTR_HOST = "host"
ATTR_PORT = "port"
ATTR_SSDP_DESCRIPTION = "ssdp_description"
ATTR_ST = "ssdp_st"
ATTR_NAME = "name"
ATTR_MODEL_NAME = "model_name"
ATTR_MODEL_NUMBER = "model_number"
ATTR_SERIAL = "serial_number"
ATTR_MANUFACTURER = "manufacturer"
ATTR_MANUFACTURERURL = "manufacturerURL"
ATTR_UDN = "udn"
ATTR_UPNP_DEVICE_TYPE = "upnp_device_type"
ATTR_PRESENTATIONURL = "presentation_url"
# Attributes for accessing info from SSDP response
ATTR_SSDP_LOCATION = "ssdp_location"
ATTR_SSDP_ST = "ssdp_st"
# Attributes for accessing info from retrieved UPnP device description
ATTR_UPNP_DEVICE_TYPE = "deviceType"
ATTR_UPNP_FRIENDLY_NAME = "friendlyName"
ATTR_UPNP_MANUFACTURER = "manufacturer"
ATTR_UPNP_MANUFACTURER_URL = "manufacturerURL"
ATTR_UPNP_MODEL_NAME = "modelName"
ATTR_UPNP_MODEL_NUMBER = "modelNumber"
ATTR_UPNP_PRESENTATION_URL = "presentationURL"
ATTR_UPNP_SERIAL = "serialNumber"
ATTR_UPNP_UDN = "UDN"
_LOGGER = logging.getLogger(__name__)
@ -157,24 +156,12 @@ class Scanner:
def info_from_entry(entry, device_info):
"""Get most important info from an entry."""
url = urlparse(entry.location)
"""Get info from an entry."""
info = {
ATTR_HOST: url.hostname,
ATTR_PORT: url.port,
ATTR_SSDP_DESCRIPTION: entry.location,
ATTR_ST: entry.st,
ATTR_SSDP_LOCATION: entry.location,
ATTR_SSDP_ST: entry.st,
}
if device_info:
info[ATTR_NAME] = device_info.get("friendlyName")
info[ATTR_MODEL_NAME] = device_info.get("modelName")
info[ATTR_MODEL_NUMBER] = device_info.get("modelNumber")
info[ATTR_SERIAL] = device_info.get("serialNumber")
info[ATTR_MANUFACTURER] = device_info.get("manufacturer")
info[ATTR_MANUFACTURERURL] = device_info.get("manufacturerURL")
info[ATTR_UDN] = device_info.get("UDN")
info[ATTR_UPNP_DEVICE_TYPE] = device_info.get("deviceType")
info[ATTR_PRESENTATIONURL] = device_info.get("presentationURL")
info.update(device_info)
return info

View File

@ -4,8 +4,8 @@ from unittest.mock import Mock, patch
import pydeconz
from homeassistant.components import ssdp
from homeassistant.components.deconz import config_flow
from homeassistant.components.ssdp import ATTR_MANUFACTURERURL, ATTR_SERIAL
from tests.common import MockConfigEntry
@ -213,11 +213,10 @@ async def test_bridge_ssdp_discovery(hass):
result = await hass.config_entries.flow.async_init(
config_flow.DOMAIN,
data={
config_flow.CONF_HOST: "1.2.3.4",
config_flow.CONF_PORT: 80,
ATTR_SERIAL: "id",
ATTR_MANUFACTURERURL: config_flow.DECONZ_MANUFACTURERURL,
config_flow.ATTR_UUID: "uuid:1234",
ssdp.ATTR_SSDP_LOCATION: "http://1.2.3.4:80/",
ssdp.ATTR_UPNP_MANUFACTURER_URL: config_flow.DECONZ_MANUFACTURERURL,
ssdp.ATTR_UPNP_SERIAL: "id",
ssdp.ATTR_UPNP_UDN: "uuid:1234",
},
context={"source": "ssdp"},
)
@ -230,7 +229,7 @@ async def test_bridge_ssdp_discovery_not_deconz_bridge(hass):
"""Test a non deconz bridge being discovered over ssdp."""
result = await hass.config_entries.flow.async_init(
config_flow.DOMAIN,
data={ATTR_MANUFACTURERURL: "not deconz bridge"},
data={ssdp.ATTR_UPNP_MANUFACTURER_URL: "not deconz bridge"},
context={"source": "ssdp"},
)
@ -257,10 +256,10 @@ async def test_bridge_discovery_update_existing_entry(hass):
result = await hass.config_entries.flow.async_init(
config_flow.DOMAIN,
data={
config_flow.CONF_HOST: "mock-deconz",
ATTR_SERIAL: "123ABC",
ATTR_MANUFACTURERURL: config_flow.DECONZ_MANUFACTURERURL,
config_flow.ATTR_UUID: "uuid:456DEF",
ssdp.ATTR_SSDP_LOCATION: "http://mock-deconz/",
ssdp.ATTR_UPNP_MANUFACTURER_URL: config_flow.DECONZ_MANUFACTURERURL,
ssdp.ATTR_UPNP_SERIAL: "123ABC",
ssdp.ATTR_UPNP_UDN: "uuid:456DEF",
},
context={"source": "ssdp"},
)

View File

@ -145,11 +145,10 @@ async def test_update_address(hass):
await hass.config_entries.flow.async_init(
deconz.config_flow.DOMAIN,
data={
deconz.config_flow.CONF_HOST: "2.3.4.5",
deconz.config_flow.CONF_PORT: 80,
ssdp.ATTR_SERIAL: BRIDGEID,
ssdp.ATTR_MANUFACTURERURL: deconz.config_flow.DECONZ_MANUFACTURERURL,
deconz.config_flow.ATTR_UUID: "uuid:456DEF",
ssdp.ATTR_SSDP_LOCATION: "http://2.3.4.5:80/",
ssdp.ATTR_UPNP_MANUFACTURER_URL: deconz.config_flow.DECONZ_MANUFACTURERURL,
ssdp.ATTR_UPNP_SERIAL: BRIDGEID,
ssdp.ATTR_UPNP_UDN: "uuid:456DEF",
},
context={"source": "ssdp"},
)

View File

@ -5,6 +5,7 @@ from asynctest.mock import Mock, patch as patch
from pyheos import Dispatcher, Heos, HeosPlayer, HeosSource, InputSource, const
import pytest
from homeassistant.components import ssdp
from homeassistant.components.heos import DOMAIN
from homeassistant.const import CONF_HOST
@ -118,16 +119,14 @@ def dispatcher_fixture() -> Dispatcher:
def discovery_data_fixture() -> dict:
"""Return mock discovery data for testing."""
return {
"host": "127.0.0.1",
"manufacturer": "Denon",
"model_name": "HEOS Drive",
"model_number": "DWSA-10 4.0",
"name": "Office",
"port": 60006,
"serial": None,
"ssdp_description": "http://127.0.0.1:60006/upnp/desc/aios_device/aios_device.xml",
"udn": "uuid:e61de70c-2250-1c22-0080-0005cdf512be",
"upnp_device_type": "urn:schemas-denon-com:device:AiosDevice:1",
ssdp.ATTR_SSDP_LOCATION: "http://127.0.0.1:60006/upnp/desc/aios_device/aios_device.xml",
ssdp.ATTR_UPNP_DEVICE_TYPE: "urn:schemas-denon-com:device:AiosDevice:1",
ssdp.ATTR_UPNP_FRIENDLY_NAME: "Office",
ssdp.ATTR_UPNP_MANUFACTURER: "Denon",
ssdp.ATTR_UPNP_MODEL_NAME: "HEOS Drive",
ssdp.ATTR_UPNP_MODEL_NUMBER: "DWSA-10 4.0",
ssdp.ATTR_UPNP_SERIAL: None,
ssdp.ATTR_UPNP_UDN: "uuid:e61de70c-2250-1c22-0080-0005cdf512be",
}

View File

@ -1,10 +1,13 @@
"""Tests for the Heos config flow module."""
from urllib.parse import urlparse
from pyheos import HeosError
from homeassistant import data_entry_flow
from homeassistant.components import ssdp
from homeassistant.components.heos.config_flow import HeosFlowHandler
from homeassistant.components.heos.const import DATA_DISCOVERED_HOSTS, DOMAIN
from homeassistant.const import CONF_HOST, CONF_NAME
from homeassistant.const import CONF_HOST
async def test_flow_aborts_already_setup(hass, config_entry):
@ -79,8 +82,9 @@ async def test_discovery_shows_create_form(hass, controller, discovery_data):
assert len(hass.config_entries.flow.async_progress()) == 1
assert hass.data[DATA_DISCOVERED_HOSTS] == {"Office (127.0.0.1)": "127.0.0.1"}
discovery_data[CONF_HOST] = "127.0.0.2"
discovery_data[CONF_NAME] = "Bedroom"
port = urlparse(discovery_data[ssdp.ATTR_SSDP_LOCATION]).port
discovery_data[ssdp.ATTR_SSDP_LOCATION] = f"http://127.0.0.2:{port}/"
discovery_data[ssdp.ATTR_UPNP_FRIENDLY_NAME] = "Bedroom"
await hass.config_entries.flow.async_init(
DOMAIN, context={"source": "ssdp"}, data=discovery_data
)

View File

@ -7,22 +7,9 @@ from requests.exceptions import ConnectionError
from requests_mock import ANY
from homeassistant import data_entry_flow
from homeassistant.components import ssdp
from homeassistant.components.huawei_lte.config_flow import ConfigFlowHandler
from homeassistant.components.huawei_lte.const import DOMAIN
from homeassistant.components.ssdp import (
ATTR_HOST,
ATTR_MANUFACTURER,
ATTR_MANUFACTURERURL,
ATTR_MODEL_NAME,
ATTR_MODEL_NUMBER,
ATTR_NAME,
ATTR_PORT,
ATTR_PRESENTATIONURL,
ATTR_SERIAL,
ATTR_ST,
ATTR_UDN,
ATTR_UPNP_DEVICE_TYPE,
)
from homeassistant.const import CONF_PASSWORD, CONF_URL, CONF_USERNAME
from tests.common import MockConfigEntry
@ -156,18 +143,17 @@ async def test_ssdp(flow):
url = "http://192.168.100.1/"
result = await flow.async_step_ssdp(
discovery_info={
ATTR_ST: "upnp:rootdevice",
ATTR_PORT: 60957,
ATTR_HOST: "192.168.100.1",
ATTR_MANUFACTURER: "Huawei",
ATTR_MANUFACTURERURL: "http://www.huawei.com/",
ATTR_MODEL_NAME: "Huawei router",
ATTR_MODEL_NUMBER: "12345678",
ATTR_NAME: "Mobile Wi-Fi",
ATTR_PRESENTATIONURL: url,
ATTR_SERIAL: "00000000",
ATTR_UDN: "uuid:XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
ATTR_UPNP_DEVICE_TYPE: "urn:schemas-upnp-org:device:InternetGatewayDevice:1",
ssdp.ATTR_SSDP_LOCATION: "http://192.168.100.1:60957/rootDesc.xml",
ssdp.ATTR_SSDP_ST: "upnp:rootdevice",
ssdp.ATTR_UPNP_DEVICE_TYPE: "urn:schemas-upnp-org:device:InternetGatewayDevice:1",
ssdp.ATTR_UPNP_FRIENDLY_NAME: "Mobile Wi-Fi",
ssdp.ATTR_UPNP_MANUFACTURER: "Huawei",
ssdp.ATTR_UPNP_MANUFACTURER_URL: "http://www.huawei.com/",
ssdp.ATTR_UPNP_MODEL_NAME: "Huawei router",
ssdp.ATTR_UPNP_MODEL_NUMBER: "12345678",
ssdp.ATTR_UPNP_PRESENTATION_URL: url,
ssdp.ATTR_UPNP_SERIAL: "00000000",
ssdp.ATTR_UPNP_UDN: "uuid:XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
}
)

View File

@ -7,6 +7,7 @@ import pytest
import voluptuous as vol
from homeassistant import config_entries, data_entry_flow
from homeassistant.components import ssdp
from homeassistant.components.hue import config_flow, const
from tests.common import MockConfigEntry, mock_coro
@ -208,9 +209,9 @@ async def test_bridge_ssdp(hass):
result = await flow.async_step_ssdp(
{
"host": "0.0.0.0",
"serial": "1234",
"manufacturerURL": config_flow.HUE_MANUFACTURERURL,
ssdp.ATTR_SSDP_LOCATION: "http://0.0.0.0/",
ssdp.ATTR_UPNP_MANUFACTURER_URL: config_flow.HUE_MANUFACTURERURL,
ssdp.ATTR_UPNP_SERIAL: "1234",
}
)
@ -224,7 +225,7 @@ async def test_bridge_ssdp_discover_other_bridge(hass):
flow.hass = hass
result = await flow.async_step_ssdp(
{"manufacturerURL": "http://www.notphilips.com"}
{ssdp.ATTR_UPNP_MANUFACTURER_URL: "http://www.notphilips.com"}
)
assert result["type"] == "abort"
@ -238,10 +239,10 @@ async def test_bridge_ssdp_emulated_hue(hass):
result = await flow.async_step_ssdp(
{
"name": "HASS Bridge",
"host": "0.0.0.0",
"serial": "1234",
"manufacturerURL": config_flow.HUE_MANUFACTURERURL,
ssdp.ATTR_SSDP_LOCATION: "http://0.0.0.0/",
ssdp.ATTR_UPNP_FRIENDLY_NAME: "HASS Bridge",
ssdp.ATTR_UPNP_MANUFACTURER_URL: config_flow.HUE_MANUFACTURERURL,
ssdp.ATTR_UPNP_SERIAL: "1234",
}
)
@ -257,10 +258,10 @@ async def test_bridge_ssdp_espalexa(hass):
result = await flow.async_step_ssdp(
{
"name": "Espalexa (0.0.0.0)",
"host": "0.0.0.0",
"serial": "1234",
"manufacturerURL": config_flow.HUE_MANUFACTURERURL,
ssdp.ATTR_SSDP_LOCATION: "http://0.0.0.0/",
ssdp.ATTR_UPNP_FRIENDLY_NAME: "Espalexa (0.0.0.0)",
ssdp.ATTR_UPNP_MANUFACTURER_URL: config_flow.HUE_MANUFACTURERURL,
ssdp.ATTR_UPNP_SERIAL: "1234",
}
)
@ -281,9 +282,9 @@ async def test_bridge_ssdp_already_configured(hass):
with pytest.raises(data_entry_flow.AbortFlow):
await flow.async_step_ssdp(
{
"host": "0.0.0.0",
"serial": "1234",
"manufacturerURL": config_flow.HUE_MANUFACTURERURL,
ssdp.ATTR_SSDP_LOCATION: "http://0.0.0.0/",
ssdp.ATTR_UPNP_MANUFACTURER_URL: config_flow.HUE_MANUFACTURERURL,
ssdp.ATTR_UPNP_SERIAL: "1234",
}
)

View File

@ -27,7 +27,9 @@ async def test_scan_match_st(hass):
assert mock_init.mock_calls[0][2]["context"] == {"source": "ssdp"}
@pytest.mark.parametrize("key", ("manufacturer", "deviceType"))
@pytest.mark.parametrize(
"key", (ssdp.ATTR_UPNP_MANUFACTURER, ssdp.ATTR_UPNP_DEVICE_TYPE)
)
async def test_scan_match_upnp_devicedesc(hass, aioclient_mock, key):
"""Test matching based on UPnP device description data."""
aioclient_mock.get(
@ -74,7 +76,14 @@ async def test_scan_not_all_present(hass, aioclient_mock):
return_value=[Mock(st="mock-st", location="http://1.1.1.1")],
), patch.dict(
gn_ssdp.SSDP,
{"mock-domain": [{"deviceType": "Paulus", "manufacturer": "Paulus"}]},
{
"mock-domain": [
{
ssdp.ATTR_UPNP_DEVICE_TYPE: "Paulus",
ssdp.ATTR_UPNP_MANUFACTURER: "Paulus",
}
]
},
), patch.object(
hass.config_entries.flow, "async_init", return_value=mock_coro()
) as mock_init:
@ -103,7 +112,14 @@ async def test_scan_not_all_match(hass, aioclient_mock):
return_value=[Mock(st="mock-st", location="http://1.1.1.1")],
), patch.dict(
gn_ssdp.SSDP,
{"mock-domain": [{"deviceType": "Paulus", "manufacturer": "Not-Paulus"}]},
{
"mock-domain": [
{
ssdp.ATTR_UPNP_DEVICE_TYPE: "Paulus",
ssdp.ATTR_UPNP_MANUFACTURER: "Not-Paulus",
}
]
},
), patch.object(
hass.config_entries.flow, "async_init", return_value=mock_coro()
) as mock_init: