From a94e7ec25d204868d773845dd2ba853c6e323305 Mon Sep 17 00:00:00 2001 From: Adam Mills Date: Sun, 30 Jul 2017 00:40:56 -0400 Subject: [PATCH] Fix Z-Wave barrier discovery for new API (#8706) --- homeassistant/components/cover/zwave.py | 55 ++++++++++++------ homeassistant/components/zwave/const.py | 3 + .../components/zwave/discovery_schemas.py | 22 ++++++-- tests/components/cover/test_zwave.py | 56 +++++++++++++++++-- 4 files changed, 111 insertions(+), 25 deletions(-) diff --git a/homeassistant/components/cover/zwave.py b/homeassistant/components/cover/zwave.py index b8daab81503..3c038125616 100644 --- a/homeassistant/components/cover/zwave.py +++ b/homeassistant/components/cover/zwave.py @@ -27,10 +27,12 @@ def get_device(hass, values, node_config, **kwargs): zwave.const.COMMAND_CLASS_SWITCH_MULTILEVEL and values.primary.index == 0): return ZwaveRollershutter(hass, values, invert_buttons) - elif (values.primary.command_class in [ - zwave.const.COMMAND_CLASS_SWITCH_BINARY, - zwave.const.COMMAND_CLASS_BARRIER_OPERATOR]): - return ZwaveGarageDoor(values) + elif (values.primary.command_class == + zwave.const.COMMAND_CLASS_SWITCH_BINARY): + return ZwaveGarageDoorSwitch(values) + elif (values.primary.command_class == + zwave.const.COMMAND_CLASS_BARRIER_OPERATOR): + return ZwaveGarageDoorBarrier(values) return None @@ -104,8 +106,8 @@ class ZwaveRollershutter(zwave.ZWaveDeviceEntity, CoverDevice): self._network.manager.releaseButton(self._open_id) -class ZwaveGarageDoor(zwave.ZWaveDeviceEntity, CoverDevice): - """Representation of an Zwave garage door device.""" +class ZwaveGarageDoorBase(zwave.ZWaveDeviceEntity, CoverDevice): + """Base class for a Zwave garage door device.""" def __init__(self, values): """Initialize the zwave garage door.""" @@ -118,6 +120,37 @@ class ZwaveGarageDoor(zwave.ZWaveDeviceEntity, CoverDevice): self._state = self.values.primary.data _LOGGER.debug("self._state=%s", self._state) + @property + 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 + + +class ZwaveGarageDoorSwitch(ZwaveGarageDoorBase): + """Representation of a switch based Zwave garage door device.""" + + @property + def is_closed(self): + """Return the current position of Zwave garage door.""" + return not self._state + + def close_cover(self): + """Close the garage door.""" + self.values.primary.data = False + + def open_cover(self): + """Open the garage door.""" + self.values.primary.data = True + + +class ZwaveGarageDoorBarrier(ZwaveGarageDoorBase): + """Representation of a barrier operator Zwave garage door device.""" + @property def is_opening(self): """Return true if cover is in an opening state.""" @@ -140,13 +173,3 @@ class ZwaveGarageDoor(zwave.ZWaveDeviceEntity, CoverDevice): def open_cover(self): """Open the garage door.""" self.values.primary.data = "Opened" - - @property - 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 diff --git a/homeassistant/components/zwave/const.py b/homeassistant/components/zwave/const.py index 4b18ef46475..b72d9eb0cff 100644 --- a/homeassistant/components/zwave/const.py +++ b/homeassistant/components/zwave/const.py @@ -345,6 +345,9 @@ INDEX_ALARM_TYPE = 0 INDEX_ALARM_LEVEL = 1 INDEX_ALARM_ACCESS_CONTROL = 9 +# https://github.com/OpenZWave/open-zwave/blob/de1c0e60edf1d1bee81f1ae54b1f58e66c6fd8ed/cpp/src/command_classes/BarrierOperator.cpp#L69 +INDEX_BARRIER_OPERATOR_LABEL = 1 + # https://github.com/OpenZWave/open-zwave/blob/67f180eb565f0054f517ff395c71ecd706f6a837/cpp/src/command_classes/DoorLock.cpp#L77 INDEX_DOOR_LOCK_LOCK = 0 diff --git a/homeassistant/components/zwave/discovery_schemas.py b/homeassistant/components/zwave/discovery_schemas.py index 26a5d1c4758..f38bc308649 100644 --- a/homeassistant/components/zwave/discovery_schemas.py +++ b/homeassistant/components/zwave/discovery_schemas.py @@ -92,7 +92,7 @@ DISCOVERY_SCHEMAS = [ const.DISC_INDEX: [const.INDEX_SWITCH_MULTILEVEL_DIM], const.DISC_OPTIONAL: True, }})}, - {const.DISC_COMPONENT: 'cover', # Garage Door + {const.DISC_COMPONENT: 'cover', # Garage Door Switch const.DISC_GENERIC_DEVICE_CLASS: [ const.GENERIC_TYPE_SWITCH_MULTILEVEL, const.GENERIC_TYPE_ENTRY_CONTROL], @@ -105,11 +105,25 @@ DISCOVERY_SCHEMAS = [ const.SPECIFIC_TYPE_SECURE_DOOR], const.DISC_VALUES: dict(DEFAULT_VALUES_SCHEMA, **{ const.DISC_PRIMARY: { - const.DISC_COMMAND_CLASS: [ - const.COMMAND_CLASS_BARRIER_OPERATOR, - const.COMMAND_CLASS_SWITCH_BINARY], + const.DISC_COMMAND_CLASS: [const.COMMAND_CLASS_SWITCH_BINARY], const.DISC_GENRE: const.GENRE_USER, }})}, + {const.DISC_COMPONENT: 'cover', # Garage Door Barrier + const.DISC_GENERIC_DEVICE_CLASS: [ + const.GENERIC_TYPE_SWITCH_MULTILEVEL, + const.GENERIC_TYPE_ENTRY_CONTROL], + const.DISC_SPECIFIC_DEVICE_CLASS: [ + const.SPECIFIC_TYPE_CLASS_A_MOTOR_CONTROL, + const.SPECIFIC_TYPE_CLASS_B_MOTOR_CONTROL, + const.SPECIFIC_TYPE_CLASS_C_MOTOR_CONTROL, + const.SPECIFIC_TYPE_MOTOR_MULTIPOSITION, + const.SPECIFIC_TYPE_SECURE_BARRIER_ADDON, + const.SPECIFIC_TYPE_SECURE_DOOR], + const.DISC_VALUES: dict(DEFAULT_VALUES_SCHEMA, **{ + const.DISC_PRIMARY: { + const.DISC_COMMAND_CLASS: [const.COMMAND_CLASS_BARRIER_OPERATOR], + const.DISC_INDEX: [const.INDEX_BARRIER_OPERATOR_LABEL], + }})}, {const.DISC_COMPONENT: 'fan', const.DISC_GENERIC_DEVICE_CLASS: [ const.GENERIC_TYPE_SWITCH_MULTILEVEL], diff --git a/tests/components/cover/test_zwave.py b/tests/components/cover/test_zwave.py index fe9abe7172c..4b9be9f5e00 100644 --- a/tests/components/cover/test_zwave.py +++ b/tests/components/cover/test_zwave.py @@ -32,16 +32,30 @@ def test_get_device_detects_rollershutter(hass, mock_openzwave): assert isinstance(device, zwave.ZwaveRollershutter) -def test_get_device_detects_garagedoor(hass, mock_openzwave): +def test_get_device_detects_garagedoor_switch(hass, mock_openzwave): """Test device returns garage door.""" node = MockNode() - value = MockValue(data=0, node=node, + value = MockValue(data=False, node=node, + command_class=const.COMMAND_CLASS_SWITCH_BINARY) + values = MockEntityValues(primary=value, node=node) + + device = zwave.get_device(hass=hass, node=node, values=values, + node_config={}) + assert isinstance(device, zwave.ZwaveGarageDoorSwitch) + assert device.device_class == "garage" + assert device.supported_features == SUPPORT_OPEN | SUPPORT_CLOSE + + +def test_get_device_detects_garagedoor_barrier(hass, mock_openzwave): + """Test device returns garage door.""" + node = MockNode() + value = MockValue(data="Closed", node=node, command_class=const.COMMAND_CLASS_BARRIER_OPERATOR) values = MockEntityValues(primary=value, node=node) device = zwave.get_device(hass=hass, node=node, values=values, node_config={}) - assert isinstance(device, zwave.ZwaveGarageDoor) + assert isinstance(device, zwave.ZwaveGarageDoorBarrier) assert device.device_class == "garage" assert device.supported_features == SUPPORT_OPEN | SUPPORT_CLOSE @@ -158,7 +172,39 @@ def test_roller_reverse_open_close(hass, mock_openzwave): assert value_id == close_value.value_id -def test_garage_value_changed(hass, mock_openzwave): +def test_switch_garage_value_changed(hass, mock_openzwave): + """Test position changed.""" + node = MockNode() + value = MockValue(data=False, node=node, + command_class=const.COMMAND_CLASS_SWITCH_BINARY) + values = MockEntityValues(primary=value, node=node) + device = zwave.get_device(hass=hass, node=node, values=values, + node_config={}) + + assert device.is_closed + + value.data = True + value_changed(value) + assert not device.is_closed + + +def test_switch_garage_commands(hass, mock_openzwave): + """Test position changed.""" + node = MockNode() + value = MockValue(data=False, node=node, + command_class=const.COMMAND_CLASS_SWITCH_BINARY) + values = MockEntityValues(primary=value, node=node) + device = zwave.get_device(hass=hass, node=node, values=values, + node_config={}) + + assert value.data is False + device.open_cover() + assert value.data is True + device.close_cover() + assert value.data is False + + +def test_barrier_garage_value_changed(hass, mock_openzwave): """Test position changed.""" node = MockNode() value = MockValue(data="Closed", node=node, @@ -190,7 +236,7 @@ def test_garage_value_changed(hass, mock_openzwave): assert device.is_closing -def test_garage_commands(hass, mock_openzwave): +def test_barrier_garage_commands(hass, mock_openzwave): """Test position changed.""" node = MockNode() value = MockValue(data="Closed", node=node,