Rflink: added support for lights with toggle type (#6521)
* added support for lights with toggle type
* fixed style errors
* introduced tests for the toggle type
it's not passing yet because of an assertionerror at line 407
* updated to reflect tristate of "state"
* Format code according to pep8
Added line break for import that was too long.
* fixed lint, replaced if statement with 'var = bool(test)'
* changed implementation of state check according to bug on 6bceb04ca1 (r106758784)
This commit is contained in:
parent
4e91c65d6e
commit
678f273002
3 changed files with 92 additions and 3 deletions
|
@ -14,8 +14,8 @@ from homeassistant.components.rflink import (
|
||||||
CONF_IGNORE_DEVICES, CONF_SIGNAL_REPETITIONS, DATA_DEVICE_REGISTER,
|
CONF_IGNORE_DEVICES, CONF_SIGNAL_REPETITIONS, DATA_DEVICE_REGISTER,
|
||||||
DATA_ENTITY_LOOKUP, DEVICE_DEFAULTS_SCHEMA, DOMAIN,
|
DATA_ENTITY_LOOKUP, DEVICE_DEFAULTS_SCHEMA, DOMAIN,
|
||||||
EVENT_KEY_COMMAND, EVENT_KEY_ID, SwitchableRflinkDevice, cv, vol)
|
EVENT_KEY_COMMAND, EVENT_KEY_ID, SwitchableRflinkDevice, cv, vol)
|
||||||
from homeassistant.const import CONF_NAME, CONF_PLATFORM, CONF_TYPE
|
from homeassistant.const import (
|
||||||
|
CONF_NAME, CONF_PLATFORM, CONF_TYPE, STATE_UNKNOWN)
|
||||||
DEPENDENCIES = ['rflink']
|
DEPENDENCIES = ['rflink']
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
@ -23,6 +23,7 @@ _LOGGER = logging.getLogger(__name__)
|
||||||
TYPE_DIMMABLE = 'dimmable'
|
TYPE_DIMMABLE = 'dimmable'
|
||||||
TYPE_SWITCHABLE = 'switchable'
|
TYPE_SWITCHABLE = 'switchable'
|
||||||
TYPE_HYBRID = 'hybrid'
|
TYPE_HYBRID = 'hybrid'
|
||||||
|
TYPE_TOGGLE = 'toggle'
|
||||||
|
|
||||||
PLATFORM_SCHEMA = vol.Schema({
|
PLATFORM_SCHEMA = vol.Schema({
|
||||||
vol.Required(CONF_PLATFORM): DOMAIN,
|
vol.Required(CONF_PLATFORM): DOMAIN,
|
||||||
|
@ -33,7 +34,8 @@ PLATFORM_SCHEMA = vol.Schema({
|
||||||
cv.string: {
|
cv.string: {
|
||||||
vol.Optional(CONF_NAME): cv.string,
|
vol.Optional(CONF_NAME): cv.string,
|
||||||
vol.Optional(CONF_TYPE):
|
vol.Optional(CONF_TYPE):
|
||||||
vol.Any(TYPE_DIMMABLE, TYPE_SWITCHABLE, TYPE_HYBRID),
|
vol.Any(TYPE_DIMMABLE, TYPE_SWITCHABLE,
|
||||||
|
TYPE_HYBRID, TYPE_TOGGLE),
|
||||||
vol.Optional(CONF_ALIASSES, default=[]):
|
vol.Optional(CONF_ALIASSES, default=[]):
|
||||||
vol.All(cv.ensure_list, [cv.string]),
|
vol.All(cv.ensure_list, [cv.string]),
|
||||||
vol.Optional(CONF_FIRE_EVENT, default=False): cv.boolean,
|
vol.Optional(CONF_FIRE_EVENT, default=False): cv.boolean,
|
||||||
|
@ -71,6 +73,9 @@ def entity_class_for_type(entity_type):
|
||||||
# sends 'dim' and 'on' command to support both dimmers and on/off
|
# sends 'dim' and 'on' command to support both dimmers and on/off
|
||||||
# switches. Not compatible with signal repetition.
|
# switches. Not compatible with signal repetition.
|
||||||
TYPE_HYBRID: HybridRflinkLight,
|
TYPE_HYBRID: HybridRflinkLight,
|
||||||
|
# sends only 'on' commands for switches which turn on and off
|
||||||
|
# using the same 'on' command for both.
|
||||||
|
TYPE_TOGGLE: ToggleRflinkLight,
|
||||||
}
|
}
|
||||||
|
|
||||||
return entity_device_mapping.get(entity_type, RflinkLight)
|
return entity_device_mapping.get(entity_type, RflinkLight)
|
||||||
|
@ -213,3 +218,38 @@ class HybridRflinkLight(SwitchableRflinkDevice, Light):
|
||||||
def supported_features(self):
|
def supported_features(self):
|
||||||
"""Flag supported features."""
|
"""Flag supported features."""
|
||||||
return SUPPORT_BRIGHTNESS
|
return SUPPORT_BRIGHTNESS
|
||||||
|
|
||||||
|
|
||||||
|
class ToggleRflinkLight(SwitchableRflinkDevice, Light):
|
||||||
|
"""Rflink light device which sends out only 'on' commands.
|
||||||
|
|
||||||
|
Some switches like for example Livolo light switches use the
|
||||||
|
same 'on' command to switch on and switch off the lights.
|
||||||
|
If the light is on and 'on' gets sent, the light will turn off
|
||||||
|
and if the light is off and 'on' gets sent, the light will turn on.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@property
|
||||||
|
def entity_id(self):
|
||||||
|
"""Return entity id."""
|
||||||
|
return "light.{}".format(self.name)
|
||||||
|
|
||||||
|
def _handle_event(self, event):
|
||||||
|
"""Adjust state if Rflink picks up a remote command for this device."""
|
||||||
|
self.cancel_queued_send_commands()
|
||||||
|
|
||||||
|
command = event['command']
|
||||||
|
if command == 'on':
|
||||||
|
# if the state is unknown or false, it gets set as true
|
||||||
|
# if the state is true, it gets set as false
|
||||||
|
self._state = self._state in [STATE_UNKNOWN, False]
|
||||||
|
|
||||||
|
@asyncio.coroutine
|
||||||
|
def async_turn_on(self, **kwargs):
|
||||||
|
"""Turn the device on."""
|
||||||
|
yield from self._async_handle_command('toggle')
|
||||||
|
|
||||||
|
@asyncio.coroutine
|
||||||
|
def async_turn_off(self, **kwargs):
|
||||||
|
"""Turn the device off."""
|
||||||
|
yield from self._async_handle_command('toggle')
|
||||||
|
|
|
@ -316,6 +316,12 @@ class RflinkCommand(RflinkDevice):
|
||||||
cmd = str(int(args[0] / 17))
|
cmd = str(int(args[0] / 17))
|
||||||
self._state = True
|
self._state = True
|
||||||
|
|
||||||
|
elif command == 'toggle':
|
||||||
|
cmd = 'on'
|
||||||
|
# if the state is unknown or false, it gets set as true
|
||||||
|
# if the state is true, it gets set as false
|
||||||
|
self._state = self._state in [STATE_UNKNOWN, False]
|
||||||
|
|
||||||
# Send initial command and queue repetitions.
|
# Send initial command and queue repetitions.
|
||||||
# This allows the entity state to be updated quickly and not having to
|
# This allows the entity state to be updated quickly and not having to
|
||||||
# wait for all repetitions to be sent
|
# wait for all repetitions to be sent
|
||||||
|
|
|
@ -342,3 +342,46 @@ def test_signal_repetitions_cancelling(hass, monkeypatch):
|
||||||
assert protocol.send_command_ack.call_args_list[1][0][1] == 'on'
|
assert protocol.send_command_ack.call_args_list[1][0][1] == 'on'
|
||||||
assert protocol.send_command_ack.call_args_list[2][0][1] == 'on'
|
assert protocol.send_command_ack.call_args_list[2][0][1] == 'on'
|
||||||
assert protocol.send_command_ack.call_args_list[3][0][1] == 'on'
|
assert protocol.send_command_ack.call_args_list[3][0][1] == 'on'
|
||||||
|
|
||||||
|
|
||||||
|
@asyncio.coroutine
|
||||||
|
def test_type_toggle(hass, monkeypatch):
|
||||||
|
"""Test toggle type lights (on/on)."""
|
||||||
|
config = {
|
||||||
|
'rflink': {
|
||||||
|
'port': '/dev/ttyABC0',
|
||||||
|
},
|
||||||
|
DOMAIN: {
|
||||||
|
'platform': 'rflink',
|
||||||
|
'devices': {
|
||||||
|
'toggle_0_0': {
|
||||||
|
'name': 'toggle_test',
|
||||||
|
'type': 'toggle',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
# setup mocking rflink module
|
||||||
|
event_callback, _, _, _ = yield from mock_rflink(
|
||||||
|
hass, config, DOMAIN, monkeypatch)
|
||||||
|
|
||||||
|
assert hass.states.get('light.toggle_test').state == 'off'
|
||||||
|
|
||||||
|
# test sending on command to toggle alias
|
||||||
|
event_callback({
|
||||||
|
'id': 'toggle_0_0',
|
||||||
|
'command': 'on',
|
||||||
|
})
|
||||||
|
yield from hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert hass.states.get('light.toggle_test').state == 'on'
|
||||||
|
|
||||||
|
# test sending group command to group alias
|
||||||
|
event_callback({
|
||||||
|
'id': 'toggle_0_0',
|
||||||
|
'command': 'on',
|
||||||
|
})
|
||||||
|
yield from hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert hass.states.get('light.toggle_test').state == 'off'
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue