mirror of
https://github.com/home-assistant/core.git
synced 2025-07-23 21:27:38 +00:00
Use ZeroconfServiceInfo in vizio (#60115)
Co-authored-by: epenet <epenet@users.noreply.github.com>
This commit is contained in:
parent
37430e7c9e
commit
54df81cbab
@ -11,6 +11,7 @@ from pyvizio.const import APP_HOME
|
|||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
from homeassistant import config_entries
|
from homeassistant import config_entries
|
||||||
|
from homeassistant.components import zeroconf
|
||||||
from homeassistant.components.media_player import DEVICE_CLASS_SPEAKER, DEVICE_CLASS_TV
|
from homeassistant.components.media_player import DEVICE_CLASS_SPEAKER, DEVICE_CLASS_TV
|
||||||
from homeassistant.config_entries import (
|
from homeassistant.config_entries import (
|
||||||
SOURCE_IGNORE,
|
SOURCE_IGNORE,
|
||||||
@ -26,14 +27,11 @@ from homeassistant.const import (
|
|||||||
CONF_INCLUDE,
|
CONF_INCLUDE,
|
||||||
CONF_NAME,
|
CONF_NAME,
|
||||||
CONF_PIN,
|
CONF_PIN,
|
||||||
CONF_PORT,
|
|
||||||
CONF_TYPE,
|
|
||||||
)
|
)
|
||||||
from homeassistant.core import callback
|
from homeassistant.core import callback
|
||||||
from homeassistant.data_entry_flow import FlowResult
|
from homeassistant.data_entry_flow import FlowResult
|
||||||
from homeassistant.helpers import config_validation as cv
|
from homeassistant.helpers import config_validation as cv
|
||||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||||
from homeassistant.helpers.typing import DiscoveryInfoType
|
|
||||||
from homeassistant.util.network import is_ip_address
|
from homeassistant.util.network import is_ip_address
|
||||||
|
|
||||||
from .const import (
|
from .const import (
|
||||||
@ -338,28 +336,25 @@ class VizioConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
|||||||
return await self.async_step_user(user_input=import_config)
|
return await self.async_step_user(user_input=import_config)
|
||||||
|
|
||||||
async def async_step_zeroconf(
|
async def async_step_zeroconf(
|
||||||
self, discovery_info: DiscoveryInfoType | None = None
|
self, discovery_info: zeroconf.ZeroconfServiceInfo
|
||||||
) -> FlowResult:
|
) -> FlowResult:
|
||||||
"""Handle zeroconf discovery."""
|
"""Handle zeroconf discovery."""
|
||||||
|
host = discovery_info.host
|
||||||
# If host already has port, no need to add it again
|
# If host already has port, no need to add it again
|
||||||
if ":" not in discovery_info[CONF_HOST]:
|
if ":" not in host:
|
||||||
discovery_info[
|
host = f"{host}:{discovery_info.port}"
|
||||||
CONF_HOST
|
|
||||||
] = f"{discovery_info[CONF_HOST]}:{discovery_info[CONF_PORT]}"
|
|
||||||
|
|
||||||
# Set default name to discovered device name by stripping zeroconf service
|
# Set default name to discovered device name by stripping zeroconf service
|
||||||
# (`type`) from `name`
|
# (`type`) from `name`
|
||||||
num_chars_to_strip = len(discovery_info[CONF_TYPE]) + 1
|
num_chars_to_strip = len(discovery_info.type) + 1
|
||||||
discovery_info[CONF_NAME] = discovery_info[CONF_NAME][:-num_chars_to_strip]
|
name = discovery_info.name[:-num_chars_to_strip]
|
||||||
|
|
||||||
discovery_info[CONF_DEVICE_CLASS] = await async_guess_device_type(
|
device_class = await async_guess_device_type(host)
|
||||||
discovery_info[CONF_HOST]
|
|
||||||
)
|
|
||||||
|
|
||||||
# Set unique ID early for discovery flow so we can abort if needed
|
# Set unique ID early for discovery flow so we can abort if needed
|
||||||
unique_id = await VizioAsync.get_unique_id(
|
unique_id = await VizioAsync.get_unique_id(
|
||||||
discovery_info[CONF_HOST],
|
host,
|
||||||
discovery_info[CONF_DEVICE_CLASS],
|
device_class,
|
||||||
session=async_get_clientsession(self.hass, False),
|
session=async_get_clientsession(self.hass, False),
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -372,7 +367,13 @@ class VizioConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
|||||||
# Form must be shown after discovery so user can confirm/update configuration
|
# Form must be shown after discovery so user can confirm/update configuration
|
||||||
# before ConfigEntry creation.
|
# before ConfigEntry creation.
|
||||||
self._must_show_form = True
|
self._must_show_form = True
|
||||||
return await self.async_step_user(user_input=discovery_info)
|
return await self.async_step_user(
|
||||||
|
user_input={
|
||||||
|
CONF_HOST: host,
|
||||||
|
CONF_NAME: name,
|
||||||
|
CONF_DEVICE_CLASS: device_class,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
async def async_step_pair_tv(self, user_input: dict[str, Any] = None) -> FlowResult:
|
async def async_step_pair_tv(self, user_input: dict[str, Any] = None) -> FlowResult:
|
||||||
"""
|
"""
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
"""Constants for the Vizio integration tests."""
|
"""Constants for the Vizio integration tests."""
|
||||||
|
from homeassistant.components import zeroconf
|
||||||
from homeassistant.components.media_player import (
|
from homeassistant.components.media_player import (
|
||||||
DEVICE_CLASS_SPEAKER,
|
DEVICE_CLASS_SPEAKER,
|
||||||
DEVICE_CLASS_TV,
|
DEVICE_CLASS_TV,
|
||||||
@ -23,8 +24,6 @@ from homeassistant.const import (
|
|||||||
CONF_INCLUDE,
|
CONF_INCLUDE,
|
||||||
CONF_NAME,
|
CONF_NAME,
|
||||||
CONF_PIN,
|
CONF_PIN,
|
||||||
CONF_PORT,
|
|
||||||
CONF_TYPE,
|
|
||||||
)
|
)
|
||||||
from homeassistant.util import slugify
|
from homeassistant.util import slugify
|
||||||
|
|
||||||
@ -198,10 +197,11 @@ ZEROCONF_NAME = f"{NAME}.{VIZIO_ZEROCONF_SERVICE_TYPE}"
|
|||||||
ZEROCONF_HOST = HOST.split(":")[0]
|
ZEROCONF_HOST = HOST.split(":")[0]
|
||||||
ZEROCONF_PORT = HOST.split(":")[1]
|
ZEROCONF_PORT = HOST.split(":")[1]
|
||||||
|
|
||||||
MOCK_ZEROCONF_SERVICE_INFO = {
|
MOCK_ZEROCONF_SERVICE_INFO = zeroconf.ZeroconfServiceInfo(
|
||||||
CONF_TYPE: VIZIO_ZEROCONF_SERVICE_TYPE,
|
host=ZEROCONF_HOST,
|
||||||
CONF_NAME: ZEROCONF_NAME,
|
hostname="mock_hostname",
|
||||||
CONF_HOST: ZEROCONF_HOST,
|
name=ZEROCONF_NAME,
|
||||||
CONF_PORT: ZEROCONF_PORT,
|
port=ZEROCONF_PORT,
|
||||||
"properties": {"name": "SB4031-D5"},
|
properties={"name": "SB4031-D5"},
|
||||||
}
|
type=VIZIO_ZEROCONF_SERVICE_TYPE,
|
||||||
|
)
|
||||||
|
@ -1,8 +1,11 @@
|
|||||||
"""Tests for Vizio config flow."""
|
"""Tests for Vizio config flow."""
|
||||||
|
import dataclasses
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
from homeassistant import data_entry_flow
|
from homeassistant import data_entry_flow
|
||||||
|
from homeassistant.components import zeroconf
|
||||||
from homeassistant.components.media_player import DEVICE_CLASS_SPEAKER, DEVICE_CLASS_TV
|
from homeassistant.components.media_player import DEVICE_CLASS_SPEAKER, DEVICE_CLASS_TV
|
||||||
from homeassistant.components.vizio.config_flow import _get_config_schema
|
from homeassistant.components.vizio.config_flow import _get_config_schema
|
||||||
from homeassistant.components.vizio.const import (
|
from homeassistant.components.vizio.const import (
|
||||||
@ -27,7 +30,6 @@ from homeassistant.const import (
|
|||||||
CONF_HOST,
|
CONF_HOST,
|
||||||
CONF_NAME,
|
CONF_NAME,
|
||||||
CONF_PIN,
|
CONF_PIN,
|
||||||
CONF_PORT,
|
|
||||||
)
|
)
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
|
|
||||||
@ -728,7 +730,7 @@ async def test_zeroconf_flow(
|
|||||||
vizio_guess_device_type: pytest.fixture,
|
vizio_guess_device_type: pytest.fixture,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test zeroconf config flow."""
|
"""Test zeroconf config flow."""
|
||||||
discovery_info = MOCK_ZEROCONF_SERVICE_INFO.copy()
|
discovery_info = dataclasses.replace(MOCK_ZEROCONF_SERVICE_INFO)
|
||||||
result = await hass.config_entries.flow.async_init(
|
result = await hass.config_entries.flow.async_init(
|
||||||
DOMAIN, context={"source": SOURCE_ZEROCONF}, data=discovery_info
|
DOMAIN, context={"source": SOURCE_ZEROCONF}, data=discovery_info
|
||||||
)
|
)
|
||||||
@ -739,7 +741,15 @@ async def test_zeroconf_flow(
|
|||||||
|
|
||||||
# Apply discovery updates to entry to mimic when user hits submit without changing
|
# Apply discovery updates to entry to mimic when user hits submit without changing
|
||||||
# defaults which were set from discovery parameters
|
# defaults which were set from discovery parameters
|
||||||
user_input = result["data_schema"](discovery_info)
|
user_input = result["data_schema"](
|
||||||
|
{
|
||||||
|
CONF_HOST: f"{discovery_info[zeroconf.ATTR_HOST]}:{discovery_info[zeroconf.ATTR_PORT]}",
|
||||||
|
CONF_NAME: discovery_info[zeroconf.ATTR_NAME][
|
||||||
|
: -(len(discovery_info[zeroconf.ATTR_TYPE]) + 1)
|
||||||
|
],
|
||||||
|
CONF_DEVICE_CLASS: "speaker",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
result = await hass.config_entries.flow.async_configure(
|
result = await hass.config_entries.flow.async_configure(
|
||||||
result["flow_id"], user_input=user_input
|
result["flow_id"], user_input=user_input
|
||||||
@ -768,7 +778,7 @@ async def test_zeroconf_flow_already_configured(
|
|||||||
entry.add_to_hass(hass)
|
entry.add_to_hass(hass)
|
||||||
|
|
||||||
# Try rediscovering same device
|
# Try rediscovering same device
|
||||||
discovery_info = MOCK_ZEROCONF_SERVICE_INFO.copy()
|
discovery_info = dataclasses.replace(MOCK_ZEROCONF_SERVICE_INFO)
|
||||||
result = await hass.config_entries.flow.async_init(
|
result = await hass.config_entries.flow.async_init(
|
||||||
DOMAIN, context={"source": SOURCE_ZEROCONF}, data=discovery_info
|
DOMAIN, context={"source": SOURCE_ZEROCONF}, data=discovery_info
|
||||||
)
|
)
|
||||||
@ -794,10 +804,8 @@ async def test_zeroconf_flow_with_port_in_host(
|
|||||||
entry.add_to_hass(hass)
|
entry.add_to_hass(hass)
|
||||||
|
|
||||||
# Try rediscovering same device, this time with port already in host
|
# Try rediscovering same device, this time with port already in host
|
||||||
discovery_info = MOCK_ZEROCONF_SERVICE_INFO.copy()
|
discovery_info = dataclasses.replace(MOCK_ZEROCONF_SERVICE_INFO)
|
||||||
discovery_info[
|
discovery_info.host = f"{discovery_info.host}:{discovery_info.port}"
|
||||||
CONF_HOST
|
|
||||||
] = f"{discovery_info[CONF_HOST]}:{discovery_info[CONF_PORT]}"
|
|
||||||
result = await hass.config_entries.flow.async_init(
|
result = await hass.config_entries.flow.async_init(
|
||||||
DOMAIN, context={"source": SOURCE_ZEROCONF}, data=discovery_info
|
DOMAIN, context={"source": SOURCE_ZEROCONF}, data=discovery_info
|
||||||
)
|
)
|
||||||
@ -814,7 +822,7 @@ async def test_zeroconf_dupe_fail(
|
|||||||
vizio_guess_device_type: pytest.fixture,
|
vizio_guess_device_type: pytest.fixture,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test zeroconf config flow when device gets discovered multiple times."""
|
"""Test zeroconf config flow when device gets discovered multiple times."""
|
||||||
discovery_info = MOCK_ZEROCONF_SERVICE_INFO.copy()
|
discovery_info = dataclasses.replace(MOCK_ZEROCONF_SERVICE_INFO)
|
||||||
result = await hass.config_entries.flow.async_init(
|
result = await hass.config_entries.flow.async_init(
|
||||||
DOMAIN, context={"source": SOURCE_ZEROCONF}, data=discovery_info
|
DOMAIN, context={"source": SOURCE_ZEROCONF}, data=discovery_info
|
||||||
)
|
)
|
||||||
@ -823,7 +831,7 @@ async def test_zeroconf_dupe_fail(
|
|||||||
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
|
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
|
||||||
assert result["step_id"] == "user"
|
assert result["step_id"] == "user"
|
||||||
|
|
||||||
discovery_info = MOCK_ZEROCONF_SERVICE_INFO.copy()
|
discovery_info = dataclasses.replace(MOCK_ZEROCONF_SERVICE_INFO)
|
||||||
result = await hass.config_entries.flow.async_init(
|
result = await hass.config_entries.flow.async_init(
|
||||||
DOMAIN, context={"source": SOURCE_ZEROCONF}, data=discovery_info
|
DOMAIN, context={"source": SOURCE_ZEROCONF}, data=discovery_info
|
||||||
)
|
)
|
||||||
@ -848,7 +856,7 @@ async def test_zeroconf_ignore(
|
|||||||
)
|
)
|
||||||
entry.add_to_hass(hass)
|
entry.add_to_hass(hass)
|
||||||
|
|
||||||
discovery_info = MOCK_ZEROCONF_SERVICE_INFO.copy()
|
discovery_info = dataclasses.replace(MOCK_ZEROCONF_SERVICE_INFO)
|
||||||
result = await hass.config_entries.flow.async_init(
|
result = await hass.config_entries.flow.async_init(
|
||||||
DOMAIN, context={"source": SOURCE_ZEROCONF}, data=discovery_info
|
DOMAIN, context={"source": SOURCE_ZEROCONF}, data=discovery_info
|
||||||
)
|
)
|
||||||
@ -863,7 +871,7 @@ async def test_zeroconf_no_unique_id(
|
|||||||
) -> None:
|
) -> None:
|
||||||
"""Test zeroconf discovery aborts when unique_id is None."""
|
"""Test zeroconf discovery aborts when unique_id is None."""
|
||||||
|
|
||||||
discovery_info = MOCK_ZEROCONF_SERVICE_INFO.copy()
|
discovery_info = dataclasses.replace(MOCK_ZEROCONF_SERVICE_INFO)
|
||||||
result = await hass.config_entries.flow.async_init(
|
result = await hass.config_entries.flow.async_init(
|
||||||
DOMAIN, context={"source": SOURCE_ZEROCONF}, data=discovery_info
|
DOMAIN, context={"source": SOURCE_ZEROCONF}, data=discovery_info
|
||||||
)
|
)
|
||||||
@ -888,7 +896,7 @@ async def test_zeroconf_abort_when_ignored(
|
|||||||
)
|
)
|
||||||
entry.add_to_hass(hass)
|
entry.add_to_hass(hass)
|
||||||
|
|
||||||
discovery_info = MOCK_ZEROCONF_SERVICE_INFO.copy()
|
discovery_info = dataclasses.replace(MOCK_ZEROCONF_SERVICE_INFO)
|
||||||
result = await hass.config_entries.flow.async_init(
|
result = await hass.config_entries.flow.async_init(
|
||||||
DOMAIN, context={"source": SOURCE_ZEROCONF}, data=discovery_info
|
DOMAIN, context={"source": SOURCE_ZEROCONF}, data=discovery_info
|
||||||
)
|
)
|
||||||
@ -916,7 +924,7 @@ async def test_zeroconf_flow_already_configured_hostname(
|
|||||||
entry.add_to_hass(hass)
|
entry.add_to_hass(hass)
|
||||||
|
|
||||||
# Try rediscovering same device
|
# Try rediscovering same device
|
||||||
discovery_info = MOCK_ZEROCONF_SERVICE_INFO.copy()
|
discovery_info = dataclasses.replace(MOCK_ZEROCONF_SERVICE_INFO)
|
||||||
result = await hass.config_entries.flow.async_init(
|
result = await hass.config_entries.flow.async_init(
|
||||||
DOMAIN, context={"source": SOURCE_ZEROCONF}, data=discovery_info
|
DOMAIN, context={"source": SOURCE_ZEROCONF}, data=discovery_info
|
||||||
)
|
)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user