Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions homeassistant/components/cover/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,15 @@
'garage', # Garage door control
]

SUPPORT_OPEN = 1
SUPPORT_CLOSE = 2
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why would we separate open and close? I don't think there will ever be a use case that has no open and close.

Even if a device does not have open and close specific but has set position, they could mimick open and close by setting position to fully open or fully closed. So I think that we can remove those.

Copy link
Copy Markdown
Contributor Author

@emlove emlove Feb 18, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do think that we need to keep the open/close separate from the set position, because although set position can emulate open/close, the opposite isn't true. It's very possible that there is a device that tracks position, but only has binary open/close commands.

As far as open/close being separate, I don't have any example of a device, but it certainly could be possible. I wouldn't have predicted a media player that does support next track but doesn't support previous, and then Pandora came around.

What about a compromise, where we have one flag SUPPORT_OPENCLOSE = 3, that way they could be broken out in the future if necessary, but don't clutter the current code? It's not necessary for my case, but I'd like to leave options open for the future.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, you convinced me. I'm fine with it.

SUPPORT_SET_POSITION = 4
SUPPORT_STOP = 8
SUPPORT_OPEN_TILT = 16
SUPPORT_CLOSE_TILT = 32
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here, can be merged with open tilt ?

SUPPORT_STOP_TILT = 64
SUPPORT_SET_TILT_POSITION = 128

_LOGGER = logging.getLogger(__name__)

ATTR_CURRENT_POSITION = 'current_position'
Expand Down Expand Up @@ -226,6 +235,21 @@ def state_attributes(self):

return data

@property
def supported_features(self):
"""Flag supported features."""
supported_features = SUPPORT_OPEN | SUPPORT_CLOSE | SUPPORT_STOP

if self.current_cover_position is not None:
supported_features |= SUPPORT_SET_POSITION

if self.current_cover_tilt_position is not None:
supported_features |= (
SUPPORT_OPEN_TILT | SUPPORT_CLOSE_TILT | SUPPORT_STOP_TILT |
SUPPORT_SET_TILT_POSITION)

return supported_features

@property
def is_closed(self):
"""Return if the cover is closed or not."""
Expand Down
17 changes: 14 additions & 3 deletions homeassistant/components/cover/demo.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
For more details about this platform, please refer to the documentation
https://home-assistant.io/components/demo/
"""
from homeassistant.components.cover import CoverDevice
from homeassistant.components.cover import (
CoverDevice, SUPPORT_OPEN, SUPPORT_CLOSE)
from homeassistant.helpers.event import track_utc_time_change


Expand All @@ -14,7 +15,8 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
DemoCover(hass, 'Kitchen Window'),
DemoCover(hass, 'Hall Window', 10),
DemoCover(hass, 'Living Room Window', 70, 50),
DemoCover(hass, 'Garage Door', device_class='garage'),
DemoCover(hass, 'Garage Door', device_class='garage',
supported_features=(SUPPORT_OPEN | SUPPORT_CLOSE)),
])


Expand All @@ -23,12 +25,13 @@ class DemoCover(CoverDevice):

# pylint: disable=no-self-use
def __init__(self, hass, name, position=None, tilt_position=None,
device_class=None):
device_class=None, supported_features=None):
"""Initialize the cover."""
self.hass = hass
self._name = name
self._position = position
self._device_class = device_class
self._supported_features = supported_features
self._set_position = None
self._set_tilt_position = None
self._tilt_position = tilt_position
Expand Down Expand Up @@ -71,6 +74,14 @@ def device_class(self):
"""Return the class of this device, from component DEVICE_CLASSES."""
return self._device_class

@property
def supported_features(self):
"""Flag supported features."""
if self._supported_features is not None:
return self._supported_features
else:
return super().supported_features

def close_cover(self, **kwargs):
"""Close the cover."""
if self._position == 0:
Expand Down
10 changes: 9 additions & 1 deletion homeassistant/components/cover/zwave.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,17 @@
# Because we do not compile openzwave on CI
# pylint: disable=import-error
import logging
from homeassistant.components.cover import DOMAIN
from homeassistant.components.cover import (
DOMAIN, SUPPORT_OPEN, SUPPORT_CLOSE)
from homeassistant.components.zwave import ZWaveDeviceEntity
from homeassistant.components import zwave
from homeassistant.components.zwave import workaround
from homeassistant.components.cover import CoverDevice

_LOGGER = logging.getLogger(__name__)

SUPPORT_GARAGE = SUPPORT_OPEN | SUPPORT_CLOSE


def setup_platform(hass, config, add_devices, discovery_info=None):
"""Find and return Z-Wave covers."""
Expand Down Expand Up @@ -133,3 +136,8 @@ def open_cover(self):
def device_class(self):
"""Return the class of this device, from component DEVICE_CLASSES."""
return 'garage'

@property
def supported_features(self):
"""Flag supported features."""
return SUPPORT_GARAGE
11 changes: 11 additions & 0 deletions tests/components/cover/test_demo.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,17 @@ def tearDown(self): # pylint: disable=invalid-name
"""Stop down everything that was started."""
self.hass.stop()

def test_supported_features(self):
"""Test cover supported features."""
state = self.hass.states.get('cover.garage_door')
self.assertEqual(3, state.attributes.get('supported_features'))
state = self.hass.states.get('cover.kitchen_window')
self.assertEqual(11, state.attributes.get('supported_features'))
state = self.hass.states.get('cover.hall_window')
self.assertEqual(15, state.attributes.get('supported_features'))
state = self.hass.states.get('cover.living_room_window')
self.assertEqual(255, state.attributes.get('supported_features'))

def test_close_cover(self):
"""Test closing the cover."""
state = self.hass.states.get(ENTITY_COVER)
Expand Down