Create zwave devices on OZW thread and only add them during discovery (#6096)

* Create zwave devices on OZW thread and only add them during discovery.

* Read and write devices dict from loop thread.

* More async

* replace callback with coroutine

* import common function instead of callin git
This commit is contained in:
Andrey 2017-02-23 23:06:28 +02:00 committed by Paulus Schoutsen
parent f2a2d6bfa1
commit 1d32bced1c
10 changed files with 114 additions and 130 deletions

View File

@ -10,6 +10,7 @@ import homeassistant.util.dt as dt_util
from homeassistant.helpers.event import track_point_in_time from homeassistant.helpers.event import track_point_in_time
from homeassistant.components import zwave from homeassistant.components import zwave
from homeassistant.components.zwave import workaround from homeassistant.components.zwave import workaround
from homeassistant.components.zwave import async_setup_platform # noqa # pylint: disable=unused-import
from homeassistant.components.binary_sensor import ( from homeassistant.components.binary_sensor import (
DOMAIN, DOMAIN,
BinarySensorDevice) BinarySensorDevice)
@ -18,31 +19,22 @@ _LOGGER = logging.getLogger(__name__)
DEPENDENCIES = [] DEPENDENCIES = []
def setup_platform(hass, config, add_devices, discovery_info=None): def get_device(value, **kwargs):
"""Setup the Z-Wave platform for binary sensors.""" """Create zwave entity device."""
if discovery_info is None or zwave.NETWORK is None:
return
node = zwave.NETWORK.nodes[discovery_info[zwave.const.ATTR_NODE_ID]]
value = node.values[discovery_info[zwave.const.ATTR_VALUE_ID]]
value.set_change_verified(False) value.set_change_verified(False)
device_mapping = workaround.get_device_mapping(value) device_mapping = workaround.get_device_mapping(value)
if device_mapping == workaround.WORKAROUND_NO_OFF_EVENT: if device_mapping == workaround.WORKAROUND_NO_OFF_EVENT:
# Default the multiplier to 4 # Default the multiplier to 4
re_arm_multiplier = (zwave.get_config_value(value.node, 9) or 4) re_arm_multiplier = (zwave.get_config_value(value.node, 9) or 4)
add_devices([ return ZWaveTriggerSensor(value, "motion", re_arm_multiplier * 8)
ZWaveTriggerSensor(value, "motion",
hass, re_arm_multiplier * 8)
])
return
if workaround.get_device_component_mapping(value) == DOMAIN: if workaround.get_device_component_mapping(value) == DOMAIN:
add_devices([ZWaveBinarySensor(value, None)]) return ZWaveBinarySensor(value, None)
return
if value.command_class == zwave.const.COMMAND_CLASS_SENSOR_BINARY: if value.command_class == zwave.const.COMMAND_CLASS_SENSOR_BINARY:
add_devices([ZWaveBinarySensor(value, None)]) return ZWaveBinarySensor(value, None)
return None
class ZWaveBinarySensor(BinarySensorDevice, zwave.ZWaveDeviceEntity): class ZWaveBinarySensor(BinarySensorDevice, zwave.ZWaveDeviceEntity):
@ -77,26 +69,23 @@ class ZWaveBinarySensor(BinarySensorDevice, zwave.ZWaveDeviceEntity):
class ZWaveTriggerSensor(ZWaveBinarySensor): class ZWaveTriggerSensor(ZWaveBinarySensor):
"""Representation of a stateless sensor within Z-Wave.""" """Representation of a stateless sensor within Z-Wave."""
def __init__(self, value, device_class, hass, re_arm_sec=60): def __init__(self, value, device_class, re_arm_sec=60):
"""Initialize the sensor.""" """Initialize the sensor."""
super(ZWaveTriggerSensor, self).__init__(value, device_class) super(ZWaveTriggerSensor, self).__init__(value, device_class)
self._hass = hass
self.re_arm_sec = re_arm_sec self.re_arm_sec = re_arm_sec
self.invalidate_after = dt_util.utcnow() + datetime.timedelta( self.invalidate_after = None
seconds=self.re_arm_sec)
# If it's active make sure that we set the timeout tracker
track_point_in_time(
self._hass, self.async_update_ha_state,
self.invalidate_after)
def update_properties(self): def update_properties(self):
"""Called when a value for this entity's node has changed.""" """Called when a value for this entity's node has changed."""
self._state = self._value.data self._state = self._value.data
# only allow this value to be true for re_arm secs # only allow this value to be true for re_arm secs
if not self.hass:
return
self.invalidate_after = dt_util.utcnow() + datetime.timedelta( self.invalidate_after = dt_util.utcnow() + datetime.timedelta(
seconds=self.re_arm_sec) seconds=self.re_arm_sec)
track_point_in_time( track_point_in_time(
self._hass, self.async_update_ha_state, self.hass, self.async_update_ha_state,
self.invalidate_after) self.invalidate_after)
@property @property

View File

@ -11,6 +11,7 @@ from homeassistant.components.climate import DOMAIN
from homeassistant.components.climate import ClimateDevice from homeassistant.components.climate import ClimateDevice
from homeassistant.components.zwave import ZWaveDeviceEntity from homeassistant.components.zwave import ZWaveDeviceEntity
from homeassistant.components import zwave from homeassistant.components import zwave
from homeassistant.components.zwave import async_setup_platform # noqa # pylint: disable=unused-import
from homeassistant.const import ( from homeassistant.const import (
TEMP_CELSIUS, TEMP_FAHRENHEIT, ATTR_TEMPERATURE) TEMP_CELSIUS, TEMP_FAHRENHEIT, ATTR_TEMPERATURE)
@ -32,19 +33,11 @@ DEVICE_MAPPINGS = {
} }
def setup_platform(hass, config, add_devices, discovery_info=None): def get_device(hass, value, **kwargs):
"""Set up the Z-Wave Climate devices.""" """Create zwave entity device."""
if discovery_info is None or zwave.NETWORK is None:
_LOGGER.debug("No discovery_info=%s or no NETWORK=%s",
discovery_info, zwave.NETWORK)
return
temp_unit = hass.config.units.temperature_unit temp_unit = hass.config.units.temperature_unit
node = zwave.NETWORK.nodes[discovery_info[zwave.const.ATTR_NODE_ID]]
value = node.values[discovery_info[zwave.const.ATTR_VALUE_ID]]
value.set_change_verified(False) value.set_change_verified(False)
add_devices([ZWaveClimate(value, temp_unit)]) return ZWaveClimate(value, temp_unit)
_LOGGER.debug("discovery_info=%s and zwave.NETWORK=%s",
discovery_info, zwave.NETWORK)
class ZWaveClimate(ZWaveDeviceEntity, ClimateDevice): class ZWaveClimate(ZWaveDeviceEntity, ClimateDevice):

View File

@ -11,6 +11,7 @@ from homeassistant.components.cover import (
DOMAIN, SUPPORT_OPEN, SUPPORT_CLOSE) DOMAIN, SUPPORT_OPEN, SUPPORT_CLOSE)
from homeassistant.components.zwave import ZWaveDeviceEntity from homeassistant.components.zwave import ZWaveDeviceEntity
from homeassistant.components import zwave from homeassistant.components import zwave
from homeassistant.components.zwave import async_setup_platform # noqa # pylint: disable=unused-import
from homeassistant.components.zwave import workaround from homeassistant.components.zwave import workaround
from homeassistant.components.cover import CoverDevice from homeassistant.components.cover import CoverDevice
@ -19,27 +20,20 @@ _LOGGER = logging.getLogger(__name__)
SUPPORT_GARAGE = SUPPORT_OPEN | SUPPORT_CLOSE SUPPORT_GARAGE = SUPPORT_OPEN | SUPPORT_CLOSE
def setup_platform(hass, config, add_devices, discovery_info=None): def get_device(value, **kwargs):
"""Find and return Z-Wave covers.""" """Create zwave entity device."""
if discovery_info is None or zwave.NETWORK is None:
return
node = zwave.NETWORK.nodes[discovery_info[zwave.const.ATTR_NODE_ID]]
value = node.values[discovery_info[zwave.const.ATTR_VALUE_ID]]
if (value.command_class == zwave.const.COMMAND_CLASS_SWITCH_MULTILEVEL if (value.command_class == zwave.const.COMMAND_CLASS_SWITCH_MULTILEVEL
and value.index == 0): and value.index == 0):
value.set_change_verified(False) value.set_change_verified(False)
add_devices([ZwaveRollershutter(value)]) return ZwaveRollershutter(value)
elif (value.command_class == zwave.const.COMMAND_CLASS_SWITCH_BINARY or elif (value.command_class == zwave.const.COMMAND_CLASS_SWITCH_BINARY or
value.command_class == zwave.const.COMMAND_CLASS_BARRIER_OPERATOR): value.command_class == zwave.const.COMMAND_CLASS_BARRIER_OPERATOR):
if (value.type != zwave.const.TYPE_BOOL and if (value.type != zwave.const.TYPE_BOOL and
value.genre != zwave.const.GENRE_USER): value.genre != zwave.const.GENRE_USER):
return return None
value.set_change_verified(False) value.set_change_verified(False)
add_devices([ZwaveGarageDoor(value)]) return ZwaveGarageDoor(value)
else: return None
return
class ZwaveRollershutter(zwave.ZWaveDeviceEntity, CoverDevice): class ZwaveRollershutter(zwave.ZWaveDeviceEntity, CoverDevice):

View File

@ -13,6 +13,7 @@ from homeassistant.components.light import ATTR_BRIGHTNESS, ATTR_COLOR_TEMP, \
ATTR_RGB_COLOR, SUPPORT_BRIGHTNESS, SUPPORT_COLOR_TEMP, \ ATTR_RGB_COLOR, SUPPORT_BRIGHTNESS, SUPPORT_COLOR_TEMP, \
SUPPORT_RGB_COLOR, DOMAIN, Light SUPPORT_RGB_COLOR, DOMAIN, Light
from homeassistant.components import zwave from homeassistant.components import zwave
from homeassistant.components.zwave import async_setup_platform # noqa # pylint: disable=unused-import
from homeassistant.const import STATE_OFF, STATE_ON from homeassistant.const import STATE_OFF, STATE_ON
from homeassistant.util.color import HASS_COLOR_MAX, HASS_COLOR_MIN, \ from homeassistant.util.color import HASS_COLOR_MAX, HASS_COLOR_MIN, \
color_temperature_mired_to_kelvin, color_temperature_to_rgb, \ color_temperature_mired_to_kelvin, color_temperature_to_rgb, \
@ -48,32 +49,27 @@ SUPPORT_ZWAVE_COLORTEMP = (SUPPORT_BRIGHTNESS | SUPPORT_RGB_COLOR
| SUPPORT_COLOR_TEMP) | SUPPORT_COLOR_TEMP)
def setup_platform(hass, config, add_devices, discovery_info=None): def get_device(node, value, node_config, **kwargs):
"""Find and add Z-Wave lights.""" """Create zwave entity device."""
if discovery_info is None or zwave.NETWORK is None:
return
node = zwave.NETWORK.nodes[discovery_info[zwave.const.ATTR_NODE_ID]]
value = node.values[discovery_info[zwave.const.ATTR_VALUE_ID]]
name = '{}.{}'.format(DOMAIN, zwave.object_id(value)) name = '{}.{}'.format(DOMAIN, zwave.object_id(value))
node_config = hass.data[zwave.DATA_DEVICE_CONFIG].get(name)
refresh = node_config.get(zwave.CONF_REFRESH_VALUE) refresh = node_config.get(zwave.CONF_REFRESH_VALUE)
delay = node_config.get(zwave.CONF_REFRESH_DELAY) delay = node_config.get(zwave.CONF_REFRESH_DELAY)
_LOGGER.debug('name=%s node_config=%s CONF_REFRESH_VALUE=%s' _LOGGER.debug('name=%s node_config=%s CONF_REFRESH_VALUE=%s'
' CONF_REFRESH_DELAY=%s', name, node_config, ' CONF_REFRESH_DELAY=%s', name, node_config,
refresh, delay) refresh, delay)
if value.command_class != zwave.const.COMMAND_CLASS_SWITCH_MULTILEVEL: if value.command_class != zwave.const.COMMAND_CLASS_SWITCH_MULTILEVEL:
return return None
if value.type != zwave.const.TYPE_BYTE: if value.type != zwave.const.TYPE_BYTE:
return return None
if value.genre != zwave.const.GENRE_USER: if value.genre != zwave.const.GENRE_USER:
return return None
value.set_change_verified(False) value.set_change_verified(False)
if node.has_command_class(zwave.const.COMMAND_CLASS_SWITCH_COLOR): if node.has_command_class(zwave.const.COMMAND_CLASS_SWITCH_COLOR):
add_devices([ZwaveColorLight(value, refresh, delay)]) return ZwaveColorLight(value, refresh, delay)
else: else:
add_devices([ZwaveDimmer(value, refresh, delay)]) return ZwaveDimmer(value, refresh, delay)
def brightness_state(value): def brightness_state(value):

View File

@ -13,6 +13,7 @@ import voluptuous as vol
from homeassistant.components.lock import DOMAIN, LockDevice from homeassistant.components.lock import DOMAIN, LockDevice
from homeassistant.components import zwave from homeassistant.components import zwave
from homeassistant.components.zwave import async_setup_platform # noqa # pylint: disable=unused-import
from homeassistant.config import load_yaml_config_file from homeassistant.config import load_yaml_config_file
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
@ -119,15 +120,8 @@ CLEAR_USERCODE_SCHEMA = vol.Schema({
}) })
# pylint: disable=unused-argument def get_device(hass, node, value, **kwargs):
def setup_platform(hass, config, add_devices, discovery_info=None): """Create zwave entity device."""
"""Find and return Z-Wave locks."""
if discovery_info is None or zwave.NETWORK is None:
return
node = zwave.NETWORK.nodes[discovery_info[zwave.const.ATTR_NODE_ID]]
value = node.values[discovery_info[zwave.const.ATTR_VALUE_ID]]
descriptions = load_yaml_config_file( descriptions = load_yaml_config_file(
path.join(path.dirname(__file__), 'services.yaml')) path.join(path.dirname(__file__), 'services.yaml'))
@ -182,11 +176,11 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
break break
if value.command_class != zwave.const.COMMAND_CLASS_DOOR_LOCK: if value.command_class != zwave.const.COMMAND_CLASS_DOOR_LOCK:
return return None
if value.type != zwave.const.TYPE_BOOL: if value.type != zwave.const.TYPE_BOOL:
return return None
if value.genre != zwave.const.GENRE_USER: if value.genre != zwave.const.GENRE_USER:
return return None
if node.has_command_class(zwave.const.COMMAND_CLASS_USER_CODE): if node.has_command_class(zwave.const.COMMAND_CLASS_USER_CODE):
hass.services.register(DOMAIN, hass.services.register(DOMAIN,
SERVICE_SET_USERCODE, SERVICE_SET_USERCODE,
@ -204,7 +198,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
descriptions.get(SERVICE_CLEAR_USERCODE), descriptions.get(SERVICE_CLEAR_USERCODE),
schema=CLEAR_USERCODE_SCHEMA) schema=CLEAR_USERCODE_SCHEMA)
value.set_change_verified(False) value.set_change_verified(False)
add_devices([ZwaveLock(value)]) return ZwaveLock(value)
class ZwaveLock(zwave.ZWaveDeviceEntity, LockDevice): class ZwaveLock(zwave.ZWaveDeviceEntity, LockDevice):

View File

@ -10,41 +10,25 @@ import logging
from homeassistant.components.sensor import DOMAIN from homeassistant.components.sensor import DOMAIN
from homeassistant.components import zwave from homeassistant.components import zwave
from homeassistant.const import TEMP_CELSIUS, TEMP_FAHRENHEIT from homeassistant.const import TEMP_CELSIUS, TEMP_FAHRENHEIT
from homeassistant.components.zwave import async_setup_platform # noqa # pylint: disable=unused-import
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
def setup_platform(hass, config, add_devices, discovery_info=None): def get_device(node, value, **kwargs):
"""Setup Z-Wave sensors.""" """Create zwave entity device."""
# Return on empty `discovery_info`. Given you configure HA with:
#
# sensor:
# platform: zwave
#
# `setup_platform` will be called without `discovery_info`.
if discovery_info is None or zwave.NETWORK is None:
return
node = zwave.NETWORK.nodes[discovery_info[zwave.const.ATTR_NODE_ID]]
value = node.values[discovery_info[zwave.const.ATTR_VALUE_ID]]
value.set_change_verified(False) value.set_change_verified(False)
# if 1 in groups and (NETWORK.controller.node_id not in
# groups[1].associations):
# node.groups[1].add_association(NETWORK.controller.node_id)
# Generic Device mappings # Generic Device mappings
if node.has_command_class(zwave.const.COMMAND_CLASS_SENSOR_MULTILEVEL): if node.has_command_class(zwave.const.COMMAND_CLASS_SENSOR_MULTILEVEL):
add_devices([ZWaveMultilevelSensor(value)]) return ZWaveMultilevelSensor(value)
if node.has_command_class(zwave.const.COMMAND_CLASS_METER) and \
elif node.has_command_class(zwave.const.COMMAND_CLASS_METER) and \
value.type == zwave.const.TYPE_DECIMAL: value.type == zwave.const.TYPE_DECIMAL:
add_devices([ZWaveMultilevelSensor(value)]) return ZWaveMultilevelSensor(value)
if node.has_command_class(zwave.const.COMMAND_CLASS_ALARM) or \
elif node.has_command_class(zwave.const.COMMAND_CLASS_ALARM) or \
node.has_command_class(zwave.const.COMMAND_CLASS_SENSOR_ALARM): node.has_command_class(zwave.const.COMMAND_CLASS_SENSOR_ALARM):
add_devices([ZWaveAlarmSensor(value)]) return ZWaveAlarmSensor(value)
return None
class ZWaveSensor(zwave.ZWaveDeviceEntity): class ZWaveSensor(zwave.ZWaveDeviceEntity):

View File

@ -9,27 +9,21 @@ import logging
# pylint: disable=import-error # pylint: disable=import-error
from homeassistant.components.switch import DOMAIN, SwitchDevice from homeassistant.components.switch import DOMAIN, SwitchDevice
from homeassistant.components import zwave from homeassistant.components import zwave
from homeassistant.components.zwave import async_setup_platform # noqa # pylint: disable=unused-import
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
# pylint: disable=unused-argument # pylint: disable=unused-argument
def setup_platform(hass, config, add_devices, discovery_info=None): def get_device(node, value, **kwargs):
"""Setup the Z-Wave platform.""" """Create zwave entity device."""
if discovery_info is None or zwave.NETWORK is None:
return
node = zwave.NETWORK.nodes[discovery_info[zwave.const.ATTR_NODE_ID]]
value = node.values[discovery_info[zwave.const.ATTR_VALUE_ID]]
if not node.has_command_class(zwave.const.COMMAND_CLASS_SWITCH_BINARY): if not node.has_command_class(zwave.const.COMMAND_CLASS_SWITCH_BINARY):
return return None
if value.type != zwave.const.TYPE_BOOL or value.genre != \ if value.type != zwave.const.TYPE_BOOL or value.genre != \
zwave.const.GENRE_USER: zwave.const.GENRE_USER:
return return None
value.set_change_verified(False) value.set_change_verified(False)
add_devices([ZwaveSwitch(value)]) return ZwaveSwitch(value)
class ZwaveSwitch(zwave.ZWaveDeviceEntity, SwitchDevice): class ZwaveSwitch(zwave.ZWaveDeviceEntity, SwitchDevice):

View File

@ -4,6 +4,7 @@ Support for Z-Wave.
For more details about this component, please refer to the documentation at For more details about this component, please refer to the documentation at
https://home-assistant.io/components/zwave/ https://home-assistant.io/components/zwave/
""" """
import asyncio
import logging import logging
import os.path import os.path
import time import time
@ -11,6 +12,7 @@ from pprint import pprint
import voluptuous as vol import voluptuous as vol
from homeassistant.loader import get_platform
from homeassistant.helpers import discovery from homeassistant.helpers import discovery
from homeassistant.const import ( from homeassistant.const import (
ATTR_BATTERY_LEVEL, ATTR_LOCATION, ATTR_ENTITY_ID, ATTR_WAKEUP, ATTR_BATTERY_LEVEL, ATTR_LOCATION, ATTR_ENTITY_ID, ATTR_WAKEUP,
@ -54,8 +56,10 @@ DEFAULT_CONF_REFRESH_VALUE = False
DEFAULT_CONF_REFRESH_DELAY = 5 DEFAULT_CONF_REFRESH_DELAY = 5
DOMAIN = 'zwave' DOMAIN = 'zwave'
DATA_ZWAVE_DICT = 'zwave_devices'
NETWORK = None NETWORK = None
DATA_DEVICE_CONFIG = 'zwave_device_config'
# List of tuple (DOMAIN, discovered service, supported command classes, # List of tuple (DOMAIN, discovered service, supported command classes,
# value type, genre type, specific device class). # value type, genre type, specific device class).
@ -264,6 +268,20 @@ def get_config_value(node, value_index, tries=5):
return None return None
@asyncio.coroutine
def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
"""Generic Z-Wave platform setup."""
if discovery_info is None or NETWORK is None:
return False
device = hass.data[DATA_ZWAVE_DICT].pop(
discovery_info[const.DISCOVERY_DEVICE])
if device:
yield from async_add_devices([device])
return True
else:
return False
# pylint: disable=R0914 # pylint: disable=R0914
def setup(hass, config): def setup(hass, config):
"""Setup Z-Wave. """Setup Z-Wave.
@ -294,7 +312,7 @@ def setup(hass, config):
# Load configuration # Load configuration
use_debug = config[DOMAIN].get(CONF_DEBUG) use_debug = config[DOMAIN].get(CONF_DEBUG)
autoheal = config[DOMAIN].get(CONF_AUTOHEAL) autoheal = config[DOMAIN].get(CONF_AUTOHEAL)
hass.data[DATA_DEVICE_CONFIG] = EntityValues( device_config = EntityValues(
config[DOMAIN][CONF_DEVICE_CONFIG], config[DOMAIN][CONF_DEVICE_CONFIG],
config[DOMAIN][CONF_DEVICE_CONFIG_DOMAIN], config[DOMAIN][CONF_DEVICE_CONFIG_DOMAIN],
config[DOMAIN][CONF_DEVICE_CONFIG_GLOB]) config[DOMAIN][CONF_DEVICE_CONFIG_GLOB])
@ -310,6 +328,7 @@ def setup(hass, config):
options.lock() options.lock()
NETWORK = ZWaveNetwork(options, autostart=False) NETWORK = ZWaveNetwork(options, autostart=False)
hass.data[DATA_ZWAVE_DICT] = {}
if use_debug: if use_debug:
def log_all(signal, value=None): def log_all(signal, value=None):
@ -386,7 +405,7 @@ def setup(hass, config):
component = workaround_component component = workaround_component
name = "{}.{}".format(component, object_id(value)) name = "{}.{}".format(component, object_id(value))
node_config = hass.data[DATA_DEVICE_CONFIG].get(name) node_config = device_config.get(name)
if node_config.get(CONF_IGNORED): if node_config.get(CONF_IGNORED):
_LOGGER.info( _LOGGER.info(
@ -399,11 +418,21 @@ def setup(hass, config):
value.enable_poll(polling_intensity) value.enable_poll(polling_intensity)
else: else:
value.disable_poll() 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
discovery.load_platform(hass, component, DOMAIN, { @asyncio.coroutine
const.ATTR_NODE_ID: node.node_id, def discover_device(component, device, dict_id):
const.ATTR_VALUE_ID: value.value_id, """Put device in a dictionary and call discovery on it."""
}, config) 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): def scene_activated(node, scene_id):
"""Called when a scene is activated on any node in the network.""" """Called when a scene is activated on any node in the network."""
@ -694,7 +723,10 @@ class ZWaveDeviceEntity(Entity):
"""Called when a value for this entity's node has changed.""" """Called when a value for this entity's node has changed."""
self._update_attributes() self._update_attributes()
self.update_properties() self.update_properties()
self.schedule_update_ha_state() # If value changed after device was created but before setup_platform
# was called - skip updating state.
if self.hass:
self.schedule_update_ha_state()
def _update_attributes(self): def _update_attributes(self):
"""Update the node attributes. May only be used inside callback.""" """Update the node attributes. May only be used inside callback."""

View File

@ -15,6 +15,8 @@ ATTR_CONFIG_SIZE = "size"
ATTR_CONFIG_VALUE = "value" ATTR_CONFIG_VALUE = "value"
NETWORK_READY_WAIT_SECS = 30 NETWORK_READY_WAIT_SECS = 30
DISCOVERY_DEVICE = 'device'
SERVICE_CHANGE_ASSOCIATION = "change_association" SERVICE_CHANGE_ASSOCIATION = "change_association"
SERVICE_ADD_NODE = "add_node" SERVICE_ADD_NODE = "add_node"
SERVICE_ADD_NODE_SECURE = "add_node_secure" SERVICE_ADD_NODE_SECURE = "add_node_secure"

View File

@ -5,8 +5,6 @@ from unittest.mock import MagicMock, patch
import pytest import pytest
from homeassistant.bootstrap import async_setup_component from homeassistant.bootstrap import async_setup_component
from homeassistant.components.zwave import (
DATA_DEVICE_CONFIG, DEVICE_CONFIG_SCHEMA_ENTRY)
@pytest.fixture(autouse=True) @pytest.fixture(autouse=True)
@ -24,24 +22,32 @@ def mock_openzwave():
@asyncio.coroutine @asyncio.coroutine
def test_device_config(hass): def test_valid_device_config(hass):
"""Test device config stored in hass.""" """Test valid device config."""
device_config = { device_config = {
'light.kitchen': { 'light.kitchen': {
'ignored': 'true' 'ignored': 'true'
} }
} }
yield from async_setup_component(hass, 'zwave', { result = yield from async_setup_component(hass, 'zwave', {
'zwave': { 'zwave': {
'device_config': device_config 'device_config': device_config
}}) }})
assert DATA_DEVICE_CONFIG in hass.data assert result
test_data = {
key: DEVICE_CONFIG_SCHEMA_ENTRY(value) @asyncio.coroutine
for key, value in device_config.items() def test_invalid_device_config(hass):
"""Test invalid device config."""
device_config = {
'light.kitchen': {
'some_ignored': 'true'
}
} }
result = yield from async_setup_component(hass, 'zwave', {
'zwave': {
'device_config': device_config
}})
assert hass.data[DATA_DEVICE_CONFIG].get('light.kitchen') == \ assert not result
test_data.get('light.kitchen')