From 3638b21bcbab36bf4851d0faf427e97354457072 Mon Sep 17 00:00:00 2001 From: everix1992 Date: Tue, 23 May 2017 19:00:52 -0500 Subject: [PATCH] Added new commands and functionality to the harmony remote component. (#7113) * Added new commands and functionality to the harmony remote component. -This includes the ability to optionally specify a number of times to repeat a specific command, such as pressing the volume button multiple times. -Also added a new command that allows you to send multiple commands to the harmony at once, such as sending a set of channel numbers. -Updated the unit tests for these changes. * Fix flake8 coding violations * Remove send_commands command and make send_command handle a single or list of commands * Remove send_commands tests * Update itach and kira remotes for new send_command structure. Fix pyharmony version in requirements_all.txt * Fix incorrect variable name * Fix a couple minor issues with remote tests --- homeassistant/components/remote/__init__.py | 24 ++++++++++++++++--- homeassistant/components/remote/harmony.py | 12 ++++++---- homeassistant/components/remote/itach.py | 3 ++- homeassistant/components/remote/kira.py | 10 ++++---- homeassistant/components/remote/services.yaml | 8 ++++++- requirements_all.txt | 2 +- tests/components/remote/test_demo.py | 3 ++- tests/components/remote/test_init.py | 3 ++- tests/components/remote/test_kira.py | 4 ++-- 9 files changed, 49 insertions(+), 20 deletions(-) diff --git a/homeassistant/components/remote/__init__.py b/homeassistant/components/remote/__init__.py index 6449015b712..a28ebd666f9 100755 --- a/homeassistant/components/remote/__init__.py +++ b/homeassistant/components/remote/__init__.py @@ -26,6 +26,8 @@ _LOGGER = logging.getLogger(__name__) ATTR_ACTIVITY = 'activity' ATTR_COMMAND = 'command' ATTR_DEVICE = 'device' +ATTR_NUM_REPEATS = 'num_repeats' +ATTR_DELAY_SECS = 'delay_secs' DOMAIN = 'remote' @@ -40,6 +42,9 @@ SCAN_INTERVAL = timedelta(seconds=30) SERVICE_SEND_COMMAND = 'send_command' SERVICE_SYNC = 'sync' +DEFAULT_NUM_REPEATS = '1' +DEFAULT_DELAY_SECS = '0.4' + REMOTE_SERVICE_SCHEMA = vol.Schema({ vol.Required(ATTR_ENTITY_ID): cv.entity_ids, }) @@ -50,7 +55,9 @@ REMOTE_SERVICE_TURN_ON_SCHEMA = REMOTE_SERVICE_SCHEMA.extend({ REMOTE_SERVICE_SEND_COMMAND_SCHEMA = REMOTE_SERVICE_SCHEMA.extend({ vol.Required(ATTR_DEVICE): cv.string, - vol.Required(ATTR_COMMAND): cv.string, + vol.Required(ATTR_COMMAND): vol.All(cv.ensure_list, [cv.string]), + vol.Optional(ATTR_NUM_REPEATS, default=DEFAULT_NUM_REPEATS): cv.string, + vol.Optional(ATTR_DELAY_SECS, default=DEFAULT_DELAY_SECS): cv.string }) @@ -74,11 +81,19 @@ def turn_off(hass, entity_id=None): hass.services.call(DOMAIN, SERVICE_TURN_OFF, data) -def send_command(hass, device, command, entity_id=None): +def send_command(hass, device, command, entity_id=None, + num_repeats=None, delay_secs=None): """Send a command to a device.""" data = {ATTR_DEVICE: str(device), ATTR_COMMAND: command} if entity_id: data[ATTR_ENTITY_ID] = entity_id + + if num_repeats: + data[ATTR_NUM_REPEATS] = num_repeats + + if delay_secs: + data[ATTR_DELAY_SECS] = delay_secs + hass.services.call(DOMAIN, SERVICE_SEND_COMMAND, data) @@ -97,13 +112,16 @@ def async_setup(hass, config): activity_id = service.data.get(ATTR_ACTIVITY) device = service.data.get(ATTR_DEVICE) command = service.data.get(ATTR_COMMAND) + num_repeats = service.data.get(ATTR_NUM_REPEATS) + delay_secs = service.data.get(ATTR_DELAY_SECS) for remote in target_remotes: if service.service == SERVICE_TURN_ON: yield from remote.async_turn_on(activity=activity_id) elif service.service == SERVICE_SEND_COMMAND: yield from remote.async_send_command( - device=device, command=command) + device=device, command=command, + num_repeats=num_repeats, delay_secs=delay_secs) else: yield from remote.async_turn_off() diff --git a/homeassistant/components/remote/harmony.py b/homeassistant/components/remote/harmony.py index 5a1e31bd0df..f0155cc4525 100755 --- a/homeassistant/components/remote/harmony.py +++ b/homeassistant/components/remote/harmony.py @@ -15,11 +15,12 @@ import homeassistant.helpers.config_validation as cv from homeassistant.const import ( CONF_NAME, CONF_HOST, CONF_PORT, ATTR_ENTITY_ID) from homeassistant.components.remote import ( - PLATFORM_SCHEMA, DOMAIN, ATTR_DEVICE, ATTR_COMMAND, ATTR_ACTIVITY) + PLATFORM_SCHEMA, DOMAIN, ATTR_DEVICE, ATTR_COMMAND, + ATTR_ACTIVITY, ATTR_NUM_REPEATS, ATTR_DELAY_SECS) from homeassistant.util import slugify from homeassistant.config import load_yaml_config_file -REQUIREMENTS = ['pyharmony==1.0.12'] +REQUIREMENTS = ['pyharmony==1.0.16'] _LOGGER = logging.getLogger(__name__) @@ -170,11 +171,12 @@ class HarmonyRemote(remote.RemoteDevice): pyharmony.ha_power_off(self._token, self._ip, self._port) def send_command(self, **kwargs): - """Send a command to one device.""" + """Send a set of commands to one device.""" import pyharmony - pyharmony.ha_send_command( + pyharmony.ha_send_commands( self._token, self._ip, self._port, kwargs[ATTR_DEVICE], - kwargs[ATTR_COMMAND]) + kwargs[ATTR_COMMAND], int(kwargs[ATTR_NUM_REPEATS]), + float(kwargs[ATTR_DELAY_SECS])) def sync(self): """Sync the Harmony device with the web service.""" diff --git a/homeassistant/components/remote/itach.py b/homeassistant/components/remote/itach.py index fa424576a11..e5a013a5dcf 100644 --- a/homeassistant/components/remote/itach.py +++ b/homeassistant/components/remote/itach.py @@ -104,7 +104,8 @@ class ITachIP2IRRemote(remote.RemoteDevice): def send_command(self, **kwargs): """Send a command to one device.""" - self.itachip2ir.send(self._name, kwargs[ATTR_COMMAND], 1) + for command in kwargs[ATTR_COMMAND]: + self.itachip2ir.send(self._name, command, 1) def update(self): """Update the device.""" diff --git a/homeassistant/components/remote/kira.py b/homeassistant/components/remote/kira.py index 3e816844a35..7ab73068cdb 100755 --- a/homeassistant/components/remote/kira.py +++ b/homeassistant/components/remote/kira.py @@ -64,11 +64,11 @@ class KiraRemote(Entity): def send_command(self, **kwargs): """Send a command to one device.""" - code_tuple = (kwargs.get(remote.ATTR_COMMAND), - kwargs.get(remote.ATTR_DEVICE)) - _LOGGER.info("Sending Command: %s to %s", *code_tuple) - - self._kira.sendCode(code_tuple) + for command in kwargs.get(remote.ATTR_COMMAND): + code_tuple = (command, + kwargs.get(remote.ATTR_DEVICE)) + _LOGGER.info("Sending Command: %s to %s", *code_tuple) + self._kira.sendCode(code_tuple) def async_send_command(self, **kwargs): """Send a command to a device. diff --git a/homeassistant/components/remote/services.yaml b/homeassistant/components/remote/services.yaml index 189377c503f..ff9cc3d3b16 100644 --- a/homeassistant/components/remote/services.yaml +++ b/homeassistant/components/remote/services.yaml @@ -30,8 +30,14 @@ send_command: description: Device ID to send command to example: '32756745' command: - description: Command to send + description: A single command or a list of commands to send. example: 'Play' + num_repeats: + description: An optional value that specifies the number of times you want to repeat the command(s). If not specified, the command(s) will not be repeated + example: '5' + delay_secs: + description: An optional value that specifies that number of seconds you want to wait in between repeated commands. If not specified, the default of 0.4 seconds will be used + example: '0.75' harmony_sync: description: Syncs the remote's configuration diff --git a/requirements_all.txt b/requirements_all.txt index 61bb7d82d72..7530489efd9 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -539,7 +539,7 @@ pyfttt==0.3 pygatt==3.1.1 # homeassistant.components.remote.harmony -pyharmony==1.0.12 +pyharmony==1.0.16 # homeassistant.components.binary_sensor.hikvision pyhik==0.1.2 diff --git a/tests/components/remote/test_demo.py b/tests/components/remote/test_demo.py index 0ede5d52a35..0c6fada4748 100755 --- a/tests/components/remote/test_demo.py +++ b/tests/components/remote/test_demo.py @@ -86,7 +86,8 @@ class TestDemoRemote(unittest.TestCase): remote.send_command( self.hass, entity_id='entity_id_val', - device='test_device', command='test_command') + device='test_device', command=['test_command'], + num_repeats='2', delay_secs='0.8') self.hass.block_till_done() diff --git a/tests/components/remote/test_init.py b/tests/components/remote/test_init.py index 2cdbf9d9045..b4d2ff98688 100755 --- a/tests/components/remote/test_init.py +++ b/tests/components/remote/test_init.py @@ -81,7 +81,8 @@ class TestRemote(unittest.TestCase): remote.send_command( self.hass, entity_id='entity_id_val', - device='test_device', command='test_command') + device='test_device', command=['test_command'], + num_repeats='4', delay_secs='0.6') self.hass.block_till_done() diff --git a/tests/components/remote/test_kira.py b/tests/components/remote/test_kira.py index 144504f8aa2..eaa78d44a60 100644 --- a/tests/components/remote/test_kira.py +++ b/tests/components/remote/test_kira.py @@ -49,9 +49,9 @@ class TestKiraSensor(unittest.TestCase): assert remote.name == 'kira' - command = "FAKE_COMMAND" + command = ["FAKE_COMMAND"] device = "FAKE_DEVICE" - commandTuple = (command, device) + commandTuple = (command[0], device) remote.send_command(device=device, command=command) self.mock_kira.sendCode.assert_called_with(commandTuple)