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:
parent
f59e242c63
commit
2e62053629
3 changed files with 126 additions and 10 deletions
|
@ -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
|
||||
|
|
86
homeassistant/components/rollershutter/zwave.py
Normal file
86
homeassistant/components/rollershutter/zwave.py
Normal 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
|
|
@ -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, {})
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue