Use standard entity_ids for zwave entities (#7786)

* Use standard entity_ids for zwave entities

* Include temporary opt-in for new entity ids

* Update link to blog post

* Update tests

* Add old entity_id as state attribute

* Expose ZWave value details

* Update tests

* Also show new_entity_id

* Just can't win with this one
pull/8068/head
Adam Mills 2017-06-16 13:07:17 -04:00 committed by GitHub
parent 1c2f4866e2
commit afb9cba806
8 changed files with 247 additions and 123 deletions

View File

@ -47,11 +47,11 @@ TEMP_COLD_HASS = (TEMP_COLOR_MAX - TEMP_COLOR_MIN) / 3 + TEMP_COLOR_MIN
def get_device(node, values, node_config, **kwargs):
"""Create Z-Wave entity device."""
name = '{}.{}'.format(DOMAIN, zwave.object_id(values.primary))
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"
" CONF_REFRESH_DELAY=%s", name, node_config, refresh, delay)
_LOGGER.debug("node=%d value=%d node_config=%s CONF_REFRESH_VALUE=%s"
" CONF_REFRESH_DELAY=%s", node.node_id,
values.primary.value_id, node_config, refresh, delay)
if node.has_command_class(zwave.const.COMMAND_CLASS_SWITCH_COLOR):
return ZwaveColorLight(values, refresh, delay)

View File

@ -16,6 +16,7 @@ import voluptuous as vol
from homeassistant.core import CoreState
from homeassistant.loader import get_platform
from homeassistant.helpers import discovery
from homeassistant.helpers.entity import generate_entity_id
from homeassistant.helpers.entity_component import EntityComponent
from homeassistant.const import (
ATTR_ENTITY_ID, EVENT_HOMEASSISTANT_START, EVENT_HOMEASSISTANT_STOP)
@ -55,6 +56,7 @@ CONF_DEVICE_CONFIG = 'device_config'
CONF_DEVICE_CONFIG_GLOB = 'device_config_glob'
CONF_DEVICE_CONFIG_DOMAIN = 'device_config_domain'
CONF_NETWORK_KEY = 'network_key'
CONF_NEW_ENTITY_IDS = 'new_entity_ids'
ATTR_POWER = 'power_consumption'
@ -149,6 +151,7 @@ CONFIG_SCHEMA = vol.Schema({
cv.positive_int,
vol.Optional(CONF_USB_STICK_PATH, default=DEFAULT_CONF_USB_STICK_PATH):
cv.string,
vol.Optional(CONF_NEW_ENTITY_IDS, default=False): cv.boolean,
}),
}, extra=vol.ALLOW_EXTRA)
@ -162,7 +165,7 @@ def _obj_to_dict(obj):
def _value_name(value):
"""Return the name of the value."""
return '{} {}'.format(node_name(value.node), value.label)
return '{} {}'.format(node_name(value.node), value.label).strip()
def _node_object_id(node):
@ -250,6 +253,13 @@ def setup(hass, config):
config[DOMAIN][CONF_DEVICE_CONFIG],
config[DOMAIN][CONF_DEVICE_CONFIG_DOMAIN],
config[DOMAIN][CONF_DEVICE_CONFIG_GLOB])
new_entity_ids = config[DOMAIN][CONF_NEW_ENTITY_IDS]
if not new_entity_ids:
_LOGGER.warning(
"ZWave entity_ids will soon be changing. To opt in to new "
"entity_ids now, set `new_entity_ids: true` under zwave in your "
"configuration.yaml. See the following blog post for details: "
"https://home-assistant.io/blog/2017/06/15/zwave-entity-ids/")
# Setup options
options = ZWaveOption(
@ -311,30 +321,20 @@ def setup(hass, config):
def node_added(node):
"""Handle a new node on the network."""
entity = ZWaveNodeEntity(node, network)
node_config = device_config.get(entity.entity_id)
entity = ZWaveNodeEntity(node, network, new_entity_ids)
name = node_name(node)
if new_entity_ids:
generated_id = generate_entity_id(DOMAIN + '.{}', name, [])
else:
generated_id = entity.entity_id
node_config = device_config.get(generated_id)
if node_config.get(CONF_IGNORED):
_LOGGER.info(
"Ignoring node entity %s due to device settings",
entity.entity_id)
generated_id)
return
component.add_entities([entity])
def scene_activated(node, scene_id):
"""Handle an activated scene on any node in the network."""
hass.bus.fire(const.EVENT_SCENE_ACTIVATED, {
ATTR_ENTITY_ID: _node_object_id(node),
const.ATTR_OBJECT_ID: _node_object_id(node),
const.ATTR_SCENE_ID: scene_id
})
def node_event_activated(node, value):
"""Handle a nodeevent on any node in the network."""
hass.bus.fire(const.EVENT_NODE_EVENT, {
const.ATTR_OBJECT_ID: _node_object_id(node),
const.ATTR_BASIC_LEVEL: value
})
def network_ready():
"""Handle the query of all awake nodes."""
_LOGGER.info("Zwave network is ready for use. All awake nodes "
@ -352,10 +352,6 @@ def setup(hass, config):
value_added, ZWaveNetwork.SIGNAL_VALUE_ADDED, weak=False)
dispatcher.connect(
node_added, ZWaveNetwork.SIGNAL_NODE_ADDED, weak=False)
dispatcher.connect(
scene_activated, ZWaveNetwork.SIGNAL_SCENE_EVENT, weak=False)
dispatcher.connect(
node_event_activated, ZWaveNetwork.SIGNAL_NODE_EVENT, weak=False)
dispatcher.connect(
network_ready, ZWaveNetwork.SIGNAL_AWAKE_NODES_QUERIED, weak=False)
dispatcher.connect(
@ -757,9 +753,8 @@ class ZWaveDeviceEntityValues():
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)))
_LOGGER.info("Ignoring Node %d Value %d due to workaround.",
self.primary.node.node_id, self.primary.value_id)
# No entity will be created for this value
self._workaround_ignore = True
return
@ -767,8 +762,13 @@ class ZWaveDeviceEntityValues():
workaround_component, component)
component = workaround_component
name = "{}.{}".format(component, object_id(self.primary))
node_config = self._device_config.get(name)
value_name = _value_name(self.primary)
if self._zwave_config[DOMAIN][CONF_NEW_ENTITY_IDS]:
generated_id = generate_entity_id(
component + '.{}', value_name, [])
else:
generated_id = "{}.{}".format(component, object_id(self.primary))
node_config = self._device_config.get(generated_id)
# Configure node
_LOGGER.debug("Adding Node_id=%s Generic_command_class=%s, "
@ -781,7 +781,7 @@ class ZWaveDeviceEntityValues():
if node_config.get(CONF_IGNORED):
_LOGGER.info(
"Ignoring entity %s due to device settings", name)
"Ignoring entity %s due to device settings", generated_id)
# No entity will be created for this value
self._workaround_ignore = True
return
@ -802,6 +802,12 @@ class ZWaveDeviceEntityValues():
self._workaround_ignore = True
return
device.old_entity_id = "{}.{}".format(
component, object_id(self.primary))
device.new_entity_id = "{}.{}".format(component, slugify(device.name))
if not self._zwave_config[DOMAIN][CONF_NEW_ENTITY_IDS]:
device.entity_id = device.old_entity_id
self._entity = device
dict_id = id(self)
@ -828,7 +834,6 @@ class ZWaveDeviceEntity(ZWaveBaseEntity):
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._name = _value_name(self.values.primary)
self._unique_id = "ZWAVE-{}-{}".format(self.node.node_id,
@ -895,6 +900,10 @@ class ZWaveDeviceEntity(ZWaveBaseEntity):
"""Return the device specific state attributes."""
attrs = {
const.ATTR_NODE_ID: self.node_id,
const.ATTR_VALUE_INDEX: self.values.primary.index,
const.ATTR_VALUE_INSTANCE: self.values.primary.instance,
'old_entity_id': self.old_entity_id,
'new_entity_id': self.new_entity_id,
}
if self.power_consumption is not None:

View File

@ -31,6 +31,8 @@ class ZWaveNodeValueView(HomeAssistantView):
values_data[entity_values.primary.value_id] = {
'label': entity_values.primary.label,
'index': entity_values.primary.index,
'instance': entity_values.primary.instance,
}
return self.json(values_data)

View File

@ -14,6 +14,8 @@ ATTR_BASIC_LEVEL = "basic_level"
ATTR_CONFIG_PARAMETER = "parameter"
ATTR_CONFIG_SIZE = "size"
ATTR_CONFIG_VALUE = "value"
ATTR_VALUE_INDEX = "value_index"
ATTR_VALUE_INSTANCE = "value_instance"
NETWORK_READY_WAIT_SECS = 30
DISCOVERY_DEVICE = 'device'

View File

@ -2,11 +2,13 @@
import logging
from homeassistant.core import callback
from homeassistant.const import ATTR_BATTERY_LEVEL, ATTR_WAKEUP
from homeassistant.const import ATTR_BATTERY_LEVEL, ATTR_WAKEUP, ATTR_ENTITY_ID
from homeassistant.helpers.entity import Entity
from homeassistant.util import slugify
from .const import ATTR_NODE_ID, DOMAIN, COMMAND_CLASS_WAKE_UP
from .const import (
ATTR_NODE_ID, COMMAND_CLASS_WAKE_UP, ATTR_SCENE_ID, ATTR_BASIC_LEVEL,
EVENT_NODE_EVENT, EVENT_SCENE_ACTIVATED, DOMAIN)
from .util import node_name
_LOGGER = logging.getLogger(__name__)
@ -38,6 +40,8 @@ class ZWaveBaseEntity(Entity):
def __init__(self):
"""Initialize the base Z-Wave class."""
self._update_scheduled = False
self.old_entity_id = None
self.new_entity_id = None
def maybe_schedule_update(self):
"""Maybe schedule state update.
@ -72,7 +76,7 @@ def sub_status(status, stage):
class ZWaveNodeEntity(ZWaveBaseEntity):
"""Representation of a Z-Wave node."""
def __init__(self, node, network):
def __init__(self, node, network, new_entity_ids):
"""Initialize node."""
# pylint: disable=import-error
super().__init__()
@ -84,8 +88,11 @@ class ZWaveNodeEntity(ZWaveBaseEntity):
self._name = node_name(self.node)
self._product_name = node.product_name
self._manufacturer_name = node.manufacturer_name
self.entity_id = "{}.{}_{}".format(
self.old_entity_id = "{}.{}_{}".format(
DOMAIN, slugify(self._name), self.node_id)
self.new_entity_id = "{}.{}".format(DOMAIN, slugify(self._name))
if not new_entity_ids:
self.entity_id = self.old_entity_id
self._attributes = {}
self.wakeup_interval = None
self.location = None
@ -95,6 +102,10 @@ class ZWaveNodeEntity(ZWaveBaseEntity):
dispatcher.connect(self.network_node_changed, ZWaveNetwork.SIGNAL_NODE)
dispatcher.connect(
self.network_node_changed, ZWaveNetwork.SIGNAL_NOTIFICATION)
dispatcher.connect(
self.network_node_event, ZWaveNetwork.SIGNAL_NODE_EVENT)
dispatcher.connect(
self.network_scene_activated, ZWaveNetwork.SIGNAL_SCENE_EVENT)
def network_node_changed(self, node=None, args=None):
"""Handle a changed node on the network."""
@ -134,6 +145,38 @@ class ZWaveNodeEntity(ZWaveBaseEntity):
self.maybe_schedule_update()
def network_node_event(self, node, value):
"""Handle a node activated event on the network."""
if node.node_id == self.node.node_id:
self.node_event(value)
def node_event(self, value):
"""Handle a node activated event for this node."""
if self.hass is None:
return
self.hass.bus.fire(EVENT_NODE_EVENT, {
ATTR_ENTITY_ID: self.entity_id,
ATTR_NODE_ID: self.node.node_id,
ATTR_BASIC_LEVEL: value
})
def network_scene_activated(self, node, scene_id):
"""Handle a scene activated event on the network."""
if node.node_id == self.node.node_id:
self.scene_activated(scene_id)
def scene_activated(self, scene_id):
"""Handle an activated scene for this node."""
if self.hass is None:
return
self.hass.bus.fire(EVENT_SCENE_ACTIVATED, {
ATTR_ENTITY_ID: self.entity_id,
ATTR_NODE_ID: self.node.node_id,
ATTR_SCENE_ID: scene_id
})
@property
def state(self):
"""Return the state."""
@ -169,6 +212,8 @@ class ZWaveNodeEntity(ZWaveBaseEntity):
ATTR_NODE_NAME: self._name,
ATTR_MANUFACTURER_NAME: self._manufacturer_name,
ATTR_PRODUCT_NAME: self._product_name,
'old_entity_id': self.old_entity_id,
'new_entity_id': self.new_entity_id,
}
attrs.update(self._attributes)
if self.battery_level is not None:

View File

@ -16,7 +16,8 @@ def test_get_values(hass, test_client):
ZWaveNodeValueView().register(app.router)
node = MockNode(node_id=1)
value = MockValue(value_id=123456, node=node, label='Test Label')
value = MockValue(value_id=123456, node=node, label='Test Label',
instance=1, index=2)
values = MockEntityValues(primary=value)
node2 = MockNode(node_id=2)
value2 = MockValue(value_id=234567, node=node2, label='Test Label 2')
@ -33,6 +34,8 @@ def test_get_values(hass, test_client):
assert result == {
'123456': {
'label': 'Test Label',
'instance': 1,
'index': 2,
}
}

View File

@ -214,7 +214,9 @@ def test_node_discovery(hass, mock_openzwave):
mock_receivers.append(receiver)
with patch('pydispatch.dispatcher.connect', new=mock_connect):
yield from async_setup_component(hass, 'zwave', {'zwave': {}})
yield from async_setup_component(hass, 'zwave', {'zwave': {
'new_entity_ids': True,
}})
assert len(mock_receivers) == 1
@ -222,7 +224,7 @@ def test_node_discovery(hass, mock_openzwave):
hass.async_add_job(mock_receivers[0], node)
yield from hass.async_block_till_done()
assert hass.states.get('zwave.mock_node_14').state is 'unknown'
assert hass.states.get('zwave.mock_node').state is 'unknown'
@asyncio.coroutine
@ -236,8 +238,9 @@ def test_node_ignored(hass, mock_openzwave):
with patch('pydispatch.dispatcher.connect', new=mock_connect):
yield from async_setup_component(hass, 'zwave', {'zwave': {
'new_entity_ids': True,
'device_config': {
'zwave.mock_node_14': {
'zwave.mock_node': {
'ignored': True,
}}}})
@ -247,7 +250,7 @@ def test_node_ignored(hass, mock_openzwave):
hass.async_add_job(mock_receivers[0], node)
yield from hass.async_block_till_done()
assert hass.states.get('zwave.mock_node_14') is None
assert hass.states.get('zwave.mock_node') is None
@asyncio.coroutine
@ -260,7 +263,9 @@ def test_value_discovery(hass, mock_openzwave):
mock_receivers.append(receiver)
with patch('pydispatch.dispatcher.connect', new=mock_connect):
yield from async_setup_component(hass, 'zwave', {'zwave': {}})
yield from async_setup_component(hass, 'zwave', {'zwave': {
'new_entity_ids': True,
}})
assert len(mock_receivers) == 1
@ -272,7 +277,7 @@ def test_value_discovery(hass, mock_openzwave):
yield from hass.async_block_till_done()
assert hass.states.get(
'binary_sensor.mock_node_mock_value_11_12_13').state is 'off'
'binary_sensor.mock_node_mock_value').state is 'off'
@asyncio.coroutine
@ -285,7 +290,9 @@ def test_value_discovery_existing_entity(hass, mock_openzwave):
mock_receivers.append(receiver)
with patch('pydispatch.dispatcher.connect', new=mock_connect):
yield from async_setup_component(hass, 'zwave', {'zwave': {}})
yield from async_setup_component(hass, 'zwave', {'zwave': {
'new_entity_ids': True,
}})
assert len(mock_receivers) == 1
@ -297,9 +304,9 @@ def test_value_discovery_existing_entity(hass, mock_openzwave):
hass.async_add_job(mock_receivers[0], node, setpoint)
yield from hass.async_block_till_done()
assert hass.states.get('climate.mock_node_mock_value_11_12_13').attributes[
assert hass.states.get('climate.mock_node_mock_value').attributes[
'temperature'] == 22.0
assert hass.states.get('climate.mock_node_mock_value_11_12_13').attributes[
assert hass.states.get('climate.mock_node_mock_value').attributes[
'current_temperature'] is None
def mock_update(self):
@ -314,75 +321,12 @@ def test_value_discovery_existing_entity(hass, mock_openzwave):
hass.async_add_job(mock_receivers[0], node, temperature)
yield from hass.async_block_till_done()
assert hass.states.get('climate.mock_node_mock_value_11_12_13').attributes[
assert hass.states.get('climate.mock_node_mock_value').attributes[
'temperature'] == 22.0
assert hass.states.get('climate.mock_node_mock_value_11_12_13').attributes[
assert hass.states.get('climate.mock_node_mock_value').attributes[
'current_temperature'] == 23.5
@asyncio.coroutine
def test_scene_activated(hass, mock_openzwave):
"""Test scene activated event."""
mock_receivers = []
def mock_connect(receiver, signal, *args, **kwargs):
if signal == MockNetwork.SIGNAL_SCENE_EVENT:
mock_receivers.append(receiver)
with patch('pydispatch.dispatcher.connect', new=mock_connect):
yield from async_setup_component(hass, 'zwave', {'zwave': {}})
assert len(mock_receivers) == 1
events = []
def listener(event):
events.append(event)
hass.bus.async_listen(const.EVENT_SCENE_ACTIVATED, listener)
node = MockNode(node_id=11)
scene_id = 123
hass.async_add_job(mock_receivers[0], node, scene_id)
yield from hass.async_block_till_done()
assert len(events) == 1
assert events[0].data[ATTR_ENTITY_ID] == "mock_node_11"
assert events[0].data[const.ATTR_OBJECT_ID] == "mock_node_11"
assert events[0].data[const.ATTR_SCENE_ID] == scene_id
@asyncio.coroutine
def test_node_event_activated(hass, mock_openzwave):
"""Test Node event activated event."""
mock_receivers = []
def mock_connect(receiver, signal, *args, **kwargs):
if signal == MockNetwork.SIGNAL_NODE_EVENT:
mock_receivers.append(receiver)
with patch('pydispatch.dispatcher.connect', new=mock_connect):
yield from async_setup_component(hass, 'zwave', {'zwave': {}})
assert len(mock_receivers) == 1
events = []
def listener(event):
events.append(event)
hass.bus.async_listen(const.EVENT_NODE_EVENT, listener)
node = MockNode(node_id=11)
value = 234
hass.async_add_job(mock_receivers[0], node, value)
yield from hass.async_block_till_done()
assert len(events) == 1
assert events[0].data[const.ATTR_OBJECT_ID] == "mock_node_11"
assert events[0].data[const.ATTR_BASIC_LEVEL] == value
@asyncio.coroutine
def test_network_ready(hass, mock_openzwave):
"""Test Node network ready event."""
@ -393,7 +337,9 @@ def test_network_ready(hass, mock_openzwave):
mock_receivers.append(receiver)
with patch('pydispatch.dispatcher.connect', new=mock_connect):
yield from async_setup_component(hass, 'zwave', {'zwave': {}})
yield from async_setup_component(hass, 'zwave', {'zwave': {
'new_entity_ids': True,
}})
assert len(mock_receivers) == 1
@ -420,7 +366,9 @@ def test_network_complete(hass, mock_openzwave):
mock_receivers.append(receiver)
with patch('pydispatch.dispatcher.connect', new=mock_connect):
yield from async_setup_component(hass, 'zwave', {'zwave': {}})
yield from async_setup_component(hass, 'zwave', {'zwave': {
'new_entity_ids': True,
}})
assert len(mock_receivers) == 1
@ -450,7 +398,9 @@ class TestZWaveDeviceEntityValues(unittest.TestCase):
self.hass = get_test_home_assistant()
self.hass.start()
setup_component(self.hass, 'zwave', {'zwave': {}})
setup_component(self.hass, 'zwave', {'zwave': {
'new_entity_ids': True,
}})
self.hass.block_till_done()
self.node = MockNode()
@ -478,9 +428,10 @@ class TestZWaveDeviceEntityValues(unittest.TestCase):
self.no_match_value = MockValue(
command_class='mock_bad_class', node=self.node)
self.entity_id = '{}.{}'.format('mock_component',
zwave.object_id(self.primary))
self.zwave_config = {}
self.entity_id = 'mock_component.mock_node_mock_value'
self.zwave_config = {'zwave': {
'new_entity_ids': True,
}}
self.device_config = {self.entity_id: {}}
def tearDown(self): # pylint: disable=invalid-name
@ -491,6 +442,11 @@ class TestZWaveDeviceEntityValues(unittest.TestCase):
@patch.object(zwave, 'discovery')
def test_entity_discovery(self, discovery, get_platform):
"""Test the creation of a new entity."""
mock_platform = MagicMock()
get_platform.return_value = mock_platform
mock_device = MagicMock()
mock_device.name = 'test_device'
mock_platform.get_device.return_value = mock_device
values = zwave.ZWaveDeviceEntityValues(
hass=self.hass,
schema=self.mock_schema,
@ -550,6 +506,11 @@ class TestZWaveDeviceEntityValues(unittest.TestCase):
@patch.object(zwave, 'discovery')
def test_entity_existing_values(self, discovery, get_platform):
"""Test the loading of already discovered values."""
mock_platform = MagicMock()
get_platform.return_value = mock_platform
mock_device = MagicMock()
mock_device.name = 'test_device'
mock_platform.get_device.return_value = mock_device
self.node.values = {
self.primary.value_id: self.primary,
self.secondary.value_id: self.secondary,
@ -613,11 +574,15 @@ class TestZWaveDeviceEntityValues(unittest.TestCase):
@patch.object(zwave, 'discovery')
def test_entity_workaround_component(self, discovery, get_platform):
"""Test ignore workaround."""
mock_platform = MagicMock()
get_platform.return_value = mock_platform
mock_device = MagicMock()
mock_device.name = 'test_device'
mock_platform.get_device.return_value = mock_device
self.node.manufacturer_id = '010f'
self.node.product_type = '0b00'
self.primary.command_class = const.COMMAND_CLASS_SENSOR_ALARM
self.entity_id = '{}.{}'.format('binary_sensor',
zwave.object_id(self.primary))
self.entity_id = 'binary_sensor.mock_node_mock_value'
self.device_config = {self.entity_id: {}}
self.mock_schema = {
@ -721,6 +686,11 @@ class TestZWaveDeviceEntityValues(unittest.TestCase):
@patch.object(zwave, 'discovery')
def test_config_polling_intensity(self, discovery, get_platform):
"""Test polling intensity."""
mock_platform = MagicMock()
get_platform.return_value = mock_platform
mock_device = MagicMock()
mock_device.name = 'test_device'
mock_platform.get_device.return_value = mock_device
self.node.values = {
self.primary.value_id: self.primary,
self.secondary.value_id: self.secondary,
@ -770,7 +740,9 @@ class TestZWaveServices(unittest.TestCase):
self.hass.start()
# Initialize zwave
setup_component(self.hass, 'zwave', {'zwave': {}})
setup_component(self.hass, 'zwave', {'zwave': {
'new_entity_ids': True,
}})
self.hass.block_till_done()
self.zwave_network = self.hass.data[DATA_NETWORK]
self.zwave_network.state = MockNetwork.STATE_READY

View File

@ -4,7 +4,8 @@ import unittest
from unittest.mock import patch, MagicMock
import tests.mock.zwave as mock_zwave
import pytest
from homeassistant.components.zwave import node_entity
from homeassistant.components.zwave import node_entity, const
from homeassistant.const import ATTR_ENTITY_ID
@asyncio.coroutine
@ -30,6 +31,92 @@ def test_maybe_schedule_update(hass, mock_openzwave):
assert len(mock_call_later.mock_calls) == 2
@asyncio.coroutine
def test_node_event_activated(hass, mock_openzwave):
"""Test Node event activated event."""
mock_receivers = []
def mock_connect(receiver, signal, *args, **kwargs):
if signal == mock_zwave.MockNetwork.SIGNAL_NODE_EVENT:
mock_receivers.append(receiver)
node = mock_zwave.MockNode(node_id=11)
with patch('pydispatch.dispatcher.connect', new=mock_connect):
entity = node_entity.ZWaveNodeEntity(node, mock_openzwave, True)
assert len(mock_receivers) == 1
events = []
def listener(event):
events.append(event)
hass.bus.async_listen(const.EVENT_NODE_EVENT, listener)
# Test event before entity added to hass
value = 234
hass.async_add_job(mock_receivers[0], node, value)
yield from hass.async_block_till_done()
assert len(events) == 0
# Add entity to hass
entity.hass = hass
entity.entity_id = 'zwave.mock_node'
value = 234
hass.async_add_job(mock_receivers[0], node, value)
yield from hass.async_block_till_done()
assert len(events) == 1
assert events[0].data[ATTR_ENTITY_ID] == "zwave.mock_node"
assert events[0].data[const.ATTR_NODE_ID] == 11
assert events[0].data[const.ATTR_BASIC_LEVEL] == value
@asyncio.coroutine
def test_scene_activated(hass, mock_openzwave):
"""Test scene activated event."""
mock_receivers = []
def mock_connect(receiver, signal, *args, **kwargs):
if signal == mock_zwave.MockNetwork.SIGNAL_SCENE_EVENT:
mock_receivers.append(receiver)
node = mock_zwave.MockNode(node_id=11)
with patch('pydispatch.dispatcher.connect', new=mock_connect):
entity = node_entity.ZWaveNodeEntity(node, mock_openzwave, True)
assert len(mock_receivers) == 1
events = []
def listener(event):
events.append(event)
hass.bus.async_listen(const.EVENT_SCENE_ACTIVATED, listener)
# Test event before entity added to hass
scene_id = 123
hass.async_add_job(mock_receivers[0], node, scene_id)
yield from hass.async_block_till_done()
assert len(events) == 0
# Add entity to hass
entity.hass = hass
entity.entity_id = 'zwave.mock_node'
scene_id = 123
hass.async_add_job(mock_receivers[0], node, scene_id)
yield from hass.async_block_till_done()
assert len(events) == 1
assert events[0].data[ATTR_ENTITY_ID] == "zwave.mock_node"
assert events[0].data[const.ATTR_NODE_ID] == 11
assert events[0].data[const.ATTR_SCENE_ID] == scene_id
@pytest.mark.usefixtures('mock_openzwave')
class TestZWaveNodeEntity(unittest.TestCase):
"""Class to test ZWaveNodeEntity."""
@ -44,7 +131,7 @@ class TestZWaveNodeEntity(unittest.TestCase):
self.node.manufacturer_name = 'Test Manufacturer'
self.node.product_name = 'Test Product'
self.entity = node_entity.ZWaveNodeEntity(self.node,
self.zwave_network)
self.zwave_network, True)
def test_network_node_changed_from_value(self):
"""Test for network_node_changed."""
@ -85,6 +172,8 @@ class TestZWaveNodeEntity(unittest.TestCase):
{'node_id': self.node.node_id,
'node_name': 'Mock Node',
'manufacturer_name': 'Test Manufacturer',
'old_entity_id': 'zwave.mock_node_567',
'new_entity_id': 'zwave.mock_node',
'product_name': 'Test Product'},
self.entity.device_state_attributes)
@ -143,6 +232,8 @@ class TestZWaveNodeEntity(unittest.TestCase):
{'node_id': self.node.node_id,
'node_name': 'Mock Node',
'manufacturer_name': 'Test Manufacturer',
'old_entity_id': 'zwave.mock_node_567',
'new_entity_id': 'zwave.mock_node',
'product_name': 'Test Product',
'query_stage': 'Dynamic',
'is_awake': True,