Fix COMMAND_CLASS_BARRIER_OPERATOR for dev branch of OpenZwave (#8574)

* Update zwave.py to work with updated OpenZwave library

Update zwave.py to work with updated OpenZwave library

* Update zwave.py

* Update zwave.py

* Update to fix garage door openers

Update to fix garage door support for latest version of openzwavelib

* Update to cover.zwave list of states

Update to cover.zwave to provide list of states based on dev version of
openzwave lib

* Some values not saved

* Formatting fix

* Formatting fix

* Variable typo

* Formatting fix

* Formatting

* Variable Update

Variable Update and properties added

* Formatting fixes

* Formatting Fix

* Update test case for door states

* Formatting / Testing process fix

* Formatting

* Formatting / Test Fixes

* Variable rename

* Added members to CoverDevice

* Removed un-needed else

* Formatting

* Formatting

* Variable name changes and const updates

* Changed variable names to cover_state
* Added constains into const.py
* Updated to change the main state on the cover device

* Fixes

* Formatting fixes

* Formatting/Variables

* Formatting

* Variable fixes

* Import update

* Formatting  / Variables

* Update test for new states

* Revert state changes

* Test fix

* Variable Fix

* Formatting

* Variable typo

* Missing constant

* Variable fix

* Requested changes

* Added is_opening
* Added is_closing
* Updated test based on changes

* Formatting

* Changed cover_state back to _state

* Formatting and variable fixes

* Test fixes

* Formatting and variable touchup

* Formatting

* Optimizations

* Add new cover features to demo

* Add tests for demo cover closing/opening

* Remove unused STATE_STOPPED

* Add tests for new zwave cover values
This commit is contained in:
Chris 2017-07-27 15:57:30 -07:00 committed by Adam Mills
parent 0ab0e35d59
commit e8ce41874c
6 changed files with 91 additions and 21 deletions

View File

@ -23,7 +23,7 @@ from homeassistant.const import (
SERVICE_OPEN_COVER, SERVICE_CLOSE_COVER, SERVICE_SET_COVER_POSITION, SERVICE_OPEN_COVER, SERVICE_CLOSE_COVER, SERVICE_SET_COVER_POSITION,
SERVICE_STOP_COVER, SERVICE_OPEN_COVER_TILT, SERVICE_CLOSE_COVER_TILT, SERVICE_STOP_COVER, SERVICE_OPEN_COVER_TILT, SERVICE_CLOSE_COVER_TILT,
SERVICE_STOP_COVER_TILT, SERVICE_SET_COVER_TILT_POSITION, STATE_OPEN, SERVICE_STOP_COVER_TILT, SERVICE_SET_COVER_TILT_POSITION, STATE_OPEN,
STATE_CLOSED, STATE_UNKNOWN, ATTR_ENTITY_ID) STATE_CLOSED, STATE_UNKNOWN, STATE_OPENING, STATE_CLOSING, ATTR_ENTITY_ID)
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -225,6 +225,11 @@ class CoverDevice(Entity):
@property @property
def state(self): def state(self):
"""Return the state of the cover.""" """Return the state of the cover."""
if self.is_opening:
return STATE_OPENING
if self.is_closing:
return STATE_CLOSING
closed = self.is_closed closed = self.is_closed
if closed is None: if closed is None:
@ -262,6 +267,16 @@ class CoverDevice(Entity):
return supported_features return supported_features
@property
def is_opening(self):
"""Return if the cover is opening or not."""
pass
@property
def is_closing(self):
"""Return if the cover is closing or not."""
pass
@property @property
def is_closed(self): def is_closed(self):
"""Return if the cover is closed or not.""" """Return if the cover is closed or not."""

View File

@ -35,10 +35,12 @@ class DemoCover(CoverDevice):
self._set_position = None self._set_position = None
self._set_tilt_position = None self._set_tilt_position = None
self._tilt_position = tilt_position self._tilt_position = tilt_position
self._closing = True self._requested_closing = True
self._closing_tilt = True self._requested_closing_tilt = True
self._unsub_listener_cover = None self._unsub_listener_cover = None
self._unsub_listener_cover_tilt = None self._unsub_listener_cover_tilt = None
self._is_opening = False
self._is_closing = False
if position is None: if position is None:
self._closed = True self._closed = True
else: else:
@ -69,6 +71,16 @@ class DemoCover(CoverDevice):
"""Return if the cover is closed.""" """Return if the cover is closed."""
return self._closed return self._closed
@property
def is_closing(self):
"""Return if the cover is closing."""
return self._is_closing
@property
def is_opening(self):
"""Return if the cover is opening."""
return self._is_opening
@property @property
def device_class(self): def device_class(self):
"""Return the class of this device, from component DEVICE_CLASSES.""" """Return the class of this device, from component DEVICE_CLASSES."""
@ -90,8 +102,10 @@ class DemoCover(CoverDevice):
self.schedule_update_ha_state() self.schedule_update_ha_state()
return return
self._is_closing = True
self._listen_cover() self._listen_cover()
self._closing = True self._requested_closing = True
self.schedule_update_ha_state()
def close_cover_tilt(self, **kwargs): def close_cover_tilt(self, **kwargs):
"""Close the cover tilt.""" """Close the cover tilt."""
@ -99,7 +113,7 @@ class DemoCover(CoverDevice):
return return
self._listen_cover_tilt() self._listen_cover_tilt()
self._closing_tilt = True self._requested_closing_tilt = True
def open_cover(self, **kwargs): def open_cover(self, **kwargs):
"""Open the cover.""" """Open the cover."""
@ -110,8 +124,10 @@ class DemoCover(CoverDevice):
self.schedule_update_ha_state() self.schedule_update_ha_state()
return return
self._is_opening = True
self._listen_cover() self._listen_cover()
self._closing = False self._requested_closing = False
self.schedule_update_ha_state()
def open_cover_tilt(self, **kwargs): def open_cover_tilt(self, **kwargs):
"""Open the cover tilt.""" """Open the cover tilt."""
@ -119,7 +135,7 @@ class DemoCover(CoverDevice):
return return
self._listen_cover_tilt() self._listen_cover_tilt()
self._closing_tilt = False self._requested_closing_tilt = False
def set_cover_position(self, position, **kwargs): def set_cover_position(self, position, **kwargs):
"""Move the cover to a specific position.""" """Move the cover to a specific position."""
@ -128,7 +144,7 @@ class DemoCover(CoverDevice):
return return
self._listen_cover() self._listen_cover()
self._closing = position < self._position self._requested_closing = position < self._position
def set_cover_tilt_position(self, tilt_position, **kwargs): def set_cover_tilt_position(self, tilt_position, **kwargs):
"""Move the cover til to a specific position.""" """Move the cover til to a specific position."""
@ -137,10 +153,12 @@ class DemoCover(CoverDevice):
return return
self._listen_cover_tilt() self._listen_cover_tilt()
self._closing_tilt = tilt_position < self._tilt_position self._requested_closing_tilt = tilt_position < self._tilt_position
def stop_cover(self, **kwargs): def stop_cover(self, **kwargs):
"""Stop the cover.""" """Stop the cover."""
self._is_closing = False
self._is_opening = False
if self._position is None: if self._position is None:
return return
if self._unsub_listener_cover is not None: if self._unsub_listener_cover is not None:
@ -166,7 +184,7 @@ class DemoCover(CoverDevice):
def _time_changed_cover(self, now): def _time_changed_cover(self, now):
"""Track time changes.""" """Track time changes."""
if self._closing: if self._requested_closing:
self._position -= 10 self._position -= 10
else: else:
self._position += 10 self._position += 10
@ -186,7 +204,7 @@ class DemoCover(CoverDevice):
def _time_changed_cover_tilt(self, now): def _time_changed_cover_tilt(self, now):
"""Track time changes.""" """Track time changes."""
if self._closing_tilt: if self._requested_closing_tilt:
self._tilt_position -= 10 self._tilt_position -= 10
else: else:
self._tilt_position += 10 self._tilt_position += 10

View File

@ -110,24 +110,36 @@ class ZwaveGarageDoor(zwave.ZWaveDeviceEntity, CoverDevice):
def __init__(self, values): def __init__(self, values):
"""Initialize the zwave garage door.""" """Initialize the zwave garage door."""
ZWaveDeviceEntity.__init__(self, values, DOMAIN) ZWaveDeviceEntity.__init__(self, values, DOMAIN)
self._state = None
self.update_properties() self.update_properties()
def update_properties(self): def update_properties(self):
"""Handle data changes for node values.""" """Handle data changes for node values."""
self._state = self.values.primary.data self._state = self.values.primary.data
_LOGGER.debug("self._state=%s", self._state)
@property
def is_opening(self):
"""Return true if cover is in an opening state."""
return self._state == "Opening"
@property
def is_closing(self):
"""Return true if cover is in an closing state."""
return self._state == "Closing"
@property @property
def is_closed(self): def is_closed(self):
"""Return the current position of Zwave garage door.""" """Return the current position of Zwave garage door."""
return not self._state return self._state == "Closed"
def close_cover(self): def close_cover(self):
"""Close the garage door.""" """Close the garage door."""
self.values.primary.data = False self.values.primary.data = "Closed"
def open_cover(self): def open_cover(self):
"""Open the garage door.""" """Open the garage door."""
self.values.primary.data = True self.values.primary.data = "Opened"
@property @property
def device_class(self): def device_class(self):

View File

@ -188,7 +188,9 @@ STATE_HOME = 'home'
STATE_NOT_HOME = 'not_home' STATE_NOT_HOME = 'not_home'
STATE_UNKNOWN = 'unknown' STATE_UNKNOWN = 'unknown'
STATE_OPEN = 'open' STATE_OPEN = 'open'
STATE_OPENING = 'opening'
STATE_CLOSED = 'closed' STATE_CLOSED = 'closed'
STATE_CLOSING = 'closing'
STATE_PLAYING = 'playing' STATE_PLAYING = 'playing'
STATE_PAUSED = 'paused' STATE_PAUSED = 'paused'
STATE_IDLE = 'idle' STATE_IDLE = 'idle'

View File

@ -38,29 +38,37 @@ class TestCoverDemo(unittest.TestCase):
def test_close_cover(self): def test_close_cover(self):
"""Test closing the cover.""" """Test closing the cover."""
state = self.hass.states.get(ENTITY_COVER) state = self.hass.states.get(ENTITY_COVER)
self.assertEqual(state.state, 'open')
self.assertEqual(70, state.attributes.get('current_position')) self.assertEqual(70, state.attributes.get('current_position'))
cover.close_cover(self.hass, ENTITY_COVER) cover.close_cover(self.hass, ENTITY_COVER)
self.hass.block_till_done() self.hass.block_till_done()
state = self.hass.states.get(ENTITY_COVER)
self.assertEqual(state.state, 'closing')
for _ in range(7): for _ in range(7):
future = dt_util.utcnow() + timedelta(seconds=1) future = dt_util.utcnow() + timedelta(seconds=1)
fire_time_changed(self.hass, future) fire_time_changed(self.hass, future)
self.hass.block_till_done() self.hass.block_till_done()
state = self.hass.states.get(ENTITY_COVER) state = self.hass.states.get(ENTITY_COVER)
self.assertEqual(state.state, 'closed')
self.assertEqual(0, state.attributes.get('current_position')) self.assertEqual(0, state.attributes.get('current_position'))
def test_open_cover(self): def test_open_cover(self):
"""Test opening the cover.""" """Test opening the cover."""
state = self.hass.states.get(ENTITY_COVER) state = self.hass.states.get(ENTITY_COVER)
self.assertEqual(state.state, 'open')
self.assertEqual(70, state.attributes.get('current_position')) self.assertEqual(70, state.attributes.get('current_position'))
cover.open_cover(self.hass, ENTITY_COVER) cover.open_cover(self.hass, ENTITY_COVER)
self.hass.block_till_done() self.hass.block_till_done()
state = self.hass.states.get(ENTITY_COVER)
self.assertEqual(state.state, 'opening')
for _ in range(7): for _ in range(7):
future = dt_util.utcnow() + timedelta(seconds=1) future = dt_util.utcnow() + timedelta(seconds=1)
fire_time_changed(self.hass, future) fire_time_changed(self.hass, future)
self.hass.block_till_done() self.hass.block_till_done()
state = self.hass.states.get(ENTITY_COVER) state = self.hass.states.get(ENTITY_COVER)
self.assertEqual(state.state, 'open')
self.assertEqual(100, state.attributes.get('current_position')) self.assertEqual(100, state.attributes.get('current_position'))
def test_set_cover_position(self): def test_set_cover_position(self):

View File

@ -161,31 +161,46 @@ def test_roller_reverse_open_close(hass, mock_openzwave):
def test_garage_value_changed(hass, mock_openzwave): def test_garage_value_changed(hass, mock_openzwave):
"""Test position changed.""" """Test position changed."""
node = MockNode() node = MockNode()
value = MockValue(data=False, node=node, value = MockValue(data="Closed", node=node,
command_class=const.COMMAND_CLASS_BARRIER_OPERATOR) command_class=const.COMMAND_CLASS_BARRIER_OPERATOR)
values = MockEntityValues(primary=value, node=node) values = MockEntityValues(primary=value, node=node)
device = zwave.get_device(hass=hass, node=node, values=values, device = zwave.get_device(hass=hass, node=node, values=values,
node_config={}) node_config={})
assert device.is_closed assert device.is_closed
assert not device.is_opening
assert not device.is_closing
value.data = True value.data = "Opening"
value_changed(value) value_changed(value)
assert not device.is_closed assert not device.is_closed
assert device.is_opening
assert not device.is_closing
value.data = "Opened"
value_changed(value)
assert not device.is_closed
assert not device.is_opening
assert not device.is_closing
value.data = "Closing"
value_changed(value)
assert not device.is_closed
assert not device.is_opening
assert device.is_closing
def test_garage_commands(hass, mock_openzwave): def test_garage_commands(hass, mock_openzwave):
"""Test position changed.""" """Test position changed."""
node = MockNode() node = MockNode()
value = MockValue(data=False, node=node, value = MockValue(data="Closed", node=node,
command_class=const.COMMAND_CLASS_BARRIER_OPERATOR) command_class=const.COMMAND_CLASS_BARRIER_OPERATOR)
values = MockEntityValues(primary=value, node=node) values = MockEntityValues(primary=value, node=node)
device = zwave.get_device(hass=hass, node=node, values=values, device = zwave.get_device(hass=hass, node=node, values=values,
node_config={}) node_config={})
assert value.data is False assert value.data == "Closed"
device.open_cover() device.open_cover()
assert value.data is True assert value.data == "Opened"
device.close_cover() device.close_cover()
assert value.data is False assert value.data == "Closed"