Zwave garagedoor (#2361)
* First go at zwave Garage door * Refactor of zwave discovery * Allaround fixes for rollershutter and garage door
This commit is contained in:
parent
600a3e3965
commit
ec8dc25c9c
3 changed files with 168 additions and 52 deletions
70
homeassistant/components/garage_door/zwave.py
Normal file
70
homeassistant/components/garage_door/zwave.py
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
"""
|
||||||
|
Support for Zwave garage door components.
|
||||||
|
|
||||||
|
For more details about this platform, please refer to the documentation
|
||||||
|
https://home-assistant.io/components/garagedoor.zwave/
|
||||||
|
"""
|
||||||
|
# Because we do not compile openzwave on CI
|
||||||
|
# pylint: disable=import-error
|
||||||
|
import logging
|
||||||
|
from homeassistant.components.garage_door import DOMAIN
|
||||||
|
from homeassistant.components.zwave import ZWaveDeviceEntity
|
||||||
|
from homeassistant.components import zwave
|
||||||
|
from homeassistant.components.garage_door import GarageDoorDevice
|
||||||
|
|
||||||
|
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 garage door device."""
|
||||||
|
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_BINARY:
|
||||||
|
return
|
||||||
|
if value.type != zwave.TYPE_BOOL:
|
||||||
|
return
|
||||||
|
if value.genre != zwave.GENRE_USER:
|
||||||
|
return
|
||||||
|
|
||||||
|
value.set_change_verified(False)
|
||||||
|
add_devices([ZwaveGarageDoor(value)])
|
||||||
|
|
||||||
|
|
||||||
|
class ZwaveGarageDoor(zwave.ZWaveDeviceEntity, GarageDoorDevice):
|
||||||
|
"""Representation of an Zwave garage door device."""
|
||||||
|
|
||||||
|
def __init__(self, value):
|
||||||
|
"""Initialize the zwave garage door."""
|
||||||
|
from openzwave.network import ZWaveNetwork
|
||||||
|
from pydispatch import dispatcher
|
||||||
|
ZWaveDeviceEntity.__init__(self, value, DOMAIN)
|
||||||
|
self._node = value.node
|
||||||
|
self._state = value.data
|
||||||
|
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._state = value.data
|
||||||
|
self.update_ha_state(True)
|
||||||
|
_LOGGER.debug("Value changed on network %s", value)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_closed(self):
|
||||||
|
"""Return the current position of Zwave garage door."""
|
||||||
|
return self._state
|
||||||
|
|
||||||
|
def close_door(self):
|
||||||
|
"""Close the garage door."""
|
||||||
|
self._value.node.set_switch(self._value.value_id, False)
|
||||||
|
|
||||||
|
def open_door(self):
|
||||||
|
"""Open the garage door."""
|
||||||
|
self._value.node.set_switch(self._value.value_id, True)
|
|
@ -28,7 +28,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
|
||||||
|
|
||||||
if value.command_class != zwave.COMMAND_CLASS_SWITCH_MULTILEVEL:
|
if value.command_class != zwave.COMMAND_CLASS_SWITCH_MULTILEVEL:
|
||||||
return
|
return
|
||||||
if value.index != 1:
|
if value.index != 0:
|
||||||
return
|
return
|
||||||
|
|
||||||
value.set_change_verified(False)
|
value.set_change_verified(False)
|
||||||
|
@ -56,26 +56,15 @@ class ZwaveRollershutter(zwave.ZWaveDeviceEntity, RollershutterDevice):
|
||||||
@property
|
@property
|
||||||
def current_position(self):
|
def current_position(self):
|
||||||
"""Return the current position of Zwave roller shutter."""
|
"""Return the current position of Zwave roller shutter."""
|
||||||
for value in self._node.get_values(
|
return self._value.data
|
||||||
class_id=COMMAND_CLASS_SWITCH_MULTILEVEL).values():
|
|
||||||
if value.command_class == 38 and value.index == 0:
|
|
||||||
return value.data
|
|
||||||
|
|
||||||
def move_up(self, **kwargs):
|
def move_up(self, **kwargs):
|
||||||
"""Move the roller shutter up."""
|
"""Move the roller shutter up."""
|
||||||
for value in self._node.get_values(
|
self._node.set_dimmer(self._value.value_id, 0)
|
||||||
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):
|
def move_down(self, **kwargs):
|
||||||
"""Move the roller shutter down."""
|
"""Move the roller shutter down."""
|
||||||
for value in self._node.get_values(
|
self._node.set_dimmer(self._value.value_id, 100)
|
||||||
class_id=COMMAND_CLASS_SWITCH_MULTILEVEL).values():
|
|
||||||
if value.command_class == 38 and value.index == 0:
|
|
||||||
value.data = 0
|
|
||||||
break
|
|
||||||
|
|
||||||
def stop(self, **kwargs):
|
def stop(self, **kwargs):
|
||||||
"""Stop the roller shutter."""
|
"""Stop the roller shutter."""
|
||||||
|
@ -84,3 +73,4 @@ class ZwaveRollershutter(zwave.ZWaveDeviceEntity, RollershutterDevice):
|
||||||
# Rollershutter will toggle between UP (True), DOWN (False).
|
# Rollershutter will toggle between UP (True), DOWN (False).
|
||||||
# It also stops the shutter if the same value is sent while moving.
|
# It also stops the shutter if the same value is sent while moving.
|
||||||
value.data = value.data
|
value.data = value.data
|
||||||
|
break
|
||||||
|
|
|
@ -39,23 +39,39 @@ SERVICE_TEST_NETWORK = "test_network"
|
||||||
|
|
||||||
EVENT_SCENE_ACTIVATED = "zwave.scene_activated"
|
EVENT_SCENE_ACTIVATED = "zwave.scene_activated"
|
||||||
|
|
||||||
COMMAND_CLASS_SWITCH_MULTILEVEL = 38
|
COMMAND_CLASS_WHATEVER = None
|
||||||
COMMAND_CLASS_DOOR_LOCK = 98
|
|
||||||
COMMAND_CLASS_SWITCH_BINARY = 37
|
|
||||||
COMMAND_CLASS_SENSOR_BINARY = 48
|
|
||||||
COMMAND_CLASS_SENSOR_MULTILEVEL = 49
|
COMMAND_CLASS_SENSOR_MULTILEVEL = 49
|
||||||
COMMAND_CLASS_METER = 50
|
COMMAND_CLASS_METER = 50
|
||||||
|
COMMAND_CLASS_ALARM = 113
|
||||||
|
COMMAND_CLASS_SWITCH_BINARY = 37
|
||||||
|
COMMAND_CLASS_SENSOR_BINARY = 48
|
||||||
|
COMMAND_CLASS_SWITCH_MULTILEVEL = 38
|
||||||
|
COMMAND_CLASS_DOOR_LOCK = 98
|
||||||
|
COMMAND_CLASS_THERMOSTAT_SETPOINT = 67
|
||||||
|
COMMAND_CLASS_THERMOSTAT_FAN_MODE = 68
|
||||||
COMMAND_CLASS_BATTERY = 128
|
COMMAND_CLASS_BATTERY = 128
|
||||||
COMMAND_CLASS_ALARM = 113 # 0x71
|
|
||||||
COMMAND_CLASS_THERMOSTAT_SETPOINT = 67 # 0x43
|
GENERIC_COMMAND_CLASS_WHATEVER = None
|
||||||
COMMAND_CLASS_THERMOSTAT_FAN_MODE = 68 # 0x44
|
GENERIC_COMMAND_CLASS_MULTILEVEL_SWITCH = 17
|
||||||
|
GENERIC_COMMAND_CLASS_BINARY_SWITCH = 16
|
||||||
|
GENERIC_COMMAND_CLASS_ENTRY_CONTROL = 64
|
||||||
|
GENERIC_COMMAND_CLASS_BINARY_SENSOR = 32
|
||||||
|
GENERIC_COMMAND_CLASS_MULTILEVEL_SENSOR = 33
|
||||||
|
GENERIC_COMMAND_CLASS_METER = 49
|
||||||
|
GENERIC_COMMAND_CLASS_ALARM_SENSOR = 161
|
||||||
|
GENERIC_COMMAND_CLASS_THERMOSTAT = 8
|
||||||
|
|
||||||
SPECIFIC_DEVICE_CLASS_WHATEVER = None
|
SPECIFIC_DEVICE_CLASS_WHATEVER = None
|
||||||
|
SPECIFIC_DEVICE_CLASS_NOT_USED = 0
|
||||||
SPECIFIC_DEVICE_CLASS_MULTILEVEL_POWER_SWITCH = 1
|
SPECIFIC_DEVICE_CLASS_MULTILEVEL_POWER_SWITCH = 1
|
||||||
|
SPECIFIC_DEVICE_CLASS_ADVANCED_DOOR_LOCK = 2
|
||||||
SPECIFIC_DEVICE_CLASS_MULTIPOSITION_MOTOR = 3
|
SPECIFIC_DEVICE_CLASS_MULTIPOSITION_MOTOR = 3
|
||||||
|
SPECIFIC_DEVICE_CLASS_SECURE_KEYPAD_DOOR_LOCK = 3
|
||||||
SPECIFIC_DEVICE_CLASS_MULTILEVEL_SCENE = 4
|
SPECIFIC_DEVICE_CLASS_MULTILEVEL_SCENE = 4
|
||||||
|
SPECIFIC_DEVICE_CLASS_SECURE_DOOR = 5
|
||||||
SPECIFIC_DEVICE_CLASS_MOTOR_CONTROL_CLASS_A = 5
|
SPECIFIC_DEVICE_CLASS_MOTOR_CONTROL_CLASS_A = 5
|
||||||
SPECIFIC_DEVICE_CLASS_MOTOR_CONTROL_CLASS_B = 6
|
SPECIFIC_DEVICE_CLASS_MOTOR_CONTROL_CLASS_B = 6
|
||||||
|
SPECIFIC_DEVICE_CLASS_SECURE_BARRIER_ADD_ON = 7
|
||||||
SPECIFIC_DEVICE_CLASS_MOTOR_CONTROL_CLASS_C = 7
|
SPECIFIC_DEVICE_CLASS_MOTOR_CONTROL_CLASS_C = 7
|
||||||
|
|
||||||
GENRE_WHATEVER = None
|
GENRE_WHATEVER = None
|
||||||
|
@ -71,51 +87,67 @@ TYPE_DECIMAL = "Decimal"
|
||||||
# value type, genre type, specific device class).
|
# value type, genre type, specific device class).
|
||||||
DISCOVERY_COMPONENTS = [
|
DISCOVERY_COMPONENTS = [
|
||||||
('sensor',
|
('sensor',
|
||||||
|
[GENERIC_COMMAND_CLASS_WHATEVER],
|
||||||
|
[SPECIFIC_DEVICE_CLASS_WHATEVER],
|
||||||
[COMMAND_CLASS_SENSOR_MULTILEVEL,
|
[COMMAND_CLASS_SENSOR_MULTILEVEL,
|
||||||
COMMAND_CLASS_METER,
|
COMMAND_CLASS_METER,
|
||||||
COMMAND_CLASS_ALARM],
|
COMMAND_CLASS_ALARM],
|
||||||
TYPE_WHATEVER,
|
TYPE_WHATEVER,
|
||||||
GENRE_USER,
|
GENRE_USER),
|
||||||
SPECIFIC_DEVICE_CLASS_WHATEVER),
|
|
||||||
('light',
|
('light',
|
||||||
|
[GENERIC_COMMAND_CLASS_MULTILEVEL_SWITCH],
|
||||||
|
[SPECIFIC_DEVICE_CLASS_MULTILEVEL_POWER_SWITCH,
|
||||||
|
SPECIFIC_DEVICE_CLASS_MULTILEVEL_SCENE],
|
||||||
[COMMAND_CLASS_SWITCH_MULTILEVEL],
|
[COMMAND_CLASS_SWITCH_MULTILEVEL],
|
||||||
TYPE_BYTE,
|
TYPE_BYTE,
|
||||||
GENRE_USER,
|
GENRE_USER),
|
||||||
[SPECIFIC_DEVICE_CLASS_MULTILEVEL_POWER_SWITCH,
|
|
||||||
SPECIFIC_DEVICE_CLASS_MULTILEVEL_SCENE]),
|
|
||||||
('switch',
|
('switch',
|
||||||
|
[GENERIC_COMMAND_CLASS_BINARY_SWITCH],
|
||||||
|
[SPECIFIC_DEVICE_CLASS_WHATEVER],
|
||||||
[COMMAND_CLASS_SWITCH_BINARY],
|
[COMMAND_CLASS_SWITCH_BINARY],
|
||||||
TYPE_BOOL,
|
TYPE_BOOL,
|
||||||
GENRE_USER,
|
GENRE_USER),
|
||||||
SPECIFIC_DEVICE_CLASS_WHATEVER),
|
|
||||||
('binary_sensor',
|
('binary_sensor',
|
||||||
|
[GENERIC_COMMAND_CLASS_BINARY_SENSOR],
|
||||||
|
[SPECIFIC_DEVICE_CLASS_WHATEVER],
|
||||||
[COMMAND_CLASS_SENSOR_BINARY],
|
[COMMAND_CLASS_SENSOR_BINARY],
|
||||||
TYPE_BOOL,
|
TYPE_BOOL,
|
||||||
GENRE_USER,
|
GENRE_USER),
|
||||||
SPECIFIC_DEVICE_CLASS_WHATEVER),
|
|
||||||
('thermostat',
|
('thermostat',
|
||||||
|
[GENERIC_COMMAND_CLASS_THERMOSTAT],
|
||||||
|
[SPECIFIC_DEVICE_CLASS_WHATEVER],
|
||||||
[COMMAND_CLASS_THERMOSTAT_SETPOINT],
|
[COMMAND_CLASS_THERMOSTAT_SETPOINT],
|
||||||
TYPE_WHATEVER,
|
TYPE_WHATEVER,
|
||||||
GENRE_WHATEVER,
|
GENRE_WHATEVER),
|
||||||
SPECIFIC_DEVICE_CLASS_WHATEVER),
|
|
||||||
('hvac',
|
('hvac',
|
||||||
|
[GENERIC_COMMAND_CLASS_THERMOSTAT],
|
||||||
|
[SPECIFIC_DEVICE_CLASS_WHATEVER],
|
||||||
[COMMAND_CLASS_THERMOSTAT_FAN_MODE],
|
[COMMAND_CLASS_THERMOSTAT_FAN_MODE],
|
||||||
TYPE_WHATEVER,
|
TYPE_WHATEVER,
|
||||||
GENRE_WHATEVER,
|
GENRE_WHATEVER),
|
||||||
SPECIFIC_DEVICE_CLASS_WHATEVER),
|
|
||||||
('lock',
|
('lock',
|
||||||
|
[GENERIC_COMMAND_CLASS_ENTRY_CONTROL],
|
||||||
|
[SPECIFIC_DEVICE_CLASS_ADVANCED_DOOR_LOCK,
|
||||||
|
SPECIFIC_DEVICE_CLASS_SECURE_KEYPAD_DOOR_LOCK],
|
||||||
[COMMAND_CLASS_DOOR_LOCK],
|
[COMMAND_CLASS_DOOR_LOCK],
|
||||||
TYPE_BOOL,
|
TYPE_BOOL,
|
||||||
GENRE_USER,
|
GENRE_USER),
|
||||||
SPECIFIC_DEVICE_CLASS_WHATEVER),
|
|
||||||
('rollershutter',
|
('rollershutter',
|
||||||
[COMMAND_CLASS_SWITCH_MULTILEVEL],
|
[GENERIC_COMMAND_CLASS_MULTILEVEL_SWITCH],
|
||||||
TYPE_WHATEVER,
|
|
||||||
GENRE_USER,
|
|
||||||
[SPECIFIC_DEVICE_CLASS_MOTOR_CONTROL_CLASS_A,
|
[SPECIFIC_DEVICE_CLASS_MOTOR_CONTROL_CLASS_A,
|
||||||
SPECIFIC_DEVICE_CLASS_MOTOR_CONTROL_CLASS_B,
|
SPECIFIC_DEVICE_CLASS_MOTOR_CONTROL_CLASS_B,
|
||||||
SPECIFIC_DEVICE_CLASS_MOTOR_CONTROL_CLASS_C,
|
SPECIFIC_DEVICE_CLASS_MOTOR_CONTROL_CLASS_C,
|
||||||
SPECIFIC_DEVICE_CLASS_MULTIPOSITION_MOTOR]),
|
SPECIFIC_DEVICE_CLASS_MULTIPOSITION_MOTOR],
|
||||||
|
[COMMAND_CLASS_WHATEVER],
|
||||||
|
TYPE_WHATEVER,
|
||||||
|
GENRE_USER),
|
||||||
|
('garage_door',
|
||||||
|
[GENERIC_COMMAND_CLASS_ENTRY_CONTROL],
|
||||||
|
[SPECIFIC_DEVICE_CLASS_SECURE_BARRIER_ADD_ON,
|
||||||
|
SPECIFIC_DEVICE_CLASS_SECURE_DOOR],
|
||||||
|
[COMMAND_CLASS_SWITCH_BINARY],
|
||||||
|
TYPE_BOOL,
|
||||||
|
GENRE_USER)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@ -244,25 +276,49 @@ def setup(hass, config):
|
||||||
def value_added(node, value):
|
def value_added(node, value):
|
||||||
"""Called when a value is added to a node on the network."""
|
"""Called when a value is added to a node on the network."""
|
||||||
for (component,
|
for (component,
|
||||||
command_ids,
|
generic_device_class,
|
||||||
|
specific_device_class,
|
||||||
|
command_class,
|
||||||
value_type,
|
value_type,
|
||||||
value_genre,
|
value_genre) in DISCOVERY_COMPONENTS:
|
||||||
specific_device_class) in DISCOVERY_COMPONENTS:
|
|
||||||
|
|
||||||
if value.command_class not in command_ids:
|
_LOGGER.debug("Component=%s Node_id=%s query start",
|
||||||
|
component, node.node_id)
|
||||||
|
if node.generic not in generic_device_class and \
|
||||||
|
None not in generic_device_class:
|
||||||
|
_LOGGER.debug("node.generic %s not None and in \
|
||||||
|
generic_device_class %s",
|
||||||
|
node.generic, generic_device_class)
|
||||||
continue
|
continue
|
||||||
if value_type is not None and value_type != value.type:
|
if node.specific not in specific_device_class and \
|
||||||
|
None not in specific_device_class:
|
||||||
|
_LOGGER.debug("node.specific %s is not None and in \
|
||||||
|
specific_device_class %s", node.specific,
|
||||||
|
specific_device_class)
|
||||||
continue
|
continue
|
||||||
if value_genre is not None and value_genre != value.genre:
|
if value.command_class not in command_class and \
|
||||||
|
None not in command_class:
|
||||||
|
_LOGGER.debug("value.command_class %s is not None \
|
||||||
|
and in command_class %s",
|
||||||
|
value.command_class, command_class)
|
||||||
continue
|
continue
|
||||||
if specific_device_class is not None and \
|
if value_type != value.type and value_type is not None:
|
||||||
specific_device_class != node.specific:
|
_LOGGER.debug("value.type %s != value_type %s",
|
||||||
|
value.type, value_type)
|
||||||
|
continue
|
||||||
|
if value_genre != value.genre and value_genre is not None:
|
||||||
|
_LOGGER.debug("value.genre %s != value_genre %s",
|
||||||
|
value.genre, value_genre)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Configure node
|
# Configure node
|
||||||
_LOGGER.debug("Node_id=%s Value type=%s Genre=%s \
|
_LOGGER.debug("Adding Node_id=%s Generic_command_class=%s, \
|
||||||
Specific Device_class=%s", node.node_id,
|
Specific_command_class=%s, \
|
||||||
value.type, value.genre, specific_device_class)
|
Command_class=%s, Value type=%s, \
|
||||||
|
Genre=%s", node.node_id,
|
||||||
|
node.generic, node.specific,
|
||||||
|
value.command_class, value.type,
|
||||||
|
value.genre)
|
||||||
name = "{}.{}".format(component, _object_id(value))
|
name = "{}.{}".format(component, _object_id(value))
|
||||||
|
|
||||||
node_config = customize.get(name, {})
|
node_config = customize.get(name, {})
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue