mirror of
https://github.com/home-assistant/core.git
synced 2025-07-17 02:07:09 +00:00
Add generic command/button functionality to webostv (#30379)
* add generic command/button functionality to webostv * update codeowners
This commit is contained in:
parent
9064058a03
commit
c1936f6fe4
@ -365,6 +365,7 @@ homeassistant/components/waqi/* @andrey-git
|
|||||||
homeassistant/components/watson_tts/* @rutkai
|
homeassistant/components/watson_tts/* @rutkai
|
||||||
homeassistant/components/weather/* @fabaff
|
homeassistant/components/weather/* @fabaff
|
||||||
homeassistant/components/weblink/* @home-assistant/core
|
homeassistant/components/weblink/* @home-assistant/core
|
||||||
|
homeassistant/components/webostv/* @bendavid
|
||||||
homeassistant/components/websocket_api/* @home-assistant/core
|
homeassistant/components/websocket_api/* @home-assistant/core
|
||||||
homeassistant/components/wemo/* @sqldiablo
|
homeassistant/components/wemo/* @sqldiablo
|
||||||
homeassistant/components/withings/* @vangorra
|
homeassistant/components/withings/* @vangorra
|
||||||
|
@ -7,6 +7,7 @@ import voluptuous as vol
|
|||||||
from websockets.exceptions import ConnectionClosed
|
from websockets.exceptions import ConnectionClosed
|
||||||
|
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
|
ATTR_ENTITY_ID,
|
||||||
CONF_CUSTOMIZE,
|
CONF_CUSTOMIZE,
|
||||||
CONF_HOST,
|
CONF_HOST,
|
||||||
CONF_ICON,
|
CONF_ICON,
|
||||||
@ -14,6 +15,7 @@ from homeassistant.const import (
|
|||||||
EVENT_HOMEASSISTANT_STOP,
|
EVENT_HOMEASSISTANT_STOP,
|
||||||
)
|
)
|
||||||
import homeassistant.helpers.config_validation as cv
|
import homeassistant.helpers.config_validation as cv
|
||||||
|
from homeassistant.helpers.dispatcher import async_dispatcher_send
|
||||||
|
|
||||||
DOMAIN = "webostv"
|
DOMAIN = "webostv"
|
||||||
|
|
||||||
@ -23,6 +25,12 @@ CONF_STANDBY_CONNECTION = "standby_connection"
|
|||||||
DEFAULT_NAME = "LG webOS Smart TV"
|
DEFAULT_NAME = "LG webOS Smart TV"
|
||||||
WEBOSTV_CONFIG_FILE = "webostv.conf"
|
WEBOSTV_CONFIG_FILE = "webostv.conf"
|
||||||
|
|
||||||
|
SERVICE_BUTTON = "button"
|
||||||
|
ATTR_BUTTON = "button"
|
||||||
|
|
||||||
|
SERVICE_COMMAND = "command"
|
||||||
|
ATTR_COMMAND = "command"
|
||||||
|
|
||||||
CUSTOMIZE_SCHEMA = vol.Schema(
|
CUSTOMIZE_SCHEMA = vol.Schema(
|
||||||
{vol.Optional(CONF_SOURCES, default=[]): vol.All(cv.ensure_list, [cv.string])}
|
{vol.Optional(CONF_SOURCES, default=[]): vol.All(cv.ensure_list, [cv.string])}
|
||||||
)
|
)
|
||||||
@ -50,6 +58,17 @@ CONFIG_SCHEMA = vol.Schema(
|
|||||||
extra=vol.ALLOW_EXTRA,
|
extra=vol.ALLOW_EXTRA,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
CALL_SCHEMA = vol.Schema({vol.Required(ATTR_ENTITY_ID): cv.comp_entity_ids})
|
||||||
|
|
||||||
|
BUTTON_SCHEMA = CALL_SCHEMA.extend({vol.Required(ATTR_BUTTON): cv.string})
|
||||||
|
|
||||||
|
COMMAND_SCHEMA = CALL_SCHEMA.extend({vol.Required(ATTR_COMMAND): cv.string})
|
||||||
|
|
||||||
|
SERVICE_TO_METHOD = {
|
||||||
|
SERVICE_BUTTON: {"method": "async_button", "schema": BUTTON_SCHEMA},
|
||||||
|
SERVICE_COMMAND: {"method": "async_command", "schema": COMMAND_SCHEMA},
|
||||||
|
}
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
@ -57,6 +76,18 @@ async def async_setup(hass, config):
|
|||||||
"""Set up the LG WebOS TV platform."""
|
"""Set up the LG WebOS TV platform."""
|
||||||
hass.data[DOMAIN] = {}
|
hass.data[DOMAIN] = {}
|
||||||
|
|
||||||
|
async def async_service_handler(service):
|
||||||
|
method = SERVICE_TO_METHOD.get(service.service)
|
||||||
|
data = service.data.copy()
|
||||||
|
data["method"] = method["method"]
|
||||||
|
async_dispatcher_send(hass, DOMAIN, data)
|
||||||
|
|
||||||
|
for service in SERVICE_TO_METHOD:
|
||||||
|
schema = SERVICE_TO_METHOD[service]["schema"]
|
||||||
|
hass.services.async_register(
|
||||||
|
DOMAIN, service, async_service_handler, schema=schema
|
||||||
|
)
|
||||||
|
|
||||||
tasks = [async_setup_tv(hass, config, conf) for conf in config[DOMAIN]]
|
tasks = [async_setup_tv(hass, config, conf) for conf in config[DOMAIN]]
|
||||||
if tasks:
|
if tasks:
|
||||||
await asyncio.gather(*tasks)
|
await asyncio.gather(*tasks)
|
||||||
|
@ -6,5 +6,5 @@
|
|||||||
"aiopylgtv==0.2.4"
|
"aiopylgtv==0.2.4"
|
||||||
],
|
],
|
||||||
"dependencies": ["configurator"],
|
"dependencies": ["configurator"],
|
||||||
"codeowners": []
|
"codeowners": ["@bendavid"]
|
||||||
}
|
}
|
||||||
|
@ -24,13 +24,16 @@ from homeassistant.components.media_player.const import (
|
|||||||
SUPPORT_VOLUME_STEP,
|
SUPPORT_VOLUME_STEP,
|
||||||
)
|
)
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
|
ATTR_ENTITY_ID,
|
||||||
CONF_CUSTOMIZE,
|
CONF_CUSTOMIZE,
|
||||||
CONF_HOST,
|
CONF_HOST,
|
||||||
CONF_NAME,
|
CONF_NAME,
|
||||||
|
ENTITY_MATCH_ALL,
|
||||||
STATE_OFF,
|
STATE_OFF,
|
||||||
STATE_PAUSED,
|
STATE_PAUSED,
|
||||||
STATE_PLAYING,
|
STATE_PLAYING,
|
||||||
)
|
)
|
||||||
|
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||||
from homeassistant.helpers.script import Script
|
from homeassistant.helpers.script import Script
|
||||||
|
|
||||||
from . import CONF_ON_ACTION, CONF_SOURCES, DOMAIN
|
from . import CONF_ON_ACTION, CONF_SOURCES, DOMAIN
|
||||||
@ -131,7 +134,9 @@ class LgWebOSMediaPlayerEntity(MediaPlayerDevice):
|
|||||||
self._last_icon = None
|
self._last_icon = None
|
||||||
|
|
||||||
async def async_added_to_hass(self):
|
async def async_added_to_hass(self):
|
||||||
"""Connect and subscribe to state updates."""
|
"""Connect and subscribe to dispatcher signals and state updates."""
|
||||||
|
async_dispatcher_connect(self.hass, DOMAIN, self.async_signal_handler)
|
||||||
|
|
||||||
await self._client.register_state_update_callback(
|
await self._client.register_state_update_callback(
|
||||||
self.async_handle_state_update
|
self.async_handle_state_update
|
||||||
)
|
)
|
||||||
@ -144,6 +149,17 @@ class LgWebOSMediaPlayerEntity(MediaPlayerDevice):
|
|||||||
"""Call disconnect on removal."""
|
"""Call disconnect on removal."""
|
||||||
self._client.unregister_state_update_callback(self.async_handle_state_update)
|
self._client.unregister_state_update_callback(self.async_handle_state_update)
|
||||||
|
|
||||||
|
async def async_signal_handler(self, data):
|
||||||
|
"""Handle domain-specific signal by calling appropriate method."""
|
||||||
|
entity_ids = data[ATTR_ENTITY_ID]
|
||||||
|
if entity_ids == ENTITY_MATCH_ALL or self.entity_id in entity_ids:
|
||||||
|
params = {
|
||||||
|
key: value
|
||||||
|
for key, value in data.items()
|
||||||
|
if key not in ["entity_id", "method"]
|
||||||
|
}
|
||||||
|
await getattr(self, data["method"])(**params)
|
||||||
|
|
||||||
async def async_handle_state_update(self):
|
async def async_handle_state_update(self):
|
||||||
"""Update state from WebOsClient."""
|
"""Update state from WebOsClient."""
|
||||||
self._current_source_id = self._client.current_appId
|
self._current_source_id = self._client.current_appId
|
||||||
@ -406,3 +422,13 @@ class LgWebOSMediaPlayerEntity(MediaPlayerDevice):
|
|||||||
await self._client.channel_down()
|
await self._client.channel_down()
|
||||||
else:
|
else:
|
||||||
await self._client.rewind()
|
await self._client.rewind()
|
||||||
|
|
||||||
|
@cmd
|
||||||
|
async def async_button(self, button):
|
||||||
|
"""Send a button press."""
|
||||||
|
await self._client.button(button)
|
||||||
|
|
||||||
|
@cmd
|
||||||
|
async def async_command(self, command):
|
||||||
|
"""Send a command."""
|
||||||
|
await self._client.request(command)
|
||||||
|
26
homeassistant/components/webostv/services.yaml
Normal file
26
homeassistant/components/webostv/services.yaml
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
# Describes the format for available webostv services
|
||||||
|
|
||||||
|
button:
|
||||||
|
description: 'Send a button press command.'
|
||||||
|
fields:
|
||||||
|
entity_id:
|
||||||
|
description: Name(s) of the webostv entities where to run the API method.
|
||||||
|
example: 'media_player.living_room_tv'
|
||||||
|
button:
|
||||||
|
description: Name of the button to press. Known possible values are
|
||||||
|
LEFT, RIGHT, DOWN, UP, HOME, BACK, ENTER, DASH, INFO, ASTERISK, CC, EXIT,
|
||||||
|
MUTE, RED, GREEN, BLUE, VOLUMEUP, VOLUMEDOWN, CHANNELUP, CHANNELDOWN,
|
||||||
|
0, 1, 2, 3, 4, 5, 6, 7, 8, 9
|
||||||
|
example: 'LEFT'
|
||||||
|
|
||||||
|
command:
|
||||||
|
description: 'Send a command.'
|
||||||
|
fields:
|
||||||
|
entity_id:
|
||||||
|
description: Name(s) of the webostv entities where to run the API method.
|
||||||
|
example: 'media_player.living_room_tv'
|
||||||
|
command:
|
||||||
|
description: Endpoint of the command. Known valid endpoints are listed in
|
||||||
|
https://github.com/TheRealLink/pylgtv/blob/master/pylgtv/endpoints.py
|
||||||
|
example: 'media.controls/rewind'
|
||||||
|
|
@ -9,7 +9,13 @@ from homeassistant.components.media_player.const import (
|
|||||||
ATTR_MEDIA_VOLUME_MUTED,
|
ATTR_MEDIA_VOLUME_MUTED,
|
||||||
SERVICE_SELECT_SOURCE,
|
SERVICE_SELECT_SOURCE,
|
||||||
)
|
)
|
||||||
from homeassistant.components.webostv import DOMAIN
|
from homeassistant.components.webostv import (
|
||||||
|
ATTR_BUTTON,
|
||||||
|
ATTR_COMMAND,
|
||||||
|
DOMAIN,
|
||||||
|
SERVICE_BUTTON,
|
||||||
|
SERVICE_COMMAND,
|
||||||
|
)
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
ATTR_ENTITY_ID,
|
ATTR_ENTITY_ID,
|
||||||
CONF_HOST,
|
CONF_HOST,
|
||||||
@ -75,3 +81,34 @@ async def test_select_source_with_empty_source_list(hass, client):
|
|||||||
assert hass.states.is_state(ENTITY_ID, "playing")
|
assert hass.states.is_state(ENTITY_ID, "playing")
|
||||||
client.launch_app.assert_not_called()
|
client.launch_app.assert_not_called()
|
||||||
client.set_input.assert_not_called()
|
client.set_input.assert_not_called()
|
||||||
|
|
||||||
|
|
||||||
|
async def test_button(hass, client):
|
||||||
|
"""Test generic button functionality."""
|
||||||
|
|
||||||
|
await setup_webostv(hass)
|
||||||
|
|
||||||
|
data = {
|
||||||
|
ATTR_ENTITY_ID: ENTITY_ID,
|
||||||
|
ATTR_BUTTON: "test",
|
||||||
|
}
|
||||||
|
await hass.services.async_call(DOMAIN, SERVICE_BUTTON, data)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
client.button.assert_called_once()
|
||||||
|
client.button.assert_called_with("test")
|
||||||
|
|
||||||
|
|
||||||
|
async def test_command(hass, client):
|
||||||
|
"""Test generic button functionality."""
|
||||||
|
|
||||||
|
await setup_webostv(hass)
|
||||||
|
|
||||||
|
data = {
|
||||||
|
ATTR_ENTITY_ID: ENTITY_ID,
|
||||||
|
ATTR_COMMAND: "test",
|
||||||
|
}
|
||||||
|
await hass.services.async_call(DOMAIN, SERVICE_COMMAND, data)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
client.request.assert_called_with("test")
|
||||||
|
Loading…
x
Reference in New Issue
Block a user