From 7564d1fb523a7c41f7349dcef341d6e8d5ba9320 Mon Sep 17 00:00:00 2001 From: kbickar Date: Mon, 17 Jun 2019 17:09:31 -0400 Subject: [PATCH] Added toggle service to covers (#23198) * Added toggle service to cover * Added toggle tilt service and tilt closed property * Added is_tilt_closed so tilt can be toggled * Added toggle services * Added toggle tilt service * Removed spaces * Added tests for tilt services * Updated tests * Added range conversion in comparison * Added tests to cover broken areas * Fixed open/close tilt values and added toggle function * Added default toggle behavior using tilt_position of 0, reverted other changes * blank space * Added constants and swapped assert comparisons * Fixed attribute name * Added mqtt responses in test * Added constants * Space * Fix tilt_optimistic flag being ignored if status topic set * Added more tests * Changed async toggle call * Updated group tilt test * Updated format of asserts * Updated states calls * Updated function variables * merge fixes * Added blank line * Changed calls to async * More async updates --- homeassistant/components/cover/__init__.py | 49 +++- homeassistant/components/cover/services.yaml | 22 +- homeassistant/components/homematic/cover.py | 1 + homeassistant/components/mqtt/cover.py | 20 +- homeassistant/const.py | 1 + tests/components/demo/test_cover.py | 147 +++++++++--- tests/components/group/test_cover.py | 221 ++++++++++++++----- tests/components/mqtt/test_cover.py | 210 ++++++++++++++++-- tests/components/template/test_cover.py | 43 ++++ 9 files changed, 596 insertions(+), 118 deletions(-) diff --git a/homeassistant/components/cover/__init__.py b/homeassistant/components/cover/__init__.py index 4b05dedbf5e..4e90a7bd186 100644 --- a/homeassistant/components/cover/__init__.py +++ b/homeassistant/components/cover/__init__.py @@ -15,9 +15,10 @@ from homeassistant.components import group from homeassistant.helpers import intent from homeassistant.const import ( SERVICE_OPEN_COVER, SERVICE_CLOSE_COVER, SERVICE_SET_COVER_POSITION, - SERVICE_STOP_COVER, SERVICE_OPEN_COVER_TILT, SERVICE_CLOSE_COVER_TILT, - SERVICE_STOP_COVER_TILT, SERVICE_SET_COVER_TILT_POSITION, STATE_OPEN, - STATE_CLOSED, STATE_OPENING, STATE_CLOSING, ATTR_ENTITY_ID) + SERVICE_STOP_COVER, SERVICE_TOGGLE, SERVICE_OPEN_COVER_TILT, + SERVICE_CLOSE_COVER_TILT, SERVICE_STOP_COVER_TILT, + SERVICE_SET_COVER_TILT_POSITION, SERVICE_TOGGLE_COVER_TILT, + STATE_OPEN, STATE_CLOSED, STATE_OPENING, STATE_CLOSING, ATTR_ENTITY_ID) _LOGGER = logging.getLogger(__name__) @@ -118,6 +119,11 @@ async def async_setup(hass, config): 'async_stop_cover' ) + component.async_register_entity_service( + SERVICE_TOGGLE, COVER_SERVICE_SCHEMA, + 'async_toggle' + ) + component.async_register_entity_service( SERVICE_OPEN_COVER_TILT, COVER_SERVICE_SCHEMA, 'async_open_cover_tilt' @@ -138,6 +144,11 @@ async def async_setup(hass, config): 'async_set_cover_tilt_position' ) + component.async_register_entity_service( + SERVICE_TOGGLE_COVER_TILT, COVER_SERVICE_SCHEMA, + 'async_toggle_tilt' + ) + hass.helpers.intent.async_register(intent.ServiceIntentHandler( INTENT_OPEN_COVER, DOMAIN, SERVICE_OPEN_COVER, "Opened {}")) @@ -259,6 +270,22 @@ class CoverDevice(Entity): """ return self.hass.async_add_job(ft.partial(self.close_cover, **kwargs)) + def toggle(self, **kwargs) -> None: + """Toggle the entity.""" + if self.is_closed: + self.open_cover(**kwargs) + else: + self.close_cover(**kwargs) + + def async_toggle(self, **kwargs): + """Toggle the entity. + + This method must be run in the event loop and returns a coroutine. + """ + if self.is_closed: + return self.async_open_cover(**kwargs) + return self.async_close_cover(**kwargs) + def set_cover_position(self, **kwargs): """Move the cover to a specific position.""" pass @@ -329,3 +356,19 @@ class CoverDevice(Entity): """ return self.hass.async_add_job( ft.partial(self.stop_cover_tilt, **kwargs)) + + def toggle_tilt(self, **kwargs) -> None: + """Toggle the entity.""" + if self.current_cover_tilt_position == 0: + self.open_cover_tilt(**kwargs) + else: + self.close_cover_tilt(**kwargs) + + def async_toggle_tilt(self, **kwargs): + """Toggle the entity. + + This method must be run in the event loop and returns a coroutine. + """ + if self.current_cover_tilt_position == 0: + return self.async_open_cover_tilt(**kwargs) + return self.async_close_cover_tilt(**kwargs) diff --git a/homeassistant/components/cover/services.yaml b/homeassistant/components/cover/services.yaml index 79f00180a89..64534e40974 100644 --- a/homeassistant/components/cover/services.yaml +++ b/homeassistant/components/cover/services.yaml @@ -14,6 +14,13 @@ close_cover: description: Name(s) of cover(s) to close. example: 'cover.living_room' +toggle: + description: Toggles a cover open/closed. + fields: + entity_id: + description: Name(s) of cover(s) to toggle. + example: 'cover.garage_door' + set_cover_position: description: Move to specific position all or specified cover. fields: @@ -36,21 +43,28 @@ open_cover_tilt: fields: entity_id: description: Name(s) of cover(s) tilt to open. - example: 'cover.living_room' + example: 'cover.living_room_blinds' close_cover_tilt: description: Close all or specified cover tilt. fields: entity_id: description: Name(s) of cover(s) to close tilt. - example: 'cover.living_room' + example: 'cover.living_room_blinds' + +toggle_cover_tilt: + description: Toggles a cover tilt open/closed. + fields: + entity_id: + description: Name(s) of cover(s) to toggle tilt. + example: 'cover.living_room_blinds' set_cover_tilt_position: description: Move to specific position all or specified cover tilt. fields: entity_id: description: Name(s) of cover(s) to set cover tilt position. - example: 'cover.living_room' + example: 'cover.living_room_blinds' tilt_position: description: Tilt position of the cover (0 to 100). example: 30 @@ -60,4 +74,4 @@ stop_cover_tilt: fields: entity_id: description: Name(s) of cover(s) to stop. - example: 'cover.living_room' + example: 'cover.living_room_blinds' diff --git a/homeassistant/components/homematic/cover.py b/homeassistant/components/homematic/cover.py index 387eb26f433..28e66f39a50 100644 --- a/homeassistant/components/homematic/cover.py +++ b/homeassistant/components/homematic/cover.py @@ -48,6 +48,7 @@ class HMCover(HMDevice, CoverDevice): """Return if the cover is closed.""" if self.current_cover_position is not None: return self.current_cover_position == 0 + return None def open_cover(self, **kwargs): """Open the cover.""" diff --git a/homeassistant/components/mqtt/cover.py b/homeassistant/components/mqtt/cover.py index 17385e77ec3..0c62f230032 100644 --- a/homeassistant/components/mqtt/cover.py +++ b/homeassistant/components/mqtt/cover.py @@ -282,7 +282,6 @@ class MqttCover(MqttAttributes, MqttAvailability, MqttDiscoveryUpdate, if self._config.get(CONF_TILT_STATUS_TOPIC) is None: self._tilt_optimistic = True else: - self._tilt_optimistic = False self._tilt_value = STATE_UNKNOWN topics['tilt_status_topic'] = { 'topic': self._config.get(CONF_TILT_STATUS_TOPIC), @@ -405,7 +404,8 @@ class MqttCover(MqttAttributes, MqttAvailability, MqttDiscoveryUpdate, self._config[CONF_QOS], self._config[CONF_RETAIN]) if self._tilt_optimistic: - self._tilt_value = self._config[CONF_TILT_OPEN_POSITION] + self._tilt_value = self.find_percentage_in_range( + float(self._config[CONF_TILT_OPEN_POSITION])) self.async_write_ha_state() async def async_close_cover_tilt(self, **kwargs): @@ -416,7 +416,8 @@ class MqttCover(MqttAttributes, MqttAvailability, MqttDiscoveryUpdate, self._config[CONF_QOS], self._config[CONF_RETAIN]) if self._tilt_optimistic: - self._tilt_value = self._config[CONF_TILT_CLOSED_POSITION] + self._tilt_value = self.find_percentage_in_range( + float(self._config[CONF_TILT_CLOSED_POSITION])) self.async_write_ha_state() async def async_set_cover_tilt_position(self, **kwargs): @@ -464,6 +465,19 @@ class MqttCover(MqttAttributes, MqttAvailability, MqttDiscoveryUpdate, self._position = percentage_position self.async_write_ha_state() + async def async_toggle_tilt(self, **kwargs): + """Toggle the entity.""" + if self.is_tilt_closed(): + await self.async_open_cover_tilt(**kwargs) + else: + await self.async_close_cover_tilt(**kwargs) + + def is_tilt_closed(self): + """Return if the cover is tilted closed.""" + return self._tilt_value == \ + self.find_percentage_in_range( + float(self._config[CONF_TILT_CLOSED_POSITION])) + def find_percentage_in_range(self, position, range_type=TILT_PAYLOAD): """Find the 0-100% value within the specified range.""" # the range of motion as defined by the min max values diff --git a/homeassistant/const.py b/homeassistant/const.py index 258c4d0e4e2..4b78ab9618b 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -411,6 +411,7 @@ SERVICE_SET_COVER_POSITION = 'set_cover_position' SERVICE_SET_COVER_TILT_POSITION = 'set_cover_tilt_position' SERVICE_STOP_COVER = 'stop_cover' SERVICE_STOP_COVER_TILT = 'stop_cover_tilt' +SERVICE_TOGGLE_COVER_TILT = 'toggle_cover_tilt' SERVICE_SELECT_OPTION = 'select_option' diff --git a/tests/components/demo/test_cover.py b/tests/components/demo/test_cover.py index 011928f851a..1477afc44d2 100644 --- a/tests/components/demo/test_cover.py +++ b/tests/components/demo/test_cover.py @@ -4,9 +4,12 @@ from datetime import timedelta import pytest from homeassistant.components.cover import ( - ATTR_POSITION, ATTR_TILT_POSITION, DOMAIN) + ATTR_POSITION, ATTR_CURRENT_POSITION, ATTR_CURRENT_TILT_POSITION, + ATTR_TILT_POSITION, DOMAIN) from homeassistant.const import ( - ATTR_ENTITY_ID, SERVICE_CLOSE_COVER, SERVICE_CLOSE_COVER_TILT, + ATTR_ENTITY_ID, ATTR_SUPPORTED_FEATURES, + STATE_OPEN, STATE_OPENING, STATE_CLOSED, STATE_CLOSING, SERVICE_TOGGLE, + SERVICE_CLOSE_COVER, SERVICE_CLOSE_COVER_TILT, SERVICE_TOGGLE_COVER_TILT, SERVICE_OPEN_COVER, SERVICE_OPEN_COVER_TILT, SERVICE_SET_COVER_POSITION, SERVICE_SET_COVER_TILT_POSITION, SERVICE_STOP_COVER, SERVICE_STOP_COVER_TILT) @@ -29,60 +32,100 @@ async def setup_comp(hass): async def test_supported_features(hass, setup_comp): """Test cover supported features.""" state = hass.states.get('cover.garage_door') - assert 3 == state.attributes.get('supported_features') + assert state.attributes[ATTR_SUPPORTED_FEATURES] == 3 state = hass.states.get('cover.kitchen_window') - assert 11 == state.attributes.get('supported_features') + assert state.attributes[ATTR_SUPPORTED_FEATURES] == 11 state = hass.states.get('cover.hall_window') - assert 15 == state.attributes.get('supported_features') + assert state.attributes[ATTR_SUPPORTED_FEATURES] == 15 state = hass.states.get('cover.living_room_window') - assert 255 == state.attributes.get('supported_features') + assert state.attributes[ATTR_SUPPORTED_FEATURES] == 255 async def test_close_cover(hass, setup_comp): """Test closing the cover.""" state = hass.states.get(ENTITY_COVER) - assert state.state == 'open' - assert 70 == state.attributes.get('current_position') + assert state.state == STATE_OPEN + assert state.attributes[ATTR_CURRENT_POSITION] == 70 await hass.services.async_call( DOMAIN, SERVICE_CLOSE_COVER, {ATTR_ENTITY_ID: ENTITY_COVER}, blocking=True) state = hass.states.get(ENTITY_COVER) - assert state.state == 'closing' + assert state.state == STATE_CLOSING for _ in range(7): future = dt_util.utcnow() + timedelta(seconds=1) async_fire_time_changed(hass, future) await hass.async_block_till_done() state = hass.states.get(ENTITY_COVER) - assert state.state == 'closed' - assert 0 == state.attributes.get('current_position') + assert state.state == STATE_CLOSED + assert state.attributes[ATTR_CURRENT_POSITION] == 0 async def test_open_cover(hass, setup_comp): """Test opening the cover.""" state = hass.states.get(ENTITY_COVER) - assert state.state == 'open' - assert 70 == state.attributes.get('current_position') + assert state.state == STATE_OPEN + assert state.attributes[ATTR_CURRENT_POSITION] == 70 await hass.services.async_call( DOMAIN, SERVICE_OPEN_COVER, {ATTR_ENTITY_ID: ENTITY_COVER}, blocking=True) state = hass.states.get(ENTITY_COVER) - assert state.state == 'opening' + assert state.state == STATE_OPENING for _ in range(7): future = dt_util.utcnow() + timedelta(seconds=1) async_fire_time_changed(hass, future) await hass.async_block_till_done() state = hass.states.get(ENTITY_COVER) - assert state.state == 'open' - assert 100 == state.attributes.get('current_position') + assert state.state == STATE_OPEN + assert state.attributes[ATTR_CURRENT_POSITION] == 100 + + +async def test_toggle_cover(hass, setup_comp): + """Test toggling the cover.""" + # Start open + await hass.services.async_call( + DOMAIN, SERVICE_OPEN_COVER, + {ATTR_ENTITY_ID: ENTITY_COVER}, blocking=True) + for _ in range(7): + future = dt_util.utcnow() + timedelta(seconds=1) + async_fire_time_changed(hass, future) + await hass.async_block_till_done() + + state = hass.states.get(ENTITY_COVER) + assert state.state == STATE_OPEN + assert state.attributes['current_position'] == 100 + # Toggle closed + await hass.services.async_call( + DOMAIN, SERVICE_TOGGLE, + {ATTR_ENTITY_ID: ENTITY_COVER}, blocking=True) + for _ in range(10): + future = dt_util.utcnow() + timedelta(seconds=1) + async_fire_time_changed(hass, future) + await hass.async_block_till_done() + + state = hass.states.get(ENTITY_COVER) + assert state.state == STATE_CLOSED + assert state.attributes[ATTR_CURRENT_POSITION] == 0 + # Toggle open + await hass.services.async_call( + DOMAIN, SERVICE_TOGGLE, + {ATTR_ENTITY_ID: ENTITY_COVER}, blocking=True) + for _ in range(10): + future = dt_util.utcnow() + timedelta(seconds=1) + async_fire_time_changed(hass, future) + await hass.async_block_till_done() + + state = hass.states.get(ENTITY_COVER) + assert state.state == STATE_OPEN + assert state.attributes[ATTR_CURRENT_POSITION] == 100 async def test_set_cover_position(hass, setup_comp): """Test moving the cover to a specific position.""" state = hass.states.get(ENTITY_COVER) - assert 70 == state.attributes.get('current_position') + assert state.attributes[ATTR_CURRENT_POSITION] == 70 await hass.services.async_call( DOMAIN, SERVICE_SET_COVER_POSITION, {ATTR_ENTITY_ID: ENTITY_COVER, ATTR_POSITION: 10}, blocking=True) @@ -92,13 +135,13 @@ async def test_set_cover_position(hass, setup_comp): await hass.async_block_till_done() state = hass.states.get(ENTITY_COVER) - assert 10 == state.attributes.get('current_position') + assert state.attributes[ATTR_CURRENT_POSITION] == 10 async def test_stop_cover(hass, setup_comp): """Test stopping the cover.""" state = hass.states.get(ENTITY_COVER) - assert 70 == state.attributes.get('current_position') + assert state.attributes[ATTR_CURRENT_POSITION] == 70 await hass.services.async_call( DOMAIN, SERVICE_OPEN_COVER, {ATTR_ENTITY_ID: ENTITY_COVER}, blocking=True) @@ -111,13 +154,13 @@ async def test_stop_cover(hass, setup_comp): async_fire_time_changed(hass, future) await hass.async_block_till_done() state = hass.states.get(ENTITY_COVER) - assert 80 == state.attributes.get('current_position') + assert state.attributes[ATTR_CURRENT_POSITION] == 80 async def test_close_cover_tilt(hass, setup_comp): """Test closing the cover tilt.""" state = hass.states.get(ENTITY_COVER) - assert 50 == state.attributes.get('current_tilt_position') + assert state.attributes[ATTR_CURRENT_TILT_POSITION] == 50 await hass.services.async_call( DOMAIN, SERVICE_CLOSE_COVER_TILT, {ATTR_ENTITY_ID: ENTITY_COVER}, blocking=True) @@ -127,13 +170,13 @@ async def test_close_cover_tilt(hass, setup_comp): await hass.async_block_till_done() state = hass.states.get(ENTITY_COVER) - assert 0 == state.attributes.get('current_tilt_position') + assert state.attributes[ATTR_CURRENT_TILT_POSITION] == 0 async def test_open_cover_tilt(hass, setup_comp): """Test opening the cover tilt.""" state = hass.states.get(ENTITY_COVER) - assert 50 == state.attributes.get('current_tilt_position') + assert state.attributes[ATTR_CURRENT_TILT_POSITION] == 50 await hass.services.async_call( DOMAIN, SERVICE_OPEN_COVER_TILT, {ATTR_ENTITY_ID: ENTITY_COVER}, blocking=True) @@ -143,29 +186,67 @@ async def test_open_cover_tilt(hass, setup_comp): await hass.async_block_till_done() state = hass.states.get(ENTITY_COVER) - assert 100 == state.attributes.get('current_tilt_position') + assert state.attributes[ATTR_CURRENT_TILT_POSITION] == 100 -async def test_set_cover_tilt_position(hass, setup_comp): - """Test moving the cover til to a specific position.""" - state = hass.states.get(ENTITY_COVER) - assert 50 == state.attributes.get('current_tilt_position') +async def test_toggle_cover_tilt(hass, setup_comp): + """Test toggling the cover tilt.""" + # Start open await hass.services.async_call( - DOMAIN, SERVICE_SET_COVER_TILT_POSITION, - {ATTR_ENTITY_ID: ENTITY_COVER, ATTR_TILT_POSITION: 90}, blocking=True) + DOMAIN, SERVICE_OPEN_COVER_TILT, + {ATTR_ENTITY_ID: ENTITY_COVER}, blocking=True) for _ in range(7): future = dt_util.utcnow() + timedelta(seconds=1) async_fire_time_changed(hass, future) await hass.async_block_till_done() state = hass.states.get(ENTITY_COVER) - assert 90 == state.attributes.get('current_tilt_position') + assert state.attributes[ATTR_CURRENT_TILT_POSITION] == 100 + # Toggle closed + await hass.services.async_call( + DOMAIN, SERVICE_TOGGLE_COVER_TILT, + {ATTR_ENTITY_ID: ENTITY_COVER}, blocking=True) + for _ in range(10): + future = dt_util.utcnow() + timedelta(seconds=1) + async_fire_time_changed(hass, future) + await hass.async_block_till_done() + + state = hass.states.get(ENTITY_COVER) + assert state.attributes[ATTR_CURRENT_TILT_POSITION] == 0 + # Toggle Open + await hass.services.async_call( + DOMAIN, SERVICE_TOGGLE_COVER_TILT, + {ATTR_ENTITY_ID: ENTITY_COVER}, blocking=True) + for _ in range(10): + future = dt_util.utcnow() + timedelta(seconds=1) + async_fire_time_changed(hass, future) + await hass.async_block_till_done() + + state = hass.states.get(ENTITY_COVER) + assert state.attributes[ATTR_CURRENT_TILT_POSITION] == 100 + + +async def test_set_cover_tilt_position(hass, setup_comp): + """Test moving the cover til to a specific position.""" + state = hass.states.get(ENTITY_COVER) + assert state.attributes[ATTR_CURRENT_TILT_POSITION] == 50 + await hass.services.async_call( + DOMAIN, SERVICE_SET_COVER_TILT_POSITION, + {ATTR_ENTITY_ID: ENTITY_COVER, ATTR_TILT_POSITION: 90}, + blocking=True) + for _ in range(7): + future = dt_util.utcnow() + timedelta(seconds=1) + async_fire_time_changed(hass, future) + await hass.async_block_till_done() + + state = hass.states.get(ENTITY_COVER) + assert state.attributes[ATTR_CURRENT_TILT_POSITION] == 90 async def test_stop_cover_tilt(hass, setup_comp): """Test stopping the cover tilt.""" state = hass.states.get(ENTITY_COVER) - assert 50 == state.attributes.get('current_tilt_position') + assert state.attributes[ATTR_CURRENT_TILT_POSITION] == 50 await hass.services.async_call( DOMAIN, SERVICE_CLOSE_COVER_TILT, {ATTR_ENTITY_ID: ENTITY_COVER}, blocking=True) @@ -178,4 +259,4 @@ async def test_stop_cover_tilt(hass, setup_comp): async_fire_time_changed(hass, future) await hass.async_block_till_done() state = hass.states.get(ENTITY_COVER) - assert 40 == state.attributes.get('current_tilt_position') + assert state.attributes[ATTR_CURRENT_TILT_POSITION] == 40 diff --git a/tests/components/group/test_cover.py b/tests/components/group/test_cover.py index 04e8f9c964d..8dd9f9bcbb5 100644 --- a/tests/components/group/test_cover.py +++ b/tests/components/group/test_cover.py @@ -11,6 +11,7 @@ from homeassistant.const import ( ATTR_ASSUMED_STATE, ATTR_ENTITY_ID, ATTR_FRIENDLY_NAME, ATTR_SUPPORTED_FEATURES, CONF_ENTITIES, SERVICE_CLOSE_COVER, SERVICE_CLOSE_COVER_TILT, + SERVICE_TOGGLE, SERVICE_TOGGLE_COVER_TILT, SERVICE_OPEN_COVER, SERVICE_OPEN_COVER_TILT, SERVICE_SET_COVER_POSITION, SERVICE_SET_COVER_TILT_POSITION, SERVICE_STOP_COVER, SERVICE_STOP_COVER_TILT, STATE_OPEN, STATE_CLOSED) @@ -52,11 +53,11 @@ async def test_attributes(hass): state = hass.states.get(COVER_GROUP) assert state.state == STATE_CLOSED - assert state.attributes.get(ATTR_FRIENDLY_NAME) == DEFAULT_NAME - assert state.attributes.get(ATTR_ASSUMED_STATE) is None - assert state.attributes.get(ATTR_SUPPORTED_FEATURES) == 0 - assert state.attributes.get(ATTR_CURRENT_POSITION) is None - assert state.attributes.get(ATTR_CURRENT_TILT_POSITION) is None + assert state.attributes[ATTR_FRIENDLY_NAME] == DEFAULT_NAME + assert ATTR_ASSUMED_STATE not in state.attributes + assert state.attributes[ATTR_SUPPORTED_FEATURES] == 0 + assert ATTR_CURRENT_POSITION not in state.attributes + assert ATTR_CURRENT_TILT_POSITION not in state.attributes # Add Entity that supports open / close / stop hass.states.async_set( @@ -65,10 +66,10 @@ async def test_attributes(hass): state = hass.states.get(COVER_GROUP) assert state.state == STATE_OPEN - assert state.attributes.get(ATTR_ASSUMED_STATE) is None - assert state.attributes.get(ATTR_SUPPORTED_FEATURES) == 11 - assert state.attributes.get(ATTR_CURRENT_POSITION) is None - assert state.attributes.get(ATTR_CURRENT_TILT_POSITION) is None + assert ATTR_ASSUMED_STATE not in state.attributes + assert state.attributes[ATTR_SUPPORTED_FEATURES] == 11 + assert ATTR_CURRENT_POSITION not in state.attributes + assert ATTR_CURRENT_TILT_POSITION not in state.attributes # Add Entity that supports set_cover_position hass.states.async_set( @@ -78,10 +79,10 @@ async def test_attributes(hass): state = hass.states.get(COVER_GROUP) assert state.state == STATE_OPEN - assert state.attributes.get(ATTR_ASSUMED_STATE) is None - assert state.attributes.get(ATTR_SUPPORTED_FEATURES) == 15 - assert state.attributes.get(ATTR_CURRENT_POSITION) == 70 - assert state.attributes.get(ATTR_CURRENT_TILT_POSITION) is None + assert ATTR_ASSUMED_STATE not in state.attributes + assert state.attributes[ATTR_SUPPORTED_FEATURES] == 15 + assert state.attributes[ATTR_CURRENT_POSITION] == 70 + assert ATTR_CURRENT_TILT_POSITION not in state.attributes # Add Entity that supports open tilt / close tilt / stop tilt hass.states.async_set( @@ -90,10 +91,10 @@ async def test_attributes(hass): state = hass.states.get(COVER_GROUP) assert state.state == STATE_OPEN - assert state.attributes.get(ATTR_ASSUMED_STATE) is None - assert state.attributes.get(ATTR_SUPPORTED_FEATURES) == 127 - assert state.attributes.get(ATTR_CURRENT_POSITION) == 70 - assert state.attributes.get(ATTR_CURRENT_TILT_POSITION) is None + assert ATTR_ASSUMED_STATE not in state.attributes + assert state.attributes[ATTR_SUPPORTED_FEATURES] == 127 + assert state.attributes[ATTR_CURRENT_POSITION] == 70 + assert ATTR_CURRENT_TILT_POSITION not in state.attributes # Add Entity that supports set_tilt_position hass.states.async_set( @@ -103,10 +104,10 @@ async def test_attributes(hass): state = hass.states.get(COVER_GROUP) assert state.state == STATE_OPEN - assert state.attributes.get(ATTR_ASSUMED_STATE) is None - assert state.attributes.get(ATTR_SUPPORTED_FEATURES) == 255 - assert state.attributes.get(ATTR_CURRENT_POSITION) == 70 - assert state.attributes.get(ATTR_CURRENT_TILT_POSITION) == 60 + assert ATTR_ASSUMED_STATE not in state.attributes + assert state.attributes[ATTR_SUPPORTED_FEATURES] == 255 + assert state.attributes[ATTR_CURRENT_POSITION] == 70 + assert state.attributes[ATTR_CURRENT_TILT_POSITION] == 60 # ### Test assumed state ### # ########################## @@ -119,10 +120,10 @@ async def test_attributes(hass): state = hass.states.get(COVER_GROUP) assert state.state == STATE_OPEN - assert state.attributes.get(ATTR_ASSUMED_STATE) is True - assert state.attributes.get(ATTR_SUPPORTED_FEATURES) == 244 - assert state.attributes.get(ATTR_CURRENT_POSITION) == 100 - assert state.attributes.get(ATTR_CURRENT_TILT_POSITION) == 60 + assert state.attributes[ATTR_ASSUMED_STATE] is True + assert state.attributes[ATTR_SUPPORTED_FEATURES] == 244 + assert state.attributes[ATTR_CURRENT_POSITION] == 100 + assert state.attributes[ATTR_CURRENT_TILT_POSITION] == 60 hass.states.async_remove(DEMO_COVER) hass.states.async_remove(DEMO_COVER_POS) @@ -130,10 +131,10 @@ async def test_attributes(hass): state = hass.states.get(COVER_GROUP) assert state.state == STATE_OPEN - assert state.attributes.get(ATTR_ASSUMED_STATE) is None - assert state.attributes.get(ATTR_SUPPORTED_FEATURES) == 240 - assert state.attributes.get(ATTR_CURRENT_POSITION) is None - assert state.attributes.get(ATTR_CURRENT_TILT_POSITION) == 60 + assert ATTR_ASSUMED_STATE not in state.attributes + assert state.attributes[ATTR_SUPPORTED_FEATURES] == 240 + assert ATTR_CURRENT_POSITION not in state.attributes + assert state.attributes[ATTR_CURRENT_TILT_POSITION] == 60 # For tilts hass.states.async_set( @@ -143,10 +144,10 @@ async def test_attributes(hass): state = hass.states.get(COVER_GROUP) assert state.state == STATE_OPEN - assert state.attributes.get(ATTR_ASSUMED_STATE) is True - assert state.attributes.get(ATTR_SUPPORTED_FEATURES) == 128 - assert state.attributes.get(ATTR_CURRENT_POSITION) is None - assert state.attributes.get(ATTR_CURRENT_TILT_POSITION) == 100 + assert state.attributes[ATTR_ASSUMED_STATE] is True + assert state.attributes[ATTR_SUPPORTED_FEATURES] == 128 + assert ATTR_CURRENT_POSITION not in state.attributes + assert state.attributes[ATTR_CURRENT_TILT_POSITION] == 100 hass.states.async_remove(DEMO_COVER_TILT) hass.states.async_set(DEMO_TILT, STATE_CLOSED) @@ -154,17 +155,17 @@ async def test_attributes(hass): state = hass.states.get(COVER_GROUP) assert state.state == STATE_CLOSED - assert state.attributes.get(ATTR_ASSUMED_STATE) is None - assert state.attributes.get(ATTR_SUPPORTED_FEATURES) == 0 - assert state.attributes.get(ATTR_CURRENT_POSITION) is None - assert state.attributes.get(ATTR_CURRENT_TILT_POSITION) is None + assert ATTR_ASSUMED_STATE not in state.attributes + assert state.attributes[ATTR_SUPPORTED_FEATURES] == 0 + assert ATTR_CURRENT_POSITION not in state.attributes + assert ATTR_CURRENT_TILT_POSITION not in state.attributes hass.states.async_set( DEMO_TILT, STATE_CLOSED, {ATTR_ASSUMED_STATE: True}) await hass.async_block_till_done() state = hass.states.get(COVER_GROUP) - assert state.attributes.get(ATTR_ASSUMED_STATE) is True + assert state.attributes[ATTR_ASSUMED_STATE] is True async def test_open_covers(hass, setup_comp): @@ -179,13 +180,13 @@ async def test_open_covers(hass, setup_comp): state = hass.states.get(COVER_GROUP) assert state.state == STATE_OPEN - assert state.attributes.get(ATTR_CURRENT_POSITION) == 100 + assert state.attributes[ATTR_CURRENT_POSITION] == 100 assert hass.states.get(DEMO_COVER).state == STATE_OPEN assert hass.states.get(DEMO_COVER_POS) \ - .attributes.get(ATTR_CURRENT_POSITION) == 100 + .attributes[ATTR_CURRENT_POSITION] == 100 assert hass.states.get(DEMO_COVER_TILT) \ - .attributes.get(ATTR_CURRENT_POSITION) == 100 + .attributes[ATTR_CURRENT_POSITION] == 100 async def test_close_covers(hass, setup_comp): @@ -200,13 +201,66 @@ async def test_close_covers(hass, setup_comp): state = hass.states.get(COVER_GROUP) assert state.state == STATE_CLOSED - assert state.attributes.get(ATTR_CURRENT_POSITION) == 0 + assert state.attributes[ATTR_CURRENT_POSITION] == 0 assert hass.states.get(DEMO_COVER).state == STATE_CLOSED assert hass.states.get(DEMO_COVER_POS) \ - .attributes.get(ATTR_CURRENT_POSITION) == 0 + .attributes[ATTR_CURRENT_POSITION] == 0 assert hass.states.get(DEMO_COVER_TILT) \ - .attributes.get(ATTR_CURRENT_POSITION) == 0 + .attributes[ATTR_CURRENT_POSITION] == 0 + + +async def test_toggle_covers(hass, setup_comp): + """Test toggle cover function.""" + # Start covers in open state + await hass.services.async_call( + DOMAIN, SERVICE_OPEN_COVER, + {ATTR_ENTITY_ID: COVER_GROUP}, blocking=True) + for _ in range(10): + future = dt_util.utcnow() + timedelta(seconds=1) + async_fire_time_changed(hass, future) + await hass.async_block_till_done() + + state = hass.states.get(COVER_GROUP) + assert state.state == STATE_OPEN + + # Toggle will close covers + await hass.services.async_call( + DOMAIN, SERVICE_TOGGLE, + {ATTR_ENTITY_ID: COVER_GROUP}, blocking=True) + for _ in range(10): + future = dt_util.utcnow() + timedelta(seconds=1) + async_fire_time_changed(hass, future) + await hass.async_block_till_done() + + state = hass.states.get(COVER_GROUP) + assert state.state == STATE_CLOSED + assert state.attributes[ATTR_CURRENT_POSITION] == 0 + + assert hass.states.get(DEMO_COVER).state == STATE_CLOSED + assert hass.states.get(DEMO_COVER_POS) \ + .attributes[ATTR_CURRENT_POSITION] == 0 + assert hass.states.get(DEMO_COVER_TILT) \ + .attributes[ATTR_CURRENT_POSITION] == 0 + + # Toggle again will open covers + await hass.services.async_call( + DOMAIN, SERVICE_TOGGLE, + {ATTR_ENTITY_ID: COVER_GROUP}, blocking=True) + for _ in range(10): + future = dt_util.utcnow() + timedelta(seconds=1) + async_fire_time_changed(hass, future) + await hass.async_block_till_done() + + state = hass.states.get(COVER_GROUP) + assert state.state == STATE_OPEN + assert state.attributes[ATTR_CURRENT_POSITION] == 100 + + assert hass.states.get(DEMO_COVER).state == STATE_OPEN + assert hass.states.get(DEMO_COVER_POS) \ + .attributes[ATTR_CURRENT_POSITION] == 100 + assert hass.states.get(DEMO_COVER_TILT) \ + .attributes[ATTR_CURRENT_POSITION] == 100 async def test_stop_covers(hass, setup_comp): @@ -227,13 +281,13 @@ async def test_stop_covers(hass, setup_comp): state = hass.states.get(COVER_GROUP) assert state.state == STATE_OPEN - assert state.attributes.get(ATTR_CURRENT_POSITION) == 100 + assert state.attributes[ATTR_CURRENT_POSITION] == 100 assert hass.states.get(DEMO_COVER).state == STATE_OPEN assert hass.states.get(DEMO_COVER_POS) \ - .attributes.get(ATTR_CURRENT_POSITION) == 20 + .attributes[ATTR_CURRENT_POSITION] == 20 assert hass.states.get(DEMO_COVER_TILT) \ - .attributes.get(ATTR_CURRENT_POSITION) == 80 + .attributes[ATTR_CURRENT_POSITION] == 80 async def test_set_cover_position(hass, setup_comp): @@ -248,13 +302,13 @@ async def test_set_cover_position(hass, setup_comp): state = hass.states.get(COVER_GROUP) assert state.state == STATE_OPEN - assert state.attributes.get(ATTR_CURRENT_POSITION) == 50 + assert state.attributes[ATTR_CURRENT_POSITION] == 50 assert hass.states.get(DEMO_COVER).state == STATE_CLOSED assert hass.states.get(DEMO_COVER_POS) \ - .attributes.get(ATTR_CURRENT_POSITION) == 50 + .attributes[ATTR_CURRENT_POSITION] == 50 assert hass.states.get(DEMO_COVER_TILT) \ - .attributes.get(ATTR_CURRENT_POSITION) == 50 + .attributes[ATTR_CURRENT_POSITION] == 50 async def test_open_tilts(hass, setup_comp): @@ -269,10 +323,10 @@ async def test_open_tilts(hass, setup_comp): state = hass.states.get(COVER_GROUP) assert state.state == STATE_OPEN - assert state.attributes.get(ATTR_CURRENT_TILT_POSITION) == 100 + assert state.attributes[ATTR_CURRENT_TILT_POSITION] == 100 assert hass.states.get(DEMO_COVER_TILT) \ - .attributes.get(ATTR_CURRENT_TILT_POSITION) == 100 + .attributes[ATTR_CURRENT_TILT_POSITION] == 100 async def test_close_tilts(hass, setup_comp): @@ -287,10 +341,61 @@ async def test_close_tilts(hass, setup_comp): state = hass.states.get(COVER_GROUP) assert state.state == STATE_OPEN - assert state.attributes.get(ATTR_CURRENT_TILT_POSITION) == 0 + assert state.attributes[ATTR_CURRENT_TILT_POSITION] == 0 assert hass.states.get(DEMO_COVER_TILT) \ - .attributes.get(ATTR_CURRENT_TILT_POSITION) == 0 + .attributes[ATTR_CURRENT_TILT_POSITION] == 0 + + +async def test_toggle_tilts(hass, setup_comp): + """Test toggle tilt function.""" + # Start tilted open + await hass.services.async_call( + DOMAIN, SERVICE_OPEN_COVER_TILT, + {ATTR_ENTITY_ID: COVER_GROUP}, blocking=True) + for _ in range(10): + future = dt_util.utcnow() + timedelta(seconds=1) + async_fire_time_changed(hass, future) + await hass.async_block_till_done() + + state = hass.states.get(COVER_GROUP) + assert state.state == STATE_OPEN + assert state.attributes[ATTR_CURRENT_TILT_POSITION] == 100 + + assert hass.states.get(DEMO_COVER_TILT) \ + .attributes[ATTR_CURRENT_TILT_POSITION] == 100 + + # Toggle will tilt closed + await hass.services.async_call( + DOMAIN, SERVICE_TOGGLE_COVER_TILT, + {ATTR_ENTITY_ID: COVER_GROUP}, blocking=True) + for _ in range(10): + future = dt_util.utcnow() + timedelta(seconds=1) + async_fire_time_changed(hass, future) + await hass.async_block_till_done() + + state = hass.states.get(COVER_GROUP) + assert state.state == STATE_OPEN + assert state.attributes[ATTR_CURRENT_TILT_POSITION] == 0 + + assert hass.states.get(DEMO_COVER_TILT) \ + .attributes[ATTR_CURRENT_TILT_POSITION] == 0 + + # Toggle again will tilt open + await hass.services.async_call( + DOMAIN, SERVICE_TOGGLE_COVER_TILT, + {ATTR_ENTITY_ID: COVER_GROUP}, blocking=True) + for _ in range(10): + future = dt_util.utcnow() + timedelta(seconds=1) + async_fire_time_changed(hass, future) + await hass.async_block_till_done() + + state = hass.states.get(COVER_GROUP) + assert state.state == STATE_OPEN + assert state.attributes[ATTR_CURRENT_TILT_POSITION] == 100 + + assert hass.states.get(DEMO_COVER_TILT) \ + .attributes[ATTR_CURRENT_TILT_POSITION] == 100 async def test_stop_tilts(hass, setup_comp): @@ -311,10 +416,10 @@ async def test_stop_tilts(hass, setup_comp): state = hass.states.get(COVER_GROUP) assert state.state == STATE_OPEN - assert state.attributes.get(ATTR_CURRENT_TILT_POSITION) == 60 + assert state.attributes[ATTR_CURRENT_TILT_POSITION] == 60 assert hass.states.get(DEMO_COVER_TILT) \ - .attributes.get(ATTR_CURRENT_TILT_POSITION) == 60 + .attributes[ATTR_CURRENT_TILT_POSITION] == 60 async def test_set_tilt_positions(hass, setup_comp): @@ -329,7 +434,7 @@ async def test_set_tilt_positions(hass, setup_comp): state = hass.states.get(COVER_GROUP) assert state.state == STATE_OPEN - assert state.attributes.get(ATTR_CURRENT_TILT_POSITION) == 80 + assert state.attributes[ATTR_CURRENT_TILT_POSITION] == 80 assert hass.states.get(DEMO_COVER_TILT) \ - .attributes.get(ATTR_CURRENT_TILT_POSITION) == 80 + .attributes[ATTR_CURRENT_TILT_POSITION] == 80 diff --git a/tests/components/mqtt/test_cover.py b/tests/components/mqtt/test_cover.py index 91b0355ad22..6ffc0df4809 100644 --- a/tests/components/mqtt/test_cover.py +++ b/tests/components/mqtt/test_cover.py @@ -11,7 +11,7 @@ from homeassistant.const import ( SERVICE_CLOSE_COVER_TILT, SERVICE_OPEN_COVER, SERVICE_OPEN_COVER_TILT, SERVICE_SET_COVER_POSITION, SERVICE_SET_COVER_TILT_POSITION, SERVICE_STOP_COVER, STATE_CLOSED, STATE_OPEN, STATE_UNAVAILABLE, - STATE_UNKNOWN) + SERVICE_TOGGLE, SERVICE_TOGGLE_COVER_TILT, STATE_UNKNOWN) from homeassistant.setup import async_setup_component from tests.common import ( @@ -174,6 +174,26 @@ async def test_optimistic_state_change(hass, mqtt_mock): cover.DOMAIN, SERVICE_CLOSE_COVER, {ATTR_ENTITY_ID: 'cover.test'}, blocking=True) + mqtt_mock.async_publish.assert_called_once_with( + 'command-topic', 'CLOSE', 0, False) + mqtt_mock.async_publish.reset_mock() + state = hass.states.get('cover.test') + assert STATE_CLOSED == state.state + + await hass.services.async_call( + cover.DOMAIN, SERVICE_TOGGLE, + {ATTR_ENTITY_ID: 'cover.test'}, blocking=True) + + mqtt_mock.async_publish.assert_called_once_with( + 'command-topic', 'OPEN', 0, False) + mqtt_mock.async_publish.reset_mock() + state = hass.states.get('cover.test') + assert STATE_OPEN == state.state + + await hass.services.async_call( + cover.DOMAIN, SERVICE_TOGGLE, + {ATTR_ENTITY_ID: 'cover.test'}, blocking=True) + mqtt_mock.async_publish.assert_called_once_with( 'command-topic', 'CLOSE', 0, False) state = hass.states.get('cover.test') @@ -534,6 +554,36 @@ async def test_tilt_via_invocation_defaults(hass, mqtt_mock): mqtt_mock.async_publish.assert_called_once_with( 'tilt-command-topic', 0, 0, False) + mqtt_mock.async_publish.reset_mock() + + # Close tilt status would be received from device when non-optimistic + async_fire_mqtt_message(hass, 'tilt-status-topic', '0') + + current_cover_tilt_position = hass.states.get( + 'cover.test').attributes['current_tilt_position'] + assert current_cover_tilt_position == 0 + + await hass.services.async_call( + cover.DOMAIN, SERVICE_TOGGLE_COVER_TILT, + {ATTR_ENTITY_ID: 'cover.test'}, blocking=True) + + mqtt_mock.async_publish.assert_called_once_with( + 'tilt-command-topic', 100, 0, False) + mqtt_mock.async_publish.reset_mock() + + # Open tilt status would be received from device when non-optimistic + async_fire_mqtt_message(hass, 'tilt-status-topic', '100') + + current_cover_tilt_position = hass.states.get( + 'cover.test').attributes['current_tilt_position'] + assert current_cover_tilt_position == 100 + + await hass.services.async_call( + cover.DOMAIN, SERVICE_TOGGLE_COVER_TILT, + {ATTR_ENTITY_ID: 'cover.test'}, blocking=True) + + mqtt_mock.async_publish.assert_called_once_with( + 'tilt-command-topic', 0, 0, False) async def test_tilt_given_value(hass, mqtt_mock): @@ -550,25 +600,157 @@ async def test_tilt_given_value(hass, mqtt_mock): 'payload_stop': 'STOP', 'tilt_command_topic': 'tilt-command-topic', 'tilt_status_topic': 'tilt-status-topic', - 'tilt_opened_value': 400, - 'tilt_closed_value': 125 + 'tilt_opened_value': 80, + 'tilt_closed_value': 25 } }) await hass.services.async_call( - cover.DOMAIN, SERVICE_OPEN_COVER_TILT, {ATTR_ENTITY_ID: 'cover.test'}, - blocking=True) + cover.DOMAIN, SERVICE_OPEN_COVER_TILT, + {ATTR_ENTITY_ID: 'cover.test'}, blocking=True) mqtt_mock.async_publish.assert_called_once_with( - 'tilt-command-topic', 400, 0, False) + 'tilt-command-topic', 80, 0, False) mqtt_mock.async_publish.reset_mock() await hass.services.async_call( - cover.DOMAIN, SERVICE_CLOSE_COVER_TILT, {ATTR_ENTITY_ID: 'cover.test'}, - blocking=True) + cover.DOMAIN, SERVICE_CLOSE_COVER_TILT, + {ATTR_ENTITY_ID: 'cover.test'}, blocking=True) mqtt_mock.async_publish.assert_called_once_with( - 'tilt-command-topic', 125, 0, False) + 'tilt-command-topic', 25, 0, False) + mqtt_mock.async_publish.reset_mock() + + # Close tilt status would be received from device when non-optimistic + async_fire_mqtt_message(hass, 'tilt-status-topic', '25') + + current_cover_tilt_position = hass.states.get( + 'cover.test').attributes['current_tilt_position'] + assert current_cover_tilt_position == 25 + + await hass.services.async_call( + cover.DOMAIN, SERVICE_TOGGLE_COVER_TILT, + {ATTR_ENTITY_ID: 'cover.test'}, blocking=True) + + mqtt_mock.async_publish.assert_called_once_with( + 'tilt-command-topic', 80, 0, False) + mqtt_mock.async_publish.reset_mock() + + # Open tilt status would be received from device when non-optimistic + async_fire_mqtt_message(hass, 'tilt-status-topic', '80') + + current_cover_tilt_position = hass.states.get( + 'cover.test').attributes['current_tilt_position'] + assert current_cover_tilt_position == 80 + + await hass.services.async_call( + cover.DOMAIN, SERVICE_TOGGLE_COVER_TILT, + {ATTR_ENTITY_ID: 'cover.test'}, blocking=True) + + mqtt_mock.async_publish.assert_called_once_with( + 'tilt-command-topic', 25, 0, False) + + +async def test_tilt_given_value_optimistic(hass, mqtt_mock): + """Test tilting to a given value.""" + assert await async_setup_component(hass, cover.DOMAIN, { + cover.DOMAIN: { + 'platform': 'mqtt', + 'name': 'test', + 'state_topic': 'state-topic', + 'command_topic': 'command-topic', + 'qos': 0, + 'payload_open': 'OPEN', + 'payload_close': 'CLOSE', + 'payload_stop': 'STOP', + 'tilt_command_topic': 'tilt-command-topic', + 'tilt_status_topic': 'tilt-status-topic', + 'tilt_opened_value': 80, + 'tilt_closed_value': 25, + 'tilt_optimistic': True + } + }) + + await hass.services.async_call( + cover.DOMAIN, SERVICE_OPEN_COVER_TILT, + {ATTR_ENTITY_ID: 'cover.test'}, blocking=True) + + current_cover_tilt_position = hass.states.get( + 'cover.test').attributes['current_tilt_position'] + assert current_cover_tilt_position == 80 + + mqtt_mock.async_publish.assert_called_once_with( + 'tilt-command-topic', 80, 0, False) + mqtt_mock.async_publish.reset_mock() + + await hass.services.async_call( + cover.DOMAIN, SERVICE_CLOSE_COVER_TILT, + {ATTR_ENTITY_ID: 'cover.test'}, blocking=True) + + current_cover_tilt_position = hass.states.get( + 'cover.test').attributes['current_tilt_position'] + assert current_cover_tilt_position == 25 + + mqtt_mock.async_publish.assert_called_once_with( + 'tilt-command-topic', 25, 0, False) + + +async def test_tilt_given_value_altered_range(hass, mqtt_mock): + """Test tilting to a given value.""" + assert await async_setup_component(hass, cover.DOMAIN, { + cover.DOMAIN: { + 'platform': 'mqtt', + 'name': 'test', + 'state_topic': 'state-topic', + 'command_topic': 'command-topic', + 'qos': 0, + 'payload_open': 'OPEN', + 'payload_close': 'CLOSE', + 'payload_stop': 'STOP', + 'tilt_command_topic': 'tilt-command-topic', + 'tilt_status_topic': 'tilt-status-topic', + 'tilt_opened_value': 25, + 'tilt_closed_value': 0, + 'tilt_min': 0, + 'tilt_max': 50, + 'tilt_optimistic': True + } + }) + + await hass.services.async_call( + cover.DOMAIN, SERVICE_OPEN_COVER_TILT, + {ATTR_ENTITY_ID: 'cover.test'}, blocking=True) + + current_cover_tilt_position = hass.states.get( + 'cover.test').attributes['current_tilt_position'] + assert current_cover_tilt_position == 50 + + mqtt_mock.async_publish.assert_called_once_with( + 'tilt-command-topic', 25, 0, False) + mqtt_mock.async_publish.reset_mock() + + await hass.services.async_call( + cover.DOMAIN, SERVICE_CLOSE_COVER_TILT, + {ATTR_ENTITY_ID: 'cover.test'}, blocking=True) + + current_cover_tilt_position = hass.states.get( + 'cover.test').attributes['current_tilt_position'] + assert current_cover_tilt_position == 0 + + mqtt_mock.async_publish.assert_called_once_with( + 'tilt-command-topic', 0, 0, False) + mqtt_mock.async_publish.reset_mock() + + await hass.services.async_call( + cover.DOMAIN, SERVICE_TOGGLE_COVER_TILT, + {ATTR_ENTITY_ID: 'cover.test'}, blocking=True) + + current_cover_tilt_position = hass.states.get( + 'cover.test').attributes['current_tilt_position'] + assert current_cover_tilt_position == 50 + + mqtt_mock.async_publish.assert_called_once_with( + 'tilt-command-topic', 25, 0, False) async def test_tilt_via_topic(hass, mqtt_mock): @@ -584,9 +766,7 @@ async def test_tilt_via_topic(hass, mqtt_mock): 'payload_close': 'CLOSE', 'payload_stop': 'STOP', 'tilt_command_topic': 'tilt-command-topic', - 'tilt_status_topic': 'tilt-status-topic', - 'tilt_opened_value': 400, - 'tilt_closed_value': 125 + 'tilt_status_topic': 'tilt-status-topic' } }) @@ -650,8 +830,6 @@ async def test_tilt_via_topic_altered_range(hass, mqtt_mock): 'payload_stop': 'STOP', 'tilt_command_topic': 'tilt-command-topic', 'tilt_status_topic': 'tilt-status-topic', - 'tilt_opened_value': 400, - 'tilt_closed_value': 125, 'tilt_min': 0, 'tilt_max': 50 } @@ -730,9 +908,7 @@ async def test_tilt_position(hass, mqtt_mock): 'payload_close': 'CLOSE', 'payload_stop': 'STOP', 'tilt_command_topic': 'tilt-command-topic', - 'tilt_status_topic': 'tilt-status-topic', - 'tilt_opened_value': 400, - 'tilt_closed_value': 125 + 'tilt_status_topic': 'tilt-status-topic' } }) diff --git a/tests/components/template/test_cover.py b/tests/components/template/test_cover.py index 703ef787ec7..83ba7bdf816 100644 --- a/tests/components/template/test_cover.py +++ b/tests/components/template/test_cover.py @@ -7,6 +7,7 @@ from homeassistant.components.cover import ( ATTR_POSITION, ATTR_TILT_POSITION, DOMAIN) from homeassistant.const import ( ATTR_ENTITY_ID, SERVICE_CLOSE_COVER, SERVICE_CLOSE_COVER_TILT, + SERVICE_TOGGLE, SERVICE_TOGGLE_COVER_TILT, SERVICE_OPEN_COVER, SERVICE_OPEN_COVER_TILT, SERVICE_SET_COVER_POSITION, SERVICE_SET_COVER_TILT_POSITION, SERVICE_STOP_COVER, STATE_CLOSED, STATE_OPEN) @@ -464,6 +465,20 @@ async def test_set_position(hass, calls): state = hass.states.get('cover.test_template_cover') assert state.attributes.get('current_position') == 0.0 + await hass.services.async_call( + DOMAIN, SERVICE_TOGGLE, + {ATTR_ENTITY_ID: ENTITY_COVER}, blocking=True) + await hass.async_block_till_done() + state = hass.states.get('cover.test_template_cover') + assert state.attributes.get('current_position') == 100.0 + + await hass.services.async_call( + DOMAIN, SERVICE_TOGGLE, + {ATTR_ENTITY_ID: ENTITY_COVER}, blocking=True) + await hass.async_block_till_done() + state = hass.states.get('cover.test_template_cover') + assert state.attributes.get('current_position') == 0.0 + await hass.services.async_call( DOMAIN, SERVICE_SET_COVER_POSITION, {ATTR_ENTITY_ID: ENTITY_COVER, ATTR_POSITION: 25}, blocking=True) @@ -626,6 +641,20 @@ async def test_set_position_optimistic(hass, calls): state = hass.states.get('cover.test_template_cover') assert state.state == STATE_OPEN + await hass.services.async_call( + DOMAIN, SERVICE_TOGGLE, + {ATTR_ENTITY_ID: ENTITY_COVER}, blocking=True) + await hass.async_block_till_done() + state = hass.states.get('cover.test_template_cover') + assert state.state == STATE_CLOSED + + await hass.services.async_call( + DOMAIN, SERVICE_TOGGLE, + {ATTR_ENTITY_ID: ENTITY_COVER}, blocking=True) + await hass.async_block_till_done() + state = hass.states.get('cover.test_template_cover') + assert state.state == STATE_OPEN + async def test_set_tilt_position_optimistic(hass, calls): """Test the optimistic tilt_position mode.""" @@ -675,6 +704,20 @@ async def test_set_tilt_position_optimistic(hass, calls): state = hass.states.get('cover.test_template_cover') assert state.attributes.get('current_tilt_position') == 100.0 + await hass.services.async_call( + DOMAIN, SERVICE_TOGGLE_COVER_TILT, + {ATTR_ENTITY_ID: ENTITY_COVER}, blocking=True) + await hass.async_block_till_done() + state = hass.states.get('cover.test_template_cover') + assert state.attributes.get('current_tilt_position') == 0.0 + + await hass.services.async_call( + DOMAIN, SERVICE_TOGGLE_COVER_TILT, + {ATTR_ENTITY_ID: ENTITY_COVER}, blocking=True) + await hass.async_block_till_done() + state = hass.states.get('cover.test_template_cover') + assert state.attributes.get('current_tilt_position') == 100.0 + async def test_icon_template(hass, calls): """Test icon template."""