Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions homeassistant/components/webostv/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,13 +92,13 @@ async def async_step_pairing(
errors["base"] = "cannot_connect"
else:
await self.async_set_unique_id(
client.hello_info["deviceUUID"], raise_on_progress=False
client.tv_info.hello["deviceUUID"], raise_on_progress=False
)
self._abort_if_unique_id_configured({CONF_HOST: self._host})
data = {CONF_HOST: self._host, CONF_CLIENT_SECRET: client.client_key}

if not self._name:
self._name = f"{DEFAULT_NAME} {client.system_info['modelName']}"
self._name = f"{DEFAULT_NAME} {client.tv_info.system['modelName']}"
return self.async_create_entry(title=self._name, data=data)

return self.async_show_form(step_id="pairing", errors=errors)
Expand Down Expand Up @@ -176,7 +176,7 @@ async def async_step_reconfigure(
except WEBOSTV_EXCEPTIONS:
errors["base"] = "cannot_connect"
else:
await self.async_set_unique_id(client.hello_info["deviceUUID"])
await self.async_set_unique_id(client.tv_info.hello["deviceUUID"])
self._abort_if_unique_id_mismatch(reason="wrong_device")
data = {CONF_HOST: host, CONF_CLIENT_SECRET: client.client_key}
return self.async_update_reload_and_abort(reconfigure_entry, data=data)
Expand Down Expand Up @@ -214,7 +214,7 @@ async def async_step_init(
sources_list = []
try:
client = await async_control_connect(self.hass, self.host, self.key)
sources_list = get_sources(client)
sources_list = get_sources(client.tv_state)
except WebOsTvPairError:
errors["base"] = "error_pairing"
except WEBOSTV_EXCEPTIONS:
Expand Down
18 changes: 9 additions & 9 deletions homeassistant/components/webostv/diagnostics.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,15 @@ async def async_get_config_entry_diagnostics(
client_data = {
"is_registered": client.is_registered(),
"is_connected": client.is_connected(),
"current_app_id": client.current_app_id,
"current_channel": client.current_channel,
"apps": client.apps,
"inputs": client.inputs,
"system_info": client.system_info,
"software_info": client.software_info,
"hello_info": client.hello_info,
"sound_output": client.sound_output,
"is_on": client.is_on,
"current_app_id": client.tv_state.current_app_id,
"current_channel": client.tv_state.current_channel,
"apps": client.tv_state.apps,
"inputs": client.tv_state.inputs,
"system_info": client.tv_info.system,
"software_info": client.tv_info.software,
"hello_info": client.tv_info.hello,
"sound_output": client.tv_state.sound_output,
"is_on": client.tv_state.is_on,
}

return async_redact_data(
Expand Down
8 changes: 4 additions & 4 deletions homeassistant/components/webostv/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

import logging

from aiowebostv import WebOsClient
from aiowebostv import WebOsClient, WebOsTvState

from homeassistant.config_entries import ConfigEntry, ConfigEntryState
from homeassistant.const import CONF_CLIENT_SECRET, CONF_HOST
Expand Down Expand Up @@ -83,16 +83,16 @@ def async_get_client_by_device_entry(
)


def get_sources(client: WebOsClient) -> list[str]:
def get_sources(tv_state: WebOsTvState) -> list[str]:
"""Construct sources list."""
sources = []
found_live_tv = False
for app in client.apps.values():
for app in tv_state.apps.values():
sources.append(app["title"])
if app["id"] == LIVE_TV_APP_ID:
found_live_tv = True

for source in client.inputs.values():
for source in tv_state.inputs.values():
sources.append(source["label"])
if source["appId"] == LIVE_TV_APP_ID:
found_live_tv = True
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/webostv/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"documentation": "https://www.home-assistant.io/integrations/webostv",
"iot_class": "local_push",
"loggers": ["aiowebostv"],
"requirements": ["aiowebostv==0.6.2"],
"requirements": ["aiowebostv==0.7.0"],
"ssdp": [
{
"st": "urn:lge-com:service:webos-second-screen:1"
Expand Down
67 changes: 35 additions & 32 deletions homeassistant/components/webostv/media_player.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
import logging
from typing import Any, Concatenate, cast

from aiowebostv import WebOsClient, WebOsTvPairError
from aiowebostv import WebOsTvPairError, WebOsTvState
import voluptuous as vol

from homeassistant import util
Expand Down Expand Up @@ -205,51 +205,52 @@ async def async_will_remove_from_hass(self) -> None:
"""Call disconnect on removal."""
self._client.unregister_state_update_callback(self.async_handle_state_update)

async def async_handle_state_update(self, _client: WebOsClient) -> None:
async def async_handle_state_update(self, tv_state: WebOsTvState) -> None:
"""Update state from WebOsClient."""
self._update_states()
self.async_write_ha_state()

def _update_states(self) -> None:
"""Update entity state attributes."""
tv_state = self._client.tv_state
self._update_sources()

self._attr_state = (
MediaPlayerState.ON if self._client.is_on else MediaPlayerState.OFF
MediaPlayerState.ON if tv_state.is_on else MediaPlayerState.OFF
)
self._attr_is_volume_muted = cast(bool, self._client.muted)
self._attr_is_volume_muted = cast(bool, tv_state.muted)

self._attr_volume_level = None
if self._client.volume is not None:
self._attr_volume_level = self._client.volume / 100.0
if tv_state.volume is not None:
self._attr_volume_level = tv_state.volume / 100.0

self._attr_source = self._current_source
self._attr_source_list = sorted(self._source_list)

self._attr_media_content_type = None
if self._client.current_app_id == LIVE_TV_APP_ID:
if tv_state.current_app_id == LIVE_TV_APP_ID:
self._attr_media_content_type = MediaType.CHANNEL

self._attr_media_title = None
if (self._client.current_app_id == LIVE_TV_APP_ID) and (
self._client.current_channel is not None
if (tv_state.current_app_id == LIVE_TV_APP_ID) and (
tv_state.current_channel is not None
):
self._attr_media_title = cast(
str, self._client.current_channel.get("channelName")
str, tv_state.current_channel.get("channelName")
)

self._attr_media_image_url = None
if self._client.current_app_id in self._client.apps:
icon: str = self._client.apps[self._client.current_app_id]["largeIcon"]
if tv_state.current_app_id in tv_state.apps:
icon: str = tv_state.apps[tv_state.current_app_id]["largeIcon"]
if not icon.startswith("http"):
icon = self._client.apps[self._client.current_app_id]["icon"]
icon = tv_state.apps[tv_state.current_app_id]["icon"]
self._attr_media_image_url = icon

if self.state != MediaPlayerState.OFF or not self._supported_features:
supported = SUPPORT_WEBOSTV
if self._client.sound_output == "external_speaker":
if tv_state.sound_output == "external_speaker":
supported = supported | SUPPORT_WEBOSTV_VOLUME
elif self._client.sound_output != "lineout":
elif tv_state.sound_output != "lineout":
supported = (
supported
| SUPPORT_WEBOSTV_VOLUME
Expand All @@ -265,45 +266,47 @@ def _update_states(self) -> None:
)

self._attr_assumed_state = True
if self._client.is_on and self._client.media_state:
if tv_state.is_on and tv_state.media_state:
self._attr_assumed_state = False
for entry in self._client.media_state:
for entry in tv_state.media_state:
if entry.get("playState") == "playing":
self._attr_state = MediaPlayerState.PLAYING
elif entry.get("playState") == "paused":
self._attr_state = MediaPlayerState.PAUSED
elif entry.get("playState") == "unloaded":
self._attr_state = MediaPlayerState.IDLE

tv_info = self._client.tv_info
if self.state != MediaPlayerState.OFF:
maj_v = self._client.software_info.get("major_ver")
min_v = self._client.software_info.get("minor_ver")
maj_v = tv_info.software.get("major_ver")
min_v = tv_info.software.get("minor_ver")
if maj_v and min_v:
self._attr_device_info["sw_version"] = f"{maj_v}.{min_v}"

if model := self._client.system_info.get("modelName"):
if model := tv_info.system.get("modelName"):
self._attr_device_info["model"] = model

if serial_number := self._client.system_info.get("serialNumber"):
if serial_number := tv_info.system.get("serialNumber"):
self._attr_device_info["serial_number"] = serial_number

self._attr_extra_state_attributes = {}
if self._client.sound_output is not None or self.state != MediaPlayerState.OFF:
if tv_state.sound_output is not None or self.state != MediaPlayerState.OFF:
self._attr_extra_state_attributes = {
ATTR_SOUND_OUTPUT: self._client.sound_output
ATTR_SOUND_OUTPUT: tv_state.sound_output
}

def _update_sources(self) -> None:
"""Update list of sources from current source, apps, inputs and configured list."""
tv_state = self._client.tv_state
source_list = self._source_list
self._source_list = {}
conf_sources = self._sources

found_live_tv = False
for app in self._client.apps.values():
for app in tv_state.apps.values():
if app["id"] == LIVE_TV_APP_ID:
found_live_tv = True
if app["id"] == self._client.current_app_id:
if app["id"] == tv_state.current_app_id:
self._current_source = app["title"]
self._source_list[app["title"]] = app
elif (
Expand All @@ -314,10 +317,10 @@ def _update_sources(self) -> None:
):
self._source_list[app["title"]] = app

for source in self._client.inputs.values():
for source in tv_state.inputs.values():
if source["appId"] == LIVE_TV_APP_ID:
found_live_tv = True
if source["appId"] == self._client.current_app_id:
if source["appId"] == tv_state.current_app_id:
self._current_source = source["label"]
self._source_list[source["label"]] = source
elif (
Expand All @@ -334,7 +337,7 @@ def _update_sources(self) -> None:
# not appear in the app or input lists in some cases
elif not found_live_tv:
app = {"id": LIVE_TV_APP_ID, "title": "Live TV"}
if self._client.current_app_id == LIVE_TV_APP_ID:
if tv_state.current_app_id == LIVE_TV_APP_ID:
self._current_source = app["title"]
self._source_list["Live TV"] = app
elif (
Expand Down Expand Up @@ -434,12 +437,12 @@ async def async_play_media(
"""Play a piece of media."""
_LOGGER.debug("Call play media type <%s>, Id <%s>", media_type, media_id)

if media_type == MediaType.CHANNEL and self._client.channels:
if media_type == MediaType.CHANNEL and self._client.tv_state.channels:
_LOGGER.debug("Searching channel")
partial_match_channel_id = None
perfect_match_channel_id = None

for channel in self._client.channels:
for channel in self._client.tv_state.channels:
if media_id == channel["channelNumber"]:
perfect_match_channel_id = channel["channelId"]
continue
Expand Down Expand Up @@ -484,15 +487,15 @@ async def async_media_stop(self) -> None:
@cmd
async def async_media_next_track(self) -> None:
"""Send next track command."""
if self._client.current_app_id == LIVE_TV_APP_ID:
if self._client.tv_state.current_app_id == LIVE_TV_APP_ID:
await self._client.channel_up()
else:
await self._client.fast_forward()

@cmd
async def async_media_previous_track(self) -> None:
"""Send the previous track command."""
if self._client.current_app_id == LIVE_TV_APP_ID:
if self._client.tv_state.current_app_id == LIVE_TV_APP_ID:
await self._client.channel_down()
else:
await self._client.rewind()
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/webostv/notify.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ async def async_send_message(self, message: str = "", **kwargs: Any) -> None:
data = kwargs[ATTR_DATA]
icon_path = data.get(ATTR_ICON) if data else None

if not client.is_on:
if not client.tv_state.is_on:
raise HomeAssistantError(
translation_domain=DOMAIN,
translation_key="notify_device_off",
Expand Down
2 changes: 1 addition & 1 deletion requirements_all.txt

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion requirements_test_all.txt

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

33 changes: 19 additions & 14 deletions tests/components/webostv/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from collections.abc import Generator
from unittest.mock import AsyncMock, Mock, patch

from aiowebostv import WebOsTvInfo, WebOsTvState
import pytest

from homeassistant.components.webostv.const import LIVE_TV_APP_ID
Expand Down Expand Up @@ -40,26 +41,30 @@ def client_fixture():
),
):
client = mock_client_class.return_value
client.hello_info = {"deviceUUID": FAKE_UUID}
client.software_info = {"major_ver": "major", "minor_ver": "minor"}
client.system_info = {"modelName": TV_MODEL, "serialNumber": "1234567890"}
client.tv_info = WebOsTvInfo(
hello={"deviceUUID": FAKE_UUID},
system={"modelName": TV_MODEL, "serialNumber": "1234567890"},
software={"major_ver": "major", "minor_ver": "minor"},
)
client.client_key = CLIENT_KEY
client.apps = MOCK_APPS
client.inputs = MOCK_INPUTS
client.current_app_id = LIVE_TV_APP_ID
client.tv_state = WebOsTvState(
apps=MOCK_APPS,
inputs=MOCK_INPUTS,
current_app_id=LIVE_TV_APP_ID,
channels=[CHANNEL_1, CHANNEL_2],
current_channel=CHANNEL_1,
volume=37,
sound_output="speaker",
muted=False,
is_on=True,
media_state=[{"playState": ""}],
)

client.channels = [CHANNEL_1, CHANNEL_2]
client.current_channel = CHANNEL_1

client.volume = 37
client.sound_output = "speaker"
client.muted = False
client.is_on = True
client.is_registered = Mock(return_value=True)
client.is_connected = Mock(return_value=True)

async def mock_state_update_callback():
await client.register_state_update_callback.call_args[0][0](client)
await client.register_state_update_callback.call_args[0][0](client.tv_state)

client.mock_state_update = AsyncMock(side_effect=mock_state_update_callback)

Expand Down
6 changes: 3 additions & 3 deletions tests/components/webostv/test_config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,8 @@ async def test_options_flow_live_tv_in_apps(
hass: HomeAssistant, client, apps, inputs
) -> None:
"""Test options config flow Live TV found in apps."""
client.apps = apps
client.inputs = inputs
client.tv_state.apps = apps
client.tv_state.inputs = inputs
entry = await setup_webostv(hass)

result = await hass.config_entries.options.async_init(entry.entry_id)
Expand Down Expand Up @@ -411,7 +411,7 @@ async def test_reconfigure_wrong_device(hass: HomeAssistant, client) -> None:
assert result["type"] is FlowResultType.FORM
assert result["step_id"] == "reconfigure"

client.hello_info = {"deviceUUID": "wrong_uuid"}
client.tv_info.hello = {"deviceUUID": "wrong_uuid"}
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
user_input={CONF_HOST: "new_host"},
Expand Down
Loading
Loading