diff --git a/homeassistant/components/climate/zwave.py b/homeassistant/components/climate/zwave.py index ad6c89bcea1..e4c586965a6 100755 --- a/homeassistant/components/climate/zwave.py +++ b/homeassistant/components/climate/zwave.py @@ -246,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 diff --git a/homeassistant/components/cover/zwave.py b/homeassistant/components/cover/zwave.py index aa2cdf858fd..46f23a68515 100644 --- a/homeassistant/components/cover/zwave.py +++ b/homeassistant/components/cover/zwave.py @@ -41,6 +41,7 @@ class ZwaveRollershutter(zwave.ZWaveDeviceEntity, CoverDevice): 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(value) @@ -48,20 +49,35 @@ class ZwaveRollershutter(zwave.ZWaveDeviceEntity, CoverDevice): _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.get_value( - class_id=zwave.const.COMMAND_CLASS_SWITCH_MULTILEVEL, - label=['Level'], member='data') - self._open_id = self.get_value( - class_id=zwave.const.COMMAND_CLASS_SWITCH_MULTILEVEL, - label=['Open', 'Up'], member='value_id') - self._close_id = self.get_value( - class_id=zwave.const.COMMAND_CLASS_SWITCH_MULTILEVEL, - label=['Close', 'Down'], member='value_id') - if self._workaround == workaround.WORKAROUND_REVERSE_OPEN_CLOSE: + 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): diff --git a/homeassistant/components/light/zwave.py b/homeassistant/components/light/zwave.py index 84aebffab0e..7e23a68b887 100644 --- a/homeassistant/components/light/zwave.py +++ b/homeassistant/components/light/zwave.py @@ -107,7 +107,7 @@ class ZwaveDimmer(zwave.ZWaveDeviceEntity, Light): # Brightness self._brightness, self._state = brightness_state(self._value) - def value_changed(self, value): + def value_changed(self): """Called when a value for this entity's node has changed.""" if self._refresh_value: if self._refreshing: @@ -124,7 +124,7 @@ class ZwaveDimmer(zwave.ZWaveDeviceEntity, Light): self._timer = Timer(self._delay, _refresh_value) self._timer.start() return - super().value_changed(value) + super().value_changed() @property def brightness(self): @@ -188,6 +188,12 @@ class ZwaveColorLight(ZwaveDimmer): 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 diff --git a/homeassistant/components/lock/zwave.py b/homeassistant/components/lock/zwave.py index ba1df32130d..cfafe955e2c 100644 --- a/homeassistant/components/lock/zwave.py +++ b/homeassistant/components/lock/zwave.py @@ -292,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 diff --git a/homeassistant/components/zwave/__init__.py b/homeassistant/components/zwave/__init__.py index f05fb2a9ae5..dacc7549c58 100755 --- a/homeassistant/components/zwave/__init__.py +++ b/homeassistant/components/zwave/__init__.py @@ -708,6 +708,10 @@ class ZWaveDeviceEntity(Entity): self._value = value self._value.set_change_verified(False) self.entity_id = "{}.{}".format(domain, self._object_id()) + + self._wakeup_value_id = None + self._battery_value_id = None + self._power_value_id = None self._update_attributes() dispatcher.connect( @@ -715,13 +719,19 @@ class ZWaveDeviceEntity(Entity): def network_value_changed(self, value): """Called when a value has changed on the network.""" - if self._value.value_id == value.value_id or \ - self._value.node == value.node: - _LOGGER.debug('Value changed for label %s', self._value.label) - self.value_changed(value) + if self._value.value_id == value.value_id: + return self.value_changed() - def value_changed(self, value): + 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 @@ -729,25 +739,64 @@ class ZWaveDeviceEntity(Entity): if self.hass: self.schedule_update_ha_state() + 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 [] + + 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._value.node.node_id self.location = self._value.node.location - self.battery_level = self._value.node.get_battery_level() + self.battery_level = self._value.node.get_battery_level( + self._battery_value_id) self.wakeup_interval = None - if self._value.node.can_wake_up(): - self.wakeup_interval = self.get_value( - class_id=const.COMMAND_CLASS_WAKE_UP, - member='data') - power_value = self.get_value( - class_id=[const.COMMAND_CLASS_SENSOR_MULTILEVEL, - const.COMMAND_CLASS_METER], - label=['Power']) + 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 def _value_handler(self, method=None, class_id=None, index=None, - label=None, data=None, member=None, **kwargs): + 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. @@ -763,8 +812,9 @@ class ZWaveDeviceEntity(Entity): values.extend(self._value.node.get_values( class_id=cid, **kwargs).values()) _LOGGER.debug('method=%s, class_id=%s, index=%s, label=%s, data=%s,' - ' member=%s, kwargs=%s', - method, class_id, index, label, data, member, kwargs) + ' 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: @@ -783,6 +833,8 @@ class ZWaveDeviceEntity(Entity): 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: