mirror of
https://github.com/home-assistant/core.git
synced 2025-07-25 22:27:07 +00:00
Add service to trigger roku search (#37014)
This commit is contained in:
parent
2c7876fa66
commit
6610bbe7bb
@ -3,9 +3,13 @@ DOMAIN = "roku"
|
|||||||
|
|
||||||
# Attributes
|
# Attributes
|
||||||
ATTR_IDENTIFIERS = "identifiers"
|
ATTR_IDENTIFIERS = "identifiers"
|
||||||
|
ATTR_KEYWORD = "keyword"
|
||||||
ATTR_MANUFACTURER = "manufacturer"
|
ATTR_MANUFACTURER = "manufacturer"
|
||||||
ATTR_MODEL = "model"
|
ATTR_MODEL = "model"
|
||||||
ATTR_SOFTWARE_VERSION = "sw_version"
|
ATTR_SOFTWARE_VERSION = "sw_version"
|
||||||
|
|
||||||
# Default Values
|
# Default Values
|
||||||
DEFAULT_PORT = 8060
|
DEFAULT_PORT = 8060
|
||||||
|
|
||||||
|
# Services
|
||||||
|
SERVICE_SEARCH = "search"
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
import logging
|
import logging
|
||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
|
import voluptuous as vol
|
||||||
|
|
||||||
from homeassistant.components.media_player import MediaPlayerEntity
|
from homeassistant.components.media_player import MediaPlayerEntity
|
||||||
from homeassistant.components.media_player.const import (
|
from homeassistant.components.media_player.const import (
|
||||||
MEDIA_TYPE_APP,
|
MEDIA_TYPE_APP,
|
||||||
@ -24,9 +26,10 @@ from homeassistant.const import (
|
|||||||
STATE_PLAYING,
|
STATE_PLAYING,
|
||||||
STATE_STANDBY,
|
STATE_STANDBY,
|
||||||
)
|
)
|
||||||
|
from homeassistant.helpers import entity_platform
|
||||||
|
|
||||||
from . import RokuDataUpdateCoordinator, RokuEntity, roku_exception_handler
|
from . import RokuDataUpdateCoordinator, RokuEntity, roku_exception_handler
|
||||||
from .const import DOMAIN
|
from .const import ATTR_KEYWORD, DOMAIN, SERVICE_SEARCH
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -43,6 +46,8 @@ SUPPORT_ROKU = (
|
|||||||
| SUPPORT_TURN_OFF
|
| SUPPORT_TURN_OFF
|
||||||
)
|
)
|
||||||
|
|
||||||
|
SEARCH_SCHEMA = {vol.Required(ATTR_KEYWORD): str}
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_entry(hass, entry, async_add_entities):
|
async def async_setup_entry(hass, entry, async_add_entities):
|
||||||
"""Set up the Roku config entry."""
|
"""Set up the Roku config entry."""
|
||||||
@ -50,6 +55,12 @@ async def async_setup_entry(hass, entry, async_add_entities):
|
|||||||
unique_id = coordinator.data.info.serial_number
|
unique_id = coordinator.data.info.serial_number
|
||||||
async_add_entities([RokuMediaPlayer(unique_id, coordinator)], True)
|
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):
|
class RokuMediaPlayer(RokuEntity, MediaPlayerEntity):
|
||||||
"""Representation of a Roku media player on the network."""
|
"""Representation of a Roku media player on the network."""
|
||||||
@ -170,6 +181,11 @@ class RokuMediaPlayer(RokuEntity, MediaPlayerEntity):
|
|||||||
"""List of available input sources."""
|
"""List of available input sources."""
|
||||||
return ["Home"] + sorted(app.name for app in self.coordinator.data.apps)
|
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
|
@roku_exception_handler
|
||||||
async def async_turn_on(self) -> None:
|
async def async_turn_on(self) -> None:
|
||||||
"""Turn on the Roku."""
|
"""Turn on the Roku."""
|
||||||
|
9
homeassistant/components/roku/services.yaml
Normal file
9
homeassistant/components/roku/services.yaml
Normal file
@ -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"
|
@ -104,6 +104,8 @@ def mock_connection(
|
|||||||
re.compile(f"{roku_url}/launch/.*"), text="OK",
|
re.compile(f"{roku_url}/launch/.*"), text="OK",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
aioclient_mock.post(f"{roku_url}/search", text="OK")
|
||||||
|
|
||||||
|
|
||||||
def mock_connection_error(
|
def mock_connection_error(
|
||||||
aioclient_mock: AiohttpClientMocker,
|
aioclient_mock: AiohttpClientMocker,
|
||||||
@ -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}/keypress/.*"), exc=SocketGIAError)
|
||||||
aioclient_mock.post(re.compile(f"{roku_url}/launch/.*"), 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(
|
def mock_connection_server_error(
|
||||||
@ -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}/keypress/.*"), status=500)
|
||||||
aioclient_mock.post(re.compile(f"{roku_url}/launch/.*"), 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(
|
async def setup_integration(
|
||||||
|
@ -28,6 +28,7 @@ from homeassistant.components.media_player.const import (
|
|||||||
SUPPORT_VOLUME_MUTE,
|
SUPPORT_VOLUME_MUTE,
|
||||||
SUPPORT_VOLUME_STEP,
|
SUPPORT_VOLUME_STEP,
|
||||||
)
|
)
|
||||||
|
from homeassistant.components.roku.const import ATTR_KEYWORD, DOMAIN, SERVICE_SEARCH
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
ATTR_ENTITY_ID,
|
ATTR_ENTITY_ID,
|
||||||
SERVICE_MEDIA_NEXT_TRACK,
|
SERVICE_MEDIA_NEXT_TRACK,
|
||||||
@ -422,3 +423,19 @@ async def test_tv_services(
|
|||||||
)
|
)
|
||||||
|
|
||||||
tune_mock.assert_called_once_with("55")
|
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")
|
||||||
|
@ -39,7 +39,7 @@ async def test_unique_id(
|
|||||||
async def test_main_services(
|
async def test_main_services(
|
||||||
hass: HomeAssistantType, aioclient_mock: AiohttpClientMocker
|
hass: HomeAssistantType, aioclient_mock: AiohttpClientMocker
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test the different services."""
|
"""Test platform services."""
|
||||||
await setup_integration(hass, aioclient_mock)
|
await setup_integration(hass, aioclient_mock)
|
||||||
|
|
||||||
with patch("homeassistant.components.roku.Roku.remote") as remote_mock:
|
with patch("homeassistant.components.roku.Roku.remote") as remote_mock:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user