Improve state tracking for WebOsTV (#31042)
* upgrade to aiopylgtv 0.3.0 and corresponding simplification and cleanup of webostv state tracking * properly handle case where Live TV is not reported in list of apps * fix tests (entity state is no longer linked to source id) * fix pylint checks * avoid unnecessary retrieval of channel list * use only standard home assistant states
This commit is contained in:
parent
e5365779fe
commit
fae74f7ed7
6 changed files with 52 additions and 68 deletions
|
@ -21,7 +21,6 @@ DOMAIN = "webostv"
|
|||
|
||||
CONF_SOURCES = "sources"
|
||||
CONF_ON_ACTION = "turn_on_action"
|
||||
CONF_STANDBY_CONNECTION = "standby_connection"
|
||||
DEFAULT_NAME = "LG webOS Smart TV"
|
||||
WEBOSTV_CONFIG_FILE = "webostv.conf"
|
||||
|
||||
|
@ -46,9 +45,6 @@ CONFIG_SCHEMA = vol.Schema(
|
|||
vol.Required(CONF_HOST): cv.string,
|
||||
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
|
||||
vol.Optional(CONF_ON_ACTION): cv.SCRIPT_SCHEMA,
|
||||
vol.Optional(
|
||||
CONF_STANDBY_CONNECTION, default=False
|
||||
): cv.boolean,
|
||||
vol.Optional(CONF_ICON): cv.string,
|
||||
}
|
||||
)
|
||||
|
@ -100,9 +96,8 @@ async def async_setup_tv(hass, config, conf):
|
|||
|
||||
host = conf[CONF_HOST]
|
||||
config_file = hass.config.path(WEBOSTV_CONFIG_FILE)
|
||||
standby_connection = conf[CONF_STANDBY_CONNECTION]
|
||||
|
||||
client = WebOsClient(host, config_file, standby_connection=standby_connection)
|
||||
client = WebOsClient(host, config_file)
|
||||
hass.data[DOMAIN][host] = {"client": client}
|
||||
|
||||
if client.is_registered():
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"domain": "webostv",
|
||||
"name": "LG webOS Smart TV",
|
||||
"documentation": "https://www.home-assistant.io/integrations/webostv",
|
||||
"requirements": ["aiopylgtv==0.2.7"],
|
||||
"requirements": ["aiopylgtv==0.3.0"],
|
||||
"dependencies": ["configurator"],
|
||||
"codeowners": ["@bendavid"]
|
||||
}
|
||||
|
|
|
@ -59,6 +59,8 @@ SUPPORT_WEBOSTV = (
|
|||
MIN_TIME_BETWEEN_SCANS = timedelta(seconds=10)
|
||||
MIN_TIME_BETWEEN_FORCED_SCANS = timedelta(seconds=1)
|
||||
|
||||
LIVE_TV_APP_ID = "com.webos.app.livetv"
|
||||
|
||||
|
||||
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
|
||||
"""Set up the LG WebOS TV platform."""
|
||||
|
@ -121,17 +123,8 @@ class LgWebOSMediaPlayerEntity(MediaPlayerDevice):
|
|||
# Assume that the TV is not paused
|
||||
self._paused = False
|
||||
|
||||
# Assume that the TV is not muted
|
||||
self._muted = False
|
||||
self._volume = 0
|
||||
self._current_source = None
|
||||
self._current_source_id = None
|
||||
self._state = None
|
||||
self._source_list = {}
|
||||
self._app_list = {}
|
||||
self._input_list = {}
|
||||
self._channel = None
|
||||
self._last_icon = None
|
||||
|
||||
async def async_added_to_hass(self):
|
||||
"""Connect and subscribe to dispatcher signals and state updates."""
|
||||
|
@ -141,10 +134,6 @@ class LgWebOSMediaPlayerEntity(MediaPlayerDevice):
|
|||
self.async_handle_state_update
|
||||
)
|
||||
|
||||
# force state update if needed
|
||||
if self._state is None:
|
||||
await self.async_handle_state_update()
|
||||
|
||||
async def async_will_remove_from_hass(self):
|
||||
"""Call disconnect on removal."""
|
||||
self._client.unregister_state_update_callback(self.async_handle_state_update)
|
||||
|
@ -162,18 +151,6 @@ class LgWebOSMediaPlayerEntity(MediaPlayerDevice):
|
|||
|
||||
async def async_handle_state_update(self):
|
||||
"""Update state from WebOsClient."""
|
||||
self._current_source_id = self._client.current_appId
|
||||
self._muted = self._client.muted
|
||||
self._volume = self._client.volume
|
||||
self._channel = self._client.current_channel
|
||||
self._app_list = self._client.apps
|
||||
self._input_list = self._client.inputs
|
||||
|
||||
if self._current_source_id == "":
|
||||
self._state = STATE_OFF
|
||||
else:
|
||||
self._state = STATE_ON
|
||||
|
||||
self.update_sources()
|
||||
|
||||
self.async_schedule_update_ha_state(False)
|
||||
|
@ -183,8 +160,11 @@ class LgWebOSMediaPlayerEntity(MediaPlayerDevice):
|
|||
self._source_list = {}
|
||||
conf_sources = self._customize[CONF_SOURCES]
|
||||
|
||||
for app in self._app_list.values():
|
||||
if app["id"] == self._current_source_id:
|
||||
found_live_tv = False
|
||||
for app in self._client.apps.values():
|
||||
if app["id"] == LIVE_TV_APP_ID:
|
||||
found_live_tv = True
|
||||
if app["id"] == self._client.current_appId:
|
||||
self._current_source = app["title"]
|
||||
self._source_list[app["title"]] = app
|
||||
elif (
|
||||
|
@ -195,8 +175,10 @@ class LgWebOSMediaPlayerEntity(MediaPlayerDevice):
|
|||
):
|
||||
self._source_list[app["title"]] = app
|
||||
|
||||
for source in self._input_list.values():
|
||||
if source["appId"] == self._current_source_id:
|
||||
for source in self._client.inputs.values():
|
||||
if source["appId"] == LIVE_TV_APP_ID:
|
||||
found_live_tv = True
|
||||
if source["appId"] == self._client.current_appId:
|
||||
self._current_source = source["label"]
|
||||
self._source_list[source["label"]] = source
|
||||
elif (
|
||||
|
@ -206,6 +188,20 @@ class LgWebOSMediaPlayerEntity(MediaPlayerDevice):
|
|||
):
|
||||
self._source_list[source["label"]] = source
|
||||
|
||||
# special handling of live tv since this might not appear in the app or input lists in some cases
|
||||
if not found_live_tv:
|
||||
app = {"id": LIVE_TV_APP_ID, "title": "Live TV"}
|
||||
if LIVE_TV_APP_ID == self._client.current_appId:
|
||||
self._current_source = app["title"]
|
||||
self._source_list["Live TV"] = app
|
||||
elif (
|
||||
not conf_sources
|
||||
or app["id"] in conf_sources
|
||||
or any(word in app["title"] for word in conf_sources)
|
||||
or any(word in app["id"] for word in conf_sources)
|
||||
):
|
||||
self._source_list["Live TV"] = app
|
||||
|
||||
@util.Throttle(MIN_TIME_BETWEEN_SCANS, MIN_TIME_BETWEEN_FORCED_SCANS)
|
||||
async def async_update(self):
|
||||
"""Connect."""
|
||||
|
@ -231,17 +227,24 @@ class LgWebOSMediaPlayerEntity(MediaPlayerDevice):
|
|||
@property
|
||||
def state(self):
|
||||
"""Return the state of the device."""
|
||||
return self._state
|
||||
client_state = self._client.power_state.get("state")
|
||||
if client_state in [None, "Power Off", "Suspend", "Active Standby"]:
|
||||
return STATE_OFF
|
||||
|
||||
return STATE_ON
|
||||
|
||||
@property
|
||||
def is_volume_muted(self):
|
||||
"""Boolean if volume is currently muted."""
|
||||
return self._muted
|
||||
return self._client.muted
|
||||
|
||||
@property
|
||||
def volume_level(self):
|
||||
"""Volume level of the media player (0..1)."""
|
||||
return self._volume / 100.0
|
||||
if self._client.volume is not None:
|
||||
return self._client.volume / 100.0
|
||||
|
||||
return None
|
||||
|
||||
@property
|
||||
def source(self):
|
||||
|
@ -256,30 +259,27 @@ class LgWebOSMediaPlayerEntity(MediaPlayerDevice):
|
|||
@property
|
||||
def media_content_type(self):
|
||||
"""Content type of current playing media."""
|
||||
return MEDIA_TYPE_CHANNEL
|
||||
if self._client.current_appId == LIVE_TV_APP_ID:
|
||||
return MEDIA_TYPE_CHANNEL
|
||||
|
||||
return None
|
||||
|
||||
@property
|
||||
def media_title(self):
|
||||
"""Title of current playing media."""
|
||||
if (self._channel is not None) and ("channelName" in self._channel):
|
||||
return self._channel["channelName"]
|
||||
if (self._client.current_appId == LIVE_TV_APP_ID) and (
|
||||
self._client.current_channel is not None
|
||||
):
|
||||
return self._client.current_channel.get("channelName")
|
||||
return None
|
||||
|
||||
@property
|
||||
def media_image_url(self):
|
||||
"""Image url of current playing media."""
|
||||
if self._current_source_id in self._app_list:
|
||||
icon = self._app_list[self._current_source_id]["largeIcon"]
|
||||
if self._client.current_appId in self._client.apps:
|
||||
icon = self._client.apps[self._client.current_appId]["largeIcon"]
|
||||
if not icon.startswith("http"):
|
||||
icon = self._app_list[self._current_source_id]["icon"]
|
||||
|
||||
# 'icon' holds a URL with a transient key. Avoid unnecessary
|
||||
# updates by returning the same URL until the image changes.
|
||||
if self._last_icon and (
|
||||
icon.split("/")[-1] == self._last_icon.split("/")[-1]
|
||||
):
|
||||
return self._last_icon
|
||||
self._last_icon = icon
|
||||
icon = self._client.apps[self._client.current_appId]["icon"]
|
||||
return icon
|
||||
return None
|
||||
|
||||
|
@ -293,22 +293,13 @@ class LgWebOSMediaPlayerEntity(MediaPlayerDevice):
|
|||
@cmd
|
||||
async def async_turn_off(self):
|
||||
"""Turn off media player."""
|
||||
|
||||
# in some situations power_off may cause the TV to switch back on
|
||||
if self._state != STATE_OFF:
|
||||
await self._client.power_off()
|
||||
await self._client.power_off()
|
||||
|
||||
async def async_turn_on(self):
|
||||
"""Turn on the media player."""
|
||||
connected = self._client.is_connected()
|
||||
if self._on_script:
|
||||
await self._on_script.async_run()
|
||||
|
||||
# if connection was already active
|
||||
# ensure is still alive
|
||||
if connected:
|
||||
await self._client.get_current_app()
|
||||
|
||||
@cmd
|
||||
async def async_volume_up(self):
|
||||
"""Volume up the media player."""
|
||||
|
@ -360,7 +351,7 @@ class LgWebOSMediaPlayerEntity(MediaPlayerDevice):
|
|||
partial_match_channel_id = None
|
||||
perfect_match_channel_id = None
|
||||
|
||||
for channel in await self._client.get_channels():
|
||||
for channel in self._client.channels:
|
||||
if media_id == channel["channelNumber"]:
|
||||
perfect_match_channel_id = channel["channelId"]
|
||||
continue
|
||||
|
|
|
@ -190,7 +190,7 @@ aionotion==1.1.0
|
|||
aiopvapi==1.6.14
|
||||
|
||||
# homeassistant.components.webostv
|
||||
aiopylgtv==0.2.7
|
||||
aiopylgtv==0.3.0
|
||||
|
||||
# homeassistant.components.switcher_kis
|
||||
aioswitcher==2019.4.26
|
||||
|
|
|
@ -69,7 +69,7 @@ aiohue==1.10.1
|
|||
aionotion==1.1.0
|
||||
|
||||
# homeassistant.components.webostv
|
||||
aiopylgtv==0.2.7
|
||||
aiopylgtv==0.3.0
|
||||
|
||||
# homeassistant.components.switcher_kis
|
||||
aioswitcher==2019.4.26
|
||||
|
|
|
@ -21,7 +21,6 @@ from homeassistant.const import (
|
|||
CONF_HOST,
|
||||
CONF_NAME,
|
||||
SERVICE_VOLUME_MUTE,
|
||||
STATE_ON,
|
||||
)
|
||||
from homeassistant.setup import async_setup_component
|
||||
|
||||
|
@ -79,7 +78,6 @@ async def test_select_source_with_empty_source_list(hass, client):
|
|||
await hass.services.async_call(media_player.DOMAIN, SERVICE_SELECT_SOURCE, data)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert hass.states.is_state(ENTITY_ID, STATE_ON)
|
||||
client.launch_app.assert_not_called()
|
||||
client.set_input.assert_not_called()
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue