Improve Roku (#34431)

This commit is contained in:
Chris Talkington 2020-04-21 23:06:23 -05:00 committed by GitHub
parent 7f77e99e4d
commit 6dd836589c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 72 additions and 27 deletions

View File

@ -10,7 +10,6 @@ from roku import RokuException
from homeassistant.components.media_player import MediaPlayerDevice from homeassistant.components.media_player import MediaPlayerDevice
from homeassistant.components.media_player.const import ( from homeassistant.components.media_player.const import (
MEDIA_TYPE_CHANNEL, MEDIA_TYPE_CHANNEL,
MEDIA_TYPE_MOVIE,
SUPPORT_NEXT_TRACK, SUPPORT_NEXT_TRACK,
SUPPORT_PLAY, SUPPORT_PLAY,
SUPPORT_PLAY_MEDIA, SUPPORT_PLAY_MEDIA,
@ -66,12 +65,7 @@ class RokuDevice(MediaPlayerDevice):
self._power_state = self.roku.power_state self._power_state = self.roku.power_state
self.ip_address = self.roku.host self.ip_address = self.roku.host
self.channels = self.get_source_list() self.channels = self.get_source_list()
self.current_app = self.roku.current_app
if self.roku.current_app is not None:
self.current_app = self.roku.current_app
else:
self.current_app = None
self._available = True self._available = True
except (RequestsConnectionError, RequestsReadTimeout, RokuException): except (RequestsConnectionError, RequestsReadTimeout, RokuException):
self._available = False self._available = False
@ -90,6 +84,7 @@ class RokuDevice(MediaPlayerDevice):
"""Return the name of the device.""" """Return the name of the device."""
if self._device_info.user_device_name: if self._device_info.user_device_name:
return self._device_info.user_device_name return self._device_info.user_device_name
return f"Roku {self._device_info.serial_num}" return f"Roku {self._device_info.serial_num}"
@property @property
@ -103,8 +98,10 @@ class RokuDevice(MediaPlayerDevice):
if self.current_app.name == "Power Saver" or self.current_app.is_screensaver: if self.current_app.name == "Power Saver" or self.current_app.is_screensaver:
return STATE_IDLE return STATE_IDLE
if self.current_app.name == "Roku": if self.current_app.name == "Roku":
return STATE_HOME return STATE_HOME
if self.current_app.name is not None: if self.current_app.name is not None:
return STATE_PLAYING return STATE_PLAYING
@ -139,23 +136,17 @@ class RokuDevice(MediaPlayerDevice):
@property @property
def media_content_type(self): def media_content_type(self):
"""Content type of current playing media.""" """Content type of current playing media."""
if self.current_app is None: if self.current_app is None or self.current_app.name in ("Power Saver", "Roku"):
return None return None
if self.current_app.name == "Power Saver":
return None return MEDIA_TYPE_CHANNEL
if self.current_app.name == "Roku":
return None
return MEDIA_TYPE_MOVIE
@property @property
def media_image_url(self): def media_image_url(self):
"""Image url of current playing media.""" """Image url of current playing media."""
if self.current_app is None: if self.current_app is None or self.current_app.name in ("Power Saver", "Roku"):
return None
if self.current_app.name == "Roku":
return None
if self.current_app.name == "Power Saver":
return None return None
if self.current_app.id is None: if self.current_app.id is None:
return None return None
@ -233,14 +224,17 @@ class RokuDevice(MediaPlayerDevice):
MEDIA_TYPE_CHANNEL, MEDIA_TYPE_CHANNEL,
) )
return return
if self.current_app is not None: if self.current_app is not None:
self.roku.launch(self.roku["tvinput.dtv"], {"ch": media_id}) self.roku.launch(self.roku["tvinput.dtv"], {"ch": media_id})
def select_source(self, source): def select_source(self, source):
"""Select input source.""" """Select input source."""
if self.current_app is not None: if self.current_app is None:
if source == "Home": return
self.roku.home()
else: if source == "Home":
channel = self.roku[source] self.roku.home()
channel.launch() else:
channel = self.roku[source]
channel.launch()

View File

@ -1,6 +1,13 @@
"""Tests for the Roku Media Player platform.""" """Tests for the Roku Media Player platform."""
from datetime import timedelta
from asynctest import PropertyMock, patch from asynctest import PropertyMock, patch
from requests.exceptions import (
ConnectionError as RequestsConnectionError,
ReadTimeout as RequestsReadTimeout,
)
from requests_mock import Mocker from requests_mock import Mocker
from roku import RokuException
from homeassistant.components.media_player.const import ( from homeassistant.components.media_player.const import (
ATTR_INPUT_SOURCE, ATTR_INPUT_SOURCE,
@ -9,7 +16,6 @@ from homeassistant.components.media_player.const import (
ATTR_MEDIA_VOLUME_MUTED, ATTR_MEDIA_VOLUME_MUTED,
DOMAIN as MP_DOMAIN, DOMAIN as MP_DOMAIN,
MEDIA_TYPE_CHANNEL, MEDIA_TYPE_CHANNEL,
MEDIA_TYPE_MOVIE,
SERVICE_PLAY_MEDIA, SERVICE_PLAY_MEDIA,
SERVICE_SELECT_SOURCE, SERVICE_SELECT_SOURCE,
SUPPORT_NEXT_TRACK, SUPPORT_NEXT_TRACK,
@ -32,11 +38,15 @@ from homeassistant.const import (
SERVICE_VOLUME_DOWN, SERVICE_VOLUME_DOWN,
SERVICE_VOLUME_MUTE, SERVICE_VOLUME_MUTE,
SERVICE_VOLUME_UP, SERVICE_VOLUME_UP,
STATE_HOME,
STATE_PLAYING, STATE_PLAYING,
STATE_STANDBY, STATE_STANDBY,
STATE_UNAVAILABLE,
) )
from homeassistant.helpers.typing import HomeAssistantType from homeassistant.helpers.typing import HomeAssistantType
from homeassistant.util import dt as dt_util
from tests.common import async_fire_time_changed
from tests.components.roku import UPNP_SERIAL, setup_integration from tests.components.roku import UPNP_SERIAL, setup_integration
MAIN_ENTITY_ID = f"{MP_DOMAIN}.my_roku_3" MAIN_ENTITY_ID = f"{MP_DOMAIN}.my_roku_3"
@ -87,6 +97,47 @@ async def test_tv_setup(hass: HomeAssistantType, requests_mock: Mocker) -> None:
assert tv.unique_id == TV_SERIAL assert tv.unique_id == TV_SERIAL
async def test_availability(hass: HomeAssistantType, requests_mock: Mocker) -> None:
"""Test entity availability."""
now = dt_util.utcnow()
future = now + timedelta(minutes=1)
with patch("homeassistant.util.dt.utcnow", return_value=now):
await setup_integration(hass, requests_mock)
with patch("roku.Roku._get", side_effect=RokuException,), patch(
"homeassistant.util.dt.utcnow", return_value=future
):
async_fire_time_changed(hass, future)
await hass.async_block_till_done()
assert hass.states.get(MAIN_ENTITY_ID).state == STATE_UNAVAILABLE
future += timedelta(minutes=1)
with patch("roku.Roku._get", side_effect=RequestsConnectionError,), patch(
"homeassistant.util.dt.utcnow", return_value=future
):
async_fire_time_changed(hass, future)
await hass.async_block_till_done()
assert hass.states.get(MAIN_ENTITY_ID).state == STATE_UNAVAILABLE
future += timedelta(minutes=1)
with patch("roku.Roku._get", side_effect=RequestsReadTimeout,), patch(
"homeassistant.util.dt.utcnow", return_value=future
):
async_fire_time_changed(hass, future)
await hass.async_block_till_done()
assert hass.states.get(MAIN_ENTITY_ID).state == STATE_UNAVAILABLE
future += timedelta(minutes=1)
with patch("homeassistant.util.dt.utcnow", return_value=future):
async_fire_time_changed(hass, future)
await hass.async_block_till_done()
assert hass.states.get(MAIN_ENTITY_ID).state == STATE_HOME
async def test_supported_features( async def test_supported_features(
hass: HomeAssistantType, requests_mock: Mocker hass: HomeAssistantType, requests_mock: Mocker
) -> None: ) -> None:
@ -142,7 +193,7 @@ async def test_attributes(hass: HomeAssistantType, requests_mock: Mocker) -> Non
await setup_integration(hass, requests_mock) await setup_integration(hass, requests_mock)
state = hass.states.get(MAIN_ENTITY_ID) state = hass.states.get(MAIN_ENTITY_ID)
assert state.state == "home" assert state.state == STATE_HOME
assert state.attributes.get(ATTR_MEDIA_CONTENT_TYPE) is None assert state.attributes.get(ATTR_MEDIA_CONTENT_TYPE) is None
assert state.attributes.get(ATTR_INPUT_SOURCE) == "Roku" assert state.attributes.get(ATTR_INPUT_SOURCE) == "Roku"
@ -162,7 +213,7 @@ async def test_tv_attributes(hass: HomeAssistantType, requests_mock: Mocker) ->
state = hass.states.get(TV_ENTITY_ID) state = hass.states.get(TV_ENTITY_ID)
assert state.state == STATE_PLAYING assert state.state == STATE_PLAYING
assert state.attributes.get(ATTR_MEDIA_CONTENT_TYPE) == MEDIA_TYPE_MOVIE assert state.attributes.get(ATTR_MEDIA_CONTENT_TYPE) == MEDIA_TYPE_CHANNEL
assert state.attributes.get(ATTR_INPUT_SOURCE) == "Antenna TV" assert state.attributes.get(ATTR_INPUT_SOURCE) == "Antenna TV"