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 bitpull/30101/head
parent
0cb468d7b0
commit
d236a19139
|
@ -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()
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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}/",
|
||||
)
|
||||
)
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"},
|
||||
)
|
||||
|
|
|
@ -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"},
|
||||
)
|
||||
|
|
|
@ -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",
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
)
|
||||
|
|
|
@ -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",
|
||||
}
|
||||
)
|
||||
|
||||
|
|
|
@ -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",
|
||||
}
|
||||
)
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
Loading…
Reference in New Issue