Remove YAML support from vizio (#132351)

This commit is contained in:
epenet 2024-12-09 10:15:01 +01:00 committed by GitHub
parent 1ec91e7c89
commit 24b1eeb900
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 11 additions and 565 deletions

View File

@ -4,55 +4,18 @@ from __future__ import annotations
from typing import Any
import voluptuous as vol
from homeassistant.components.media_player import MediaPlayerDeviceClass
from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry, ConfigEntryState
from homeassistant.const import Platform
from homeassistant.config_entries import ConfigEntry, ConfigEntryState
from homeassistant.const import CONF_DEVICE_CLASS, Platform
from homeassistant.core import HomeAssistant
from homeassistant.helpers import config_validation as cv
from homeassistant.helpers.storage import Store
from homeassistant.helpers.typing import ConfigType
from .const import CONF_APPS, CONF_DEVICE_CLASS, DOMAIN, VIZIO_SCHEMA
from .const import CONF_APPS, DOMAIN
from .coordinator import VizioAppsDataUpdateCoordinator
def validate_apps(config: ConfigType) -> ConfigType:
"""Validate CONF_APPS is only used when CONF_DEVICE_CLASS is MediaPlayerDeviceClass.TV."""
if (
config.get(CONF_APPS) is not None
and config[CONF_DEVICE_CLASS] != MediaPlayerDeviceClass.TV
):
raise vol.Invalid(
f"'{CONF_APPS}' can only be used if {CONF_DEVICE_CLASS}' is"
f" '{MediaPlayerDeviceClass.TV}'"
)
return config
CONFIG_SCHEMA = vol.Schema(
{DOMAIN: vol.All(cv.ensure_list, [vol.All(VIZIO_SCHEMA, validate_apps)])},
extra=vol.ALLOW_EXTRA,
)
PLATFORMS = [Platform.MEDIA_PLAYER]
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
"""Component setup, run import config flow for each entry in config."""
if DOMAIN in config:
for entry in config[DOMAIN]:
hass.async_create_task(
hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_IMPORT}, data=entry
)
)
return True
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Load the saved entities."""

View File

@ -14,8 +14,6 @@ import voluptuous as vol
from homeassistant.components import zeroconf
from homeassistant.components.media_player import MediaPlayerDeviceClass
from homeassistant.config_entries import (
SOURCE_IGNORE,
SOURCE_IMPORT,
SOURCE_ZEROCONF,
ConfigEntry,
ConfigFlow,
@ -231,7 +229,7 @@ class VizioConfigFlow(ConfigFlow, domain=DOMAIN):
errors[CONF_HOST] = "existing_config_entry_found"
if not errors:
if self._must_show_form and self.source == SOURCE_ZEROCONF:
if self._must_show_form and self.context["source"] == SOURCE_ZEROCONF:
# Discovery should always display the config form before trying to
# create entry so that user can update default config options
self._must_show_form = False
@ -251,98 +249,13 @@ class VizioConfigFlow(ConfigFlow, domain=DOMAIN):
if not errors:
return await self._create_entry(user_input)
elif self._must_show_form and self.source == SOURCE_IMPORT:
# Import should always display the config form if CONF_ACCESS_TOKEN
# wasn't included but is needed so that the user can choose to update
# their configuration.yaml or to proceed with config flow pairing. We
# will also provide contextual message to user explaining why
_LOGGER.warning(
(
"Couldn't complete configuration.yaml import: '%s' key is "
"missing. Either provide '%s' key in configuration.yaml or "
"finish setup by completing configuration via frontend"
),
CONF_ACCESS_TOKEN,
CONF_ACCESS_TOKEN,
)
self._must_show_form = False
else:
self._data = copy.deepcopy(user_input)
return await self.async_step_pair_tv()
schema = self._user_schema or _get_config_schema()
if errors and self.source == SOURCE_IMPORT:
# Log an error message if import config flow fails since otherwise failure is silent
_LOGGER.error(
"Importing from configuration.yaml failed: %s",
", ".join(errors.values()),
)
return self.async_show_form(step_id="user", data_schema=schema, errors=errors)
async def async_step_import(self, import_data: dict[str, Any]) -> ConfigFlowResult:
"""Import a config entry from configuration.yaml."""
# Check if new config entry matches any existing config entries
for entry in self._async_current_entries():
# If source is ignore bypass host check and continue through loop
if entry.source == SOURCE_IGNORE:
continue
if await self.hass.async_add_executor_job(
_host_is_same, entry.data[CONF_HOST], import_data[CONF_HOST]
):
updated_options: dict[str, Any] = {}
updated_data: dict[str, Any] = {}
remove_apps = False
if entry.data[CONF_HOST] != import_data[CONF_HOST]:
updated_data[CONF_HOST] = import_data[CONF_HOST]
if entry.data[CONF_NAME] != import_data[CONF_NAME]:
updated_data[CONF_NAME] = import_data[CONF_NAME]
# Update entry.data[CONF_APPS] if import_config[CONF_APPS] differs, and
# pop entry.data[CONF_APPS] if import_config[CONF_APPS] is not specified
if entry.data.get(CONF_APPS) != import_data.get(CONF_APPS):
if not import_data.get(CONF_APPS):
remove_apps = True
else:
updated_options[CONF_APPS] = import_data[CONF_APPS]
if entry.data.get(CONF_VOLUME_STEP) != import_data[CONF_VOLUME_STEP]:
updated_options[CONF_VOLUME_STEP] = import_data[CONF_VOLUME_STEP]
if updated_options or updated_data or remove_apps:
new_data = entry.data.copy()
new_options = entry.options.copy()
if remove_apps:
new_data.pop(CONF_APPS)
new_options.pop(CONF_APPS)
if updated_data:
new_data.update(updated_data)
# options are stored in entry options and data so update both
if updated_options:
new_data.update(updated_options)
new_options.update(updated_options)
self.hass.config_entries.async_update_entry(
entry=entry, data=new_data, options=new_options
)
return self.async_abort(reason="updated_entry")
return self.async_abort(reason="already_configured_device")
self._must_show_form = True
# Store config key/value pairs that are not configurable in user step so they
# don't get lost on user step
if import_data.get(CONF_APPS):
self._apps = copy.deepcopy(import_data[CONF_APPS])
return await self.async_step_user(user_input=import_data)
async def async_step_zeroconf(
self, discovery_info: zeroconf.ZeroconfServiceInfo
) -> ConfigFlowResult:
@ -433,11 +346,6 @@ class VizioConfigFlow(ConfigFlow, domain=DOMAIN):
if pair_data:
self._data[CONF_ACCESS_TOKEN] = pair_data.auth_token
self._must_show_form = True
if self.source == SOURCE_IMPORT:
# If user is pairing via config import, show different message
return await self.async_step_pairing_complete_import()
return await self.async_step_pairing_complete()
# If no data was retrieved, it's assumed that the pairing attempt was not

View File

@ -10,14 +10,6 @@ from homeassistant.components.media_player import (
MediaPlayerDeviceClass,
MediaPlayerEntityFeature,
)
from homeassistant.const import (
CONF_ACCESS_TOKEN,
CONF_DEVICE_CLASS,
CONF_EXCLUDE,
CONF_HOST,
CONF_INCLUDE,
CONF_NAME,
)
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.typing import VolDictType
@ -84,43 +76,3 @@ VIZIO_DEVICE_CLASSES = {
MediaPlayerDeviceClass.SPEAKER: VIZIO_DEVICE_CLASS_SPEAKER,
MediaPlayerDeviceClass.TV: VIZIO_DEVICE_CLASS_TV,
}
VIZIO_SCHEMA = {
vol.Required(CONF_HOST): cv.string,
vol.Optional(CONF_ACCESS_TOKEN): cv.string,
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
vol.Optional(CONF_DEVICE_CLASS, default=DEFAULT_DEVICE_CLASS): vol.All(
cv.string,
vol.Lower,
vol.In([MediaPlayerDeviceClass.TV, MediaPlayerDeviceClass.SPEAKER]),
),
vol.Optional(CONF_VOLUME_STEP, default=DEFAULT_VOLUME_STEP): vol.All(
vol.Coerce(int), vol.Range(min=1, max=10)
),
vol.Optional(CONF_APPS): vol.All(
{
vol.Exclusive(CONF_INCLUDE, "apps_filter"): vol.All(
cv.ensure_list, [cv.string]
),
vol.Exclusive(CONF_EXCLUDE, "apps_filter"): vol.All(
cv.ensure_list, [cv.string]
),
vol.Optional(CONF_ADDITIONAL_CONFIGS): vol.All(
cv.ensure_list,
[
{
vol.Required(CONF_NAME): cv.string,
vol.Required(CONF_CONFIG): {
vol.Required(CONF_APP_ID): cv.string,
vol.Required(CONF_NAME_SPACE): vol.Coerce(int),
vol.Optional(CONF_MESSAGE, default=None): vol.Or(
cv.string, None
),
},
},
],
),
},
cv.has_at_least_one_key(CONF_INCLUDE, CONF_EXCLUDE, CONF_ADDITIONAL_CONFIGS),
),
}

View File

@ -112,14 +112,6 @@ MOCK_OPTIONS = {
CONF_VOLUME_STEP: VOLUME_STEP,
}
MOCK_IMPORT_VALID_TV_CONFIG = {
CONF_NAME: NAME,
CONF_HOST: HOST,
CONF_DEVICE_CLASS: MediaPlayerDeviceClass.TV,
CONF_ACCESS_TOKEN: ACCESS_TOKEN,
CONF_VOLUME_STEP: VOLUME_STEP,
}
MOCK_TV_WITH_INCLUDE_CONFIG = {
CONF_NAME: NAME,
CONF_HOST: HOST,
@ -147,23 +139,6 @@ MOCK_TV_WITH_ADDITIONAL_APPS_CONFIG = {
CONF_APPS: {CONF_ADDITIONAL_CONFIGS: [ADDITIONAL_APP_CONFIG]},
}
MOCK_SPEAKER_APPS_FAILURE = {
CONF_NAME: NAME,
CONF_HOST: HOST,
CONF_DEVICE_CLASS: MediaPlayerDeviceClass.SPEAKER,
CONF_ACCESS_TOKEN: ACCESS_TOKEN,
CONF_VOLUME_STEP: VOLUME_STEP,
CONF_APPS: {CONF_ADDITIONAL_CONFIGS: [ADDITIONAL_APP_CONFIG]},
}
MOCK_TV_APPS_FAILURE = {
CONF_NAME: NAME,
CONF_HOST: HOST,
CONF_DEVICE_CLASS: MediaPlayerDeviceClass.TV,
CONF_ACCESS_TOKEN: ACCESS_TOKEN,
CONF_VOLUME_STEP: VOLUME_STEP,
CONF_APPS: None,
}
MOCK_TV_APPS_WITH_VALID_APPS_CONFIG = {
CONF_HOST: HOST,

View File

@ -3,30 +3,20 @@
import dataclasses
import pytest
import voluptuous as vol
from homeassistant.components.media_player import MediaPlayerDeviceClass
from homeassistant.components.vizio.config_flow import _get_config_schema
from homeassistant.components.vizio.const import (
CONF_APPS,
CONF_APPS_TO_INCLUDE_OR_EXCLUDE,
CONF_INCLUDE,
CONF_VOLUME_STEP,
DEFAULT_NAME,
DEFAULT_VOLUME_STEP,
DOMAIN,
VIZIO_SCHEMA,
)
from homeassistant.config_entries import (
SOURCE_IGNORE,
SOURCE_IMPORT,
SOURCE_USER,
SOURCE_ZEROCONF,
)
from homeassistant.config_entries import SOURCE_IGNORE, SOURCE_USER, SOURCE_ZEROCONF
from homeassistant.const import (
CONF_ACCESS_TOKEN,
CONF_DEVICE_CLASS,
CONF_HOST,
CONF_INCLUDE,
CONF_NAME,
CONF_PIN,
)
@ -38,14 +28,11 @@ from .const import (
CURRENT_APP,
HOST,
HOST2,
MOCK_IMPORT_VALID_TV_CONFIG,
MOCK_INCLUDE_APPS,
MOCK_INCLUDE_NO_APPS,
MOCK_PIN_CONFIG,
MOCK_SPEAKER_CONFIG,
MOCK_TV_CONFIG_NO_TOKEN,
MOCK_TV_WITH_ADDITIONAL_APPS_CONFIG,
MOCK_TV_WITH_EXCLUDE_CONFIG,
MOCK_USER_VALID_TV_CONFIG,
MOCK_ZEROCONF_SERVICE_INFO,
NAME,
@ -370,297 +357,6 @@ async def test_user_ignore(hass: HomeAssistant) -> None:
assert result["type"] is FlowResultType.CREATE_ENTRY
@pytest.mark.usefixtures("vizio_connect", "vizio_bypass_setup")
async def test_import_flow_minimum_fields(hass: HomeAssistant) -> None:
"""Test import config flow with minimum fields."""
result = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": SOURCE_IMPORT},
data=vol.Schema(VIZIO_SCHEMA)(
{CONF_HOST: HOST, CONF_DEVICE_CLASS: MediaPlayerDeviceClass.SPEAKER}
),
)
assert result["type"] is FlowResultType.CREATE_ENTRY
assert result["title"] == DEFAULT_NAME
assert result["data"][CONF_NAME] == DEFAULT_NAME
assert result["data"][CONF_HOST] == HOST
assert result["data"][CONF_DEVICE_CLASS] == MediaPlayerDeviceClass.SPEAKER
assert result["data"][CONF_VOLUME_STEP] == DEFAULT_VOLUME_STEP
@pytest.mark.usefixtures("vizio_connect", "vizio_bypass_setup")
async def test_import_flow_all_fields(hass: HomeAssistant) -> None:
"""Test import config flow with all fields."""
result = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": SOURCE_IMPORT},
data=vol.Schema(VIZIO_SCHEMA)(MOCK_IMPORT_VALID_TV_CONFIG),
)
assert result["type"] is FlowResultType.CREATE_ENTRY
assert result["title"] == NAME
assert result["data"][CONF_NAME] == NAME
assert result["data"][CONF_HOST] == HOST
assert result["data"][CONF_DEVICE_CLASS] == MediaPlayerDeviceClass.TV
assert result["data"][CONF_ACCESS_TOKEN] == ACCESS_TOKEN
assert result["data"][CONF_VOLUME_STEP] == VOLUME_STEP
@pytest.mark.usefixtures("vizio_connect", "vizio_bypass_setup")
async def test_import_entity_already_configured(hass: HomeAssistant) -> None:
"""Test entity is already configured during import setup."""
entry = MockConfigEntry(
domain=DOMAIN,
data=vol.Schema(VIZIO_SCHEMA)(MOCK_SPEAKER_CONFIG),
options={CONF_VOLUME_STEP: VOLUME_STEP},
)
entry.add_to_hass(hass)
fail_entry = vol.Schema(VIZIO_SCHEMA)(MOCK_SPEAKER_CONFIG.copy())
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_IMPORT}, data=fail_entry
)
assert result["type"] is FlowResultType.ABORT
assert result["reason"] == "already_configured_device"
@pytest.mark.usefixtures("vizio_connect", "vizio_bypass_update")
async def test_import_flow_update_options(hass: HomeAssistant) -> None:
"""Test import config flow with updated options."""
result = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": SOURCE_IMPORT},
data=vol.Schema(VIZIO_SCHEMA)(MOCK_SPEAKER_CONFIG),
)
await hass.async_block_till_done()
assert result["result"].options == {CONF_VOLUME_STEP: DEFAULT_VOLUME_STEP}
assert result["type"] is FlowResultType.CREATE_ENTRY
entry_id = result["result"].entry_id
updated_config = MOCK_SPEAKER_CONFIG.copy()
updated_config[CONF_VOLUME_STEP] = VOLUME_STEP + 1
result = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": SOURCE_IMPORT},
data=vol.Schema(VIZIO_SCHEMA)(updated_config),
)
assert result["type"] is FlowResultType.ABORT
assert result["reason"] == "updated_entry"
config_entry = hass.config_entries.async_get_entry(entry_id)
assert config_entry.options[CONF_VOLUME_STEP] == VOLUME_STEP + 1
@pytest.mark.usefixtures("vizio_connect", "vizio_bypass_update")
async def test_import_flow_update_name_and_apps(hass: HomeAssistant) -> None:
"""Test import config flow with updated name and apps."""
result = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": SOURCE_IMPORT},
data=vol.Schema(VIZIO_SCHEMA)(MOCK_IMPORT_VALID_TV_CONFIG),
)
await hass.async_block_till_done()
assert result["result"].data[CONF_NAME] == NAME
assert result["type"] is FlowResultType.CREATE_ENTRY
entry_id = result["result"].entry_id
updated_config = MOCK_IMPORT_VALID_TV_CONFIG.copy()
updated_config[CONF_NAME] = NAME2
updated_config[CONF_APPS] = {CONF_INCLUDE: [CURRENT_APP]}
result = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": SOURCE_IMPORT},
data=vol.Schema(VIZIO_SCHEMA)(updated_config),
)
assert result["type"] is FlowResultType.ABORT
assert result["reason"] == "updated_entry"
config_entry = hass.config_entries.async_get_entry(entry_id)
assert config_entry.data[CONF_NAME] == NAME2
assert config_entry.data[CONF_APPS] == {CONF_INCLUDE: [CURRENT_APP]}
assert config_entry.options[CONF_APPS] == {CONF_INCLUDE: [CURRENT_APP]}
@pytest.mark.usefixtures("vizio_connect", "vizio_bypass_update")
async def test_import_flow_update_remove_apps(hass: HomeAssistant) -> None:
"""Test import config flow with removed apps."""
result = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": SOURCE_IMPORT},
data=vol.Schema(VIZIO_SCHEMA)(MOCK_TV_WITH_EXCLUDE_CONFIG),
)
await hass.async_block_till_done()
assert result["result"].data[CONF_NAME] == NAME
assert result["type"] is FlowResultType.CREATE_ENTRY
config_entry = hass.config_entries.async_get_entry(result["result"].entry_id)
assert CONF_APPS in config_entry.data
assert CONF_APPS in config_entry.options
updated_config = MOCK_TV_WITH_EXCLUDE_CONFIG.copy()
updated_config.pop(CONF_APPS)
result = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": SOURCE_IMPORT},
data=vol.Schema(VIZIO_SCHEMA)(updated_config),
)
assert result["type"] is FlowResultType.ABORT
assert result["reason"] == "updated_entry"
assert CONF_APPS not in config_entry.data
assert CONF_APPS not in config_entry.options
@pytest.mark.usefixtures(
"vizio_connect", "vizio_bypass_setup", "vizio_complete_pairing"
)
async def test_import_needs_pairing(hass: HomeAssistant) -> None:
"""Test pairing config flow when access token not provided for tv during import."""
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_IMPORT}, data=MOCK_TV_CONFIG_NO_TOKEN
)
assert result["type"] is FlowResultType.FORM
assert result["step_id"] == "user"
result = await hass.config_entries.flow.async_configure(
result["flow_id"], user_input=MOCK_TV_CONFIG_NO_TOKEN
)
assert result["type"] is FlowResultType.FORM
assert result["step_id"] == "pair_tv"
result = await hass.config_entries.flow.async_configure(
result["flow_id"], user_input=MOCK_PIN_CONFIG
)
assert result["type"] is FlowResultType.FORM
assert result["step_id"] == "pairing_complete_import"
result = await hass.config_entries.flow.async_configure(result["flow_id"])
assert result["type"] is FlowResultType.CREATE_ENTRY
assert result["title"] == NAME
assert result["data"][CONF_NAME] == NAME
assert result["data"][CONF_HOST] == HOST
assert result["data"][CONF_DEVICE_CLASS] == MediaPlayerDeviceClass.TV
@pytest.mark.usefixtures(
"vizio_connect", "vizio_bypass_setup", "vizio_complete_pairing"
)
async def test_import_with_apps_needs_pairing(hass: HomeAssistant) -> None:
"""Test pairing config flow when access token not provided for tv but apps are included during import."""
import_config = MOCK_TV_CONFIG_NO_TOKEN.copy()
import_config[CONF_APPS] = {CONF_INCLUDE: [CURRENT_APP]}
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_IMPORT}, data=import_config
)
assert result["type"] is FlowResultType.FORM
assert result["step_id"] == "user"
# Mock inputting info without apps to make sure apps get stored
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
user_input=_get_config_schema(MOCK_TV_CONFIG_NO_TOKEN)(MOCK_TV_CONFIG_NO_TOKEN),
)
assert result["type"] is FlowResultType.FORM
assert result["step_id"] == "pair_tv"
result = await hass.config_entries.flow.async_configure(
result["flow_id"], user_input=MOCK_PIN_CONFIG
)
assert result["type"] is FlowResultType.FORM
assert result["step_id"] == "pairing_complete_import"
result = await hass.config_entries.flow.async_configure(result["flow_id"])
assert result["type"] is FlowResultType.CREATE_ENTRY
assert result["title"] == NAME
assert result["data"][CONF_NAME] == NAME
assert result["data"][CONF_HOST] == HOST
assert result["data"][CONF_DEVICE_CLASS] == MediaPlayerDeviceClass.TV
assert result["data"][CONF_APPS][CONF_INCLUDE] == [CURRENT_APP]
@pytest.mark.usefixtures("vizio_connect", "vizio_bypass_update")
async def test_import_flow_additional_configs(hass: HomeAssistant) -> None:
"""Test import config flow with additional configs defined in CONF_APPS."""
result = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": SOURCE_IMPORT},
data=vol.Schema(VIZIO_SCHEMA)(MOCK_TV_WITH_ADDITIONAL_APPS_CONFIG),
)
await hass.async_block_till_done()
assert result["result"].data[CONF_NAME] == NAME
assert result["type"] is FlowResultType.CREATE_ENTRY
config_entry = hass.config_entries.async_get_entry(result["result"].entry_id)
assert CONF_APPS in config_entry.data
assert CONF_APPS not in config_entry.options
@pytest.mark.usefixtures("vizio_connect", "vizio_bypass_setup")
async def test_import_error(
hass: HomeAssistant,
caplog: pytest.LogCaptureFixture,
) -> None:
"""Test that error is logged when import config has an error."""
entry = MockConfigEntry(
domain=DOMAIN,
data=vol.Schema(VIZIO_SCHEMA)(MOCK_SPEAKER_CONFIG),
options={CONF_VOLUME_STEP: VOLUME_STEP},
unique_id=UNIQUE_ID,
)
entry.add_to_hass(hass)
fail_entry = MOCK_SPEAKER_CONFIG.copy()
fail_entry[CONF_HOST] = "0.0.0.0"
result = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": SOURCE_IMPORT},
data=vol.Schema(VIZIO_SCHEMA)(fail_entry),
)
assert result["type"] is FlowResultType.FORM
# Ensure error gets logged
vizio_log_list = [
log
for log in caplog.records
if log.name == "homeassistant.components.vizio.config_flow"
]
assert len(vizio_log_list) == 1
@pytest.mark.usefixtures("vizio_connect", "vizio_bypass_setup")
async def test_import_ignore(hass: HomeAssistant) -> None:
"""Test import config flow doesn't throw an error when there's an existing ignored source."""
entry = MockConfigEntry(
domain=DOMAIN,
data=MOCK_SPEAKER_CONFIG,
options={CONF_VOLUME_STEP: VOLUME_STEP},
source=SOURCE_IGNORE,
)
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),
)
assert result["type"] is FlowResultType.CREATE_ENTRY
@pytest.mark.usefixtures(
"vizio_connect", "vizio_bypass_setup", "vizio_guess_device_type"
)
@ -854,26 +550,3 @@ async def test_zeroconf_flow_already_configured_hostname(hass: HomeAssistant) ->
# Flow should abort because device is already setup
assert result["type"] is FlowResultType.ABORT
assert result["reason"] == "already_configured"
@pytest.mark.usefixtures("vizio_connect", "vizio_bypass_setup", "vizio_hostname_check")
async def test_import_flow_already_configured_hostname(hass: HomeAssistant) -> 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"] is FlowResultType.ABORT
assert result["reason"] == "updated_entry"
assert entry.data[CONF_HOST] == HOST

View File

@ -7,7 +7,6 @@ import pytest
from homeassistant.components.vizio.const import DOMAIN
from homeassistant.const import STATE_UNAVAILABLE, Platform
from homeassistant.core import HomeAssistant
from homeassistant.setup import async_setup_component
import homeassistant.util.dt as dt_util
from .const import MOCK_SPEAKER_CONFIG, MOCK_USER_VALID_TV_CONFIG, UNIQUE_ID
@ -15,16 +14,6 @@ from .const import MOCK_SPEAKER_CONFIG, MOCK_USER_VALID_TV_CONFIG, UNIQUE_ID
from tests.common import MockConfigEntry, async_fire_time_changed
@pytest.mark.usefixtures("vizio_connect", "vizio_update")
async def test_setup_component(hass: HomeAssistant) -> None:
"""Test component setup."""
assert await async_setup_component(
hass, DOMAIN, {DOMAIN: MOCK_USER_VALID_TV_CONFIG}
)
await hass.async_block_till_done()
assert len(hass.states.async_entity_ids(Platform.MEDIA_PLAYER)) == 1
@pytest.mark.usefixtures("vizio_connect", "vizio_update")
async def test_tv_load_and_unload(hass: HomeAssistant) -> None:
"""Test loading and unloading TV entry."""

View File

@ -19,7 +19,6 @@ from pyvizio.const import (
MAX_VOLUME,
UNKNOWN_APP,
)
import voluptuous as vol
from homeassistant.components.media_player import (
ATTR_INPUT_SOURCE,
@ -42,7 +41,6 @@ from homeassistant.components.media_player import (
SERVICE_VOLUME_UP,
MediaPlayerDeviceClass,
)
from homeassistant.components.vizio import validate_apps
from homeassistant.components.vizio.const import (
CONF_ADDITIONAL_CONFIGS,
CONF_APPS,
@ -50,7 +48,6 @@ from homeassistant.components.vizio.const import (
DEFAULT_VOLUME_STEP,
DOMAIN,
SERVICE_UPDATE_SETTING,
VIZIO_SCHEMA,
)
from homeassistant.const import ATTR_ENTITY_ID, STATE_OFF, STATE_ON, STATE_UNAVAILABLE
from homeassistant.core import HomeAssistant
@ -69,9 +66,7 @@ from .const import (
EQ_LIST,
INPUT_LIST,
INPUT_LIST_WITH_APPS,
MOCK_SPEAKER_APPS_FAILURE,
MOCK_SPEAKER_CONFIG,
MOCK_TV_APPS_FAILURE,
MOCK_TV_WITH_ADDITIONAL_APPS_CONFIG,
MOCK_TV_WITH_EXCLUDE_CONFIG,
MOCK_TV_WITH_INCLUDE_CONFIG,
@ -155,7 +150,7 @@ async def _test_setup_tv(hass: HomeAssistant, vizio_power_state: bool | None) ->
config_entry = MockConfigEntry(
domain=DOMAIN,
data=vol.Schema(VIZIO_SCHEMA)(MOCK_USER_VALID_TV_CONFIG),
data=MOCK_USER_VALID_TV_CONFIG,
unique_id=UNIQUE_ID,
)
@ -181,7 +176,7 @@ async def _test_setup_speaker(
config_entry = MockConfigEntry(
domain=DOMAIN,
data=vol.Schema(VIZIO_SCHEMA)(MOCK_SPEAKER_CONFIG),
data=MOCK_SPEAKER_CONFIG,
unique_id=UNIQUE_ID,
)
@ -215,7 +210,7 @@ async def _cm_for_test_setup_tv_with_apps(
) -> AsyncIterator[None]:
"""Context manager to setup test for Vizio TV with support for apps."""
config_entry = MockConfigEntry(
domain=DOMAIN, data=vol.Schema(VIZIO_SCHEMA)(device_config), unique_id=UNIQUE_ID
domain=DOMAIN, data=device_config, unique_id=UNIQUE_ID
)
async with _cm_for_test_setup_without_apps(
@ -641,15 +636,6 @@ async def test_setup_with_apps_additional_apps_config(
assert not service_call2.called
def test_invalid_apps_config(hass: HomeAssistant) -> None:
"""Test that schema validation fails on certain conditions."""
with pytest.raises(vol.Invalid):
vol.Schema(vol.All(VIZIO_SCHEMA, validate_apps))(MOCK_TV_APPS_FAILURE)
with pytest.raises(vol.Invalid):
vol.Schema(vol.All(VIZIO_SCHEMA, validate_apps))(MOCK_SPEAKER_APPS_FAILURE)
@pytest.mark.usefixtures("vizio_connect", "vizio_update_with_apps")
async def test_setup_with_unknown_app_config(
hass: HomeAssistant,
@ -687,7 +673,7 @@ async def test_setup_tv_without_mute(hass: HomeAssistant) -> None:
"""Test Vizio TV entity setup when mute property isn't returned by Vizio API."""
config_entry = MockConfigEntry(
domain=DOMAIN,
data=vol.Schema(VIZIO_SCHEMA)(MOCK_USER_VALID_TV_CONFIG),
data=MOCK_USER_VALID_TV_CONFIG,
unique_id=UNIQUE_ID,
)
@ -742,7 +728,7 @@ async def test_vizio_update_with_apps_on_input(hass: HomeAssistant) -> None:
"""Test a vizio TV with apps that is on a TV input."""
config_entry = MockConfigEntry(
domain=DOMAIN,
data=vol.Schema(VIZIO_SCHEMA)(MOCK_USER_VALID_TV_CONFIG),
data=MOCK_USER_VALID_TV_CONFIG,
unique_id=UNIQUE_ID,
)
await _add_config_entry_to_hass(hass, config_entry)