Skip to content
Closed
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
4 changes: 3 additions & 1 deletion homeassistant/components/zwave/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
CONF_DEVICE_CONFIG = 'device_config'
CONF_DEVICE_CONFIG_GLOB = 'device_config_glob'
CONF_DEVICE_CONFIG_DOMAIN = 'device_config_domain'
CONF_TILT_OPEN_POSITION = 'tilt_open_position'

DATA_ZWAVE_CONFIG = 'zwave_config'

Expand Down Expand Up @@ -153,7 +154,8 @@
vol.Optional(CONF_REFRESH_VALUE, default=DEFAULT_CONF_REFRESH_VALUE):
cv.boolean,
vol.Optional(CONF_REFRESH_DELAY, default=DEFAULT_CONF_REFRESH_DELAY):
cv.positive_int
cv.positive_int,
vol.Optional(CONF_TILT_OPEN_POSITION): cv.positive_int,
})

SIGNAL_REFRESH_ENTITY_FORMAT = 'zwave_refresh_entity_{}'
Expand Down
132 changes: 129 additions & 3 deletions homeassistant/components/zwave/cover.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,37 @@
import logging
from homeassistant.core import callback
from homeassistant.components.cover import (
DOMAIN, SUPPORT_OPEN, SUPPORT_CLOSE, ATTR_POSITION)
DOMAIN, SUPPORT_OPEN, SUPPORT_CLOSE, ATTR_POSITION, ATTR_TILT_POSITION)
from homeassistant.components.cover import CoverDevice
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from . import (
ZWaveDeviceEntity, CONF_INVERT_OPENCLOSE_BUTTONS, CONF_INVERT_PERCENT,
workaround)
workaround, CONF_TILT_OPEN_POSITION)
from .const import (
COMMAND_CLASS_SWITCH_MULTILEVEL, COMMAND_CLASS_SWITCH_BINARY,
COMMAND_CLASS_BARRIER_OPERATOR, DATA_NETWORK)
COMMAND_CLASS_BARRIER_OPERATOR, COMMAND_CLASS_MANUFACTURER_PROPRIETARY,
DATA_NETWORK)

_LOGGER = logging.getLogger(__name__)

SUPPORT_GARAGE = SUPPORT_OPEN | SUPPORT_CLOSE


def _to_hex_str(id_in_bytes):
"""Convert a two byte value to a hex string.

Example: 0x1234 --> '0x1234'
"""
return '0x{:04x}'.format(id_in_bytes)


# For whatever reason node.manufacturer_id is of type string. So we need
# to convert the values.
FIBARO = _to_hex_str(workaround.FIBARO)
FIBARO_SHUTTERS = [_to_hex_str(workaround.FGR222_SHUTTER2),
_to_hex_str(workaround.FGRM222_SHUTTER2)]


async def async_setup_platform(
hass, config, async_add_entities, discovery_info=None):
"""Old method of setting up Z-Wave covers."""
Expand All @@ -40,6 +56,10 @@ def get_device(hass, values, node_config, **kwargs):
if (values.primary.command_class ==
COMMAND_CLASS_SWITCH_MULTILEVEL
and values.primary.index == 0):
if values.primary.node.manufacturer_id == FIBARO \
and values.primary.node.product_type in FIBARO_SHUTTERS:
return FibaroFGRM222(hass, values, invert_buttons, invert_percent,
node_config.get(CONF_TILT_OPEN_POSITION))
return ZwaveRollershutter(hass, values, invert_buttons, invert_percent)
if values.primary.command_class == COMMAND_CLASS_SWITCH_BINARY:
return ZwaveGarageDoorSwitch(values)
Expand Down Expand Up @@ -191,3 +211,109 @@ def close_cover(self, **kwargs):
def open_cover(self, **kwargs):
"""Open the garage door."""
self.values.primary.data = "Opened"


class FibaroFGRM222(ZwaveRollershutter):
"""Implementation of proprietary features for Fibaro FGR-222 / FGRM-222.

This adds support for the tilt feature for the ventian blind mode.
To enable this you need to configure the devices to use the venetian blind
Comment thread
ChristianKuehnel marked this conversation as resolved.
mode and to enable the proprietary command class:
* Set "3: Reports type to Blind position reports sent"
to value "the main controller using Fibar Command Class"
* Set "10: Roller Shutter operating modes"
to value "2 - Venetian Blind Mode, with positioning"
"""

def __init__(self, hass, values, invert_buttons, invert_percent,
open_tilt_position: int):
"""Initialize the FGRM-222."""
self._value_blinds = None
self._value_tilt = None
self._has_tilt_mode = False # type: bool
self._open_tilt_position = 50 # type: int
if open_tilt_position is not None:
self._open_tilt_position = open_tilt_position
super().__init__(hass, values, invert_buttons, invert_percent)

@property
def current_cover_tilt_position(self) -> int:
"""Get the tilt of the blinds.

Saturate values <5 and >94 so that it's easier to detect the end
positions in automations.
"""
if not self._has_tilt_mode:
return None
if self._value_tilt.data <= 5:
return 0
if self._value_tilt.data >= 95:
return 100
return self._value_tilt.data

def set_cover_tilt_position(self, **kwargs):
"""Move the cover tilt to a specific position."""
if not self._has_tilt_mode:
_LOGGER.error("Can't set cover tilt as device is not yet set up.")
else:
# Limit the range to [0-99], as this what that the ZWave command
# accepts.
tilt_position = max(0, min(99, kwargs.get(ATTR_TILT_POSITION)))
_LOGGER.debug("setting tilt to %d", tilt_position)
self._value_tilt.data = tilt_position

def open_cover_tilt(self, **kwargs):
"""Set slats to horizontal position."""
self.set_cover_tilt_position(tilt_position=self._open_tilt_position)

def close_cover_tilt(self, **kwargs):
"""Close the slats."""
self.set_cover_tilt_position(tilt_position=0)

def set_cover_position(self, **kwargs):
"""Move the roller shutter to a specific position.

If the venetian blinds mode is not activated, fall back to
the behavior of the parent class.
"""
if not self._has_tilt_mode:
super().set_cover_position(**kwargs)
else:
_LOGGER.debug('Setting cover position to %s',
kwargs.get(ATTR_POSITION))
self._value_blinds.data = kwargs.get(ATTR_POSITION)

def _configure_values(self):
"""Get the value objects from the node."""
for value in self.node.get_values(
class_id=COMMAND_CLASS_MANUFACTURER_PROPRIETARY).values():
if value is None:
continue
if value.index == 0:
self._value_blinds = value
elif value.index == 1:
self._value_tilt = value
else:
_LOGGER.warning('Undefined index %d for this command class',
value.index)

# If we've ever seen tilt != 0 assume we are in the venetian mode.
# This is not the best way to detect it. Once the bug below is
# resolved, check the config values of the node and only enable the
# tilt mode if they are set accordingly.
# https://github.com/home-assistant/home-assistant/issues/24404

if self._value_tilt is not None and self._value_tilt.data > 0:
self._has_tilt_mode = True
_LOGGER.info('Zwave node %s is a Fibaro FGR-222/FGRM-222'
' with tilt support.',
self.node_id)

def update_properties(self):
"""React on properties being updated."""
if not self._has_tilt_mode:
self._configure_values()
if self._value_blinds is not None:
self._current_position = self._value_blinds.data
else:
super().update_properties()