Use ZeroconfServiceInfo in vizio (#60115)

Co-authored-by: epenet <epenet@users.noreply.github.com>
This commit is contained in:
epenet 2021-11-29 18:27:15 +01:00 committed by GitHub
parent 37430e7c9e
commit 54df81cbab
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 48 additions and 39 deletions

View File

@ -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:
""" """

View File

@ -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,
)

View File

@ -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
) )