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
This commit is contained in:
everix1992 2017-05-23 19:00:52 -05:00 committed by Paulus Schoutsen
parent 54c45f80c1
commit 3638b21bcb
9 changed files with 49 additions and 20 deletions

View File

@ -26,6 +26,8 @@ _LOGGER = logging.getLogger(__name__)
ATTR_ACTIVITY = 'activity' ATTR_ACTIVITY = 'activity'
ATTR_COMMAND = 'command' ATTR_COMMAND = 'command'
ATTR_DEVICE = 'device' ATTR_DEVICE = 'device'
ATTR_NUM_REPEATS = 'num_repeats'
ATTR_DELAY_SECS = 'delay_secs'
DOMAIN = 'remote' DOMAIN = 'remote'
@ -40,6 +42,9 @@ SCAN_INTERVAL = timedelta(seconds=30)
SERVICE_SEND_COMMAND = 'send_command' SERVICE_SEND_COMMAND = 'send_command'
SERVICE_SYNC = 'sync' SERVICE_SYNC = 'sync'
DEFAULT_NUM_REPEATS = '1'
DEFAULT_DELAY_SECS = '0.4'
REMOTE_SERVICE_SCHEMA = vol.Schema({ REMOTE_SERVICE_SCHEMA = vol.Schema({
vol.Required(ATTR_ENTITY_ID): cv.entity_ids, 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({ REMOTE_SERVICE_SEND_COMMAND_SCHEMA = REMOTE_SERVICE_SCHEMA.extend({
vol.Required(ATTR_DEVICE): cv.string, 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) 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.""" """Send a command to a device."""
data = {ATTR_DEVICE: str(device), ATTR_COMMAND: command} data = {ATTR_DEVICE: str(device), ATTR_COMMAND: command}
if entity_id: if entity_id:
data[ATTR_ENTITY_ID] = 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) hass.services.call(DOMAIN, SERVICE_SEND_COMMAND, data)
@ -97,13 +112,16 @@ def async_setup(hass, config):
activity_id = service.data.get(ATTR_ACTIVITY) activity_id = service.data.get(ATTR_ACTIVITY)
device = service.data.get(ATTR_DEVICE) device = service.data.get(ATTR_DEVICE)
command = service.data.get(ATTR_COMMAND) 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: for remote in target_remotes:
if service.service == SERVICE_TURN_ON: if service.service == SERVICE_TURN_ON:
yield from remote.async_turn_on(activity=activity_id) yield from remote.async_turn_on(activity=activity_id)
elif service.service == SERVICE_SEND_COMMAND: elif service.service == SERVICE_SEND_COMMAND:
yield from remote.async_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: else:
yield from remote.async_turn_off() yield from remote.async_turn_off()

View File

@ -15,11 +15,12 @@ import homeassistant.helpers.config_validation as cv
from homeassistant.const import ( from homeassistant.const import (
CONF_NAME, CONF_HOST, CONF_PORT, ATTR_ENTITY_ID) CONF_NAME, CONF_HOST, CONF_PORT, ATTR_ENTITY_ID)
from homeassistant.components.remote import ( 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.util import slugify
from homeassistant.config import load_yaml_config_file from homeassistant.config import load_yaml_config_file
REQUIREMENTS = ['pyharmony==1.0.12'] REQUIREMENTS = ['pyharmony==1.0.16']
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -170,11 +171,12 @@ class HarmonyRemote(remote.RemoteDevice):
pyharmony.ha_power_off(self._token, self._ip, self._port) pyharmony.ha_power_off(self._token, self._ip, self._port)
def send_command(self, **kwargs): def send_command(self, **kwargs):
"""Send a command to one device.""" """Send a set of commands to one device."""
import pyharmony import pyharmony
pyharmony.ha_send_command( pyharmony.ha_send_commands(
self._token, self._ip, self._port, kwargs[ATTR_DEVICE], 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): def sync(self):
"""Sync the Harmony device with the web service.""" """Sync the Harmony device with the web service."""

View File

@ -104,7 +104,8 @@ class ITachIP2IRRemote(remote.RemoteDevice):
def send_command(self, **kwargs): def send_command(self, **kwargs):
"""Send a command to one device.""" """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): def update(self):
"""Update the device.""" """Update the device."""

View File

@ -64,10 +64,10 @@ class KiraRemote(Entity):
def send_command(self, **kwargs): def send_command(self, **kwargs):
"""Send a command to one device.""" """Send a command to one device."""
code_tuple = (kwargs.get(remote.ATTR_COMMAND), for command in kwargs.get(remote.ATTR_COMMAND):
code_tuple = (command,
kwargs.get(remote.ATTR_DEVICE)) kwargs.get(remote.ATTR_DEVICE))
_LOGGER.info("Sending Command: %s to %s", *code_tuple) _LOGGER.info("Sending Command: %s to %s", *code_tuple)
self._kira.sendCode(code_tuple) self._kira.sendCode(code_tuple)
def async_send_command(self, **kwargs): def async_send_command(self, **kwargs):

View File

@ -30,8 +30,14 @@ send_command:
description: Device ID to send command to description: Device ID to send command to
example: '32756745' example: '32756745'
command: command:
description: Command to send description: A single command or a list of commands to send.
example: 'Play' 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: harmony_sync:
description: Syncs the remote's configuration description: Syncs the remote's configuration

View File

@ -539,7 +539,7 @@ pyfttt==0.3
pygatt==3.1.1 pygatt==3.1.1
# homeassistant.components.remote.harmony # homeassistant.components.remote.harmony
pyharmony==1.0.12 pyharmony==1.0.16
# homeassistant.components.binary_sensor.hikvision # homeassistant.components.binary_sensor.hikvision
pyhik==0.1.2 pyhik==0.1.2

View File

@ -86,7 +86,8 @@ class TestDemoRemote(unittest.TestCase):
remote.send_command( remote.send_command(
self.hass, entity_id='entity_id_val', 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() self.hass.block_till_done()

View File

@ -81,7 +81,8 @@ class TestRemote(unittest.TestCase):
remote.send_command( remote.send_command(
self.hass, entity_id='entity_id_val', 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() self.hass.block_till_done()

View File

@ -49,9 +49,9 @@ class TestKiraSensor(unittest.TestCase):
assert remote.name == 'kira' assert remote.name == 'kira'
command = "FAKE_COMMAND" command = ["FAKE_COMMAND"]
device = "FAKE_DEVICE" device = "FAKE_DEVICE"
commandTuple = (command, device) commandTuple = (command[0], device)
remote.send_command(device=device, command=command) remote.send_command(device=device, command=command)
self.mock_kira.sendCode.assert_called_with(commandTuple) self.mock_kira.sendCode.assert_called_with(commandTuple)