mirror of
https://github.com/home-assistant/core.git
synced 2025-07-17 10:17:09 +00:00
Vizio: when checking new host against existing config entry hosts, make check hostname aware (#37397)
* make ip check hostname aware * add executor job for sync function doing IO and remove errant comma * revert change to update new_data explicitly for options keys since it is already done later * empty commit to retrigger CI
This commit is contained in:
parent
368116d242
commit
572d5a09cd
@ -1,6 +1,7 @@
|
|||||||
"""Config flow for Vizio."""
|
"""Config flow for Vizio."""
|
||||||
import copy
|
import copy
|
||||||
import logging
|
import logging
|
||||||
|
import socket
|
||||||
from typing import Any, Dict, Optional
|
from typing import Any, Dict, Optional
|
||||||
|
|
||||||
from pyvizio import VizioAsync, async_guess_device_type
|
from pyvizio import VizioAsync, async_guess_device_type
|
||||||
@ -29,6 +30,7 @@ from homeassistant.core import callback
|
|||||||
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.helpers.typing import DiscoveryInfoType
|
||||||
|
from homeassistant.util.network import is_ip_address
|
||||||
|
|
||||||
from .const import (
|
from .const import (
|
||||||
CONF_APPS,
|
CONF_APPS,
|
||||||
@ -90,7 +92,11 @@ def _get_pairing_schema(input_dict: Dict[str, Any] = None) -> vol.Schema:
|
|||||||
|
|
||||||
def _host_is_same(host1: str, host2: str) -> bool:
|
def _host_is_same(host1: str, host2: str) -> bool:
|
||||||
"""Check if host1 and host2 are the same."""
|
"""Check if host1 and host2 are the same."""
|
||||||
return host1.split(":")[0] == host2.split(":")[0]
|
host1 = host1.split(":")[0]
|
||||||
|
host1 = host1 if is_ip_address(host1) else socket.gethostbyname(host1)
|
||||||
|
host2 = host2.split(":")[0]
|
||||||
|
host2 = host2 if is_ip_address(host2) else socket.gethostbyname(host2)
|
||||||
|
return host1 == host2
|
||||||
|
|
||||||
|
|
||||||
class VizioOptionsConfigFlow(config_entries.OptionsFlow):
|
class VizioOptionsConfigFlow(config_entries.OptionsFlow):
|
||||||
@ -206,8 +212,9 @@ class VizioConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
|||||||
# If source is ignore bypass host and name check and continue through loop
|
# If source is ignore bypass host and name check and continue through loop
|
||||||
if entry.source == SOURCE_IGNORE:
|
if entry.source == SOURCE_IGNORE:
|
||||||
continue
|
continue
|
||||||
|
if await self.hass.async_add_executor_job(
|
||||||
if _host_is_same(entry.data[CONF_HOST], user_input[CONF_HOST]):
|
_host_is_same, entry.data[CONF_HOST], user_input[CONF_HOST]
|
||||||
|
):
|
||||||
errors[CONF_HOST] = "host_exists"
|
errors[CONF_HOST] = "host_exists"
|
||||||
|
|
||||||
if entry.data[CONF_NAME] == user_input[CONF_NAME]:
|
if entry.data[CONF_NAME] == user_input[CONF_NAME]:
|
||||||
@ -284,11 +291,16 @@ class VizioConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
|||||||
if entry.source == SOURCE_IGNORE:
|
if entry.source == SOURCE_IGNORE:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if _host_is_same(entry.data[CONF_HOST], import_config[CONF_HOST]):
|
if await self.hass.async_add_executor_job(
|
||||||
|
_host_is_same, entry.data[CONF_HOST], import_config[CONF_HOST]
|
||||||
|
):
|
||||||
updated_options = {}
|
updated_options = {}
|
||||||
updated_data = {}
|
updated_data = {}
|
||||||
remove_apps = False
|
remove_apps = False
|
||||||
|
|
||||||
|
if entry.data[CONF_HOST] != import_config[CONF_HOST]:
|
||||||
|
updated_data[CONF_HOST] = import_config[CONF_HOST]
|
||||||
|
|
||||||
if entry.data[CONF_NAME] != import_config[CONF_NAME]:
|
if entry.data[CONF_NAME] != import_config[CONF_NAME]:
|
||||||
updated_data[CONF_NAME] = import_config[CONF_NAME]
|
updated_data[CONF_NAME] = import_config[CONF_NAME]
|
||||||
|
|
||||||
@ -314,6 +326,7 @@ class VizioConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
|||||||
if updated_data:
|
if updated_data:
|
||||||
new_data.update(updated_data)
|
new_data.update(updated_data)
|
||||||
|
|
||||||
|
# options are stored in entry options and data so update both
|
||||||
if updated_options:
|
if updated_options:
|
||||||
new_data.update(updated_options)
|
new_data.update(updated_options)
|
||||||
new_options.update(updated_options)
|
new_options.update(updated_options)
|
||||||
@ -353,7 +366,9 @@ class VizioConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
|||||||
if entry.source == SOURCE_IGNORE:
|
if entry.source == SOURCE_IGNORE:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if _host_is_same(entry.data[CONF_HOST], discovery_info[CONF_HOST]):
|
if await self.hass.async_add_executor_job(
|
||||||
|
_host_is_same, entry.data[CONF_HOST], discovery_info[CONF_HOST]
|
||||||
|
):
|
||||||
return self.async_abort(reason="already_configured_device")
|
return self.async_abort(reason="already_configured_device")
|
||||||
|
|
||||||
# Set default name to discovered device name by stripping zeroconf service
|
# Set default name to discovered device name by stripping zeroconf service
|
||||||
|
@ -110,7 +110,7 @@ async def async_setup_entry(
|
|||||||
_LOGGER.warning("Failed to connect to %s", host)
|
_LOGGER.warning("Failed to connect to %s", host)
|
||||||
raise PlatformNotReady
|
raise PlatformNotReady
|
||||||
|
|
||||||
entity = VizioDevice(config_entry, device, name, device_class,)
|
entity = VizioDevice(config_entry, device, name, device_class)
|
||||||
|
|
||||||
async_add_entities([entity], update_before_add=True)
|
async_add_entities([entity], update_before_add=True)
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@ from .const import (
|
|||||||
RESPONSE_TOKEN,
|
RESPONSE_TOKEN,
|
||||||
UNIQUE_ID,
|
UNIQUE_ID,
|
||||||
VERSION,
|
VERSION,
|
||||||
|
ZEROCONF_HOST,
|
||||||
MockCompletePairingResponse,
|
MockCompletePairingResponse,
|
||||||
MockStartPairingResponse,
|
MockStartPairingResponse,
|
||||||
)
|
)
|
||||||
@ -183,3 +184,13 @@ def vizio_update_with_apps_fixture(vizio_update: pytest.fixture):
|
|||||||
return_value=CURRENT_APP_CONFIG,
|
return_value=CURRENT_APP_CONFIG,
|
||||||
):
|
):
|
||||||
yield
|
yield
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(name="vizio_hostname_check")
|
||||||
|
def vizio_hostname_check():
|
||||||
|
"""Mock vizio hostname resolution."""
|
||||||
|
with patch(
|
||||||
|
"homeassistant.components.vizio.config_flow.socket.gethostbyname",
|
||||||
|
return_value=ZEROCONF_HOST,
|
||||||
|
):
|
||||||
|
yield
|
||||||
|
@ -853,3 +853,55 @@ async def test_zeroconf_abort_when_ignored(
|
|||||||
|
|
||||||
assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT
|
assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT
|
||||||
assert result["reason"] == "already_configured"
|
assert result["reason"] == "already_configured"
|
||||||
|
|
||||||
|
|
||||||
|
async def test_zeroconf_flow_already_configured_hostname(
|
||||||
|
hass: HomeAssistantType,
|
||||||
|
vizio_connect: pytest.fixture,
|
||||||
|
vizio_bypass_setup: pytest.fixture,
|
||||||
|
vizio_hostname_check: pytest.fixture,
|
||||||
|
) -> None:
|
||||||
|
"""Test entity is already configured during zeroconf setup when existing entry uses hostname."""
|
||||||
|
config = MOCK_SPEAKER_CONFIG.copy()
|
||||||
|
config[CONF_HOST] = "hostname"
|
||||||
|
entry = MockConfigEntry(
|
||||||
|
domain=DOMAIN, data=config, options={CONF_VOLUME_STEP: VOLUME_STEP}
|
||||||
|
)
|
||||||
|
entry.add_to_hass(hass)
|
||||||
|
|
||||||
|
# Try rediscovering same device
|
||||||
|
discovery_info = MOCK_ZEROCONF_SERVICE_INFO.copy()
|
||||||
|
result = await hass.config_entries.flow.async_init(
|
||||||
|
DOMAIN, context={"source": SOURCE_ZEROCONF}, data=discovery_info
|
||||||
|
)
|
||||||
|
|
||||||
|
# Flow should abort because device is already setup
|
||||||
|
assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT
|
||||||
|
assert result["reason"] == "already_configured_device"
|
||||||
|
|
||||||
|
|
||||||
|
async def test_import_flow_already_configured_hostname(
|
||||||
|
hass: HomeAssistantType,
|
||||||
|
vizio_connect: pytest.fixture,
|
||||||
|
vizio_bypass_setup: pytest.fixture,
|
||||||
|
vizio_hostname_check: pytest.fixture,
|
||||||
|
) -> None:
|
||||||
|
"""Test entity is already configured during import setup when existing entry uses hostname."""
|
||||||
|
config = MOCK_SPEAKER_CONFIG.copy()
|
||||||
|
config[CONF_HOST] = "hostname"
|
||||||
|
entry = MockConfigEntry(
|
||||||
|
domain=DOMAIN, data=config, options={CONF_VOLUME_STEP: VOLUME_STEP}
|
||||||
|
)
|
||||||
|
entry.add_to_hass(hass)
|
||||||
|
|
||||||
|
result = await hass.config_entries.flow.async_init(
|
||||||
|
DOMAIN,
|
||||||
|
context={"source": SOURCE_IMPORT},
|
||||||
|
data=vol.Schema(VIZIO_SCHEMA)(MOCK_SPEAKER_CONFIG),
|
||||||
|
)
|
||||||
|
|
||||||
|
# Flow should abort because device was updated
|
||||||
|
assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT
|
||||||
|
assert result["reason"] == "updated_entry"
|
||||||
|
|
||||||
|
assert entry.data[CONF_HOST] == HOST
|
||||||
|
Loading…
x
Reference in New Issue
Block a user