diff --git a/homeassistant/components/cover/rflink.py b/homeassistant/components/cover/rflink.py index 353cccc7d4f..cdc7cac3adb 100644 --- a/homeassistant/components/cover/rflink.py +++ b/homeassistant/components/cover/rflink.py @@ -15,8 +15,8 @@ from homeassistant.components.rflink import ( from homeassistant.components.cover import ( CoverDevice, PLATFORM_SCHEMA) import homeassistant.helpers.config_validation as cv -from homeassistant.const import CONF_NAME - +from homeassistant.helpers.restore_state import RestoreEntity +from homeassistant.const import CONF_NAME, STATE_OPEN DEPENDENCIES = ['rflink'] @@ -60,9 +60,17 @@ async def async_setup_platform(hass, config, async_add_entities, async_add_entities(devices_from_config(config)) -class RflinkCover(RflinkCommand, CoverDevice): +class RflinkCover(RflinkCommand, CoverDevice, RestoreEntity): """Rflink entity which can switch on/stop/off (eg: cover).""" + async def async_added_to_hass(self): + """Restore RFLink cover state (OPEN/CLOSE).""" + await super().async_added_to_hass() + + old_state = await self.async_get_last_state() + if old_state is not None: + self._state = old_state.state == STATE_OPEN + def _handle_event(self, event): """Adjust state if Rflink picks up a remote command for this device.""" self.cancel_queued_send_commands() diff --git a/homeassistant/components/light/rflink.py b/homeassistant/components/light/rflink.py index 3b60280c582..ef389bb84f9 100644 --- a/homeassistant/components/light/rflink.py +++ b/homeassistant/components/light/rflink.py @@ -148,17 +148,29 @@ async def async_setup_platform(hass, config, async_add_entities, hass.data[DATA_DEVICE_REGISTER][EVENT_KEY_COMMAND] = add_new_device +# pylint: disable=too-many-ancestors class RflinkLight(SwitchableRflinkDevice, Light): """Representation of a Rflink light.""" pass +# pylint: disable=too-many-ancestors class DimmableRflinkLight(SwitchableRflinkDevice, Light): """Rflink light device that support dimming.""" _brightness = 255 + async def async_added_to_hass(self): + """Restore RFLink light brightness attribute.""" + await super().async_added_to_hass() + + old_state = await self.async_get_last_state() + if old_state is not None and \ + old_state.attributes.get(ATTR_BRIGHTNESS) is not None: + # restore also brightness in dimmables devices + self._brightness = int(old_state.attributes[ATTR_BRIGHTNESS]) + async def async_turn_on(self, **kwargs): """Turn the device on.""" if ATTR_BRIGHTNESS in kwargs: @@ -179,6 +191,7 @@ class DimmableRflinkLight(SwitchableRflinkDevice, Light): return SUPPORT_BRIGHTNESS +# pylint: disable=too-many-ancestors class HybridRflinkLight(SwitchableRflinkDevice, Light): """Rflink light device that sends out both dim and on/off commands. @@ -196,6 +209,16 @@ class HybridRflinkLight(SwitchableRflinkDevice, Light): _brightness = 255 + async def async_added_to_hass(self): + """Restore RFLink light brightness attribute.""" + await super().async_added_to_hass() + + old_state = await self.async_get_last_state() + if old_state is not None and \ + old_state.attributes.get(ATTR_BRIGHTNESS) is not None: + # restore also brightness in dimmables devices + self._brightness = int(old_state.attributes[ATTR_BRIGHTNESS]) + async def async_turn_on(self, **kwargs): """Turn the device on and set dim level.""" if ATTR_BRIGHTNESS in kwargs: @@ -222,6 +245,7 @@ class HybridRflinkLight(SwitchableRflinkDevice, Light): return SUPPORT_BRIGHTNESS +# pylint: disable=too-many-ancestors class ToggleRflinkLight(SwitchableRflinkDevice, Light): """Rflink light device which sends out only 'on' commands. diff --git a/homeassistant/components/rflink.py b/homeassistant/components/rflink.py index b3c58da1076..89392b8565f 100644 --- a/homeassistant/components/rflink.py +++ b/homeassistant/components/rflink.py @@ -13,7 +13,7 @@ import voluptuous as vol from homeassistant.const import ( ATTR_ENTITY_ID, CONF_COMMAND, CONF_HOST, CONF_PORT, - EVENT_HOMEASSISTANT_STOP) + STATE_ON, EVENT_HOMEASSISTANT_STOP) from homeassistant.core import CoreState, callback from homeassistant.exceptions import HomeAssistantError import homeassistant.helpers.config_validation as cv @@ -21,7 +21,7 @@ from homeassistant.helpers.deprecation import get_deprecated from homeassistant.helpers.entity import Entity from homeassistant.helpers.dispatcher import ( async_dispatcher_send, async_dispatcher_connect) - +from homeassistant.helpers.restore_state import RestoreEntity REQUIREMENTS = ['rflink==0.0.37'] @@ -499,9 +499,17 @@ class RflinkCommand(RflinkDevice): self._async_send_command(cmd, repetitions - 1)) -class SwitchableRflinkDevice(RflinkCommand): +class SwitchableRflinkDevice(RflinkCommand, RestoreEntity): """Rflink entity which can switch on/off (eg: light, switch).""" + async def async_added_to_hass(self): + """Restore RFLink device state (ON/OFF).""" + await super().async_added_to_hass() + + old_state = await self.async_get_last_state() + if old_state is not None: + self._state = old_state.state == STATE_ON + def _handle_event(self, event): """Adjust state if Rflink picks up a remote command for this device.""" self.cancel_queued_send_commands() diff --git a/homeassistant/components/switch/rflink.py b/homeassistant/components/switch/rflink.py index 51bf5543584..25e4e367fdf 100644 --- a/homeassistant/components/switch/rflink.py +++ b/homeassistant/components/switch/rflink.py @@ -67,6 +67,7 @@ async def async_setup_platform(hass, config, async_add_entities, async_add_entities(devices_from_config(config)) +# pylint: disable=too-many-ancestors class RflinkSwitch(SwitchableRflinkDevice, SwitchDevice): """Representation of a Rflink switch.""" diff --git a/tests/components/cover/test_rflink.py b/tests/components/cover/test_rflink.py new file mode 100644 index 00000000000..4f88d24d97f --- /dev/null +++ b/tests/components/cover/test_rflink.py @@ -0,0 +1,497 @@ +"""Test for RFLink cover components. + +Test setup of RFLink covers component/platform. State tracking and +control of RFLink cover devices. + +""" + +import logging + +from homeassistant.components.rflink import EVENT_BUTTON_PRESSED +from homeassistant.const import ( + SERVICE_OPEN_COVER, SERVICE_CLOSE_COVER, + STATE_OPEN, STATE_CLOSED, ATTR_ENTITY_ID) +from homeassistant.core import callback, State, CoreState + +from tests.common import mock_restore_cache +from ..test_rflink import mock_rflink + +DOMAIN = 'cover' + +CONFIG = { + 'rflink': { + 'port': '/dev/ttyABC0', + 'ignore_devices': ['ignore_wildcard_*', 'ignore_cover'], + }, + DOMAIN: { + 'platform': 'rflink', + 'devices': { + 'protocol_0_0': { + 'name': 'test', + 'aliases': ['test_alias_0_0'], + }, + 'cover_0_0': { + 'name': 'dim_test', + }, + 'cover_0_1': { + 'name': 'cover_test', + } + }, + }, +} + +_LOGGER = logging.getLogger(__name__) + + +async def test_default_setup(hass, monkeypatch): + """Test all basic functionality of the RFLink cover component.""" + # setup mocking rflink module + event_callback, create, protocol, _ = await mock_rflink( + hass, CONFIG, DOMAIN, monkeypatch) + + # make sure arguments are passed + assert create.call_args_list[0][1]['ignore'] + + # test default state of cover loaded from config + cover_initial = hass.states.get(DOMAIN + '.test') + assert cover_initial.state == STATE_CLOSED + assert cover_initial.attributes['assumed_state'] + + # cover should follow state of the hardware device by interpreting + # incoming events for its name and aliases + + # mock incoming command event for this device + event_callback({ + 'id': 'protocol_0_0', + 'command': 'up', + }) + await hass.async_block_till_done() + + cover_after_first_command = hass.states.get(DOMAIN + '.test') + assert cover_after_first_command.state == STATE_OPEN + # not sure why, but cover have always assumed_state=true + assert cover_after_first_command.attributes.get('assumed_state') + + # mock incoming command event for this device + event_callback({ + 'id': 'protocol_0_0', + 'command': 'down', + }) + await hass.async_block_till_done() + + assert hass.states.get(DOMAIN + '.test').state == STATE_CLOSED + + # should respond to group command + event_callback({ + 'id': 'protocol_0_0', + 'command': 'allon', + }) + await hass.async_block_till_done() + + cover_after_first_command = hass.states.get(DOMAIN + '.test') + assert cover_after_first_command.state == STATE_OPEN + + # should respond to group command + event_callback({ + 'id': 'protocol_0_0', + 'command': 'alloff', + }) + await hass.async_block_till_done() + + assert hass.states.get(DOMAIN + '.test').state == STATE_CLOSED + + # test following aliases + # mock incoming command event for this device alias + event_callback({ + 'id': 'test_alias_0_0', + 'command': 'up', + }) + await hass.async_block_till_done() + + assert hass.states.get(DOMAIN + '.test').state == STATE_OPEN + + # test changing state from HA propagates to RFLink + hass.async_create_task( + hass.services.async_call(DOMAIN, SERVICE_CLOSE_COVER, + {ATTR_ENTITY_ID: DOMAIN + '.test'})) + await hass.async_block_till_done() + assert hass.states.get(DOMAIN + '.test').state == STATE_CLOSED + 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] == 'DOWN' + + hass.async_create_task( + hass.services.async_call(DOMAIN, SERVICE_OPEN_COVER, + {ATTR_ENTITY_ID: DOMAIN + '.test'})) + await hass.async_block_till_done() + assert hass.states.get(DOMAIN + '.test').state == STATE_OPEN + assert protocol.send_command_ack.call_args_list[1][0][1] == 'UP' + + +async def test_firing_bus_event(hass, monkeypatch): + """Incoming RFLink command events should be put on the HA event bus.""" + config = { + 'rflink': { + 'port': '/dev/ttyABC0', + }, + DOMAIN: { + 'platform': 'rflink', + 'devices': { + 'protocol_0_0': { + 'name': 'test', + 'aliases': ['test_alias_0_0'], + 'fire_event': True, + }, + }, + }, + } + + # setup mocking rflink module + event_callback, _, _, _ = await mock_rflink( + hass, config, DOMAIN, monkeypatch) + + calls = [] + + @callback + def listener(event): + calls.append(event) + hass.bus.async_listen_once(EVENT_BUTTON_PRESSED, listener) + + # test event for new unconfigured sensor + event_callback({ + 'id': 'protocol_0_0', + 'command': 'down', + }) + await hass.async_block_till_done() + + assert calls[0].data == {'state': 'down', 'entity_id': DOMAIN + '.test'} + + +async def test_signal_repetitions(hass, monkeypatch): + """Command should be sent amount of configured repetitions.""" + config = { + 'rflink': { + 'port': '/dev/ttyABC0', + }, + DOMAIN: { + 'platform': 'rflink', + 'device_defaults': { + 'signal_repetitions': 3, + }, + 'devices': { + 'protocol_0_0': { + 'name': 'test', + 'signal_repetitions': 2, + }, + 'protocol_0_1': { + 'name': 'test1', + }, + }, + }, + } + + # setup mocking rflink module + _, _, protocol, _ = await mock_rflink(hass, config, DOMAIN, monkeypatch) + + # test if signal repetition is performed according to configuration + hass.async_create_task( + hass.services.async_call(DOMAIN, SERVICE_OPEN_COVER, + {ATTR_ENTITY_ID: DOMAIN + '.test'})) + + # wait for commands and repetitions to finish + await hass.async_block_till_done() + + assert protocol.send_command_ack.call_count == 2 + + # test if default apply to configured devices + hass.async_create_task( + hass.services.async_call(DOMAIN, SERVICE_OPEN_COVER, + {ATTR_ENTITY_ID: DOMAIN + '.test1'})) + + # wait for commands and repetitions to finish + await hass.async_block_till_done() + + assert protocol.send_command_ack.call_count == 5 + + +async def test_signal_repetitions_alternation(hass, monkeypatch): + """Simultaneously switching entities must alternate repetitions.""" + config = { + 'rflink': { + 'port': '/dev/ttyABC0', + }, + DOMAIN: { + 'platform': 'rflink', + 'devices': { + 'protocol_0_0': { + 'name': 'test', + 'signal_repetitions': 2, + }, + 'protocol_0_1': { + 'name': 'test1', + 'signal_repetitions': 2, + }, + }, + }, + } + + # setup mocking rflink module + _, _, protocol, _ = await mock_rflink( + hass, config, DOMAIN, monkeypatch) + + hass.async_create_task( + hass.services.async_call(DOMAIN, SERVICE_CLOSE_COVER, + {ATTR_ENTITY_ID: DOMAIN + '.test'})) + hass.async_create_task( + hass.services.async_call(DOMAIN, SERVICE_CLOSE_COVER, + {ATTR_ENTITY_ID: DOMAIN + '.test1'})) + + await hass.async_block_till_done() + + assert protocol.send_command_ack.call_args_list[0][0][0] == 'protocol_0_0' + assert protocol.send_command_ack.call_args_list[1][0][0] == 'protocol_0_1' + assert protocol.send_command_ack.call_args_list[2][0][0] == 'protocol_0_0' + assert protocol.send_command_ack.call_args_list[3][0][0] == 'protocol_0_1' + + +async def test_signal_repetitions_cancelling(hass, monkeypatch): + """Cancel outstanding repetitions when state changed.""" + config = { + 'rflink': { + 'port': '/dev/ttyABC0', + }, + DOMAIN: { + 'platform': 'rflink', + 'devices': { + 'protocol_0_0': { + 'name': 'test', + 'signal_repetitions': 3, + }, + }, + }, + } + + # setup mocking rflink module + _, _, protocol, _ = await mock_rflink( + hass, config, DOMAIN, monkeypatch) + + hass.async_create_task( + hass.services.async_call(DOMAIN, SERVICE_CLOSE_COVER, + {ATTR_ENTITY_ID: DOMAIN + '.test'})) + + hass.async_create_task( + hass.services.async_call(DOMAIN, SERVICE_OPEN_COVER, + {ATTR_ENTITY_ID: DOMAIN + '.test'})) + + await hass.async_block_till_done() + + assert protocol.send_command_ack.call_args_list[0][0][1] == 'DOWN' + assert protocol.send_command_ack.call_args_list[1][0][1] == 'UP' + assert protocol.send_command_ack.call_args_list[2][0][1] == 'UP' + assert protocol.send_command_ack.call_args_list[3][0][1] == 'UP' + + +async 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_aliases': ['test_group_0_0'], + }, + }, + }, + } + + # setup mocking rflink module + event_callback, _, _, _ = await mock_rflink( + hass, config, DOMAIN, monkeypatch) + + assert hass.states.get(DOMAIN + '.test').state == STATE_CLOSED + + # test sending group command to group alias + event_callback({ + 'id': 'test_group_0_0', + 'command': 'allon', + }) + await hass.async_block_till_done() + + assert hass.states.get(DOMAIN + '.test').state == STATE_OPEN + + # test sending group command to group alias + event_callback({ + 'id': 'test_group_0_0', + 'command': 'down', + }) + await hass.async_block_till_done() + + assert hass.states.get(DOMAIN + '.test').state == STATE_OPEN + + +async 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_aliases': ['test_nogroup_0_0'], + }, + }, + }, + } + + # setup mocking rflink module + event_callback, _, _, _ = await mock_rflink( + hass, config, DOMAIN, monkeypatch) + + assert hass.states.get(DOMAIN + '.test').state == STATE_CLOSED + + # test sending group command to nogroup alias + event_callback({ + 'id': 'test_nogroup_0_0', + 'command': 'allon', + }) + await hass.async_block_till_done() + # should not affect state + assert hass.states.get(DOMAIN + '.test').state == STATE_CLOSED + + # test sending group command to nogroup alias + event_callback({ + 'id': 'test_nogroup_0_0', + 'command': 'up', + }) + await hass.async_block_till_done() + # should affect state + assert hass.states.get(DOMAIN + '.test').state == STATE_OPEN + + +async 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, _, _, _ = await mock_rflink( + hass, config, DOMAIN, monkeypatch) + + assert hass.states.get(DOMAIN + '.test').state == STATE_CLOSED + + # test sending group command to nogroup + event_callback({ + 'id': 'test_nogroup_0_0', + 'command': 'allon', + }) + await hass.async_block_till_done() + # should not affect state + assert hass.states.get(DOMAIN + '.test').state == STATE_CLOSED + + # test sending group command to nogroup + event_callback({ + 'id': 'test_nogroup_0_0', + 'command': 'up', + }) + await hass.async_block_till_done() + # should affect state + assert hass.states.get(DOMAIN + '.test').state == STATE_OPEN + + +async def test_disable_automatic_add(hass, monkeypatch): + """If disabled new devices should not be automatically added.""" + config = { + 'rflink': { + 'port': '/dev/ttyABC0', + }, + DOMAIN: { + 'platform': 'rflink', + 'automatic_add': False, + }, + } + + # setup mocking rflink module + event_callback, _, _, _ = await mock_rflink( + hass, config, DOMAIN, monkeypatch) + + # test event for new unconfigured sensor + event_callback({ + 'id': 'protocol_0_0', + 'command': 'down', + }) + await hass.async_block_till_done() + + # make sure new device is not added + assert not hass.states.get(DOMAIN + '.protocol_0_0') + + +async def test_restore_state(hass, monkeypatch): + """Ensure states are restored on startup.""" + config = { + 'rflink': { + 'port': '/dev/ttyABC0', + }, + DOMAIN: { + 'platform': 'rflink', + 'devices': { + 'RTS_12345678_0': { + 'name': 'c1', + }, + 'test_restore_2': { + 'name': 'c2', + }, + 'test_restore_3': { + 'name': 'c3', + }, + 'test_restore_4': { + 'name': 'c4', + }, + }, + }, + } + + mock_restore_cache(hass, ( + State(DOMAIN + '.c1', STATE_OPEN, ), + State(DOMAIN + '.c2', STATE_CLOSED, ), + )) + + hass.state = CoreState.starting + + # setup mocking rflink module + _, _, _, _ = await mock_rflink(hass, config, DOMAIN, monkeypatch) + + state = hass.states.get(DOMAIN + '.c1') + assert state + assert state.state == STATE_OPEN + + state = hass.states.get(DOMAIN + '.c2') + assert state + assert state.state == STATE_CLOSED + + state = hass.states.get(DOMAIN + '.c3') + assert state + assert state.state == STATE_CLOSED + + # not cached cover must default values + state = hass.states.get(DOMAIN + '.c4') + assert state + assert state.state == STATE_CLOSED + assert state.attributes['assumed_state'] diff --git a/tests/components/light/test_rflink.py b/tests/components/light/test_rflink.py index c55c16077e0..e77e4c0ff44 100644 --- a/tests/components/light/test_rflink.py +++ b/tests/components/light/test_rflink.py @@ -1,7 +1,7 @@ -"""Test for RFlink light components. +"""Test for RFLink light components. -Test setup of rflink lights component/platform. State tracking and -control of Rflink switch devices. +Test setup of RFLink lights component/platform. State tracking and +control of RFLink switch devices. """ @@ -10,9 +10,10 @@ import asyncio from homeassistant.components.light import ATTR_BRIGHTNESS from homeassistant.components.rflink import EVENT_BUTTON_PRESSED from homeassistant.const import ( - ATTR_ENTITY_ID, SERVICE_TURN_OFF, SERVICE_TURN_ON) -from homeassistant.core import callback + ATTR_ENTITY_ID, SERVICE_TURN_OFF, SERVICE_TURN_ON, STATE_ON, STATE_OFF) +from homeassistant.core import callback, State, CoreState +from tests.common import mock_restore_cache from ..test_rflink import mock_rflink DOMAIN = 'light' @@ -44,7 +45,7 @@ CONFIG = { @asyncio.coroutine def test_default_setup(hass, monkeypatch): - """Test all basic functionality of the rflink switch component.""" + """Test all basic functionality of the RFLink switch component.""" # setup mocking rflink module event_callback, create, protocol, _ = yield from mock_rflink( hass, CONFIG, DOMAIN, monkeypatch) @@ -119,7 +120,7 @@ def test_default_setup(hass, monkeypatch): assert hass.states.get(DOMAIN + '.protocol2_0_1').state == 'on' - # test changing state from HA propagates to Rflink + # test changing state from HA propagates to RFLink hass.async_add_job( hass.services.async_call(DOMAIN, SERVICE_TURN_OFF, {ATTR_ENTITY_ID: DOMAIN + '.test'})) @@ -175,7 +176,7 @@ def test_default_setup(hass, monkeypatch): @asyncio.coroutine def test_firing_bus_event(hass, monkeypatch): - """Incoming Rflink command events should be put on the HA event bus.""" + """Incoming RFLink command events should be put on the HA event bus.""" config = { 'rflink': { 'port': '/dev/ttyABC0', @@ -560,3 +561,56 @@ def test_disable_automatic_add(hass, monkeypatch): # make sure new device is not added assert not hass.states.get(DOMAIN + '.protocol_0_0') + + +@asyncio.coroutine +def test_restore_state(hass, monkeypatch): + """Ensure states are restored on startup.""" + config = { + 'rflink': { + 'port': '/dev/ttyABC0', + }, + DOMAIN: { + 'platform': 'rflink', + 'devices': { + 'NewKaku_12345678_0': { + 'name': 'l1', + 'type': 'hybrid', + }, + 'test_restore_2': { + 'name': 'l2', + }, + 'test_restore_3': { + 'name': 'l3', + }, + }, + }, + } + + mock_restore_cache(hass, ( + State(DOMAIN + '.l1', STATE_ON, {ATTR_BRIGHTNESS: "123", }), + State(DOMAIN + '.l2', STATE_ON, {ATTR_BRIGHTNESS: "321", }), + State(DOMAIN + '.l3', STATE_OFF, ), + )) + + hass.state = CoreState.starting + + # setup mocking rflink module + _, _, _, _ = yield from mock_rflink(hass, config, DOMAIN, monkeypatch) + + # dimmable light must restore brightness + state = hass.states.get(DOMAIN + '.l1') + assert state + assert state.state == STATE_ON + assert state.attributes[ATTR_BRIGHTNESS] == 123 + + # normal light do NOT must restore brightness + state = hass.states.get(DOMAIN + '.l2') + assert state + assert state.state == STATE_ON + assert not state.attributes.get(ATTR_BRIGHTNESS) + + # OFF state also restores (or not) + state = hass.states.get(DOMAIN + '.l3') + assert state + assert state.state == STATE_OFF diff --git a/tests/components/switch/test_rflink.py b/tests/components/switch/test_rflink.py index 77a6b572e96..8603545b563 100644 --- a/tests/components/switch/test_rflink.py +++ b/tests/components/switch/test_rflink.py @@ -9,9 +9,10 @@ import asyncio from homeassistant.components.rflink import EVENT_BUTTON_PRESSED from homeassistant.const import ( - ATTR_ENTITY_ID, SERVICE_TURN_OFF, SERVICE_TURN_ON) -from homeassistant.core import callback + ATTR_ENTITY_ID, SERVICE_TURN_OFF, SERVICE_TURN_ON, STATE_ON, STATE_OFF) +from homeassistant.core import callback, State, CoreState +from tests.common import mock_restore_cache from ..test_rflink import mock_rflink DOMAIN = 'switch' @@ -310,3 +311,43 @@ def test_not_firing_default(hass, monkeypatch): yield from hass.async_block_till_done() assert not calls, 'an event has been fired' + + +@asyncio.coroutine +def test_restore_state(hass, monkeypatch): + """Ensure states are restored on startup.""" + config = { + 'rflink': { + 'port': '/dev/ttyABC0', + }, + DOMAIN: { + 'platform': 'rflink', + 'devices': { + 'test': { + 'name': 's1', + 'aliases': ['test_alias_0_0'], + }, + 'switch_test': { + 'name': 's2', + } + } + } + } + + mock_restore_cache(hass, ( + State(DOMAIN + '.s1', STATE_ON, ), + State(DOMAIN + '.s2', STATE_OFF, ), + )) + + hass.state = CoreState.starting + + # setup mocking rflink module + _, _, _, _ = yield from mock_rflink(hass, config, DOMAIN, monkeypatch) + + state = hass.states.get(DOMAIN + '.s1') + assert state + assert state.state == STATE_ON + + state = hass.states.get(DOMAIN + '.s2') + assert state + assert state.state == STATE_OFF