mirror of
https://github.com/home-assistant/core.git
synced 2025-07-22 04:37:06 +00:00
Rflink group commands (#5969)
* Add support for group commands (allon/alloff). Add 'group_aliasses' config attribute that only respond to group commands. Add nogroup_aliases that only respond to 'on' 'off' commands. Allow settings device id group behaviour. * Fix linting. * Fix lint.
This commit is contained in:
parent
63c15e997a
commit
e1ed076015
@ -11,11 +11,13 @@ from homeassistant.components.light import (
|
||||
ATTR_BRIGHTNESS, SUPPORT_BRIGHTNESS, Light)
|
||||
from homeassistant.components.rflink import (
|
||||
CONF_ALIASSES, CONF_DEVICE_DEFAULTS, CONF_DEVICES, CONF_FIRE_EVENT,
|
||||
CONF_IGNORE_DEVICES, CONF_SIGNAL_REPETITIONS, DATA_DEVICE_REGISTER,
|
||||
DATA_ENTITY_LOOKUP, DEVICE_DEFAULTS_SCHEMA, DOMAIN,
|
||||
EVENT_KEY_COMMAND, EVENT_KEY_ID, SwitchableRflinkDevice, cv, vol)
|
||||
CONF_GROUP, CONF_GROUP_ALIASSES, CONF_IGNORE_DEVICES,
|
||||
CONF_NOGROUP_ALIASSES, CONF_SIGNAL_REPETITIONS, DATA_DEVICE_REGISTER,
|
||||
DATA_ENTITY_GROUP_LOOKUP, DATA_ENTITY_LOOKUP, DEVICE_DEFAULTS_SCHEMA,
|
||||
DOMAIN, EVENT_KEY_COMMAND, EVENT_KEY_ID, SwitchableRflinkDevice, cv, vol)
|
||||
from homeassistant.const import (
|
||||
CONF_NAME, CONF_PLATFORM, CONF_TYPE, STATE_UNKNOWN)
|
||||
|
||||
DEPENDENCIES = ['rflink']
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
@ -38,8 +40,13 @@ PLATFORM_SCHEMA = vol.Schema({
|
||||
TYPE_HYBRID, TYPE_TOGGLE),
|
||||
vol.Optional(CONF_ALIASSES, default=[]):
|
||||
vol.All(cv.ensure_list, [cv.string]),
|
||||
vol.Optional(CONF_GROUP_ALIASSES, default=[]):
|
||||
vol.All(cv.ensure_list, [cv.string]),
|
||||
vol.Optional(CONF_NOGROUP_ALIASSES, default=[]):
|
||||
vol.All(cv.ensure_list, [cv.string]),
|
||||
vol.Optional(CONF_FIRE_EVENT, default=False): cv.boolean,
|
||||
vol.Optional(CONF_SIGNAL_REPETITIONS): vol.Coerce(int),
|
||||
vol.Optional(CONF_GROUP, default=True): cv.boolean,
|
||||
},
|
||||
}),
|
||||
})
|
||||
@ -110,7 +117,24 @@ def devices_from_config(domain_config, hass=None):
|
||||
devices.append(device)
|
||||
|
||||
# Register entity (and aliasses) to listen to incoming rflink events
|
||||
for _id in [device_id] + config[CONF_ALIASSES]:
|
||||
|
||||
# device id and normal aliasses respond to normal and group command
|
||||
hass.data[DATA_ENTITY_LOOKUP][
|
||||
EVENT_KEY_COMMAND][device_id].append(device)
|
||||
if config[CONF_GROUP]:
|
||||
hass.data[DATA_ENTITY_GROUP_LOOKUP][
|
||||
EVENT_KEY_COMMAND][device_id].append(device)
|
||||
for _id in config[CONF_ALIASSES]:
|
||||
hass.data[DATA_ENTITY_LOOKUP][
|
||||
EVENT_KEY_COMMAND][_id].append(device)
|
||||
hass.data[DATA_ENTITY_GROUP_LOOKUP][
|
||||
EVENT_KEY_COMMAND][_id].append(device)
|
||||
# group_aliasses only respond to group commands
|
||||
for _id in config[CONF_GROUP_ALIASSES]:
|
||||
hass.data[DATA_ENTITY_GROUP_LOOKUP][
|
||||
EVENT_KEY_COMMAND][_id].append(device)
|
||||
# nogroup_aliasses only respond to normal commands
|
||||
for _id in config[CONF_NOGROUP_ALIASSES]:
|
||||
hass.data[DATA_ENTITY_LOOKUP][
|
||||
EVENT_KEY_COMMAND][_id].append(device)
|
||||
|
||||
|
@ -20,7 +20,7 @@ from homeassistant.exceptions import HomeAssistantError
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.helpers.entity import Entity
|
||||
|
||||
REQUIREMENTS = ['rflink==0.0.28']
|
||||
REQUIREMENTS = ['rflink==0.0.31']
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
@ -28,6 +28,9 @@ ATTR_EVENT = 'event'
|
||||
ATTR_STATE = 'state'
|
||||
|
||||
CONF_ALIASSES = 'aliasses'
|
||||
CONF_GROUP_ALIASSES = 'group_aliasses'
|
||||
CONF_GROUP = 'group'
|
||||
CONF_NOGROUP_ALIASSES = 'nogroup_aliasses'
|
||||
CONF_DEVICE_DEFAULTS = 'device_defaults'
|
||||
CONF_DEVICES = 'devices'
|
||||
CONF_FIRE_EVENT = 'fire_event'
|
||||
@ -38,6 +41,7 @@ CONF_WAIT_FOR_ACK = 'wait_for_ack'
|
||||
|
||||
DATA_DEVICE_REGISTER = 'rflink_device_register'
|
||||
DATA_ENTITY_LOOKUP = 'rflink_entity_lookup'
|
||||
DATA_ENTITY_GROUP_LOOKUP = 'rflink_entity_group_only_lookup'
|
||||
DEFAULT_RECONNECT_INTERVAL = 10
|
||||
DEFAULT_SIGNAL_REPETITIONS = 1
|
||||
CONNECTION_TIMEOUT = 10
|
||||
@ -48,6 +52,8 @@ EVENT_KEY_ID = 'id'
|
||||
EVENT_KEY_SENSOR = 'sensor'
|
||||
EVENT_KEY_UNIT = 'unit'
|
||||
|
||||
RFLINK_GROUP_COMMANDS = ['allon', 'alloff']
|
||||
|
||||
DOMAIN = 'rflink'
|
||||
|
||||
DEVICE_DEFAULTS_SCHEMA = vol.Schema({
|
||||
@ -94,6 +100,10 @@ def async_setup(hass, config):
|
||||
EVENT_KEY_COMMAND: defaultdict(list),
|
||||
EVENT_KEY_SENSOR: defaultdict(list),
|
||||
}
|
||||
hass.data[DATA_ENTITY_GROUP_LOOKUP] = {
|
||||
EVENT_KEY_COMMAND: defaultdict(list),
|
||||
EVENT_KEY_SENSOR: defaultdict(list),
|
||||
}
|
||||
|
||||
# Allow platform to specify function to register new unknown devices
|
||||
hass.data[DATA_DEVICE_REGISTER] = {}
|
||||
@ -116,7 +126,14 @@ def async_setup(hass, config):
|
||||
|
||||
# Lookup entities who registered this device id as device id or alias
|
||||
event_id = event.get('id', None)
|
||||
entities = hass.data[DATA_ENTITY_LOOKUP][event_type][event_id]
|
||||
|
||||
is_group_event = (event_type == EVENT_KEY_COMMAND and
|
||||
event[EVENT_KEY_COMMAND] in RFLINK_GROUP_COMMANDS)
|
||||
if is_group_event:
|
||||
entities = hass.data[DATA_ENTITY_GROUP_LOOKUP][event_type].get(
|
||||
event_id, [])
|
||||
else:
|
||||
entities = hass.data[DATA_ENTITY_LOOKUP][event_type][event_id]
|
||||
|
||||
if entities:
|
||||
# Propagate event to every entity matching the device id
|
||||
@ -202,8 +219,8 @@ class RflinkDevice(Entity):
|
||||
platform = None
|
||||
_state = STATE_UNKNOWN
|
||||
|
||||
def __init__(self, device_id, hass, name=None,
|
||||
aliasses=None, fire_event=False,
|
||||
def __init__(self, device_id, hass, name=None, aliasses=None, group=True,
|
||||
group_aliasses=None, nogroup_aliasses=None, fire_event=False,
|
||||
signal_repetitions=DEFAULT_SIGNAL_REPETITIONS):
|
||||
"""Initialize the device."""
|
||||
self.hass = hass
|
||||
@ -215,12 +232,6 @@ class RflinkDevice(Entity):
|
||||
else:
|
||||
self._name = device_id
|
||||
|
||||
# Generate list of device_ids to match against
|
||||
if aliasses:
|
||||
self._aliasses = aliasses
|
||||
else:
|
||||
self._aliasses = []
|
||||
|
||||
self._should_fire_event = fire_event
|
||||
self._signal_repetitions = signal_repetitions
|
||||
|
||||
@ -375,9 +386,9 @@ class SwitchableRflinkDevice(RflinkCommand):
|
||||
self.cancel_queued_send_commands()
|
||||
|
||||
command = event['command']
|
||||
if command == 'on':
|
||||
if command in ['on', 'allon']:
|
||||
self._state = True
|
||||
elif command == 'off':
|
||||
elif command in ['off', 'alloff']:
|
||||
self._state = False
|
||||
|
||||
def async_turn_on(self, **kwargs):
|
||||
|
@ -659,7 +659,7 @@ qnapstats==0.2.3
|
||||
radiotherm==1.2
|
||||
|
||||
# homeassistant.components.rflink
|
||||
rflink==0.0.28
|
||||
rflink==0.0.31
|
||||
|
||||
# homeassistant.components.sensor.ring
|
||||
ring_doorbell==0.1.0
|
||||
|
@ -81,6 +81,25 @@ def test_default_setup(hass, monkeypatch):
|
||||
|
||||
assert hass.states.get('light.test').state == 'off'
|
||||
|
||||
# should repond to group command
|
||||
event_callback({
|
||||
'id': 'protocol_0_0',
|
||||
'command': 'allon',
|
||||
})
|
||||
yield from hass.async_block_till_done()
|
||||
|
||||
light_after_first_command = hass.states.get('light.test')
|
||||
assert light_after_first_command.state == 'on'
|
||||
|
||||
# should repond to group command
|
||||
event_callback({
|
||||
'id': 'protocol_0_0',
|
||||
'command': 'alloff',
|
||||
})
|
||||
yield from hass.async_block_till_done()
|
||||
|
||||
assert hass.states.get('light.test').state == 'off'
|
||||
|
||||
# test following aliasses
|
||||
# mock incoming command event for this device alias
|
||||
event_callback({
|
||||
@ -385,3 +404,132 @@ def test_type_toggle(hass, monkeypatch):
|
||||
yield from hass.async_block_till_done()
|
||||
|
||||
assert hass.states.get('light.toggle_test').state == 'off'
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
def test_group_alias(hass, monkeypatch):
|
||||
"""Group aliases should only respond to group commands (allon/alloff)."""
|
||||
config = {
|
||||
'rflink': {
|
||||
'port': '/dev/ttyABC0',
|
||||
},
|
||||
DOMAIN: {
|
||||
'platform': 'rflink',
|
||||
'devices': {
|
||||
'protocol_0_0': {
|
||||
'name': 'test',
|
||||
'group_aliasses': ['test_group_0_0'],
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
# setup mocking rflink module
|
||||
event_callback, _, _, _ = yield from mock_rflink(
|
||||
hass, config, DOMAIN, monkeypatch)
|
||||
|
||||
assert hass.states.get('light.test').state == 'off'
|
||||
|
||||
# test sending group command to group alias
|
||||
event_callback({
|
||||
'id': 'test_group_0_0',
|
||||
'command': 'allon',
|
||||
})
|
||||
yield from hass.async_block_till_done()
|
||||
|
||||
assert hass.states.get('light.test').state == 'on'
|
||||
|
||||
# test sending group command to group alias
|
||||
event_callback({
|
||||
'id': 'test_group_0_0',
|
||||
'command': 'off',
|
||||
})
|
||||
yield from hass.async_block_till_done()
|
||||
|
||||
assert hass.states.get('light.test').state == 'on'
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
def test_nogroup_alias(hass, monkeypatch):
|
||||
"""Non group aliases should not respond to group commands."""
|
||||
config = {
|
||||
'rflink': {
|
||||
'port': '/dev/ttyABC0',
|
||||
},
|
||||
DOMAIN: {
|
||||
'platform': 'rflink',
|
||||
'devices': {
|
||||
'protocol_0_0': {
|
||||
'name': 'test',
|
||||
'nogroup_aliasses': ['test_nogroup_0_0'],
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
# setup mocking rflink module
|
||||
event_callback, _, _, _ = yield from mock_rflink(
|
||||
hass, config, DOMAIN, monkeypatch)
|
||||
|
||||
assert hass.states.get('light.test').state == 'off'
|
||||
|
||||
# test sending group command to nogroup alias
|
||||
event_callback({
|
||||
'id': 'test_nogroup_0_0',
|
||||
'command': 'allon',
|
||||
})
|
||||
yield from hass.async_block_till_done()
|
||||
# should not affect state
|
||||
assert hass.states.get('light.test').state == 'off'
|
||||
|
||||
# test sending group command to nogroup alias
|
||||
event_callback({
|
||||
'id': 'test_nogroup_0_0',
|
||||
'command': 'on',
|
||||
})
|
||||
yield from hass.async_block_till_done()
|
||||
# should affect state
|
||||
assert hass.states.get('light.test').state == 'on'
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
def test_nogroup_device_id(hass, monkeypatch):
|
||||
"""Device id that do not respond to group commands (allon/alloff)."""
|
||||
config = {
|
||||
'rflink': {
|
||||
'port': '/dev/ttyABC0',
|
||||
},
|
||||
DOMAIN: {
|
||||
'platform': 'rflink',
|
||||
'devices': {
|
||||
'test_nogroup_0_0': {
|
||||
'name': 'test',
|
||||
'group': False,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
# setup mocking rflink module
|
||||
event_callback, _, _, _ = yield from mock_rflink(
|
||||
hass, config, DOMAIN, monkeypatch)
|
||||
|
||||
assert hass.states.get('light.test').state == 'off'
|
||||
|
||||
# test sending group command to nogroup
|
||||
event_callback({
|
||||
'id': 'test_nogroup_0_0',
|
||||
'command': 'allon',
|
||||
})
|
||||
yield from hass.async_block_till_done()
|
||||
# should not affect state
|
||||
assert hass.states.get('light.test').state == 'off'
|
||||
|
||||
# test sending group command to nogroup
|
||||
event_callback({
|
||||
'id': 'test_nogroup_0_0',
|
||||
'command': 'on',
|
||||
})
|
||||
yield from hass.async_block_till_done()
|
||||
# should affect state
|
||||
assert hass.states.get('light.test').state == 'on'
|
||||
|
Loading…
x
Reference in New Issue
Block a user