mirror of
https://github.com/home-assistant/core.git
synced 2025-06-25 01:21:51 +02:00
Add ssdp discovery to Onkyo (#131066)
This commit is contained in:
@ -1066,8 +1066,8 @@ build.json @home-assistant/supervisor
|
||||
/tests/components/ondilo_ico/ @JeromeHXP
|
||||
/homeassistant/components/onewire/ @garbled1 @epenet
|
||||
/tests/components/onewire/ @garbled1 @epenet
|
||||
/homeassistant/components/onkyo/ @arturpragacz
|
||||
/tests/components/onkyo/ @arturpragacz
|
||||
/homeassistant/components/onkyo/ @arturpragacz @eclair4151
|
||||
/tests/components/onkyo/ @arturpragacz @eclair4151
|
||||
/homeassistant/components/onvif/ @hunterjm
|
||||
/tests/components/onvif/ @hunterjm
|
||||
/homeassistant/components/open_meteo/ @frenck
|
||||
|
@ -4,7 +4,9 @@ import logging
|
||||
from typing import Any
|
||||
|
||||
import voluptuous as vol
|
||||
from yarl import URL
|
||||
|
||||
from homeassistant.components import ssdp
|
||||
from homeassistant.config_entries import (
|
||||
SOURCE_RECONFIGURE,
|
||||
ConfigEntry,
|
||||
@ -165,6 +167,49 @@ class OnkyoConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||
),
|
||||
)
|
||||
|
||||
async def async_step_ssdp(
|
||||
self, discovery_info: ssdp.SsdpServiceInfo
|
||||
) -> ConfigFlowResult:
|
||||
"""Handle flow initialized by SSDP discovery."""
|
||||
_LOGGER.debug("Config flow start ssdp: %s", discovery_info)
|
||||
|
||||
if udn := discovery_info.ssdp_udn:
|
||||
udn_parts = udn.split(":")
|
||||
if len(udn_parts) == 2:
|
||||
uuid = udn_parts[1]
|
||||
last_uuid_section = uuid.split("-")[-1].upper()
|
||||
await self.async_set_unique_id(last_uuid_section)
|
||||
self._abort_if_unique_id_configured()
|
||||
|
||||
if discovery_info.ssdp_location is None:
|
||||
_LOGGER.error("SSDP location is None")
|
||||
return self.async_abort(reason="unknown")
|
||||
|
||||
host = URL(discovery_info.ssdp_location).host
|
||||
|
||||
if host is None:
|
||||
_LOGGER.error("SSDP host is None")
|
||||
return self.async_abort(reason="unknown")
|
||||
|
||||
try:
|
||||
info = await async_interview(host)
|
||||
except OSError:
|
||||
_LOGGER.exception("Unexpected exception interviewing host %s", host)
|
||||
return self.async_abort(reason="unknown")
|
||||
|
||||
if info is None:
|
||||
_LOGGER.debug("SSDP eiscp is None: %s", host)
|
||||
return self.async_abort(reason="cannot_connect")
|
||||
|
||||
await self.async_set_unique_id(info.identifier)
|
||||
self._abort_if_unique_id_configured(updates={CONF_HOST: info.host})
|
||||
|
||||
self._receiver_info = info
|
||||
|
||||
title_string = f"{info.model_name} ({info.host})"
|
||||
self.context["title_placeholders"] = {"name": title_string}
|
||||
return await self.async_step_configure_receiver()
|
||||
|
||||
async def async_step_configure_receiver(
|
||||
self, user_input: dict[str, Any] | None = None
|
||||
) -> ConfigFlowResult:
|
||||
|
@ -1,11 +1,49 @@
|
||||
{
|
||||
"domain": "onkyo",
|
||||
"name": "Onkyo",
|
||||
"codeowners": ["@arturpragacz"],
|
||||
"codeowners": ["@arturpragacz", "@eclair4151"],
|
||||
"config_flow": true,
|
||||
"documentation": "https://www.home-assistant.io/integrations/onkyo",
|
||||
"integration_type": "device",
|
||||
"iot_class": "local_push",
|
||||
"loggers": ["pyeiscp"],
|
||||
"requirements": ["pyeiscp==0.0.7"]
|
||||
"requirements": ["pyeiscp==0.0.7"],
|
||||
"ssdp": [
|
||||
{
|
||||
"manufacturer": "ONKYO",
|
||||
"deviceType": "urn:schemas-upnp-org:device:MediaRenderer:1"
|
||||
},
|
||||
{
|
||||
"manufacturer": "ONKYO",
|
||||
"deviceType": "urn:schemas-upnp-org:device:MediaRenderer:2"
|
||||
},
|
||||
{
|
||||
"manufacturer": "ONKYO",
|
||||
"deviceType": "urn:schemas-upnp-org:device:MediaRenderer:3"
|
||||
},
|
||||
{
|
||||
"manufacturer": "Onkyo & Pioneer Corporation",
|
||||
"deviceType": "urn:schemas-upnp-org:device:MediaRenderer:1"
|
||||
},
|
||||
{
|
||||
"manufacturer": "Onkyo & Pioneer Corporation",
|
||||
"deviceType": "urn:schemas-upnp-org:device:MediaRenderer:2"
|
||||
},
|
||||
{
|
||||
"manufacturer": "Onkyo & Pioneer Corporation",
|
||||
"deviceType": "urn:schemas-upnp-org:device:MediaRenderer:3"
|
||||
},
|
||||
{
|
||||
"manufacturer": "Pioneer",
|
||||
"deviceType": "urn:schemas-upnp-org:device:MediaRenderer:1"
|
||||
},
|
||||
{
|
||||
"manufacturer": "Pioneer",
|
||||
"deviceType": "urn:schemas-upnp-org:device:MediaRenderer:2"
|
||||
},
|
||||
{
|
||||
"manufacturer": "Pioneer",
|
||||
"deviceType": "urn:schemas-upnp-org:device:MediaRenderer:3"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -224,6 +224,44 @@ SSDP = {
|
||||
"manufacturer": "The OctoPrint Project",
|
||||
},
|
||||
],
|
||||
"onkyo": [
|
||||
{
|
||||
"deviceType": "urn:schemas-upnp-org:device:MediaRenderer:1",
|
||||
"manufacturer": "ONKYO",
|
||||
},
|
||||
{
|
||||
"deviceType": "urn:schemas-upnp-org:device:MediaRenderer:2",
|
||||
"manufacturer": "ONKYO",
|
||||
},
|
||||
{
|
||||
"deviceType": "urn:schemas-upnp-org:device:MediaRenderer:3",
|
||||
"manufacturer": "ONKYO",
|
||||
},
|
||||
{
|
||||
"deviceType": "urn:schemas-upnp-org:device:MediaRenderer:1",
|
||||
"manufacturer": "Onkyo & Pioneer Corporation",
|
||||
},
|
||||
{
|
||||
"deviceType": "urn:schemas-upnp-org:device:MediaRenderer:2",
|
||||
"manufacturer": "Onkyo & Pioneer Corporation",
|
||||
},
|
||||
{
|
||||
"deviceType": "urn:schemas-upnp-org:device:MediaRenderer:3",
|
||||
"manufacturer": "Onkyo & Pioneer Corporation",
|
||||
},
|
||||
{
|
||||
"deviceType": "urn:schemas-upnp-org:device:MediaRenderer:1",
|
||||
"manufacturer": "Pioneer",
|
||||
},
|
||||
{
|
||||
"deviceType": "urn:schemas-upnp-org:device:MediaRenderer:2",
|
||||
"manufacturer": "Pioneer",
|
||||
},
|
||||
{
|
||||
"deviceType": "urn:schemas-upnp-org:device:MediaRenderer:3",
|
||||
"manufacturer": "Pioneer",
|
||||
},
|
||||
],
|
||||
"openhome": [
|
||||
{
|
||||
"st": "urn:av-openhome-org:service:Product:1",
|
||||
|
@ -6,6 +6,7 @@ from unittest.mock import patch
|
||||
import pytest
|
||||
|
||||
from homeassistant import config_entries
|
||||
from homeassistant.components import ssdp
|
||||
from homeassistant.components.onkyo import InputSource
|
||||
from homeassistant.components.onkyo.config_flow import OnkyoConfigFlow
|
||||
from homeassistant.components.onkyo.const import (
|
||||
@ -83,6 +84,35 @@ async def test_manual_invalid_host(hass: HomeAssistant, stub_mock_discovery) ->
|
||||
assert host_result["errors"]["base"] == "cannot_connect"
|
||||
|
||||
|
||||
async def test_ssdp_discovery_already_configured(
|
||||
hass: HomeAssistant, default_mock_discovery
|
||||
) -> None:
|
||||
"""Test SSDP discovery with already configured device."""
|
||||
config_entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
data={CONF_HOST: "192.168.1.100"},
|
||||
unique_id="id1",
|
||||
)
|
||||
config_entry.add_to_hass(hass)
|
||||
|
||||
discovery_info = ssdp.SsdpServiceInfo(
|
||||
ssdp_location="http://192.168.1.100:8080",
|
||||
upnp={ssdp.ATTR_UPNP_FRIENDLY_NAME: "Onkyo Receiver"},
|
||||
ssdp_usn="uuid:mock_usn",
|
||||
ssdp_udn="uuid:00000000-0000-0000-0000-000000000000",
|
||||
ssdp_st="mock_st",
|
||||
)
|
||||
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN,
|
||||
context={"source": config_entries.SOURCE_SSDP},
|
||||
data=discovery_info,
|
||||
)
|
||||
|
||||
assert result["type"] is FlowResultType.ABORT
|
||||
assert result["reason"] == "already_configured"
|
||||
|
||||
|
||||
async def test_manual_valid_host_unexpected_error(
|
||||
hass: HomeAssistant, empty_mock_discovery
|
||||
) -> None:
|
||||
@ -198,6 +228,123 @@ async def test_discovery_with_one_selected(hass: HomeAssistant) -> None:
|
||||
assert select_result["description_placeholders"]["name"] == "type 42 (host 42)"
|
||||
|
||||
|
||||
async def test_ssdp_discovery_success(
|
||||
hass: HomeAssistant, default_mock_discovery
|
||||
) -> None:
|
||||
"""Test SSDP discovery with valid host."""
|
||||
discovery_info = ssdp.SsdpServiceInfo(
|
||||
ssdp_location="http://192.168.1.100:8080",
|
||||
upnp={ssdp.ATTR_UPNP_FRIENDLY_NAME: "Onkyo Receiver"},
|
||||
ssdp_usn="uuid:mock_usn",
|
||||
ssdp_udn="uuid:00000000-0000-0000-0000-000000000000",
|
||||
ssdp_st="mock_st",
|
||||
)
|
||||
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN,
|
||||
context={"source": config_entries.SOURCE_SSDP},
|
||||
data=discovery_info,
|
||||
)
|
||||
|
||||
assert result["type"] is FlowResultType.FORM
|
||||
assert result["step_id"] == "configure_receiver"
|
||||
|
||||
select_result = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"],
|
||||
user_input={"volume_resolution": 200, "input_sources": ["TV"]},
|
||||
)
|
||||
|
||||
assert select_result["type"] is FlowResultType.CREATE_ENTRY
|
||||
assert select_result["data"]["host"] == "192.168.1.100"
|
||||
assert select_result["result"].unique_id == "id1"
|
||||
|
||||
|
||||
async def test_ssdp_discovery_host_info_error(hass: HomeAssistant) -> None:
|
||||
"""Test SSDP discovery with host info error."""
|
||||
discovery_info = ssdp.SsdpServiceInfo(
|
||||
ssdp_location="http://192.168.1.100:8080",
|
||||
upnp={ssdp.ATTR_UPNP_FRIENDLY_NAME: "Onkyo Receiver"},
|
||||
ssdp_usn="uuid:mock_usn",
|
||||
ssdp_st="mock_st",
|
||||
)
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.onkyo.receiver.pyeiscp.Connection.discover",
|
||||
side_effect=OSError,
|
||||
):
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN,
|
||||
context={"source": config_entries.SOURCE_SSDP},
|
||||
data=discovery_info,
|
||||
)
|
||||
|
||||
assert result["type"] is FlowResultType.ABORT
|
||||
assert result["reason"] == "unknown"
|
||||
|
||||
|
||||
async def test_ssdp_discovery_host_none_info(
|
||||
hass: HomeAssistant, stub_mock_discovery
|
||||
) -> None:
|
||||
"""Test SSDP discovery with host info error."""
|
||||
discovery_info = ssdp.SsdpServiceInfo(
|
||||
ssdp_location="http://192.168.1.100:8080",
|
||||
upnp={ssdp.ATTR_UPNP_FRIENDLY_NAME: "Onkyo Receiver"},
|
||||
ssdp_usn="uuid:mock_usn",
|
||||
ssdp_st="mock_st",
|
||||
)
|
||||
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN,
|
||||
context={"source": config_entries.SOURCE_SSDP},
|
||||
data=discovery_info,
|
||||
)
|
||||
|
||||
assert result["type"] is FlowResultType.ABORT
|
||||
assert result["reason"] == "cannot_connect"
|
||||
|
||||
|
||||
async def test_ssdp_discovery_no_location(
|
||||
hass: HomeAssistant, default_mock_discovery
|
||||
) -> None:
|
||||
"""Test SSDP discovery with no location."""
|
||||
discovery_info = ssdp.SsdpServiceInfo(
|
||||
ssdp_location=None,
|
||||
upnp={ssdp.ATTR_UPNP_FRIENDLY_NAME: "Onkyo Receiver"},
|
||||
ssdp_usn="uuid:mock_usn",
|
||||
ssdp_st="mock_st",
|
||||
)
|
||||
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN,
|
||||
context={"source": config_entries.SOURCE_SSDP},
|
||||
data=discovery_info,
|
||||
)
|
||||
|
||||
assert result["type"] is FlowResultType.ABORT
|
||||
assert result["reason"] == "unknown"
|
||||
|
||||
|
||||
async def test_ssdp_discovery_no_host(
|
||||
hass: HomeAssistant, default_mock_discovery
|
||||
) -> None:
|
||||
"""Test SSDP discovery with no host."""
|
||||
discovery_info = ssdp.SsdpServiceInfo(
|
||||
ssdp_location="http://",
|
||||
upnp={ssdp.ATTR_UPNP_FRIENDLY_NAME: "Onkyo Receiver"},
|
||||
ssdp_usn="uuid:mock_usn",
|
||||
ssdp_st="mock_st",
|
||||
)
|
||||
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN,
|
||||
context={"source": config_entries.SOURCE_SSDP},
|
||||
data=discovery_info,
|
||||
)
|
||||
|
||||
assert result["type"] is FlowResultType.ABORT
|
||||
assert result["reason"] == "unknown"
|
||||
|
||||
|
||||
async def test_configure_empty_source_list(
|
||||
hass: HomeAssistant, default_mock_discovery
|
||||
) -> None:
|
||||
|
Reference in New Issue
Block a user