Align switch group handling with light. (#7577)

This commit is contained in:
Johan Bloemberg 2017-06-02 09:05:34 +02:00 committed by Paulus Schoutsen
parent 2b70b1881a
commit d472d81538
3 changed files with 195 additions and 42 deletions

View File

@ -9,8 +9,10 @@ import logging
from homeassistant.components.rflink import (
CONF_ALIASSES, CONF_DEVICE_DEFAULTS, CONF_DEVICES, CONF_FIRE_EVENT,
CONF_SIGNAL_REPETITIONS, DATA_ENTITY_LOOKUP, DEVICE_DEFAULTS_SCHEMA,
DOMAIN, EVENT_KEY_COMMAND, SwitchableRflinkDevice, cv, vol)
CONF_GROUP, CONF_GROUP_ALIASSES, CONF_NOGROUP_ALIASSES,
CONF_SIGNAL_REPETITIONS, DATA_ENTITY_GROUP_LOOKUP, DATA_ENTITY_LOOKUP,
DEVICE_DEFAULTS_SCHEMA, DOMAIN, EVENT_KEY_COMMAND, SwitchableRflinkDevice,
cv, vol)
from homeassistant.components.switch import SwitchDevice
from homeassistant.const import CONF_NAME, CONF_PLATFORM
@ -27,8 +29,13 @@ PLATFORM_SCHEMA = vol.Schema({
vol.Optional(CONF_NAME): cv.string,
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,
},
}),
})
@ -43,9 +50,26 @@ def devices_from_config(domain_config, hass=None):
devices.append(device)
# Register entity (and aliasses) to listen to incoming rflink events
for _id in config[CONF_ALIASSES] + [device_id]:
# 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)
return devices

View File

@ -53,7 +53,7 @@ def test_default_setup(hass, monkeypatch):
assert create.call_args_list[0][1]['ignore']
# test default state of light loaded from config
light_initial = hass.states.get('light.test')
light_initial = hass.states.get(DOMAIN + '.test')
assert light_initial.state == 'off'
assert light_initial.attributes['assumed_state']
@ -67,7 +67,7 @@ def test_default_setup(hass, monkeypatch):
})
yield from hass.async_block_till_done()
light_after_first_command = hass.states.get('light.test')
light_after_first_command = hass.states.get(DOMAIN + '.test')
assert light_after_first_command.state == 'on'
# also after receiving first command state not longer has to be assumed
assert 'assumed_state' not in light_after_first_command.attributes
@ -79,7 +79,7 @@ def test_default_setup(hass, monkeypatch):
})
yield from hass.async_block_till_done()
assert hass.states.get('light.test').state == 'off'
assert hass.states.get(DOMAIN + '.test').state == 'off'
# should repond to group command
event_callback({
@ -88,7 +88,7 @@ def test_default_setup(hass, monkeypatch):
})
yield from hass.async_block_till_done()
light_after_first_command = hass.states.get('light.test')
light_after_first_command = hass.states.get(DOMAIN + '.test')
assert light_after_first_command.state == 'on'
# should repond to group command
@ -98,7 +98,7 @@ def test_default_setup(hass, monkeypatch):
})
yield from hass.async_block_till_done()
assert hass.states.get('light.test').state == 'off'
assert hass.states.get(DOMAIN + '.test').state == 'off'
# test following aliasses
# mock incoming command event for this device alias
@ -108,7 +108,7 @@ def test_default_setup(hass, monkeypatch):
})
yield from hass.async_block_till_done()
assert hass.states.get('light.test').state == 'on'
assert hass.states.get(DOMAIN + '.test').state == 'on'
# test event for new unconfigured sensor
event_callback({
@ -117,22 +117,22 @@ def test_default_setup(hass, monkeypatch):
})
yield from hass.async_block_till_done()
assert hass.states.get('light.protocol2_0_1').state == 'on'
assert hass.states.get(DOMAIN + '.protocol2_0_1').state == 'on'
# test changing state from HA propagates to Rflink
hass.async_add_job(
hass.services.async_call(DOMAIN, SERVICE_TURN_OFF,
{ATTR_ENTITY_ID: 'light.test'}))
{ATTR_ENTITY_ID: DOMAIN + '.test'}))
yield from hass.async_block_till_done()
assert hass.states.get('light.test').state == 'off'
assert hass.states.get(DOMAIN + '.test').state == 'off'
assert protocol.send_command_ack.call_args_list[0][0][0] == 'protocol_0_0'
assert protocol.send_command_ack.call_args_list[0][0][1] == 'off'
hass.async_add_job(
hass.services.async_call(DOMAIN, SERVICE_TURN_ON,
{ATTR_ENTITY_ID: 'light.test'}))
{ATTR_ENTITY_ID: DOMAIN + '.test'}))
yield from hass.async_block_till_done()
assert hass.states.get('light.test').state == 'on'
assert hass.states.get(DOMAIN + '.test').state == 'on'
assert protocol.send_command_ack.call_args_list[1][0][1] == 'on'
# protocols supporting dimming and on/off should create hybrid light entity
@ -143,7 +143,7 @@ def test_default_setup(hass, monkeypatch):
yield from hass.async_block_till_done()
hass.async_add_job(
hass.services.async_call(DOMAIN, SERVICE_TURN_ON,
{ATTR_ENTITY_ID: 'light.newkaku_0_1'}))
{ATTR_ENTITY_ID: DOMAIN + '.newkaku_0_1'}))
yield from hass.async_block_till_done()
# dimmable should send highest dim level when turning on
@ -155,7 +155,7 @@ def test_default_setup(hass, monkeypatch):
hass.async_add_job(
hass.services.async_call(DOMAIN, SERVICE_TURN_ON,
{
ATTR_ENTITY_ID: 'light.newkaku_0_1',
ATTR_ENTITY_ID: DOMAIN + '.newkaku_0_1',
ATTR_BRIGHTNESS: 128,
}))
yield from hass.async_block_till_done()
@ -165,7 +165,7 @@ def test_default_setup(hass, monkeypatch):
hass.async_add_job(
hass.services.async_call(DOMAIN, SERVICE_TURN_ON,
{
ATTR_ENTITY_ID: 'light.dim_test',
ATTR_ENTITY_ID: DOMAIN + '.dim_test',
ATTR_BRIGHTNESS: 128,
}))
yield from hass.async_block_till_done()
@ -210,7 +210,7 @@ def test_firing_bus_event(hass, monkeypatch):
})
yield from hass.async_block_till_done()
assert calls[0].data == {'state': 'off', 'entity_id': 'light.test'}
assert calls[0].data == {'state': 'off', 'entity_id': DOMAIN + '.test'}
@asyncio.coroutine
@ -247,7 +247,7 @@ def test_signal_repetitions(hass, monkeypatch):
# test if signal repetition is performed according to configuration
hass.async_add_job(
hass.services.async_call(DOMAIN, SERVICE_TURN_OFF,
{ATTR_ENTITY_ID: 'light.test'}))
{ATTR_ENTITY_ID: DOMAIN + '.test'}))
# wait for commands and repetitions to finish
yield from hass.async_block_till_done()
@ -257,7 +257,7 @@ def test_signal_repetitions(hass, monkeypatch):
# test if default apply to configured devcies
hass.async_add_job(
hass.services.async_call(DOMAIN, SERVICE_TURN_OFF,
{ATTR_ENTITY_ID: 'light.test1'}))
{ATTR_ENTITY_ID: DOMAIN + '.test1'}))
# wait for commands and repetitions to finish
yield from hass.async_block_till_done()
@ -275,7 +275,7 @@ def test_signal_repetitions(hass, monkeypatch):
hass.async_add_job(
hass.services.async_call(DOMAIN, SERVICE_TURN_OFF,
{ATTR_ENTITY_ID: 'light.protocol_0_2'}))
{ATTR_ENTITY_ID: DOMAIN + '.protocol_0_2'}))
# wait for commands and repetitions to finish
yield from hass.async_block_till_done()
@ -311,10 +311,10 @@ def test_signal_repetitions_alternation(hass, monkeypatch):
hass.async_add_job(
hass.services.async_call(DOMAIN, SERVICE_TURN_OFF,
{ATTR_ENTITY_ID: 'light.test'}))
{ATTR_ENTITY_ID: DOMAIN + '.test'}))
hass.async_add_job(
hass.services.async_call(DOMAIN, SERVICE_TURN_OFF,
{ATTR_ENTITY_ID: 'light.test1'}))
{ATTR_ENTITY_ID: DOMAIN + '.test1'}))
yield from hass.async_block_till_done()
@ -348,11 +348,11 @@ def test_signal_repetitions_cancelling(hass, monkeypatch):
hass.async_add_job(
hass.services.async_call(DOMAIN, SERVICE_TURN_OFF,
{ATTR_ENTITY_ID: 'light.test'}))
{ATTR_ENTITY_ID: DOMAIN + '.test'}))
hass.async_add_job(
hass.services.async_call(DOMAIN, SERVICE_TURN_ON,
{ATTR_ENTITY_ID: 'light.test'}))
{ATTR_ENTITY_ID: DOMAIN + '.test'}))
yield from hass.async_block_till_done()
@ -385,7 +385,7 @@ def test_type_toggle(hass, monkeypatch):
event_callback, _, _, _ = yield from mock_rflink(
hass, config, DOMAIN, monkeypatch)
assert hass.states.get('light.toggle_test').state == 'off'
assert hass.states.get(DOMAIN + '.toggle_test').state == 'off'
# test sending on command to toggle alias
event_callback({
@ -394,7 +394,7 @@ def test_type_toggle(hass, monkeypatch):
})
yield from hass.async_block_till_done()
assert hass.states.get('light.toggle_test').state == 'on'
assert hass.states.get(DOMAIN + '.toggle_test').state == 'on'
# test sending group command to group alias
event_callback({
@ -403,7 +403,7 @@ def test_type_toggle(hass, monkeypatch):
})
yield from hass.async_block_till_done()
assert hass.states.get('light.toggle_test').state == 'off'
assert hass.states.get(DOMAIN + '.toggle_test').state == 'off'
@asyncio.coroutine
@ -428,7 +428,7 @@ def test_group_alias(hass, monkeypatch):
event_callback, _, _, _ = yield from mock_rflink(
hass, config, DOMAIN, monkeypatch)
assert hass.states.get('light.test').state == 'off'
assert hass.states.get(DOMAIN + '.test').state == 'off'
# test sending group command to group alias
event_callback({
@ -437,7 +437,7 @@ def test_group_alias(hass, monkeypatch):
})
yield from hass.async_block_till_done()
assert hass.states.get('light.test').state == 'on'
assert hass.states.get(DOMAIN + '.test').state == 'on'
# test sending group command to group alias
event_callback({
@ -446,7 +446,7 @@ def test_group_alias(hass, monkeypatch):
})
yield from hass.async_block_till_done()
assert hass.states.get('light.test').state == 'on'
assert hass.states.get(DOMAIN + '.test').state == 'on'
@asyncio.coroutine
@ -471,7 +471,7 @@ def test_nogroup_alias(hass, monkeypatch):
event_callback, _, _, _ = yield from mock_rflink(
hass, config, DOMAIN, monkeypatch)
assert hass.states.get('light.test').state == 'off'
assert hass.states.get(DOMAIN + '.test').state == 'off'
# test sending group command to nogroup alias
event_callback({
@ -480,7 +480,7 @@ def test_nogroup_alias(hass, monkeypatch):
})
yield from hass.async_block_till_done()
# should not affect state
assert hass.states.get('light.test').state == 'off'
assert hass.states.get(DOMAIN + '.test').state == 'off'
# test sending group command to nogroup alias
event_callback({
@ -489,7 +489,7 @@ def test_nogroup_alias(hass, monkeypatch):
})
yield from hass.async_block_till_done()
# should affect state
assert hass.states.get('light.test').state == 'on'
assert hass.states.get(DOMAIN + '.test').state == 'on'
@asyncio.coroutine
@ -514,7 +514,7 @@ def test_nogroup_device_id(hass, monkeypatch):
event_callback, _, _, _ = yield from mock_rflink(
hass, config, DOMAIN, monkeypatch)
assert hass.states.get('light.test').state == 'off'
assert hass.states.get(DOMAIN + '.test').state == 'off'
# test sending group command to nogroup
event_callback({
@ -523,7 +523,7 @@ def test_nogroup_device_id(hass, monkeypatch):
})
yield from hass.async_block_till_done()
# should not affect state
assert hass.states.get('light.test').state == 'off'
assert hass.states.get(DOMAIN + '.test').state == 'off'
# test sending group command to nogroup
event_callback({
@ -532,7 +532,7 @@ def test_nogroup_device_id(hass, monkeypatch):
})
yield from hass.async_block_till_done()
# should affect state
assert hass.states.get('light.test').state == 'on'
assert hass.states.get(DOMAIN + '.test').state == 'on'
@asyncio.coroutine
@ -560,4 +560,4 @@ def test_disable_automatic_add(hass, monkeypatch):
yield from hass.async_block_till_done()
# make sure new device is not added
assert not hass.states.get('light.protocol_0_0')
assert not hass.states.get(DOMAIN + '.protocol_0_0')

View File

@ -86,15 +86,144 @@ def test_default_setup(hass, monkeypatch):
# test changing state from HA propagates to Rflink
hass.async_add_job(
hass.services.async_call(DOMAIN, SERVICE_TURN_OFF,
{ATTR_ENTITY_ID: 'switch.test'}))
{ATTR_ENTITY_ID: DOMAIN + '.test'}))
yield from hass.async_block_till_done()
assert hass.states.get('switch.test').state == 'off'
assert hass.states.get(DOMAIN + '.test').state == 'off'
assert protocol.send_command_ack.call_args_list[0][0][0] == 'protocol_0_0'
assert protocol.send_command_ack.call_args_list[0][0][1] == 'off'
hass.async_add_job(
hass.services.async_call(DOMAIN, SERVICE_TURN_ON,
{ATTR_ENTITY_ID: 'switch.test'}))
{ATTR_ENTITY_ID: DOMAIN + '.test'}))
yield from hass.async_block_till_done()
assert hass.states.get('switch.test').state == 'on'
assert hass.states.get(DOMAIN + '.test').state == 'on'
assert protocol.send_command_ack.call_args_list[1][0][1] == 'on'
@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(DOMAIN + '.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(DOMAIN + '.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(DOMAIN + '.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(DOMAIN + '.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(DOMAIN + '.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(DOMAIN + '.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(DOMAIN + '.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(DOMAIN + '.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(DOMAIN + '.test').state == 'on'