From f7d25396a463fcfb8afbb50199b3128413fefd31 Mon Sep 17 00:00:00 2001 From: Eugenio Panadero <eugenio.panadero@gmail.com> Date: Wed, 17 May 2017 14:42:47 +0200 Subject: [PATCH] Kodi specific service to call Kodi API methods (#7603) * Kodi specific services to call Kodi API methods - new service: `kodi_execute_addon` to run a Kodi Addon with optional parameters. Results of the Kodi API call, if any, are redirected in a Home Assistant event: `kodi_execute_addon_result`. - new service: `kodi_run_method` to run a Kodi JSONRPC API method with optional parameters. Results of the Kodi API call are redirected in a Home Assistant event: `kodi_run_method_result`. - Add descriptions in services.yaml. - Add `timeout` parameter to yaml config (needed to make slow queries to the JSONRPC API, default timeout is set to 5s). - Trigger events with the results of the Kodi API calls, with: ``` event_data = { 'result': api_call_results, 'result_ok': boolean, 'input': api_call_parameters, 'entity_id': 'media_player.kodi'} ``` * no need to clean OrderedDicts; no need for the `kodi_execute_addon` service * no need for the `kodi_execute_addon` service * unused import * naming changes --- homeassistant/components/media_player/kodi.py | 44 +++++++++++++++++-- .../components/media_player/services.yaml | 11 +++++ 2 files changed, 51 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/media_player/kodi.py b/homeassistant/components/media_player/kodi.py index 18c01c396ac..9861887df89 100644 --- a/homeassistant/components/media_player/kodi.py +++ b/homeassistant/components/media_player/kodi.py @@ -24,7 +24,7 @@ from homeassistant.components.media_player import ( from homeassistant.const import ( STATE_IDLE, STATE_OFF, STATE_PAUSED, STATE_PLAYING, CONF_HOST, CONF_NAME, CONF_PORT, CONF_SSL, CONF_PROXY_SSL, CONF_USERNAME, CONF_PASSWORD, - EVENT_HOMEASSISTANT_STOP) + CONF_TIMEOUT, EVENT_HOMEASSISTANT_STOP) from homeassistant.core import callback from homeassistant.helpers.aiohttp_client import async_get_clientsession import homeassistant.helpers.config_validation as cv @@ -34,6 +34,8 @@ REQUIREMENTS = ['jsonrpc-async==0.6', 'jsonrpc-websocket==0.5'] _LOGGER = logging.getLogger(__name__) +EVENT_KODI_CALL_METHOD_RESULT = 'kodi_call_method_result' + CONF_TCP_PORT = 'tcp_port' CONF_TURN_OFF_ACTION = 'turn_off_action' CONF_ENABLE_WEBSOCKET = 'enable_websocket' @@ -74,6 +76,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Optional(CONF_TCP_PORT, default=DEFAULT_TCP_PORT): cv.port, vol.Optional(CONF_PROXY_SSL, default=DEFAULT_PROXY_SSL): cv.boolean, vol.Optional(CONF_TURN_OFF_ACTION, default=None): vol.In(TURN_OFF_ACTION), + vol.Optional(CONF_TIMEOUT, default=DEFAULT_TIMEOUT): cv.positive_int, vol.Inclusive(CONF_USERNAME, 'auth'): cv.string, vol.Inclusive(CONF_PASSWORD, 'auth'): cv.string, vol.Optional(CONF_ENABLE_WEBSOCKET, default=DEFAULT_ENABLE_WEBSOCKET): @@ -81,6 +84,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) SERVICE_ADD_MEDIA = 'kodi_add_to_playlist' +SERVICE_CALL_METHOD = 'kodi_call_method' DATA_KODI = 'kodi' @@ -88,6 +92,7 @@ ATTR_MEDIA_TYPE = 'media_type' ATTR_MEDIA_NAME = 'media_name' ATTR_MEDIA_ARTIST_NAME = 'artist_name' ATTR_MEDIA_ID = 'media_id' +ATTR_METHOD = 'method' MEDIA_PLAYER_ADD_MEDIA_SCHEMA = MEDIA_PLAYER_SCHEMA.extend({ vol.Required(ATTR_MEDIA_TYPE): cv.string, @@ -95,11 +100,17 @@ MEDIA_PLAYER_ADD_MEDIA_SCHEMA = MEDIA_PLAYER_SCHEMA.extend({ vol.Optional(ATTR_MEDIA_NAME): cv.string, vol.Optional(ATTR_MEDIA_ARTIST_NAME): cv.string, }) +MEDIA_PLAYER_CALL_METHOD_SCHEMA = MEDIA_PLAYER_SCHEMA.extend({ + vol.Required(ATTR_METHOD): cv.string, +}, extra=vol.ALLOW_EXTRA) SERVICE_TO_METHOD = { SERVICE_ADD_MEDIA: { 'method': 'async_add_media_to_playlist', 'schema': MEDIA_PLAYER_ADD_MEDIA_SCHEMA}, + SERVICE_CALL_METHOD: { + 'method': 'async_call_method', + 'schema': MEDIA_PLAYER_CALL_METHOD_SCHEMA}, } @@ -127,7 +138,8 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): host=host, port=port, tcp_port=tcp_port, encryption=encryption, username=config.get(CONF_USERNAME), password=config.get(CONF_PASSWORD), - turn_off_action=config.get(CONF_TURN_OFF_ACTION), websocket=websocket) + turn_off_action=config.get(CONF_TURN_OFF_ACTION), + timeout=config.get(CONF_TIMEOUT), websocket=websocket) hass.data[DATA_KODI].append(entity) async_add_devices([entity], update_before_add=True) @@ -199,7 +211,7 @@ class KodiDevice(MediaPlayerDevice): def __init__(self, hass, name, host, port, tcp_port, encryption=False, username=None, password=None, turn_off_action=None, - websocket=True): + timeout=DEFAULT_TIMEOUT, websocket=True): """Initialize the Kodi device.""" import jsonrpc_async import jsonrpc_websocket @@ -207,7 +219,7 @@ class KodiDevice(MediaPlayerDevice): self._name = name kwargs = { - 'timeout': DEFAULT_TIMEOUT, + 'timeout': timeout, 'session': async_get_clientsession(hass), } @@ -678,6 +690,30 @@ class KodiDevice(MediaPlayerDevice): yield from self.server.Player.SetShuffle( {"playerid": self._players[0]['playerid'], "shuffle": shuffle}) + @asyncio.coroutine + def async_call_method(self, method, **kwargs): + """Run Kodi JSONRPC API method with params.""" + import jsonrpc_base + _LOGGER.debug('Run API method "%s", kwargs=%s', method, kwargs) + result_ok = False + try: + result = yield from getattr(self.server, method)(**kwargs) + result_ok = True + except jsonrpc_base.jsonrpc.ProtocolError as exc: + result = exc.args[2]['error'] + _LOGGER.error('Run API method %s.%s(%s) error: %s', + self.entity_id, method, kwargs, result) + + if isinstance(result, dict): + event_data = {'entity_id': self.entity_id, + 'result': result, + 'result_ok': result_ok, + 'input': {'method': method, 'params': kwargs}} + _LOGGER.debug('EVENT kodi_call_method_result: %s', event_data) + self.hass.bus.async_fire(EVENT_KODI_CALL_METHOD_RESULT, + event_data=event_data) + return result + @asyncio.coroutine def async_add_media_to_playlist( self, media_type, media_id=None, media_name='ALL', artist_name=''): diff --git a/homeassistant/components/media_player/services.yaml b/homeassistant/components/media_player/services.yaml index 4d5f85c05eb..00ce0987fd9 100644 --- a/homeassistant/components/media_player/services.yaml +++ b/homeassistant/components/media_player/services.yaml @@ -289,3 +289,14 @@ kodi_add_to_playlist: artist_name: description: Optional artist name for filtering media. example: 'AC/DC' + +kodi_call_method: + description: 'Call a Kodi JSONRPC API method with optional parameters. Results of the Kodi API call will be redirected in a Home Assistant event: `kodi_call_method_result`.' + + fields: + entity_id: + description: Name(s) of the Kodi entities where to run the API method. + example: 'media_player.living_room_kodi' + method: + description: Name of the Kodi JSONRPC API method to be called. + example: 'VideoLibrary.GetRecentlyAddedEpisodes'