This reverts commit 56abc7f9b4
.
pull/6526/head
parent
56abc7f9b4
commit
58826b264a
|
@ -19,34 +19,34 @@ _LOGGER = logging.getLogger(__name__)
|
|||
DEPENDENCIES = []
|
||||
|
||||
|
||||
def get_device(values, **kwargs):
|
||||
def get_device(value, **kwargs):
|
||||
"""Create zwave entity device."""
|
||||
device_mapping = workaround.get_device_mapping(values.primary)
|
||||
device_mapping = workaround.get_device_mapping(value)
|
||||
if device_mapping == workaround.WORKAROUND_NO_OFF_EVENT:
|
||||
# Default the multiplier to 4
|
||||
re_arm_multiplier = zwave.get_config_value(values.primary.node, 9) or 4
|
||||
return ZWaveTriggerSensor(values, "motion", re_arm_multiplier * 8)
|
||||
re_arm_multiplier = (zwave.get_config_value(value.node, 9) or 4)
|
||||
return ZWaveTriggerSensor(value, "motion", re_arm_multiplier * 8)
|
||||
|
||||
if workaround.get_device_component_mapping(values.primary) == DOMAIN:
|
||||
return ZWaveBinarySensor(values, None)
|
||||
if workaround.get_device_component_mapping(value) == DOMAIN:
|
||||
return ZWaveBinarySensor(value, None)
|
||||
|
||||
if values.primary.command_class == zwave.const.COMMAND_CLASS_SENSOR_BINARY:
|
||||
return ZWaveBinarySensor(values, None)
|
||||
if value.command_class == zwave.const.COMMAND_CLASS_SENSOR_BINARY:
|
||||
return ZWaveBinarySensor(value, None)
|
||||
return None
|
||||
|
||||
|
||||
class ZWaveBinarySensor(BinarySensorDevice, zwave.ZWaveDeviceEntity):
|
||||
"""Representation of a binary sensor within Z-Wave."""
|
||||
|
||||
def __init__(self, values, device_class):
|
||||
def __init__(self, value, device_class):
|
||||
"""Initialize the sensor."""
|
||||
zwave.ZWaveDeviceEntity.__init__(self, values, DOMAIN)
|
||||
zwave.ZWaveDeviceEntity.__init__(self, value, DOMAIN)
|
||||
self._sensor_type = device_class
|
||||
self._state = self.values.primary.data
|
||||
self._state = self._value.data
|
||||
|
||||
def update_properties(self):
|
||||
"""Callback on data changes for node values."""
|
||||
self._state = self.values.primary.data
|
||||
self._state = self._value.data
|
||||
|
||||
@property
|
||||
def is_on(self):
|
||||
|
@ -62,15 +62,15 @@ class ZWaveBinarySensor(BinarySensorDevice, zwave.ZWaveDeviceEntity):
|
|||
class ZWaveTriggerSensor(ZWaveBinarySensor):
|
||||
"""Representation of a stateless sensor within Z-Wave."""
|
||||
|
||||
def __init__(self, values, device_class, re_arm_sec=60):
|
||||
def __init__(self, value, device_class, re_arm_sec=60):
|
||||
"""Initialize the sensor."""
|
||||
super(ZWaveTriggerSensor, self).__init__(values, device_class)
|
||||
super(ZWaveTriggerSensor, self).__init__(value, device_class)
|
||||
self.re_arm_sec = re_arm_sec
|
||||
self.invalidate_after = None
|
||||
|
||||
def update_properties(self):
|
||||
"""Called when a value for this entity's node has changed."""
|
||||
self._state = self.values.primary.data
|
||||
self._state = self._value.data
|
||||
# only allow this value to be true for re_arm secs
|
||||
if not self.hass:
|
||||
return
|
||||
|
|
|
@ -10,6 +10,7 @@ import logging
|
|||
from homeassistant.components.climate import DOMAIN
|
||||
from homeassistant.components.climate import ClimateDevice
|
||||
from homeassistant.components.zwave import ZWaveDeviceEntity
|
||||
from homeassistant.components import zwave
|
||||
from homeassistant.components.zwave import async_setup_platform # noqa # pylint: disable=unused-import
|
||||
from homeassistant.const import (
|
||||
TEMP_CELSIUS, TEMP_FAHRENHEIT, ATTR_TEMPERATURE)
|
||||
|
@ -32,18 +33,20 @@ DEVICE_MAPPINGS = {
|
|||
}
|
||||
|
||||
|
||||
def get_device(hass, values, **kwargs):
|
||||
def get_device(hass, value, **kwargs):
|
||||
"""Create zwave entity device."""
|
||||
temp_unit = hass.config.units.temperature_unit
|
||||
return ZWaveClimate(values, temp_unit)
|
||||
return ZWaveClimate(value, temp_unit)
|
||||
|
||||
|
||||
class ZWaveClimate(ZWaveDeviceEntity, ClimateDevice):
|
||||
"""Representation of a Z-Wave Climate device."""
|
||||
|
||||
def __init__(self, values, temp_unit):
|
||||
def __init__(self, value, temp_unit):
|
||||
"""Initialize the Z-Wave climate device."""
|
||||
ZWaveDeviceEntity.__init__(self, values, DOMAIN)
|
||||
ZWaveDeviceEntity.__init__(self, value, DOMAIN)
|
||||
self._index = value.index
|
||||
self._node = value.node
|
||||
self._target_temperature = None
|
||||
self._current_temperature = None
|
||||
self._current_operation = None
|
||||
|
@ -58,11 +61,10 @@ class ZWaveClimate(ZWaveDeviceEntity, ClimateDevice):
|
|||
_LOGGER.debug("temp_unit is %s", self._unit)
|
||||
self._zxt_120 = None
|
||||
# Make sure that we have values for the key before converting to int
|
||||
if (self.node.manufacturer_id.strip() and
|
||||
self.node.product_id.strip()):
|
||||
specific_sensor_key = (
|
||||
int(self.node.manufacturer_id, 16),
|
||||
int(self.node.product_id, 16))
|
||||
if (value.node.manufacturer_id.strip() and
|
||||
value.node.product_id.strip()):
|
||||
specific_sensor_key = (int(value.node.manufacturer_id, 16),
|
||||
int(value.node.product_id, 16))
|
||||
if specific_sensor_key in DEVICE_MAPPINGS:
|
||||
if DEVICE_MAPPINGS[specific_sensor_key] == WORKAROUND_ZXT_120:
|
||||
_LOGGER.debug("Remotec ZXT-120 Zwave Thermostat"
|
||||
|
@ -73,58 +75,81 @@ class ZWaveClimate(ZWaveDeviceEntity, ClimateDevice):
|
|||
def update_properties(self):
|
||||
"""Callback on data changes for node values."""
|
||||
# Operation Mode
|
||||
if self.values.mode:
|
||||
self._current_operation = self.values.mode.data
|
||||
operation_list = self.values.mode.data_items
|
||||
if operation_list:
|
||||
self._operation_list = list(operation_list)
|
||||
self._current_operation = self.get_value(
|
||||
class_id=zwave.const.COMMAND_CLASS_THERMOSTAT_MODE, member='data')
|
||||
operation_list = self.get_value(
|
||||
class_id=zwave.const.COMMAND_CLASS_THERMOSTAT_MODE,
|
||||
member='data_items')
|
||||
if operation_list:
|
||||
self._operation_list = list(operation_list)
|
||||
_LOGGER.debug("self._operation_list=%s", self._operation_list)
|
||||
_LOGGER.debug("self._current_operation=%s", self._current_operation)
|
||||
|
||||
# Current Temp
|
||||
if self.values.temperature:
|
||||
self._current_temperature = self.values.temperature.data
|
||||
device_unit = self.values.temperature.units
|
||||
if device_unit is not None:
|
||||
self._unit = device_unit
|
||||
self._current_temperature = self.get_value(
|
||||
class_id=zwave.const.COMMAND_CLASS_SENSOR_MULTILEVEL,
|
||||
label=['Temperature'], member='data')
|
||||
device_unit = self.get_value(
|
||||
class_id=zwave.const.COMMAND_CLASS_SENSOR_MULTILEVEL,
|
||||
label=['Temperature'], member='units')
|
||||
if device_unit is not None:
|
||||
self._unit = device_unit
|
||||
|
||||
# Fan Mode
|
||||
if self.values.fan_mode:
|
||||
self._current_fan_mode = self.values.fan_mode.data
|
||||
fan_list = self.values.fan_mode.data_items
|
||||
if fan_list:
|
||||
self._fan_list = list(fan_list)
|
||||
self._current_fan_mode = self.get_value(
|
||||
class_id=zwave.const.COMMAND_CLASS_THERMOSTAT_FAN_MODE,
|
||||
member='data')
|
||||
fan_list = self.get_value(
|
||||
class_id=zwave.const.COMMAND_CLASS_THERMOSTAT_FAN_MODE,
|
||||
member='data_items')
|
||||
if fan_list:
|
||||
self._fan_list = list(fan_list)
|
||||
_LOGGER.debug("self._fan_list=%s", self._fan_list)
|
||||
_LOGGER.debug("self._current_fan_mode=%s",
|
||||
self._current_fan_mode)
|
||||
# Swing mode
|
||||
if self._zxt_120 == 1:
|
||||
if self.values.zxt_120_swing_mode:
|
||||
self._current_swing_mode = self.values.zxt_120_swing_mode.data
|
||||
swing_list = self.values.zxt_120_swing_mode.data_items
|
||||
if swing_list:
|
||||
self._swing_list = list(swing_list)
|
||||
self._current_swing_mode = (
|
||||
self.get_value(
|
||||
class_id=zwave.const.COMMAND_CLASS_CONFIGURATION,
|
||||
index=33,
|
||||
member='data'))
|
||||
swing_list = self.get_value(class_id=zwave.const
|
||||
.COMMAND_CLASS_CONFIGURATION,
|
||||
index=33,
|
||||
member='data_items')
|
||||
if swing_list:
|
||||
self._swing_list = list(swing_list)
|
||||
_LOGGER.debug("self._swing_list=%s", self._swing_list)
|
||||
_LOGGER.debug("self._current_swing_mode=%s",
|
||||
self._current_swing_mode)
|
||||
# Set point
|
||||
if self.values.primary.data == 0:
|
||||
_LOGGER.debug("Setpoint is 0, setting default to "
|
||||
"current_temperature=%s",
|
||||
self._current_temperature)
|
||||
self._target_temperature = (
|
||||
round((float(self._current_temperature)), 1))
|
||||
else:
|
||||
self._target_temperature = round(
|
||||
(float(self.values.primary.data)), 1)
|
||||
temps = []
|
||||
for value in (
|
||||
self._node.get_values(
|
||||
class_id=zwave.const.COMMAND_CLASS_THERMOSTAT_SETPOINT)
|
||||
.values()):
|
||||
temps.append((round(float(value.data)), 1))
|
||||
if value.index == self._index:
|
||||
if value.data == 0:
|
||||
_LOGGER.debug("Setpoint is 0, setting default to "
|
||||
"current_temperature=%s",
|
||||
self._current_temperature)
|
||||
self._target_temperature = (
|
||||
round((float(self._current_temperature)), 1))
|
||||
break
|
||||
else:
|
||||
self._target_temperature = round((float(value.data)), 1)
|
||||
|
||||
# Operating state
|
||||
if self.values.operating_state:
|
||||
self._operating_state = self.values.operating_state.data
|
||||
self._operating_state = self.get_value(
|
||||
class_id=zwave.const.COMMAND_CLASS_THERMOSTAT_OPERATING_STATE,
|
||||
member='data')
|
||||
|
||||
# Fan operating state
|
||||
if self.values.fan_state:
|
||||
self._fan_state = self.values.fan_state.data
|
||||
self._fan_state = self.get_value(
|
||||
class_id=zwave.const.COMMAND_CLASS_THERMOSTAT_FAN_STATE,
|
||||
member='data')
|
||||
|
||||
@property
|
||||
def should_poll(self):
|
||||
|
@ -188,24 +213,29 @@ class ZWaveClimate(ZWaveDeviceEntity, ClimateDevice):
|
|||
else:
|
||||
return
|
||||
|
||||
self.values.primary.data = temperature
|
||||
self.set_value(
|
||||
class_id=zwave.const.COMMAND_CLASS_THERMOSTAT_SETPOINT,
|
||||
index=self._index, data=temperature)
|
||||
self.schedule_update_ha_state()
|
||||
|
||||
def set_fan_mode(self, fan):
|
||||
"""Set new target fan mode."""
|
||||
if self.values.fan_mode:
|
||||
self.values.fan_mode.data = bytes(fan, 'utf-8')
|
||||
self.set_value(
|
||||
class_id=zwave.const.COMMAND_CLASS_THERMOSTAT_FAN_MODE,
|
||||
index=0, data=bytes(fan, 'utf-8'))
|
||||
|
||||
def set_operation_mode(self, operation_mode):
|
||||
"""Set new target operation mode."""
|
||||
if self.values.mode:
|
||||
self.values.mode.data = bytes(operation_mode, 'utf-8')
|
||||
self.set_value(
|
||||
class_id=zwave.const.COMMAND_CLASS_THERMOSTAT_MODE,
|
||||
index=0, data=bytes(operation_mode, 'utf-8'))
|
||||
|
||||
def set_swing_mode(self, swing_mode):
|
||||
"""Set new target swing mode."""
|
||||
if self._zxt_120 == 1:
|
||||
if self.values.zxt_120_swing_mode:
|
||||
self.values.zxt_120_swing_mode = bytes(swing_mode, 'utf-8')
|
||||
self.set_value(
|
||||
class_id=zwave.const.COMMAND_CLASS_CONFIGURATION,
|
||||
index=33, data=bytes(swing_mode, 'utf-8'))
|
||||
|
||||
@property
|
||||
def device_state_attributes(self):
|
||||
|
@ -216,3 +246,8 @@ class ZWaveClimate(ZWaveDeviceEntity, ClimateDevice):
|
|||
if self._fan_state:
|
||||
data[ATTR_FAN_STATE] = self._fan_state
|
||||
return data
|
||||
|
||||
@property
|
||||
def dependent_value_ids(self):
|
||||
"""List of value IDs a device depends on."""
|
||||
return None
|
||||
|
|
|
@ -20,49 +20,64 @@ _LOGGER = logging.getLogger(__name__)
|
|||
SUPPORT_GARAGE = SUPPORT_OPEN | SUPPORT_CLOSE
|
||||
|
||||
|
||||
def get_device(values, **kwargs):
|
||||
def get_device(value, **kwargs):
|
||||
"""Create zwave entity device."""
|
||||
if (values.primary.command_class ==
|
||||
zwave.const.COMMAND_CLASS_SWITCH_MULTILEVEL
|
||||
and values.primary.index == 0):
|
||||
return ZwaveRollershutter(values)
|
||||
elif (values.primary.command_class in [
|
||||
zwave.const.COMMAND_CLASS_SWITCH_BINARY,
|
||||
zwave.const.COMMAND_CLASS_BARRIER_OPERATOR]):
|
||||
return ZwaveGarageDoor(values)
|
||||
if (value.command_class == zwave.const.COMMAND_CLASS_SWITCH_MULTILEVEL
|
||||
and value.index == 0):
|
||||
return ZwaveRollershutter(value)
|
||||
elif (value.command_class == zwave.const.COMMAND_CLASS_SWITCH_BINARY or
|
||||
value.command_class == zwave.const.COMMAND_CLASS_BARRIER_OPERATOR):
|
||||
return ZwaveGarageDoor(value)
|
||||
return None
|
||||
|
||||
|
||||
class ZwaveRollershutter(zwave.ZWaveDeviceEntity, CoverDevice):
|
||||
"""Representation of an Zwave roller shutter."""
|
||||
|
||||
def __init__(self, values):
|
||||
def __init__(self, value):
|
||||
"""Initialize the zwave rollershutter."""
|
||||
ZWaveDeviceEntity.__init__(self, values, DOMAIN)
|
||||
ZWaveDeviceEntity.__init__(self, value, DOMAIN)
|
||||
# pylint: disable=no-member
|
||||
self._node = value.node
|
||||
self._open_id = None
|
||||
self._close_id = None
|
||||
self._current_position_id = None
|
||||
self._current_position = None
|
||||
|
||||
self._workaround = workaround.get_device_mapping(values.primary)
|
||||
self._workaround = workaround.get_device_mapping(value)
|
||||
if self._workaround:
|
||||
_LOGGER.debug("Using workaround %s", self._workaround)
|
||||
self.update_properties()
|
||||
|
||||
@property
|
||||
def dependent_value_ids(self):
|
||||
"""List of value IDs a device depends on."""
|
||||
if not self._node.is_ready:
|
||||
return None
|
||||
return [self._current_position_id]
|
||||
|
||||
def update_properties(self):
|
||||
"""Callback on data changes for node values."""
|
||||
# Position value
|
||||
self._current_position = self.values.primary.data
|
||||
|
||||
if self.values.open and self.values.close and \
|
||||
self._open_id is None and self._close_id is None:
|
||||
if self._workaround == workaround.WORKAROUND_REVERSE_OPEN_CLOSE:
|
||||
self._open_id = self.values.close.value_id
|
||||
self._close_id = self.values.open.value_id
|
||||
self._workaround = None
|
||||
else:
|
||||
self._open_id = self.values.open.value_id
|
||||
self._close_id = self.values.close.value_id
|
||||
if not self._node.is_ready:
|
||||
if self._current_position_id is None:
|
||||
self._current_position_id = self.get_value(
|
||||
class_id=zwave.const.COMMAND_CLASS_SWITCH_MULTILEVEL,
|
||||
label=['Level'], member='value_id')
|
||||
if self._open_id is None:
|
||||
self._open_id = self.get_value(
|
||||
class_id=zwave.const.COMMAND_CLASS_SWITCH_MULTILEVEL,
|
||||
label=['Open', 'Up'], member='value_id')
|
||||
if self._close_id is None:
|
||||
self._close_id = self.get_value(
|
||||
class_id=zwave.const.COMMAND_CLASS_SWITCH_MULTILEVEL,
|
||||
label=['Close', 'Down'], member='value_id')
|
||||
if self._open_id and self._close_id and \
|
||||
self._workaround == workaround.WORKAROUND_REVERSE_OPEN_CLOSE:
|
||||
self._open_id, self._close_id = self._close_id, self._open_id
|
||||
self._workaround = None
|
||||
self._current_position = self._node.get_dimmer_level(
|
||||
self._current_position_id)
|
||||
|
||||
@property
|
||||
def is_closed(self):
|
||||
|
@ -97,7 +112,7 @@ class ZwaveRollershutter(zwave.ZWaveDeviceEntity, CoverDevice):
|
|||
|
||||
def set_cover_position(self, position, **kwargs):
|
||||
"""Move the roller shutter to a specific position."""
|
||||
self.node.set_dimmer(self.values.primary.value_id, position)
|
||||
self._node.set_dimmer(self._value.value_id, position)
|
||||
|
||||
def stop_cover(self, **kwargs):
|
||||
"""Stop the roller shutter."""
|
||||
|
@ -107,14 +122,14 @@ class ZwaveRollershutter(zwave.ZWaveDeviceEntity, CoverDevice):
|
|||
class ZwaveGarageDoor(zwave.ZWaveDeviceEntity, CoverDevice):
|
||||
"""Representation of an Zwave garage door device."""
|
||||
|
||||
def __init__(self, values):
|
||||
def __init__(self, value):
|
||||
"""Initialize the zwave garage door."""
|
||||
ZWaveDeviceEntity.__init__(self, values, DOMAIN)
|
||||
ZWaveDeviceEntity.__init__(self, value, DOMAIN)
|
||||
self.update_properties()
|
||||
|
||||
def update_properties(self):
|
||||
"""Callback on data changes for node values."""
|
||||
self._state = self.values.primary.data
|
||||
self._state = self._value.data
|
||||
|
||||
@property
|
||||
def is_closed(self):
|
||||
|
@ -123,11 +138,11 @@ class ZwaveGarageDoor(zwave.ZWaveDeviceEntity, CoverDevice):
|
|||
|
||||
def close_cover(self):
|
||||
"""Close the garage door."""
|
||||
self.values.primary.data = False
|
||||
self._value.data = False
|
||||
|
||||
def open_cover(self):
|
||||
"""Open the garage door."""
|
||||
self.values.primary.data = True
|
||||
self._value.data = True
|
||||
|
||||
@property
|
||||
def device_class(self):
|
||||
|
|
|
@ -49,9 +49,9 @@ SUPPORT_ZWAVE_COLORTEMP = (SUPPORT_BRIGHTNESS | SUPPORT_RGB_COLOR
|
|||
| SUPPORT_COLOR_TEMP)
|
||||
|
||||
|
||||
def get_device(node, values, node_config, **kwargs):
|
||||
def get_device(node, value, node_config, **kwargs):
|
||||
"""Create zwave entity device."""
|
||||
name = '{}.{}'.format(DOMAIN, zwave.object_id(values.primary))
|
||||
name = '{}.{}'.format(DOMAIN, zwave.object_id(value))
|
||||
refresh = node_config.get(zwave.CONF_REFRESH_VALUE)
|
||||
delay = node_config.get(zwave.CONF_REFRESH_DELAY)
|
||||
_LOGGER.debug('name=%s node_config=%s CONF_REFRESH_VALUE=%s'
|
||||
|
@ -59,9 +59,9 @@ def get_device(node, values, node_config, **kwargs):
|
|||
refresh, delay)
|
||||
|
||||
if node.has_command_class(zwave.const.COMMAND_CLASS_SWITCH_COLOR):
|
||||
return ZwaveColorLight(values, refresh, delay)
|
||||
return ZwaveColorLight(value, refresh, delay)
|
||||
else:
|
||||
return ZwaveDimmer(values, refresh, delay)
|
||||
return ZwaveDimmer(value, refresh, delay)
|
||||
|
||||
|
||||
def brightness_state(value):
|
||||
|
@ -75,9 +75,9 @@ def brightness_state(value):
|
|||
class ZwaveDimmer(zwave.ZWaveDeviceEntity, Light):
|
||||
"""Representation of a Z-Wave dimmer."""
|
||||
|
||||
def __init__(self, values, refresh, delay):
|
||||
def __init__(self, value, refresh, delay):
|
||||
"""Initialize the light."""
|
||||
zwave.ZWaveDeviceEntity.__init__(self, values, DOMAIN)
|
||||
zwave.ZWaveDeviceEntity.__init__(self, value, DOMAIN)
|
||||
self._brightness = None
|
||||
self._state = None
|
||||
self._delay = delay
|
||||
|
@ -86,10 +86,10 @@ class ZwaveDimmer(zwave.ZWaveDeviceEntity, Light):
|
|||
|
||||
# Enable appropriate workaround flags for our device
|
||||
# Make sure that we have values for the key before converting to int
|
||||
if (self.node.manufacturer_id.strip() and
|
||||
self.node.product_id.strip()):
|
||||
specific_sensor_key = (int(self.node.manufacturer_id, 16),
|
||||
int(self.node.product_id, 16))
|
||||
if (value.node.manufacturer_id.strip() and
|
||||
value.node.product_id.strip()):
|
||||
specific_sensor_key = (int(value.node.manufacturer_id, 16),
|
||||
int(value.node.product_id, 16))
|
||||
if specific_sensor_key in DEVICE_MAPPINGS:
|
||||
if DEVICE_MAPPINGS[specific_sensor_key] == WORKAROUND_ZW098:
|
||||
_LOGGER.debug("AEOTEC ZW098 workaround enabled")
|
||||
|
@ -105,7 +105,7 @@ class ZwaveDimmer(zwave.ZWaveDeviceEntity, Light):
|
|||
def update_properties(self):
|
||||
"""Update internal properties based on zwave values."""
|
||||
# Brightness
|
||||
self._brightness, self._state = brightness_state(self.values.primary)
|
||||
self._brightness, self._state = brightness_state(self._value)
|
||||
|
||||
def value_changed(self):
|
||||
"""Called when a value for this entity's node has changed."""
|
||||
|
@ -116,7 +116,7 @@ class ZwaveDimmer(zwave.ZWaveDeviceEntity, Light):
|
|||
def _refresh_value():
|
||||
"""Used timer callback for delayed value refresh."""
|
||||
self._refreshing = True
|
||||
self.values.primary.refresh()
|
||||
self._value.refresh()
|
||||
|
||||
if self._timer is not None and self._timer.isAlive():
|
||||
self._timer.cancel()
|
||||
|
@ -151,12 +151,12 @@ class ZwaveDimmer(zwave.ZWaveDeviceEntity, Light):
|
|||
else:
|
||||
brightness = 255
|
||||
|
||||
if self.node.set_dimmer(self.values.primary.value_id, brightness):
|
||||
if self._value.node.set_dimmer(self._value.value_id, brightness):
|
||||
self._state = STATE_ON
|
||||
|
||||
def turn_off(self, **kwargs):
|
||||
"""Turn the device off."""
|
||||
if self.node.set_dimmer(self.values.primary.value_id, 0):
|
||||
if self._value.node.set_dimmer(self._value.value_id, 0):
|
||||
self._state = STATE_OFF
|
||||
|
||||
|
||||
|
@ -170,28 +170,73 @@ def ct_to_rgb(temp):
|
|||
class ZwaveColorLight(ZwaveDimmer):
|
||||
"""Representation of a Z-Wave color changing light."""
|
||||
|
||||
def __init__(self, values, refresh, delay):
|
||||
def __init__(self, value, refresh, delay):
|
||||
"""Initialize the light."""
|
||||
from openzwave.network import ZWaveNetwork
|
||||
from pydispatch import dispatcher
|
||||
|
||||
self._value_color = None
|
||||
self._value_color_channels = None
|
||||
self._color_channels = None
|
||||
self._rgb = None
|
||||
self._ct = None
|
||||
|
||||
super().__init__(values, refresh, delay)
|
||||
super().__init__(value, refresh, delay)
|
||||
|
||||
# Create a listener so the color values can be linked to this entity
|
||||
dispatcher.connect(
|
||||
self._value_added, ZWaveNetwork.SIGNAL_VALUE_ADDED)
|
||||
self._get_color_values()
|
||||
|
||||
@property
|
||||
def dependent_value_ids(self):
|
||||
"""List of value IDs a device depends on."""
|
||||
return [val.value_id for val in [
|
||||
self._value_color, self._value_color_channels] if val]
|
||||
|
||||
def _get_color_values(self):
|
||||
"""Search for color values available on this node."""
|
||||
from openzwave.network import ZWaveNetwork
|
||||
from pydispatch import dispatcher
|
||||
|
||||
_LOGGER.debug("Searching for zwave color values")
|
||||
# Currently zwave nodes only exist with one color element per node.
|
||||
if self._value_color is None:
|
||||
for value_color in self._value.node.get_rgbbulbs().values():
|
||||
self._value_color = value_color
|
||||
|
||||
if self._value_color_channels is None:
|
||||
self._value_color_channels = self.get_value(
|
||||
class_id=zwave.const.COMMAND_CLASS_SWITCH_COLOR,
|
||||
genre=zwave.const.GENRE_SYSTEM, type=zwave.const.TYPE_INT)
|
||||
|
||||
if self._value_color and self._value_color_channels:
|
||||
_LOGGER.debug("Zwave node color values found.")
|
||||
dispatcher.disconnect(
|
||||
self._value_added, ZWaveNetwork.SIGNAL_VALUE_ADDED)
|
||||
self.update_properties()
|
||||
|
||||
def _value_added(self, value):
|
||||
"""Called when a value has been added to the network."""
|
||||
if self._value.node != value.node:
|
||||
return
|
||||
# Check for the missing color values
|
||||
self._get_color_values()
|
||||
|
||||
def update_properties(self):
|
||||
"""Update internal properties based on zwave values."""
|
||||
super().update_properties()
|
||||
|
||||
if self.values.color is None:
|
||||
if self._value_color is None:
|
||||
return
|
||||
if self.values.color_channels is None:
|
||||
if self._value_color_channels is None:
|
||||
return
|
||||
|
||||
# Color Channels
|
||||
self._color_channels = self.values.color_channels.data
|
||||
self._color_channels = self._value_color_channels.data
|
||||
|
||||
# Color Data String
|
||||
data = self.values.color.data
|
||||
data = self._value_color.data
|
||||
|
||||
# RGB is always present in the openzwave color data string.
|
||||
self._rgb = [
|
||||
|
@ -284,8 +329,8 @@ class ZwaveColorLight(ZwaveDimmer):
|
|||
rgbw += format(colorval, '02x').encode('utf-8')
|
||||
rgbw += b'0000'
|
||||
|
||||
if rgbw and self.values.color:
|
||||
self.values.color.data = rgbw
|
||||
if rgbw and self._value_color:
|
||||
self._value_color.node.set_rgbw(self._value_color.value_id, rgbw)
|
||||
|
||||
super().turn_on(**kwargs)
|
||||
|
||||
|
|
|
@ -120,7 +120,7 @@ CLEAR_USERCODE_SCHEMA = vol.Schema({
|
|||
})
|
||||
|
||||
|
||||
def get_device(hass, node, values, **kwargs):
|
||||
def get_device(hass, node, value, **kwargs):
|
||||
"""Create zwave entity device."""
|
||||
descriptions = load_yaml_config_file(
|
||||
path.join(path.dirname(__file__), 'services.yaml'))
|
||||
|
@ -191,15 +191,16 @@ def get_device(hass, node, values, **kwargs):
|
|||
clear_usercode,
|
||||
descriptions.get(SERVICE_CLEAR_USERCODE),
|
||||
schema=CLEAR_USERCODE_SCHEMA)
|
||||
return ZwaveLock(values)
|
||||
return ZwaveLock(value)
|
||||
|
||||
|
||||
class ZwaveLock(zwave.ZWaveDeviceEntity, LockDevice):
|
||||
"""Representation of a Z-Wave Lock."""
|
||||
|
||||
def __init__(self, values):
|
||||
def __init__(self, value):
|
||||
"""Initialize the Z-Wave lock device."""
|
||||
zwave.ZWaveDeviceEntity.__init__(self, values, DOMAIN)
|
||||
zwave.ZWaveDeviceEntity.__init__(self, value, DOMAIN)
|
||||
self._node = value.node
|
||||
self._state = None
|
||||
self._notification = None
|
||||
self._lock_status = None
|
||||
|
@ -207,10 +208,10 @@ class ZwaveLock(zwave.ZWaveDeviceEntity, LockDevice):
|
|||
|
||||
# Enable appropriate workaround flags for our device
|
||||
# Make sure that we have values for the key before converting to int
|
||||
if (self.node.manufacturer_id.strip() and
|
||||
self.node.product_id.strip()):
|
||||
specific_sensor_key = (int(self.node.manufacturer_id, 16),
|
||||
int(self.node.product_id, 16))
|
||||
if (value.node.manufacturer_id.strip() and
|
||||
value.node.product_id.strip()):
|
||||
specific_sensor_key = (int(value.node.manufacturer_id, 16),
|
||||
int(value.node.product_id, 16))
|
||||
if specific_sensor_key in DEVICE_MAPPINGS:
|
||||
if DEVICE_MAPPINGS[specific_sensor_key] == WORKAROUND_V2BTZE:
|
||||
self._v2btze = 1
|
||||
|
@ -220,33 +221,36 @@ class ZwaveLock(zwave.ZWaveDeviceEntity, LockDevice):
|
|||
|
||||
def update_properties(self):
|
||||
"""Callback on data changes for node values."""
|
||||
self._state = self.values.primary.data
|
||||
self._state = self._value.data
|
||||
_LOGGER.debug('Lock state set from Bool value and'
|
||||
' is %s', self._state)
|
||||
if self.values.access_control:
|
||||
notification_data = self.values.access_control.data
|
||||
notification_data = self.get_value(class_id=zwave.const
|
||||
.COMMAND_CLASS_ALARM,
|
||||
label=['Access Control'],
|
||||
member='data')
|
||||
if notification_data:
|
||||
self._notification = LOCK_NOTIFICATION.get(str(notification_data))
|
||||
if self._v2btze:
|
||||
advanced_config = self.get_value(class_id=zwave.const
|
||||
.COMMAND_CLASS_CONFIGURATION,
|
||||
index=12,
|
||||
data=CONFIG_ADVANCED,
|
||||
member='data')
|
||||
if advanced_config:
|
||||
self._state = LOCK_STATUS.get(str(notification_data))
|
||||
_LOGGER.debug('Lock state set from Access Control '
|
||||
'value and is %s, get=%s',
|
||||
str(notification_data),
|
||||
self.state)
|
||||
|
||||
if self._v2btze:
|
||||
if self.values.v2btze_advanced and \
|
||||
self.values.v2btze_advanced.data == CONFIG_ADVANCED:
|
||||
self._state = LOCK_STATUS.get(str(notification_data))
|
||||
_LOGGER.debug('Lock state set from Access Control '
|
||||
'value and is %s, get=%s',
|
||||
str(notification_data),
|
||||
self.state)
|
||||
|
||||
if not self.values.alarm_type:
|
||||
return
|
||||
|
||||
alarm_type = self.values.alarm_type.data
|
||||
alarm_type = self.get_value(class_id=zwave.const
|
||||
.COMMAND_CLASS_ALARM,
|
||||
label=['Alarm Type'], member='data')
|
||||
_LOGGER.debug('Lock alarm_type is %s', str(alarm_type))
|
||||
if self.values.alarm_level:
|
||||
alarm_level = self.values.alarm_level.data
|
||||
else:
|
||||
alarm_level = None
|
||||
alarm_level = self.get_value(class_id=zwave.const
|
||||
.COMMAND_CLASS_ALARM,
|
||||
label=['Alarm Level'], member='data')
|
||||
_LOGGER.debug('Lock alarm_level is %s', str(alarm_level))
|
||||
|
||||
if not alarm_type:
|
||||
return
|
||||
if alarm_type is 21:
|
||||
|
@ -273,11 +277,11 @@ class ZwaveLock(zwave.ZWaveDeviceEntity, LockDevice):
|
|||
|
||||
def lock(self, **kwargs):
|
||||
"""Lock the device."""
|
||||
self.values.primary.data = True
|
||||
self._value.data = True
|
||||
|
||||
def unlock(self, **kwargs):
|
||||
"""Unlock the device."""
|
||||
self.values.primary.data = False
|
||||
self._value.data = False
|
||||
|
||||
@property
|
||||
def device_state_attributes(self):
|
||||
|
@ -288,3 +292,8 @@ class ZwaveLock(zwave.ZWaveDeviceEntity, LockDevice):
|
|||
if self._lock_status:
|
||||
data[ATTR_LOCK_STATUS] = self._lock_status
|
||||
return data
|
||||
|
||||
@property
|
||||
def dependent_value_ids(self):
|
||||
"""List of value IDs a device depends on."""
|
||||
return None
|
||||
|
|
|
@ -15,34 +15,34 @@ from homeassistant.components.zwave import async_setup_platform # noqa # pylint
|
|||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def get_device(node, values, **kwargs):
|
||||
def get_device(node, value, **kwargs):
|
||||
"""Create zwave entity device."""
|
||||
# Generic Device mappings
|
||||
if values.primary.command_class == zwave.const.COMMAND_CLASS_BATTERY:
|
||||
return ZWaveSensor(values)
|
||||
if value.command_class == zwave.const.COMMAND_CLASS_BATTERY:
|
||||
return ZWaveSensor(value)
|
||||
if node.has_command_class(zwave.const.COMMAND_CLASS_SENSOR_MULTILEVEL):
|
||||
return ZWaveMultilevelSensor(values)
|
||||
return ZWaveMultilevelSensor(value)
|
||||
if node.has_command_class(zwave.const.COMMAND_CLASS_METER) and \
|
||||
values.primary.type == zwave.const.TYPE_DECIMAL:
|
||||
return ZWaveMultilevelSensor(values)
|
||||
value.type == zwave.const.TYPE_DECIMAL:
|
||||
return ZWaveMultilevelSensor(value)
|
||||
if node.has_command_class(zwave.const.COMMAND_CLASS_ALARM) or \
|
||||
node.has_command_class(zwave.const.COMMAND_CLASS_SENSOR_ALARM):
|
||||
return ZWaveAlarmSensor(values)
|
||||
return ZWaveAlarmSensor(value)
|
||||
return None
|
||||
|
||||
|
||||
class ZWaveSensor(zwave.ZWaveDeviceEntity):
|
||||
"""Representation of a Z-Wave sensor."""
|
||||
|
||||
def __init__(self, values):
|
||||
def __init__(self, value):
|
||||
"""Initialize the sensor."""
|
||||
zwave.ZWaveDeviceEntity.__init__(self, values, DOMAIN)
|
||||
zwave.ZWaveDeviceEntity.__init__(self, value, DOMAIN)
|
||||
self.update_properties()
|
||||
|
||||
def update_properties(self):
|
||||
"""Callback on data changes for node values."""
|
||||
self._state = self.values.primary.data
|
||||
self._units = self.values.primary.units
|
||||
self._state = self._value.data
|
||||
self._units = self._value.units
|
||||
|
||||
@property
|
||||
def force_update(self):
|
||||
|
|
|
@ -15,30 +15,29 @@ from homeassistant.components.zwave import workaround, async_setup_platform # n
|
|||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def get_device(values, **kwargs):
|
||||
def get_device(value, **kwargs):
|
||||
"""Create zwave entity device."""
|
||||
return ZwaveSwitch(values)
|
||||
return ZwaveSwitch(value)
|
||||
|
||||
|
||||
class ZwaveSwitch(zwave.ZWaveDeviceEntity, SwitchDevice):
|
||||
"""Representation of a Z-Wave switch."""
|
||||
|
||||
def __init__(self, values):
|
||||
def __init__(self, value):
|
||||
"""Initialize the Z-Wave switch device."""
|
||||
zwave.ZWaveDeviceEntity.__init__(self, values, DOMAIN)
|
||||
self.refresh_on_update = (
|
||||
workaround.get_device_mapping(values.primary) ==
|
||||
workaround.WORKAROUND_REFRESH_NODE_ON_UPDATE)
|
||||
zwave.ZWaveDeviceEntity.__init__(self, value, DOMAIN)
|
||||
self.refresh_on_update = (workaround.get_device_mapping(value) ==
|
||||
workaround.WORKAROUND_REFRESH_NODE_ON_UPDATE)
|
||||
self.last_update = time.perf_counter()
|
||||
self._state = self.values.primary.data
|
||||
self._state = self._value.data
|
||||
|
||||
def update_properties(self):
|
||||
"""Callback on data changes for node values."""
|
||||
self._state = self.values.primary.data
|
||||
self._state = self._value.data
|
||||
if self.refresh_on_update and \
|
||||
time.perf_counter() - self.last_update > 30:
|
||||
self.last_update = time.perf_counter()
|
||||
self.node.request_state()
|
||||
self._value.node.request_state()
|
||||
|
||||
@property
|
||||
def is_on(self):
|
||||
|
@ -47,8 +46,8 @@ class ZwaveSwitch(zwave.ZWaveDeviceEntity, SwitchDevice):
|
|||
|
||||
def turn_on(self, **kwargs):
|
||||
"""Turn the device on."""
|
||||
self.node.set_switch(self.values.primary.value_id, True)
|
||||
self._value.node.set_switch(self._value.value_id, True)
|
||||
|
||||
def turn_off(self, **kwargs):
|
||||
"""Turn the device off."""
|
||||
self.node.set_switch(self.values.primary.value_id, False)
|
||||
self._value.node.set_switch(self._value.value_id, False)
|
||||
|
|
|
@ -5,7 +5,6 @@ For more details about this component, please refer to the documentation at
|
|||
https://home-assistant.io/components/zwave/
|
||||
"""
|
||||
import asyncio
|
||||
import copy
|
||||
import logging
|
||||
import os.path
|
||||
import time
|
||||
|
@ -30,8 +29,7 @@ from homeassistant.helpers.dispatcher import (
|
|||
|
||||
from . import const
|
||||
from . import workaround
|
||||
from .discovery_schemas import DISCOVERY_SCHEMAS
|
||||
from .util import check_node_schema, check_value_schema
|
||||
from .util import value_handler
|
||||
|
||||
REQUIREMENTS = ['pydispatcher==2.0.5']
|
||||
|
||||
|
@ -66,6 +64,88 @@ DATA_ZWAVE_DICT = 'zwave_devices'
|
|||
|
||||
NETWORK = None
|
||||
|
||||
|
||||
# List of tuple (DOMAIN, discovered service, supported command classes,
|
||||
# value type, genre type, specific device class).
|
||||
DISCOVERY_COMPONENTS = [
|
||||
('sensor',
|
||||
[const.GENERIC_TYPE_WHATEVER],
|
||||
[const.SPECIFIC_TYPE_WHATEVER],
|
||||
[const.COMMAND_CLASS_SENSOR_MULTILEVEL,
|
||||
const.COMMAND_CLASS_METER,
|
||||
const.COMMAND_CLASS_ALARM,
|
||||
const.COMMAND_CLASS_SENSOR_ALARM,
|
||||
const.COMMAND_CLASS_BATTERY],
|
||||
const.TYPE_WHATEVER,
|
||||
const.GENRE_USER),
|
||||
('light',
|
||||
[const.GENERIC_TYPE_SWITCH_MULTILEVEL,
|
||||
const.GENERIC_TYPE_SWITCH_REMOTE],
|
||||
[const.SPECIFIC_TYPE_POWER_SWITCH_MULTILEVEL,
|
||||
const.SPECIFIC_TYPE_SCENE_SWITCH_MULTILEVEL,
|
||||
const.SPECIFIC_TYPE_NOT_USED],
|
||||
[const.COMMAND_CLASS_SWITCH_MULTILEVEL],
|
||||
const.TYPE_BYTE,
|
||||
const.GENRE_USER),
|
||||
('switch',
|
||||
[const.GENERIC_TYPE_SENSOR_ALARM,
|
||||
const.GENERIC_TYPE_SENSOR_BINARY,
|
||||
const.GENERIC_TYPE_SWITCH_BINARY,
|
||||
const.GENERIC_TYPE_ENTRY_CONTROL,
|
||||
const.GENERIC_TYPE_SENSOR_MULTILEVEL,
|
||||
const.GENERIC_TYPE_SWITCH_MULTILEVEL,
|
||||
const.GENERIC_TYPE_SENSOR_NOTIFICATION,
|
||||
const.GENERIC_TYPE_GENERIC_CONTROLLER,
|
||||
const.GENERIC_TYPE_SWITCH_REMOTE,
|
||||
const.GENERIC_TYPE_REPEATER_SLAVE,
|
||||
const.GENERIC_TYPE_THERMOSTAT,
|
||||
const.GENERIC_TYPE_WALL_CONTROLLER],
|
||||
[const.SPECIFIC_TYPE_WHATEVER],
|
||||
[const.COMMAND_CLASS_SWITCH_BINARY],
|
||||
const.TYPE_BOOL,
|
||||
const.GENRE_USER),
|
||||
('binary_sensor',
|
||||
[const.GENERIC_TYPE_SENSOR_ALARM,
|
||||
const.GENERIC_TYPE_SENSOR_BINARY,
|
||||
const.GENERIC_TYPE_SWITCH_BINARY,
|
||||
const.GENERIC_TYPE_METER,
|
||||
const.GENERIC_TYPE_SENSOR_MULTILEVEL,
|
||||
const.GENERIC_TYPE_SWITCH_MULTILEVEL,
|
||||
const.GENERIC_TYPE_SENSOR_NOTIFICATION,
|
||||
const.GENERIC_TYPE_THERMOSTAT],
|
||||
[const.SPECIFIC_TYPE_WHATEVER],
|
||||
[const.COMMAND_CLASS_SENSOR_BINARY],
|
||||
const.TYPE_BOOL,
|
||||
const.GENRE_USER),
|
||||
('lock',
|
||||
[const.GENERIC_TYPE_ENTRY_CONTROL],
|
||||
[const.SPECIFIC_TYPE_ADVANCED_DOOR_LOCK,
|
||||
const.SPECIFIC_TYPE_SECURE_KEYPAD_DOOR_LOCK],
|
||||
[const.COMMAND_CLASS_DOOR_LOCK],
|
||||
const.TYPE_BOOL,
|
||||
const.GENRE_USER),
|
||||
('cover',
|
||||
[const.GENERIC_TYPE_SWITCH_MULTILEVEL,
|
||||
const.GENERIC_TYPE_ENTRY_CONTROL],
|
||||
[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.COMMAND_CLASS_SWITCH_BINARY,
|
||||
const.COMMAND_CLASS_BARRIER_OPERATOR,
|
||||
const.COMMAND_CLASS_SWITCH_MULTILEVEL],
|
||||
const.TYPE_WHATEVER,
|
||||
const.GENRE_USER),
|
||||
('climate',
|
||||
[const.GENERIC_TYPE_THERMOSTAT],
|
||||
[const.SPECIFIC_TYPE_WHATEVER],
|
||||
[const.COMMAND_CLASS_THERMOSTAT_SETPOINT],
|
||||
const.TYPE_WHATEVER,
|
||||
const.GENRE_WHATEVER),
|
||||
]
|
||||
|
||||
RENAME_NODE_SCHEMA = vol.Schema({
|
||||
vol.Required(ATTR_ENTITY_ID): cv.entity_id,
|
||||
vol.Required(const.ATTR_NAME): cv.string,
|
||||
|
@ -278,25 +358,92 @@ def setup(hass, config):
|
|||
|
||||
dispatcher.connect(log_all, weak=False)
|
||||
|
||||
discovered_values = []
|
||||
|
||||
def value_added(node, value):
|
||||
"""Called when a value is added to a node on the network."""
|
||||
# Check if this value should be tracked by an existing entity
|
||||
for values in discovered_values:
|
||||
values.check_value(value)
|
||||
for (component,
|
||||
generic_device_class,
|
||||
specific_device_class,
|
||||
command_class,
|
||||
value_type,
|
||||
value_genre) in DISCOVERY_COMPONENTS:
|
||||
|
||||
for schema in DISCOVERY_SCHEMAS:
|
||||
if not check_node_schema(node, schema):
|
||||
_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
|
||||
if not check_value_schema(
|
||||
value,
|
||||
schema[const.DISC_INSTANCE_VALUES][const.DISC_PRIMARY]):
|
||||
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
|
||||
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
|
||||
if value_type != value.type and value_type is not None:
|
||||
_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
|
||||
|
||||
values = ZWaveDeviceEntityValues(
|
||||
hass, schema, value, config, device_config)
|
||||
discovered_values.append(values)
|
||||
# Configure node
|
||||
_LOGGER.debug("Adding Node_id=%s Generic_command_class=%s, "
|
||||
"Specific_command_class=%s, "
|
||||
"Command_class=%s, Value type=%s, "
|
||||
"Genre=%s as %s", node.node_id,
|
||||
node.generic, node.specific,
|
||||
value.command_class, value.type,
|
||||
value.genre, component)
|
||||
workaround_component = workaround.get_device_component_mapping(
|
||||
value)
|
||||
if workaround_component and workaround_component != component:
|
||||
if workaround_component == workaround.WORKAROUND_IGNORE:
|
||||
_LOGGER.info("Ignoring device %s due to workaround.",
|
||||
"{}.{}".format(component, object_id(value)))
|
||||
continue
|
||||
_LOGGER.debug("Using %s instead of %s",
|
||||
workaround_component, component)
|
||||
component = workaround_component
|
||||
|
||||
name = "{}.{}".format(component, object_id(value))
|
||||
node_config = device_config.get(name)
|
||||
|
||||
if node_config.get(CONF_IGNORED):
|
||||
_LOGGER.info(
|
||||
"Ignoring device %s due to device settings.", name)
|
||||
return
|
||||
|
||||
polling_intensity = convert(
|
||||
node_config.get(CONF_POLLING_INTENSITY), int)
|
||||
if polling_intensity:
|
||||
value.enable_poll(polling_intensity)
|
||||
else:
|
||||
value.disable_poll()
|
||||
platform = get_platform(component, DOMAIN)
|
||||
device = platform.get_device(
|
||||
node=node, value=value, node_config=node_config, hass=hass)
|
||||
if not device:
|
||||
continue
|
||||
dict_id = value.value_id
|
||||
|
||||
@asyncio.coroutine
|
||||
def discover_device(component, device, dict_id):
|
||||
"""Put device in a dictionary and call discovery on it."""
|
||||
hass.data[DATA_ZWAVE_DICT][dict_id] = device
|
||||
yield from discovery.async_load_platform(
|
||||
hass, component, DOMAIN,
|
||||
{const.DISCOVERY_DEVICE: dict_id}, config)
|
||||
hass.add_job(discover_device, component, device, dict_id)
|
||||
|
||||
def scene_activated(node, scene_id):
|
||||
"""Called when a scene is activated on any node in the network."""
|
||||
|
@ -605,166 +752,24 @@ def setup(hass, config):
|
|||
return True
|
||||
|
||||
|
||||
class ZWaveDeviceEntityValues():
|
||||
"""Manages entity access to the underlying zwave value objects."""
|
||||
|
||||
def __init__(self, hass, schema, primary_value, zwave_config,
|
||||
device_config):
|
||||
"""Initialize the values object with the passed entity schema."""
|
||||
self._hass = hass
|
||||
self._zwave_config = zwave_config
|
||||
self._device_config = device_config
|
||||
self._schema = copy.deepcopy(schema)
|
||||
self._values = {}
|
||||
self._entity = None
|
||||
self._workaround_ignore = False
|
||||
|
||||
# Combine node value schemas and instance value schemas into one
|
||||
# values schema mapping.
|
||||
self._schema[const.DISC_VALUES] = {}
|
||||
for name in self._schema[const.DISC_NODE_VALUES].keys():
|
||||
self._values[name] = None
|
||||
self._schema[const.DISC_VALUES][name] = \
|
||||
self._schema[const.DISC_NODE_VALUES][name]
|
||||
|
||||
for name in self._schema[const.DISC_INSTANCE_VALUES].keys():
|
||||
self._values[name] = None
|
||||
self._schema[const.DISC_VALUES][name] = \
|
||||
self._schema[const.DISC_INSTANCE_VALUES][name]
|
||||
self._schema[const.DISC_VALUES][name][const.DISC_INSTANCE] = \
|
||||
[primary_value.instance]
|
||||
|
||||
self._values[const.DISC_PRIMARY] = primary_value
|
||||
self._node = primary_value.node
|
||||
self._schema[const.DISC_NODE_ID] = [self._node.node_id]
|
||||
|
||||
# Check values that have already been discovered for node
|
||||
for value in self._node.values.values():
|
||||
self.check_value(value)
|
||||
|
||||
self._check_entity_ready()
|
||||
|
||||
def __getattr__(self, name):
|
||||
"""Get the specified value for this entity."""
|
||||
return self._values[name]
|
||||
|
||||
def __iter__(self):
|
||||
"""Allow iteration over all values."""
|
||||
return iter(self._values.values())
|
||||
|
||||
def check_value(self, value):
|
||||
"""Check if the new value matches a missing value for this entity.
|
||||
|
||||
If a match is found, it is added to the values mapping.
|
||||
"""
|
||||
if not check_node_schema(value.node, self._schema):
|
||||
return
|
||||
for name in self._values:
|
||||
if self._values[name] is not None:
|
||||
continue
|
||||
if not check_value_schema(
|
||||
value, self._schema[const.DISC_VALUES][name]):
|
||||
continue
|
||||
self._values[name] = value
|
||||
if self._entity:
|
||||
self._entity.value_changed()
|
||||
|
||||
self._check_entity_ready()
|
||||
|
||||
def _check_entity_ready(self):
|
||||
"""Check if all required values are discovered and create entity."""
|
||||
if self._workaround_ignore:
|
||||
return
|
||||
if self._entity is not None:
|
||||
return
|
||||
|
||||
for name in self._schema[const.DISC_VALUES]:
|
||||
if self._values[name] is None and \
|
||||
not self._schema[const.DISC_VALUES][name].get(
|
||||
const.DISC_OPTIONAL):
|
||||
return
|
||||
|
||||
component = self._schema[const.DISC_COMPONENT]
|
||||
|
||||
workaround_component = workaround.get_device_component_mapping(
|
||||
self.primary)
|
||||
if workaround_component and workaround_component != component:
|
||||
if workaround_component == workaround.WORKAROUND_IGNORE:
|
||||
_LOGGER.info("Ignoring device %s due to workaround.",
|
||||
"{}.{}".format(
|
||||
component, object_id(self.primary)))
|
||||
# No entity will be created for this value
|
||||
self._workaround_ignore = True
|
||||
return
|
||||
_LOGGER.debug("Using %s instead of %s",
|
||||
workaround_component, component)
|
||||
component = workaround_component
|
||||
|
||||
name = "{}.{}".format(component, object_id(self.primary))
|
||||
node_config = self._device_config.get(name)
|
||||
|
||||
# Configure node
|
||||
_LOGGER.debug("Adding Node_id=%s Generic_command_class=%s, "
|
||||
"Specific_command_class=%s, "
|
||||
"Command_class=%s, Value type=%s, "
|
||||
"Genre=%s as %s", self._node.node_id,
|
||||
self._node.generic, self._node.specific,
|
||||
self.primary.command_class, self.primary.type,
|
||||
self.primary.genre, component)
|
||||
|
||||
if node_config.get(CONF_IGNORED):
|
||||
_LOGGER.info(
|
||||
"Ignoring node %s due to device settings.", self._node.node_id)
|
||||
# No entity will be created for this value
|
||||
self._workaround_ignore = True
|
||||
return
|
||||
|
||||
polling_intensity = convert(
|
||||
node_config.get(CONF_POLLING_INTENSITY), int)
|
||||
if polling_intensity:
|
||||
self.primary.enable_poll(polling_intensity)
|
||||
else:
|
||||
self.primary.disable_poll()
|
||||
|
||||
platform = get_platform(component, DOMAIN)
|
||||
device = platform.get_device(
|
||||
node=self._node, values=self,
|
||||
node_config=node_config, hass=self._hass)
|
||||
if not device:
|
||||
# No entity will be created for this value
|
||||
self._workaround_ignore = True
|
||||
return
|
||||
|
||||
self._entity = device
|
||||
|
||||
dict_id = self.primary.value_id
|
||||
|
||||
@asyncio.coroutine
|
||||
def discover_device(component, device, dict_id):
|
||||
"""Put device in a dictionary and call discovery on it."""
|
||||
self._hass.data[DATA_ZWAVE_DICT][dict_id] = device
|
||||
yield from discovery.async_load_platform(
|
||||
self._hass, component, DOMAIN,
|
||||
{const.DISCOVERY_DEVICE: dict_id}, self._zwave_config)
|
||||
self._hass.add_job(discover_device, component, device, dict_id)
|
||||
|
||||
|
||||
class ZWaveDeviceEntity(Entity):
|
||||
"""Representation of a Z-Wave node entity."""
|
||||
|
||||
def __init__(self, values, domain):
|
||||
def __init__(self, value, domain):
|
||||
"""Initialize the z-Wave device."""
|
||||
# pylint: disable=import-error
|
||||
from openzwave.network import ZWaveNetwork
|
||||
from pydispatch import dispatcher
|
||||
self.values = values
|
||||
self.node = values.primary.node
|
||||
self.values.primary.set_change_verified(False)
|
||||
self.entity_id = "{}.{}".format(domain, object_id(values.primary))
|
||||
self._value = value
|
||||
self._value.set_change_verified(False)
|
||||
self.entity_id = "{}.{}".format(domain, object_id(value))
|
||||
|
||||
self._name = _value_name(self.values.primary)
|
||||
self._unique_id = "ZWAVE-{}-{}".format(self.node.node_id,
|
||||
self.values.primary.object_id)
|
||||
self._name = _value_name(self._value)
|
||||
self._unique_id = "ZWAVE-{}-{}".format(self._value.node.node_id,
|
||||
self._value.object_id)
|
||||
self._wakeup_value_id = None
|
||||
self._battery_value_id = None
|
||||
self._power_value_id = None
|
||||
self._update_scheduled = False
|
||||
self._update_attributes()
|
||||
|
||||
|
@ -773,11 +778,19 @@ class ZWaveDeviceEntity(Entity):
|
|||
|
||||
def network_value_changed(self, value):
|
||||
"""Called when a value has changed on the network."""
|
||||
if value.value_id in [v.value_id for v in self.values if v]:
|
||||
if self._value.value_id == value.value_id:
|
||||
return self.value_changed()
|
||||
|
||||
dependent_ids = self._get_dependent_value_ids()
|
||||
if dependent_ids is None and self._value.node == value.node:
|
||||
return self.value_changed()
|
||||
if dependent_ids is not None and value.value_id in dependent_ids:
|
||||
return self.value_changed()
|
||||
|
||||
def value_changed(self):
|
||||
"""Called when a value for this entity's node has changed."""
|
||||
if not self._value.node.is_ready:
|
||||
self._update_ids()
|
||||
self._update_attributes()
|
||||
self.update_properties()
|
||||
# If value changed after device was created but before setup_platform
|
||||
|
@ -785,6 +798,29 @@ class ZWaveDeviceEntity(Entity):
|
|||
if self.hass and not self._update_scheduled:
|
||||
self.hass.add_job(self._schedule_update)
|
||||
|
||||
def _update_ids(self):
|
||||
"""Update value_ids from which to pull attributes."""
|
||||
if self._wakeup_value_id is None:
|
||||
self._wakeup_value_id = self.get_value(
|
||||
class_id=const.COMMAND_CLASS_WAKE_UP, member='value_id')
|
||||
if self._battery_value_id is None:
|
||||
self._battery_value_id = self.get_value(
|
||||
class_id=const.COMMAND_CLASS_BATTERY, member='value_id')
|
||||
if self._power_value_id is None:
|
||||
self._power_value_id = self.get_value(
|
||||
class_id=[const.COMMAND_CLASS_SENSOR_MULTILEVEL,
|
||||
const.COMMAND_CLASS_METER],
|
||||
label=['Power'], member='value_id',
|
||||
instance=self._value.instance)
|
||||
|
||||
@property
|
||||
def dependent_value_ids(self):
|
||||
"""List of value IDs a device depends on.
|
||||
|
||||
None if depends on the whole node.
|
||||
"""
|
||||
return []
|
||||
|
||||
@asyncio.coroutine
|
||||
def async_added_to_hass(self):
|
||||
"""Add device to dict."""
|
||||
|
@ -793,26 +829,45 @@ class ZWaveDeviceEntity(Entity):
|
|||
SIGNAL_REFRESH_ENTITY_FORMAT.format(self.entity_id),
|
||||
self.refresh_from_network)
|
||||
|
||||
def _get_dependent_value_ids(self):
|
||||
"""Return a list of value_ids this device depend on.
|
||||
|
||||
Return None if it depends on the whole node.
|
||||
"""
|
||||
if self.dependent_value_ids is None:
|
||||
# Device depends on node.
|
||||
return None
|
||||
if not self._value.node.is_ready:
|
||||
# Node is not ready, so depend on the whole node.
|
||||
return None
|
||||
|
||||
return [val for val in (self.dependent_value_ids + [
|
||||
self._wakeup_value_id, self._battery_value_id,
|
||||
self._power_value_id]) if val]
|
||||
|
||||
def _update_attributes(self):
|
||||
"""Update the node attributes. May only be used inside callback."""
|
||||
self.node_id = self.node.node_id
|
||||
self.location = self.node.location
|
||||
self.node_id = self._value.node.node_id
|
||||
self.location = self._value.node.location
|
||||
self.battery_level = self._value.node.get_battery_level(
|
||||
self._battery_value_id)
|
||||
self.wakeup_interval = None
|
||||
if self._wakeup_value_id:
|
||||
self.wakeup_interval = self._value.node.values[
|
||||
self._wakeup_value_id].data
|
||||
power_value = None
|
||||
if self._power_value_id:
|
||||
power_value = self._value.node.values[self._power_value_id]
|
||||
self.power_consumption = round(
|
||||
power_value.data, power_value.precision) if power_value else None
|
||||
|
||||
if self.values.battery:
|
||||
self.battery_level = self.values.battery.data
|
||||
else:
|
||||
self.battery_level = None
|
||||
def get_value(self, **kwargs):
|
||||
"""Simplifyer to get values. May only be used inside callback."""
|
||||
return value_handler(self._value, method='get', **kwargs)
|
||||
|
||||
if self.values.wakeup:
|
||||
self.wakeup_interval = self.values.wakeup.data
|
||||
else:
|
||||
self.wakeup_interval = None
|
||||
|
||||
if self.values.power:
|
||||
self.power_consumption = round(
|
||||
self.values.power.data, self.values.power.precision)
|
||||
else:
|
||||
self.power_consumption = None
|
||||
def set_value(self, **kwargs):
|
||||
"""Simplifyer to set a value."""
|
||||
return value_handler(self._value, method='set', **kwargs)
|
||||
|
||||
def update_properties(self):
|
||||
"""Callback on data changes for node values."""
|
||||
|
@ -856,8 +911,13 @@ class ZWaveDeviceEntity(Entity):
|
|||
|
||||
def refresh_from_network(self):
|
||||
"""Refresh all dependent values from zwave network."""
|
||||
for value in self.values:
|
||||
self.node.refresh_value(value.value_id)
|
||||
dependent_ids = self._get_dependent_value_ids()
|
||||
if dependent_ids is None:
|
||||
# Entity depends on the whole node
|
||||
self._value.node.refresh_info()
|
||||
return
|
||||
for value_id in dependent_ids + [self._value.value_id]:
|
||||
self._value.node.refresh_value(value_id)
|
||||
|
||||
@callback
|
||||
def _schedule_update(self):
|
||||
|
|
|
@ -311,22 +311,3 @@ TYPE_BOOL = "Bool"
|
|||
TYPE_DECIMAL = "Decimal"
|
||||
TYPE_INT = "Int"
|
||||
TYPE_LIST = "List"
|
||||
TYPE_STRING = "String"
|
||||
|
||||
DISC_COMMAND_CLASS = "command_class"
|
||||
DISC_COMPONENT = "component"
|
||||
DISC_GENERIC_DEVICE_CLASS = "generic_device_class"
|
||||
DISC_GENRE = "genre"
|
||||
DISC_INDEX = "index"
|
||||
DISC_INSTANCE_VALUES = "instance_values"
|
||||
DISC_INSTANCE = "instance"
|
||||
DISC_LABEL = "label"
|
||||
DISC_NODE_ID = "node_id"
|
||||
DISC_NODE_VALUES = "node_values"
|
||||
DISC_OPTIONAL = "optional"
|
||||
DISC_PRIMARY = "primary"
|
||||
DISC_READONLY = "readonly"
|
||||
DISC_SPECIFIC_DEVICE_CLASS = "specific_device_class"
|
||||
DISC_TYPE = "type"
|
||||
DISC_VALUES = "values"
|
||||
DISC_WRITEONLY = "writeonly"
|
||||
|
|
|
@ -1,220 +0,0 @@
|
|||
"""Zwave discovery schemas."""
|
||||
from . import const
|
||||
|
||||
DEFAULT_NODE_VALUES_SCHEMA = {
|
||||
'wakeup': {
|
||||
const.DISC_COMMAND_CLASS: [const.COMMAND_CLASS_WAKE_UP],
|
||||
const.DISC_GENRE: const.GENRE_USER,
|
||||
const.DISC_OPTIONAL: True,
|
||||
},
|
||||
'battery': {
|
||||
const.DISC_COMMAND_CLASS: [const.COMMAND_CLASS_BATTERY],
|
||||
const.DISC_OPTIONAL: True,
|
||||
},
|
||||
}
|
||||
DEFAULT_INSTANCE_VALUES_SCHEMA = {
|
||||
'power': {
|
||||
const.DISC_COMMAND_CLASS: [const.COMMAND_CLASS_SENSOR_MULTILEVEL,
|
||||
const.COMMAND_CLASS_METER],
|
||||
const.DISC_LABEL: ['Power'],
|
||||
const.DISC_OPTIONAL: True,
|
||||
},
|
||||
}
|
||||
|
||||
DISCOVERY_SCHEMAS = [
|
||||
{const.DISC_COMPONENT: 'binary_sensor',
|
||||
const.DISC_GENERIC_DEVICE_CLASS: [
|
||||
const.GENERIC_TYPE_SENSOR_ALARM,
|
||||
const.GENERIC_TYPE_SENSOR_BINARY,
|
||||
const.GENERIC_TYPE_SWITCH_BINARY,
|
||||
const.GENERIC_TYPE_METER,
|
||||
const.GENERIC_TYPE_SENSOR_MULTILEVEL,
|
||||
const.GENERIC_TYPE_SWITCH_MULTILEVEL,
|
||||
const.GENERIC_TYPE_SENSOR_NOTIFICATION,
|
||||
const.GENERIC_TYPE_THERMOSTAT],
|
||||
const.DISC_NODE_VALUES: dict(DEFAULT_NODE_VALUES_SCHEMA),
|
||||
const.DISC_INSTANCE_VALUES: dict(DEFAULT_INSTANCE_VALUES_SCHEMA, **{
|
||||
const.DISC_PRIMARY: {
|
||||
const.DISC_COMMAND_CLASS: [const.COMMAND_CLASS_SENSOR_BINARY],
|
||||
const.DISC_TYPE: const.TYPE_BOOL,
|
||||
const.DISC_GENRE: const.GENRE_USER
|
||||
}})},
|
||||
{const.DISC_COMPONENT: 'climate',
|
||||
const.DISC_GENERIC_DEVICE_CLASS: [const.GENERIC_TYPE_THERMOSTAT],
|
||||
const.DISC_NODE_VALUES: dict(DEFAULT_NODE_VALUES_SCHEMA),
|
||||
const.DISC_INSTANCE_VALUES: dict(DEFAULT_INSTANCE_VALUES_SCHEMA, **{
|
||||
const.DISC_PRIMARY: {
|
||||
const.DISC_COMMAND_CLASS: [
|
||||
const.COMMAND_CLASS_THERMOSTAT_SETPOINT],
|
||||
},
|
||||
'temperature': {
|
||||
const.DISC_COMMAND_CLASS: [const.COMMAND_CLASS_SENSOR_MULTILEVEL],
|
||||
const.DISC_LABEL: 'Temperature',
|
||||
const.DISC_OPTIONAL: True,
|
||||
},
|
||||
'mode': {
|
||||
const.DISC_COMMAND_CLASS: [const.COMMAND_CLASS_THERMOSTAT_MODE],
|
||||
const.DISC_OPTIONAL: True,
|
||||
},
|
||||
'fan_mode': {
|
||||
const.DISC_COMMAND_CLASS: [
|
||||
const.COMMAND_CLASS_THERMOSTAT_FAN_MODE],
|
||||
const.DISC_OPTIONAL: True,
|
||||
},
|
||||
'operating_state': {
|
||||
const.DISC_COMMAND_CLASS: [
|
||||
const.COMMAND_CLASS_THERMOSTAT_OPERATING_STATE],
|
||||
const.DISC_OPTIONAL: True,
|
||||
},
|
||||
'fan_state': {
|
||||
const.DISC_COMMAND_CLASS: [
|
||||
const.COMMAND_CLASS_THERMOSTAT_FAN_STATE],
|
||||
const.DISC_OPTIONAL: True,
|
||||
},
|
||||
'zxt_120_swing_mode': {
|
||||
const.DISC_COMMAND_CLASS: [const.COMMAND_CLASS_CONFIGURATION],
|
||||
const.DISC_INDEX: [33],
|
||||
const.DISC_OPTIONAL: True,
|
||||
}})},
|
||||
{const.DISC_COMPONENT: 'cover', # Rollershutter
|
||||
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_NODE_VALUES: dict(DEFAULT_NODE_VALUES_SCHEMA),
|
||||
const.DISC_INSTANCE_VALUES: dict(DEFAULT_INSTANCE_VALUES_SCHEMA, **{
|
||||
const.DISC_PRIMARY: {
|
||||
const.DISC_COMMAND_CLASS: [const.COMMAND_CLASS_SWITCH_MULTILEVEL],
|
||||
const.DISC_GENRE: const.GENRE_USER,
|
||||
},
|
||||
'open': {
|
||||
const.DISC_COMMAND_CLASS: [const.COMMAND_CLASS_SWITCH_MULTILEVEL],
|
||||
const.DISC_LABEL: ['Open', 'Up'],
|
||||
const.DISC_OPTIONAL: True,
|
||||
},
|
||||
'close': {
|
||||
const.DISC_COMMAND_CLASS: [const.COMMAND_CLASS_SWITCH_MULTILEVEL],
|
||||
const.DISC_LABEL: ['Close', 'Down'],
|
||||
const.DISC_OPTIONAL: True,
|
||||
}})},
|
||||
{const.DISC_COMPONENT: 'cover', # Garage Door
|
||||
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_NODE_VALUES: dict(DEFAULT_NODE_VALUES_SCHEMA),
|
||||
const.DISC_INSTANCE_VALUES: dict(DEFAULT_INSTANCE_VALUES_SCHEMA, **{
|
||||
const.DISC_PRIMARY: {
|
||||
const.DISC_COMMAND_CLASS: [
|
||||
const.COMMAND_CLASS_BARRIER_OPERATOR,
|
||||
const.COMMAND_CLASS_SWITCH_BINARY],
|
||||
const.DISC_GENRE: const.GENRE_USER,
|
||||
}})},
|
||||
{const.DISC_COMPONENT: 'light',
|
||||
const.DISC_GENERIC_DEVICE_CLASS: [
|
||||
const.GENERIC_TYPE_SWITCH_MULTILEVEL,
|
||||
const.GENERIC_TYPE_SWITCH_REMOTE],
|
||||
const.DISC_SPECIFIC_DEVICE_CLASS: [
|
||||
const.SPECIFIC_TYPE_POWER_SWITCH_MULTILEVEL,
|
||||
const.SPECIFIC_TYPE_SCENE_SWITCH_MULTILEVEL,
|
||||
const.SPECIFIC_TYPE_NOT_USED],
|
||||
const.DISC_NODE_VALUES: dict(DEFAULT_NODE_VALUES_SCHEMA),
|
||||
const.DISC_INSTANCE_VALUES: dict(DEFAULT_INSTANCE_VALUES_SCHEMA, **{
|
||||
const.DISC_PRIMARY: {
|
||||
const.DISC_COMMAND_CLASS: [const.COMMAND_CLASS_SWITCH_MULTILEVEL],
|
||||
const.DISC_GENRE: const.GENRE_USER,
|
||||
const.DISC_TYPE: const.TYPE_BYTE,
|
||||
},
|
||||
'color': {
|
||||
const.DISC_COMMAND_CLASS: [const.COMMAND_CLASS_SWITCH_COLOR],
|
||||
const.DISC_GENRE: const.GENRE_USER,
|
||||
const.DISC_TYPE: const.TYPE_STRING,
|
||||
const.DISC_READONLY: False,
|
||||
const.DISC_WRITEONLY: False,
|
||||
const.DISC_OPTIONAL: True,
|
||||
},
|
||||
'color_channels': {
|
||||
const.DISC_COMMAND_CLASS: [const.COMMAND_CLASS_SWITCH_COLOR],
|
||||
const.DISC_GENRE: const.GENRE_SYSTEM,
|
||||
const.DISC_TYPE: const.TYPE_INT,
|
||||
const.DISC_OPTIONAL: True,
|
||||
}})},
|
||||
{const.DISC_COMPONENT: 'lock',
|
||||
const.DISC_GENERIC_DEVICE_CLASS: [const.GENERIC_TYPE_ENTRY_CONTROL],
|
||||
const.DISC_SPECIFIC_DEVICE_CLASS: [
|
||||
const.SPECIFIC_TYPE_ADVANCED_DOOR_LOCK,
|
||||
const.SPECIFIC_TYPE_SECURE_KEYPAD_DOOR_LOCK],
|
||||
const.DISC_NODE_VALUES: dict(DEFAULT_NODE_VALUES_SCHEMA),
|
||||
const.DISC_INSTANCE_VALUES: dict(DEFAULT_INSTANCE_VALUES_SCHEMA, **{
|
||||
const.DISC_PRIMARY: {
|
||||
const.DISC_COMMAND_CLASS: [const.COMMAND_CLASS_DOOR_LOCK],
|
||||
const.DISC_TYPE: const.TYPE_BOOL,
|
||||
const.DISC_GENRE: const.GENRE_USER,
|
||||
},
|
||||
'access_control': {
|
||||
const.DISC_COMMAND_CLASS: [const.COMMAND_CLASS_ALARM],
|
||||
const.DISC_LABEL: 'Access Control',
|
||||
const.DISC_OPTIONAL: True,
|
||||
},
|
||||
'alarm_type': {
|
||||
const.DISC_COMMAND_CLASS: [const.COMMAND_CLASS_ALARM],
|
||||
const.DISC_LABEL: 'Alarm Type',
|
||||
const.DISC_OPTIONAL: True,
|
||||
},
|
||||
'alarm_level': {
|
||||
const.DISC_COMMAND_CLASS: [const.COMMAND_CLASS_ALARM],
|
||||
const.DISC_LABEL: 'Alarm Level',
|
||||
const.DISC_OPTIONAL: True,
|
||||
},
|
||||
'v2btze_advanced': {
|
||||
const.DISC_COMMAND_CLASS: [const.COMMAND_CLASS_CONFIGURATION],
|
||||
const.DISC_INDEX: [12],
|
||||
const.DISC_LABEL: 'Access Control',
|
||||
const.DISC_OPTIONAL: True,
|
||||
}})},
|
||||
{const.DISC_COMPONENT: 'sensor',
|
||||
const.DISC_NODE_VALUES: dict(DEFAULT_NODE_VALUES_SCHEMA),
|
||||
const.DISC_INSTANCE_VALUES: dict(DEFAULT_INSTANCE_VALUES_SCHEMA, **{
|
||||
const.DISC_PRIMARY: {
|
||||
const.DISC_COMMAND_CLASS: [
|
||||
const.COMMAND_CLASS_SENSOR_MULTILEVEL,
|
||||
const.COMMAND_CLASS_METER,
|
||||
const.COMMAND_CLASS_ALARM,
|
||||
const.COMMAND_CLASS_SENSOR_ALARM,
|
||||
const.COMMAND_CLASS_BATTERY],
|
||||
const.DISC_GENRE: const.GENRE_USER,
|
||||
}})},
|
||||
{const.DISC_COMPONENT: 'switch',
|
||||
const.DISC_GENERIC_DEVICE_CLASS: [
|
||||
const.GENERIC_TYPE_SENSOR_ALARM,
|
||||
const.GENERIC_TYPE_SENSOR_BINARY,
|
||||
const.GENERIC_TYPE_SWITCH_BINARY,
|
||||
const.GENERIC_TYPE_ENTRY_CONTROL,
|
||||
const.GENERIC_TYPE_SENSOR_MULTILEVEL,
|
||||
const.GENERIC_TYPE_SWITCH_MULTILEVEL,
|
||||
const.GENERIC_TYPE_SENSOR_NOTIFICATION,
|
||||
const.GENERIC_TYPE_GENERIC_CONTROLLER,
|
||||
const.GENERIC_TYPE_SWITCH_REMOTE,
|
||||
const.GENERIC_TYPE_REPEATER_SLAVE,
|
||||
const.GENERIC_TYPE_THERMOSTAT,
|
||||
const.GENERIC_TYPE_WALL_CONTROLLER],
|
||||
const.DISC_NODE_VALUES: dict(DEFAULT_NODE_VALUES_SCHEMA),
|
||||
const.DISC_INSTANCE_VALUES: dict(DEFAULT_INSTANCE_VALUES_SCHEMA, **{
|
||||
const.DISC_PRIMARY: {
|
||||
const.DISC_COMMAND_CLASS: [const.COMMAND_CLASS_SWITCH_BINARY],
|
||||
const.DISC_TYPE: const.TYPE_BOOL,
|
||||
const.DISC_GENRE: const.GENRE_USER,
|
||||
}})},
|
||||
]
|
|
@ -1,71 +1,54 @@
|
|||
"""Zwave util methods."""
|
||||
import logging
|
||||
|
||||
from . import const
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def check_node_schema(node, schema):
|
||||
"""Check if node matches the passed node schema."""
|
||||
if (const.DISC_NODE_ID in schema and
|
||||
node.node_id not in schema[const.DISC_NODE_ID]):
|
||||
_LOGGER.debug("node.node_id %s not in node_id %s",
|
||||
node.node_id, schema[const.DISC_NODE_ID])
|
||||
return False
|
||||
if (const.DISC_GENERIC_DEVICE_CLASS in schema and
|
||||
node.generic not in schema[const.DISC_GENERIC_DEVICE_CLASS]):
|
||||
_LOGGER.debug("node.generic %s not in generic_device_class %s",
|
||||
node.generic, schema[const.DISC_GENERIC_DEVICE_CLASS])
|
||||
return False
|
||||
if (const.DISC_SPECIFIC_DEVICE_CLASS in schema and
|
||||
node.specific not in schema[const.DISC_SPECIFIC_DEVICE_CLASS]):
|
||||
_LOGGER.debug("node.specific %s not in specific_device_class %s",
|
||||
node.specific, schema[const.DISC_SPECIFIC_DEVICE_CLASS])
|
||||
return False
|
||||
return True
|
||||
def value_handler(value, method=None, class_id=None, index=None,
|
||||
label=None, data=None, member=None, instance=None,
|
||||
**kwargs):
|
||||
"""Get the values for a given command_class with arguments.
|
||||
|
||||
May only be used inside callback.
|
||||
|
||||
def check_value_schema(value, schema):
|
||||
"""Check if the value matches the passed value schema."""
|
||||
if (const.DISC_COMMAND_CLASS in schema and
|
||||
value.command_class not in schema[const.DISC_COMMAND_CLASS]):
|
||||
_LOGGER.debug("value.command_class %s not in command_class %s",
|
||||
value.command_class, schema[const.DISC_COMMAND_CLASS])
|
||||
return False
|
||||
if (const.DISC_TYPE in schema and
|
||||
value.type not in schema[const.DISC_TYPE]):
|
||||
_LOGGER.debug("value.type %s not in type %s",
|
||||
value.type, schema[const.DISC_TYPE])
|
||||
return False
|
||||
if (const.DISC_GENRE in schema and
|
||||
value.genre not in schema[const.DISC_GENRE]):
|
||||
_LOGGER.debug("value.genre %s not in genre %s",
|
||||
value.genre, schema[const.DISC_GENRE])
|
||||
return False
|
||||
if (const.DISC_READONLY in schema and
|
||||
value.is_read_only is not schema[const.DISC_READONLY]):
|
||||
_LOGGER.debug("value.is_read_only %s not %s",
|
||||
value.is_read_only, schema[const.DISC_READONLY])
|
||||
return False
|
||||
if (const.DISC_WRITEONLY in schema and
|
||||
value.is_write_only is not schema[const.DISC_WRITEONLY]):
|
||||
_LOGGER.debug("value.is_write_only %s not %s",
|
||||
value.is_write_only, schema[const.DISC_WRITEONLY])
|
||||
return False
|
||||
if (const.DISC_LABEL in schema and
|
||||
value.label not in schema[const.DISC_LABEL]):
|
||||
_LOGGER.debug("value.label %s not in label %s",
|
||||
value.label, schema[const.DISC_LABEL])
|
||||
return False
|
||||
if (const.DISC_INDEX in schema and
|
||||
value.index not in schema[const.DISC_INDEX]):
|
||||
_LOGGER.debug("value.index %s not in index %s",
|
||||
value.index, schema[const.DISC_INDEX])
|
||||
return False
|
||||
if (const.DISC_INSTANCE in schema and
|
||||
value.instance not in schema[const.DISC_INSTANCE]):
|
||||
_LOGGER.debug("value.instance %s not in instance %s",
|
||||
value.instance, schema[const.DISC_INSTANCE])
|
||||
return False
|
||||
return True
|
||||
"""
|
||||
values = []
|
||||
if class_id is None:
|
||||
values.extend(value.node.get_values(**kwargs).values())
|
||||
else:
|
||||
if not isinstance(class_id, list):
|
||||
class_id = [class_id]
|
||||
for cid in class_id:
|
||||
values.extend(value.node.get_values(
|
||||
class_id=cid, **kwargs).values())
|
||||
_LOGGER.debug('method=%s, class_id=%s, index=%s, label=%s, data=%s,'
|
||||
' member=%s, instance=%d, kwargs=%s',
|
||||
method, class_id, index, label, data, member, instance,
|
||||
kwargs)
|
||||
_LOGGER.debug('values=%s', values)
|
||||
results = None
|
||||
for value in values:
|
||||
if index is not None and value.index != index:
|
||||
continue
|
||||
if label is not None:
|
||||
label_found = False
|
||||
for entry in label:
|
||||
if value.label == entry:
|
||||
label_found = True
|
||||
break
|
||||
if not label_found:
|
||||
continue
|
||||
if method == 'set':
|
||||
value.data = data
|
||||
return
|
||||
if data is not None and value.data != data:
|
||||
continue
|
||||
if instance is not None and value.instance != instance:
|
||||
continue
|
||||
if member is not None:
|
||||
results = getattr(value, member)
|
||||
else:
|
||||
results = value
|
||||
break
|
||||
_LOGGER.debug('final result=%s', results)
|
||||
return results
|
||||
|
|
Loading…
Reference in New Issue