mirror of
https://github.com/home-assistant/core.git
synced 2025-07-19 03:07:37 +00:00
Update vizio app_id state attribute to show app config dict in… (#32727)
* bump pyvizio and update app_id to show app config to aid in HA config generation. squashed from multiple commits to make a rebase on dev easier * bump pyvizio for bug fixes * fix pyvizio version number * only return app_id if app is unknown and explicitly create the dict that's returned * fix tests * fix docstring for app_id
This commit is contained in:
parent
4a0a56ebdc
commit
d5f4dfdd6b
@ -2,7 +2,7 @@
|
||||
"domain": "vizio",
|
||||
"name": "Vizio SmartCast",
|
||||
"documentation": "https://www.home-assistant.io/integrations/vizio",
|
||||
"requirements": ["pyvizio==0.1.35"],
|
||||
"requirements": ["pyvizio==0.1.44"],
|
||||
"dependencies": [],
|
||||
"codeowners": ["@raman325"],
|
||||
"config_flow": true,
|
||||
|
@ -4,8 +4,8 @@ import logging
|
||||
from typing import Any, Callable, Dict, List, Optional
|
||||
|
||||
from pyvizio import VizioAsync
|
||||
from pyvizio.const import INPUT_APPS, NO_APP_RUNNING, UNKNOWN_APP
|
||||
from pyvizio.helpers import find_app_name
|
||||
from pyvizio.api.apps import find_app_name
|
||||
from pyvizio.const import APP_HOME, APPS, INPUT_APPS, NO_APP_RUNNING, UNKNOWN_APP
|
||||
|
||||
from homeassistant.components.media_player import (
|
||||
DEVICE_CLASS_SPEAKER,
|
||||
@ -132,6 +132,7 @@ class VizioDevice(MediaPlayerDevice):
|
||||
self._is_muted = None
|
||||
self._current_input = None
|
||||
self._current_app = None
|
||||
self._current_app_config = None
|
||||
self._available_inputs = []
|
||||
self._available_apps = []
|
||||
self._conf_apps = config_entry.options.get(CONF_APPS, {})
|
||||
@ -157,20 +158,6 @@ class VizioDevice(MediaPlayerDevice):
|
||||
|
||||
return apps
|
||||
|
||||
async def _current_app_name(self) -> Optional[str]:
|
||||
"""Return name of the currently running app by parsing pyvizio output."""
|
||||
app = await self._device.get_current_app(log_api_exception=False)
|
||||
if app in [None, NO_APP_RUNNING]:
|
||||
return None
|
||||
|
||||
if app == UNKNOWN_APP and self._additional_app_configs:
|
||||
return find_app_name(
|
||||
await self._device.get_current_app_config(log_api_exception=False),
|
||||
self._additional_app_configs,
|
||||
)
|
||||
|
||||
return app
|
||||
|
||||
async def async_update(self) -> None:
|
||||
"""Retrieve latest state of the device."""
|
||||
if not self._model:
|
||||
@ -202,6 +189,7 @@ class VizioDevice(MediaPlayerDevice):
|
||||
self._current_input = None
|
||||
self._available_inputs = None
|
||||
self._current_app = None
|
||||
self._current_app_config = None
|
||||
self._available_apps = None
|
||||
return
|
||||
|
||||
@ -237,9 +225,16 @@ class VizioDevice(MediaPlayerDevice):
|
||||
if not self._available_apps:
|
||||
self._available_apps = self._apps_list(self._device.get_apps_list())
|
||||
|
||||
# Attempt to get current app name. If app name is unknown, check list
|
||||
# of additional apps specified in configuration
|
||||
self._current_app = await self._current_app_name()
|
||||
self._current_app_config = await self._device.get_current_app_config(
|
||||
log_api_exception=False
|
||||
)
|
||||
|
||||
self._current_app = find_app_name(
|
||||
self._current_app_config, [APP_HOME, *APPS, *self._additional_app_configs]
|
||||
)
|
||||
|
||||
if self._current_app == NO_APP_RUNNING:
|
||||
self._current_app = None
|
||||
|
||||
def _get_additional_app_names(self) -> List[Dict[str, Any]]:
|
||||
"""Return list of additional apps that were included in configuration.yaml."""
|
||||
@ -346,8 +341,15 @@ class VizioDevice(MediaPlayerDevice):
|
||||
|
||||
@property
|
||||
def app_id(self) -> Optional[str]:
|
||||
"""Return the current app."""
|
||||
return self._current_app
|
||||
"""Return the ID of the current app if it is unknown by pyvizio."""
|
||||
if self._current_app_config and self.app_name == UNKNOWN_APP:
|
||||
return {
|
||||
"APP_ID": self._current_app_config.APP_ID,
|
||||
"NAME_SPACE": self._current_app_config.NAME_SPACE,
|
||||
"MESSAGE": self._current_app_config.MESSAGE,
|
||||
}
|
||||
|
||||
return None
|
||||
|
||||
@property
|
||||
def app_name(self) -> Optional[str]:
|
||||
|
@ -1732,7 +1732,7 @@ pyversasense==0.0.6
|
||||
pyvesync==1.1.0
|
||||
|
||||
# homeassistant.components.vizio
|
||||
pyvizio==0.1.35
|
||||
pyvizio==0.1.44
|
||||
|
||||
# homeassistant.components.velux
|
||||
pyvlx==0.2.12
|
||||
|
@ -635,7 +635,7 @@ pyvera==0.3.7
|
||||
pyvesync==1.1.0
|
||||
|
||||
# homeassistant.components.vizio
|
||||
pyvizio==0.1.35
|
||||
pyvizio==0.1.44
|
||||
|
||||
# homeassistant.components.html5
|
||||
pywebpush==1.9.2
|
||||
|
@ -7,7 +7,7 @@ from .const import (
|
||||
ACCESS_TOKEN,
|
||||
APP_LIST,
|
||||
CH_TYPE,
|
||||
CURRENT_APP,
|
||||
CURRENT_APP_CONFIG,
|
||||
CURRENT_INPUT,
|
||||
INPUT_LIST,
|
||||
INPUT_LIST_WITH_APPS,
|
||||
@ -172,7 +172,7 @@ def vizio_update_with_apps_fixture(vizio_update: pytest.fixture):
|
||||
"homeassistant.components.vizio.media_player.VizioAsync.get_current_input",
|
||||
return_value="CAST",
|
||||
), patch(
|
||||
"homeassistant.components.vizio.media_player.VizioAsync.get_current_app",
|
||||
return_value=CURRENT_APP,
|
||||
"homeassistant.components.vizio.media_player.VizioAsync.get_current_app_config",
|
||||
return_value=CURRENT_APP_CONFIG,
|
||||
):
|
||||
yield
|
||||
|
@ -68,6 +68,7 @@ CURRENT_INPUT = "HDMI"
|
||||
INPUT_LIST = ["HDMI", "USB", "Bluetooth", "AUX"]
|
||||
|
||||
CURRENT_APP = "Hulu"
|
||||
CURRENT_APP_CONFIG = {CONF_APP_ID: "3", CONF_NAME_SPACE: 4, CONF_MESSAGE: None}
|
||||
APP_LIST = ["Hulu", "Netflix"]
|
||||
INPUT_LIST_WITH_APPS = INPUT_LIST + ["CAST"]
|
||||
CUSTOM_CONFIG = {CONF_APP_ID: "test", CONF_MESSAGE: None, CONF_NAME_SPACE: 10}
|
||||
@ -75,6 +76,11 @@ ADDITIONAL_APP_CONFIG = {
|
||||
"name": CURRENT_APP,
|
||||
CONF_CONFIG: CUSTOM_CONFIG,
|
||||
}
|
||||
UNKNOWN_APP_CONFIG = {
|
||||
"APP_ID": "UNKNOWN",
|
||||
"NAME_SPACE": 10,
|
||||
"MESSAGE": None,
|
||||
}
|
||||
|
||||
ENTITY_ID = f"{MP_DOMAIN}.{slugify(NAME)}"
|
||||
|
||||
|
@ -1,13 +1,13 @@
|
||||
"""Tests for Vizio config flow."""
|
||||
from datetime import timedelta
|
||||
import logging
|
||||
from typing import Any, Dict
|
||||
from typing import Any, Dict, Optional
|
||||
from unittest.mock import call
|
||||
|
||||
from asynctest import patch
|
||||
import pytest
|
||||
from pytest import raises
|
||||
from pyvizio._api.apps import AppConfig
|
||||
from pyvizio.api.apps import AppConfig
|
||||
from pyvizio.const import (
|
||||
DEVICE_CLASS_SPEAKER as VIZIO_DEVICE_CLASS_SPEAKER,
|
||||
DEVICE_CLASS_TV as VIZIO_DEVICE_CLASS_TV,
|
||||
@ -57,6 +57,7 @@ from .const import (
|
||||
ADDITIONAL_APP_CONFIG,
|
||||
APP_LIST,
|
||||
CURRENT_APP,
|
||||
CURRENT_APP_CONFIG,
|
||||
CURRENT_INPUT,
|
||||
CUSTOM_CONFIG,
|
||||
ENTITY_ID,
|
||||
@ -71,6 +72,7 @@ from .const import (
|
||||
MOCK_USER_VALID_TV_CONFIG,
|
||||
NAME,
|
||||
UNIQUE_ID,
|
||||
UNKNOWN_APP_CONFIG,
|
||||
VOLUME_STEP,
|
||||
)
|
||||
|
||||
@ -80,7 +82,7 @@ _LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def _test_setup(
|
||||
hass: HomeAssistantType, ha_device_class: str, vizio_power_state: bool
|
||||
hass: HomeAssistantType, ha_device_class: str, vizio_power_state: Optional[bool]
|
||||
) -> None:
|
||||
"""Test Vizio Device entity setup."""
|
||||
if vizio_power_state:
|
||||
@ -112,7 +114,7 @@ async def _test_setup(
|
||||
"homeassistant.components.vizio.media_player.VizioAsync.get_power_state",
|
||||
return_value=vizio_power_state,
|
||||
), patch(
|
||||
"homeassistant.components.vizio.media_player.VizioAsync.get_current_app",
|
||||
"homeassistant.components.vizio.media_player.VizioAsync.get_current_app_config",
|
||||
) as service_call:
|
||||
config_entry.add_to_hass(hass)
|
||||
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
||||
@ -136,7 +138,10 @@ async def _test_setup(
|
||||
|
||||
|
||||
async def _test_setup_with_apps(
|
||||
hass: HomeAssistantType, device_config: Dict[str, Any], app: str
|
||||
hass: HomeAssistantType,
|
||||
device_config: Dict[str, Any],
|
||||
app: Optional[str],
|
||||
app_config: Dict[str, Any],
|
||||
) -> None:
|
||||
"""Test Vizio Device with apps entity setup."""
|
||||
config_entry = MockConfigEntry(
|
||||
@ -152,12 +157,9 @@ async def _test_setup_with_apps(
|
||||
), patch(
|
||||
"homeassistant.components.vizio.media_player.VizioAsync.get_power_state",
|
||||
return_value=True,
|
||||
), patch(
|
||||
"homeassistant.components.vizio.media_player.VizioAsync.get_current_app",
|
||||
return_value=app,
|
||||
), patch(
|
||||
"homeassistant.components.vizio.media_player.VizioAsync.get_current_app_config",
|
||||
return_value=AppConfig(**ADDITIONAL_APP_CONFIG["config"]),
|
||||
return_value=AppConfig(**app_config),
|
||||
):
|
||||
config_entry.add_to_hass(hass)
|
||||
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
||||
@ -193,11 +195,20 @@ async def _test_setup_with_apps(
|
||||
list_to_test.remove(app_to_remove)
|
||||
|
||||
assert attr["source_list"] == list_to_test
|
||||
|
||||
if app:
|
||||
assert app in attr["source_list"] or app == UNKNOWN_APP
|
||||
if app == UNKNOWN_APP:
|
||||
assert attr["source"] == ADDITIONAL_APP_CONFIG["name"]
|
||||
else:
|
||||
assert attr["source"] == app
|
||||
assert attr["app_name"] == app
|
||||
if app == UNKNOWN_APP:
|
||||
assert attr["app_id"] == app_config
|
||||
else:
|
||||
assert "app_id" not in attr
|
||||
else:
|
||||
assert attr["source"] == "CAST"
|
||||
assert "app_id" not in attr
|
||||
assert "app_name" not in attr
|
||||
|
||||
assert (
|
||||
attr["volume_level"]
|
||||
== float(int(MAX_VOLUME[VIZIO_DEVICE_CLASS_TV] / 2))
|
||||
@ -222,7 +233,7 @@ async def _test_service(
|
||||
hass: HomeAssistantType,
|
||||
vizio_func_name: str,
|
||||
ha_service_name: str,
|
||||
additional_service_data: dict,
|
||||
additional_service_data: Optional[Dict[str, Any]],
|
||||
*args,
|
||||
**kwargs,
|
||||
) -> None:
|
||||
@ -363,8 +374,8 @@ async def test_options_update(
|
||||
|
||||
async def _test_update_availability_switch(
|
||||
hass: HomeAssistantType,
|
||||
initial_power_state: bool,
|
||||
final_power_state: bool,
|
||||
initial_power_state: Optional[bool],
|
||||
final_power_state: Optional[bool],
|
||||
caplog: pytest.fixture,
|
||||
) -> None:
|
||||
now = dt_util.utcnow()
|
||||
@ -431,7 +442,9 @@ async def test_setup_with_apps(
|
||||
caplog: pytest.fixture,
|
||||
) -> None:
|
||||
"""Test device setup with apps."""
|
||||
await _test_setup_with_apps(hass, MOCK_USER_VALID_TV_CONFIG, CURRENT_APP)
|
||||
await _test_setup_with_apps(
|
||||
hass, MOCK_USER_VALID_TV_CONFIG, CURRENT_APP, CURRENT_APP_CONFIG
|
||||
)
|
||||
await _test_service(
|
||||
hass,
|
||||
"launch_app",
|
||||
@ -448,7 +461,9 @@ async def test_setup_with_apps_include(
|
||||
caplog: pytest.fixture,
|
||||
) -> None:
|
||||
"""Test device setup with apps and apps["include"] in config."""
|
||||
await _test_setup_with_apps(hass, MOCK_TV_WITH_INCLUDE_CONFIG, CURRENT_APP)
|
||||
await _test_setup_with_apps(
|
||||
hass, MOCK_TV_WITH_INCLUDE_CONFIG, CURRENT_APP, CURRENT_APP_CONFIG
|
||||
)
|
||||
|
||||
|
||||
async def test_setup_with_apps_exclude(
|
||||
@ -458,7 +473,9 @@ async def test_setup_with_apps_exclude(
|
||||
caplog: pytest.fixture,
|
||||
) -> None:
|
||||
"""Test device setup with apps and apps["exclude"] in config."""
|
||||
await _test_setup_with_apps(hass, MOCK_TV_WITH_EXCLUDE_CONFIG, CURRENT_APP)
|
||||
await _test_setup_with_apps(
|
||||
hass, MOCK_TV_WITH_EXCLUDE_CONFIG, CURRENT_APP, CURRENT_APP_CONFIG
|
||||
)
|
||||
|
||||
|
||||
async def test_setup_with_apps_additional_apps_config(
|
||||
@ -468,7 +485,12 @@ async def test_setup_with_apps_additional_apps_config(
|
||||
caplog: pytest.fixture,
|
||||
) -> None:
|
||||
"""Test device setup with apps and apps["additional_configs"] in config."""
|
||||
await _test_setup_with_apps(hass, MOCK_TV_WITH_ADDITIONAL_APPS_CONFIG, UNKNOWN_APP)
|
||||
await _test_setup_with_apps(
|
||||
hass,
|
||||
MOCK_TV_WITH_ADDITIONAL_APPS_CONFIG,
|
||||
ADDITIONAL_APP_CONFIG["name"],
|
||||
ADDITIONAL_APP_CONFIG["config"],
|
||||
)
|
||||
|
||||
await _test_service(
|
||||
hass,
|
||||
@ -508,3 +530,27 @@ def test_invalid_apps_config(hass: HomeAssistantType):
|
||||
|
||||
with raises(vol.Invalid):
|
||||
vol.Schema(vol.All(VIZIO_SCHEMA, validate_apps))(MOCK_SPEAKER_APPS_FAILURE)
|
||||
|
||||
|
||||
async def test_setup_with_unknown_app_config(
|
||||
hass: HomeAssistantType,
|
||||
vizio_connect: pytest.fixture,
|
||||
vizio_update_with_apps: pytest.fixture,
|
||||
caplog: pytest.fixture,
|
||||
) -> None:
|
||||
"""Test device setup with apps where app config returned is unknown."""
|
||||
await _test_setup_with_apps(
|
||||
hass, MOCK_USER_VALID_TV_CONFIG, UNKNOWN_APP, UNKNOWN_APP_CONFIG
|
||||
)
|
||||
|
||||
|
||||
async def test_setup_with_no_running_app(
|
||||
hass: HomeAssistantType,
|
||||
vizio_connect: pytest.fixture,
|
||||
vizio_update_with_apps: pytest.fixture,
|
||||
caplog: pytest.fixture,
|
||||
) -> None:
|
||||
"""Test device setup with apps where no app is running."""
|
||||
await _test_setup_with_apps(
|
||||
hass, MOCK_USER_VALID_TV_CONFIG, None, vars(AppConfig())
|
||||
)
|
||||
|
Loading…
x
Reference in New Issue
Block a user