Basic implementation of Zwave Rollershutters (#2313)

* Basic implementation of Zwave Rollershutters

* Better filtering, by @wokar

* Fix typo

* Remove polling from component, and loop fix

* linter fix

* Filter to channel devices to correct component

* Remove overwriting of parent node name
This commit is contained in:
John Arild Berentsen 2016-06-20 07:30:57 +02:00 committed by Paulus Schoutsen
parent f59e242c63
commit 2e62053629
3 changed files with 126 additions and 10 deletions

View file

@ -7,7 +7,6 @@ https://home-assistant.io/components/light.zwave/
# Because we do not compile openzwave on CI
# pylint: disable=import-error
from threading import Timer
from homeassistant.components.light import ATTR_BRIGHTNESS, DOMAIN, Light
from homeassistant.components import zwave
from homeassistant.const import STATE_OFF, STATE_ON

View file

@ -0,0 +1,86 @@
"""
Support for Zwave roller shutter components.
For more details about this platform, please refer to the documentation
https://home-assistant.io/components/rollershutter.zwave/
"""
# Because we do not compile openzwave on CI
# pylint: disable=import-error
import logging
from homeassistant.components.rollershutter import DOMAIN
from homeassistant.components.zwave import ZWaveDeviceEntity
from homeassistant.components import zwave
from homeassistant.components.rollershutter import RollershutterDevice
COMMAND_CLASS_SWITCH_MULTILEVEL = 0x26 # 38
COMMAND_CLASS_SWITCH_BINARY = 0x25 # 37
_LOGGER = logging.getLogger(__name__)
def setup_platform(hass, config, add_devices, discovery_info=None):
"""Find and return Z-Wave roller shutters."""
if discovery_info is None or zwave.NETWORK is None:
return
node = zwave.NETWORK.nodes[discovery_info[zwave.ATTR_NODE_ID]]
value = node.values[discovery_info[zwave.ATTR_VALUE_ID]]
if value.command_class != zwave.COMMAND_CLASS_SWITCH_MULTILEVEL:
return
if value.index != 1:
return
value.set_change_verified(False)
add_devices([ZwaveRollershutter(value)])
class ZwaveRollershutter(zwave.ZWaveDeviceEntity, RollershutterDevice):
"""Representation of an Zwave roller shutter."""
def __init__(self, value):
"""Initialize the zwave rollershutter."""
from openzwave.network import ZWaveNetwork
from pydispatch import dispatcher
ZWaveDeviceEntity.__init__(self, value, DOMAIN)
self._node = value.node
dispatcher.connect(
self.value_changed, ZWaveNetwork.SIGNAL_VALUE_CHANGED)
def value_changed(self, value):
"""Called when a value has changed on the network."""
if self._value.node == value.node:
self.update_ha_state(True)
_LOGGER.debug("Value changed on network %s", value)
@property
def current_position(self):
"""Return the current position of Zwave roller shutter."""
for value in self._node.get_values(
class_id=COMMAND_CLASS_SWITCH_MULTILEVEL).values():
if value.command_class == 38 and value.index == 0:
return value.data
def move_up(self, **kwargs):
"""Move the roller shutter up."""
for value in self._node.get_values(
class_id=COMMAND_CLASS_SWITCH_MULTILEVEL).values():
if value.command_class == 38 and value.index == 0:
value.data = 255
break
def move_down(self, **kwargs):
"""Move the roller shutter down."""
for value in self._node.get_values(
class_id=COMMAND_CLASS_SWITCH_MULTILEVEL).values():
if value.command_class == 38 and value.index == 0:
value.data = 0
break
def stop(self, **kwargs):
"""Stop the roller shutter."""
for value in self._node.get_values(
class_id=COMMAND_CLASS_SWITCH_BINARY).values():
# Rollershutter will toggle between UP (True), DOWN (False).
# It also stops the shutter if the same value is sent while moving.
value.data = value.data

View file

@ -50,6 +50,14 @@ COMMAND_CLASS_ALARM = 113 # 0x71
COMMAND_CLASS_THERMOSTAT_SETPOINT = 67 # 0x43
COMMAND_CLASS_THERMOSTAT_FAN_MODE = 68 # 0x44
SPECIFIC_DEVICE_CLASS_WHATEVER = None
SPECIFIC_DEVICE_CLASS_MULTILEVEL_POWER_SWITCH = 1
SPECIFIC_DEVICE_CLASS_MULTIPOSITION_MOTOR = 3
SPECIFIC_DEVICE_CLASS_MULTILEVEL_SCENE = 4
SPECIFIC_DEVICE_CLASS_MOTOR_CONTROL_CLASS_A = 5
SPECIFIC_DEVICE_CLASS_MOTOR_CONTROL_CLASS_B = 6
SPECIFIC_DEVICE_CLASS_MOTOR_CONTROL_CLASS_C = 7
GENRE_WHATEVER = None
GENRE_USER = "User"
@ -60,38 +68,54 @@ TYPE_DECIMAL = "Decimal"
# List of tuple (DOMAIN, discovered service, supported command classes,
# value type).
# value type, genre type, specific device class).
DISCOVERY_COMPONENTS = [
('sensor',
[COMMAND_CLASS_SENSOR_MULTILEVEL,
COMMAND_CLASS_METER,
COMMAND_CLASS_ALARM],
TYPE_WHATEVER,
GENRE_USER),
GENRE_USER,
SPECIFIC_DEVICE_CLASS_WHATEVER),
('light',
[COMMAND_CLASS_SWITCH_MULTILEVEL],
TYPE_BYTE,
GENRE_USER),
GENRE_USER,
[SPECIFIC_DEVICE_CLASS_MULTILEVEL_POWER_SWITCH,
SPECIFIC_DEVICE_CLASS_MULTILEVEL_SCENE]),
('switch',
[COMMAND_CLASS_SWITCH_BINARY],
TYPE_BOOL,
GENRE_USER),
GENRE_USER,
SPECIFIC_DEVICE_CLASS_WHATEVER),
('binary_sensor',
[COMMAND_CLASS_SENSOR_BINARY],
TYPE_BOOL,
GENRE_USER),
GENRE_USER,
SPECIFIC_DEVICE_CLASS_WHATEVER),
('thermostat',
[COMMAND_CLASS_THERMOSTAT_SETPOINT],
TYPE_WHATEVER,
GENRE_WHATEVER),
GENRE_WHATEVER,
SPECIFIC_DEVICE_CLASS_WHATEVER),
('hvac',
[COMMAND_CLASS_THERMOSTAT_FAN_MODE],
TYPE_WHATEVER,
GENRE_WHATEVER),
GENRE_WHATEVER,
SPECIFIC_DEVICE_CLASS_WHATEVER),
('lock',
[COMMAND_CLASS_DOOR_LOCK],
TYPE_BOOL,
GENRE_USER),
GENRE_USER,
SPECIFIC_DEVICE_CLASS_WHATEVER),
('rollershutter',
[COMMAND_CLASS_SWITCH_MULTILEVEL],
TYPE_WHATEVER,
GENRE_USER,
[SPECIFIC_DEVICE_CLASS_MOTOR_CONTROL_CLASS_A,
SPECIFIC_DEVICE_CLASS_MOTOR_CONTROL_CLASS_B,
SPECIFIC_DEVICE_CLASS_MOTOR_CONTROL_CLASS_C,
SPECIFIC_DEVICE_CLASS_MULTIPOSITION_MOTOR]),
]
@ -222,7 +246,8 @@ def setup(hass, config):
for (component,
command_ids,
value_type,
value_genre) in DISCOVERY_COMPONENTS:
value_genre,
specific_device_class) in DISCOVERY_COMPONENTS:
if value.command_class not in command_ids:
continue
@ -230,8 +255,14 @@ def setup(hass, config):
continue
if value_genre is not None and value_genre != value.genre:
continue
if specific_device_class is not None and \
specific_device_class != node.specific:
continue
# Configure node
_LOGGER.debug("Node_id=%s Value type=%s Genre=%s \
Specific Device_class=%s", node.node_id,
value.type, value.genre, specific_device_class)
name = "{}.{}".format(component, _object_id(value))
node_config = customize.get(name, {})