Skip to content

Commit

Permalink
Add service to trigger roku search (home-assistant#37014)
Browse files Browse the repository at this point in the history
  • Loading branch information
ctalkington authored Jun 23, 2020
1 parent 2c7876f commit 6610bbe
Show file tree
Hide file tree
Showing 6 changed files with 52 additions and 2 deletions.
4 changes: 4 additions & 0 deletions homeassistant/components/roku/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,13 @@

# Attributes
ATTR_IDENTIFIERS = "identifiers"
ATTR_KEYWORD = "keyword"
ATTR_MANUFACTURER = "manufacturer"
ATTR_MODEL = "model"
ATTR_SOFTWARE_VERSION = "sw_version"

# Default Values
DEFAULT_PORT = 8060

# Services
SERVICE_SEARCH = "search"
18 changes: 17 additions & 1 deletion homeassistant/components/roku/media_player.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
import logging
from typing import List

import voluptuous as vol

from homeassistant.components.media_player import MediaPlayerEntity
from homeassistant.components.media_player.const import (
MEDIA_TYPE_APP,
Expand All @@ -24,9 +26,10 @@
STATE_PLAYING,
STATE_STANDBY,
)
from homeassistant.helpers import entity_platform

from . import RokuDataUpdateCoordinator, RokuEntity, roku_exception_handler
from .const import DOMAIN
from .const import ATTR_KEYWORD, DOMAIN, SERVICE_SEARCH

_LOGGER = logging.getLogger(__name__)

Expand All @@ -43,13 +46,21 @@
| SUPPORT_TURN_OFF
)

SEARCH_SCHEMA = {vol.Required(ATTR_KEYWORD): str}


async def async_setup_entry(hass, entry, async_add_entities):
"""Set up the Roku config entry."""
coordinator = hass.data[DOMAIN][entry.entry_id]
unique_id = coordinator.data.info.serial_number
async_add_entities([RokuMediaPlayer(unique_id, coordinator)], True)

platform = entity_platform.current_platform.get()

platform.async_register_entity_service(
SERVICE_SEARCH, SEARCH_SCHEMA, "search",
)


class RokuMediaPlayer(RokuEntity, MediaPlayerEntity):
"""Representation of a Roku media player on the network."""
Expand Down Expand Up @@ -170,6 +181,11 @@ def source_list(self) -> List:
"""List of available input sources."""
return ["Home"] + sorted(app.name for app in self.coordinator.data.apps)

@roku_exception_handler
async def search(self, keyword):
"""Emulate opening the search screen and entering the search keyword."""
await self.coordinator.roku.search(keyword)

@roku_exception_handler
async def async_turn_on(self) -> None:
"""Turn on the Roku."""
Expand Down
9 changes: 9 additions & 0 deletions homeassistant/components/roku/services.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
search:
description: Emulates opening thd search screen and entering the search keyword.
fields:
entity_id:
description: The entities to search on.
example: "media_player.roku"
keyword:
description: The keyword to search for.
example: "Space Jam"
4 changes: 4 additions & 0 deletions tests/components/roku/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,8 @@ def mock_connection(
re.compile(f"{roku_url}/launch/.*"), text="OK",
)

aioclient_mock.post(f"{roku_url}/search", text="OK")


def mock_connection_error(
aioclient_mock: AiohttpClientMocker,
Expand All @@ -122,6 +124,7 @@ def mock_connection_error(

aioclient_mock.post(re.compile(f"{roku_url}/keypress/.*"), exc=SocketGIAError)
aioclient_mock.post(re.compile(f"{roku_url}/launch/.*"), exc=SocketGIAError)
aioclient_mock.post(f"{roku_url}/search", exc=SocketGIAError)


def mock_connection_server_error(
Expand All @@ -141,6 +144,7 @@ def mock_connection_server_error(

aioclient_mock.post(re.compile(f"{roku_url}/keypress/.*"), status=500)
aioclient_mock.post(re.compile(f"{roku_url}/launch/.*"), status=500)
aioclient_mock.post(f"{roku_url}/search", status=500)


async def setup_integration(
Expand Down
17 changes: 17 additions & 0 deletions tests/components/roku/test_media_player.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
SUPPORT_VOLUME_MUTE,
SUPPORT_VOLUME_STEP,
)
from homeassistant.components.roku.const import ATTR_KEYWORD, DOMAIN, SERVICE_SEARCH
from homeassistant.const import (
ATTR_ENTITY_ID,
SERVICE_MEDIA_NEXT_TRACK,
Expand Down Expand Up @@ -422,3 +423,19 @@ async def test_tv_services(
)

tune_mock.assert_called_once_with("55")


async def test_integration_services(
hass: HomeAssistantType, aioclient_mock: AiohttpClientMocker
) -> None:
"""Test integration services."""
await setup_integration(hass, aioclient_mock)

with patch("homeassistant.components.roku.Roku.search") as search_mock:
await hass.services.async_call(
DOMAIN,
SERVICE_SEARCH,
{ATTR_ENTITY_ID: MAIN_ENTITY_ID, ATTR_KEYWORD: "Space Jam"},
blocking=True,
)
search_mock.assert_called_once_with("Space Jam")
2 changes: 1 addition & 1 deletion tests/components/roku/test_remote.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ async def test_unique_id(
async def test_main_services(
hass: HomeAssistantType, aioclient_mock: AiohttpClientMocker
) -> None:
"""Test the different services."""
"""Test platform services."""
await setup_integration(hass, aioclient_mock)

with patch("homeassistant.components.roku.Roku.remote") as remote_mock:
Expand Down

0 comments on commit 6610bbe

Please sign in to comment.