Add communication data attributes to Zwave node_entity (#6813)

* Add quality attribute to node

* Move quality to node_entity

* adjustments

* Line lenght

* flake8

* Cleanup and add each entry from getNodeStatistics as attribute

* resolve conflict

* Move NETWORK to hass.data

* Test Done

* Cleanup from review

* Resolve conflicts

* Review changes

* Long lines....

* blank line

* import-error-disable

* Update tests Part1... Again

* Hound

* Argh!

* Argh!

* YABBADABBADOOOOOOO!

* Enhance tests

* hound

* Resolve

* resolve tests...
This commit is contained in:
John Arild Berentsen 2017-04-12 19:09:29 +02:00 committed by GitHub
parent f68542ba0d
commit d63028e44a
8 changed files with 240 additions and 148 deletions

View file

@ -20,13 +20,13 @@ _LOGGER = logging.getLogger(__name__)
SUPPORT_GARAGE = SUPPORT_OPEN | SUPPORT_CLOSE
def get_device(values, node_config, **kwargs):
def get_device(hass, values, node_config, **kwargs):
"""Create zwave entity device."""
invert_buttons = node_config.get(zwave.CONF_INVERT_OPENCLOSE_BUTTONS)
if (values.primary.command_class ==
zwave.const.COMMAND_CLASS_SWITCH_MULTILEVEL
and values.primary.index == 0):
return ZwaveRollershutter(values, invert_buttons)
return ZwaveRollershutter(hass, values, invert_buttons)
elif (values.primary.command_class in [
zwave.const.COMMAND_CLASS_SWITCH_BINARY,
zwave.const.COMMAND_CLASS_BARRIER_OPERATOR]):
@ -37,10 +37,11 @@ def get_device(values, node_config, **kwargs):
class ZwaveRollershutter(zwave.ZWaveDeviceEntity, CoverDevice):
"""Representation of an Zwave roller shutter."""
def __init__(self, values, invert_buttons):
def __init__(self, hass, values, invert_buttons):
"""Initialize the zwave rollershutter."""
ZWaveDeviceEntity.__init__(self, values, DOMAIN)
# pylint: disable=no-member
self._network = hass.data[zwave.ZWAVE_NETWORK]
self._open_id = None
self._close_id = None
self._current_position = None
@ -90,11 +91,11 @@ class ZwaveRollershutter(zwave.ZWaveDeviceEntity, CoverDevice):
def open_cover(self, **kwargs):
"""Move the roller shutter up."""
zwave.NETWORK.manager.pressButton(self._open_id)
self._network.manager.pressButton(self._open_id)
def close_cover(self, **kwargs):
"""Move the roller shutter down."""
zwave.NETWORK.manager.pressButton(self._close_id)
self._network.manager.pressButton(self._close_id)
def set_cover_position(self, position, **kwargs):
"""Move the roller shutter to a specific position."""
@ -102,7 +103,7 @@ class ZwaveRollershutter(zwave.ZWaveDeviceEntity, CoverDevice):
def stop_cover(self, **kwargs):
"""Stop the roller shutter."""
zwave.NETWORK.manager.releaseButton(self._open_id)
self._network.manager.releaseButton(self._open_id)
class ZwaveGarageDoor(zwave.ZWaveDeviceEntity, CoverDevice):

View file

@ -128,11 +128,12 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
descriptions = load_yaml_config_file(
path.join(path.dirname(__file__), 'services.yaml'))
network = hass.data[zwave.ZWAVE_NETWORK]
def set_usercode(service):
"""Set the usercode to index X on the lock."""
node_id = service.data.get(zwave.const.ATTR_NODE_ID)
lock_node = zwave.NETWORK.nodes[node_id]
lock_node = network.nodes[node_id]
code_slot = service.data.get(ATTR_CODE_SLOT)
usercode = service.data.get(ATTR_USERCODE)
@ -151,7 +152,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
def get_usercode(service):
"""Get a usercode at index X on the lock."""
node_id = service.data.get(zwave.const.ATTR_NODE_ID)
lock_node = zwave.NETWORK.nodes[node_id]
lock_node = network.nodes[node_id]
code_slot = service.data.get(ATTR_CODE_SLOT)
for value in lock_node.get_values(
@ -164,7 +165,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
def clear_usercode(service):
"""Set usercode to slot X on the lock."""
node_id = service.data.get(zwave.const.ATTR_NODE_ID)
lock_node = zwave.NETWORK.nodes[node_id]
lock_node = network.nodes[node_id]
code_slot = service.data.get(ATTR_CODE_SLOT)
data = ''

View file

@ -65,8 +65,7 @@ DEFAULT_CONF_REFRESH_VALUE = False
DEFAULT_CONF_REFRESH_DELAY = 5
DATA_ZWAVE_DICT = 'zwave_devices'
NETWORK = None
ZWAVE_NETWORK = 'zwave_network'
RENAME_NODE_SCHEMA = vol.Schema({
vol.Required(const.ATTR_NODE_ID): vol.Coerce(int),
@ -200,7 +199,7 @@ def get_config_value(node, value_index, tries=5):
@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:
if discovery_info is None or ZWAVE_NETWORK not in hass.data:
return False
device = hass.data[DATA_ZWAVE_DICT].pop(
@ -218,9 +217,6 @@ def setup(hass, config):
Will automatically load components to support devices found on the network.
"""
# pylint: disable=global-statement, import-error
global NETWORK
descriptions = conf_util.load_yaml_config_file(
os.path.join(os.path.dirname(__file__), 'services.yaml'))
@ -232,6 +228,7 @@ def setup(hass, config):
"https://home-assistant.io/components/zwave/")
return False
from pydispatch import dispatcher
# pylint: disable=import-error
from openzwave.option import ZWaveOption
from openzwave.network import ZWaveNetwork
from openzwave.group import ZWaveGroup
@ -257,7 +254,7 @@ def setup(hass, config):
options.set_console_output(use_debug)
options.lock()
NETWORK = ZWaveNetwork(options, autostart=False)
network = hass.data[ZWAVE_NETWORK] = ZWaveNetwork(options, autostart=False)
hass.data[DATA_ZWAVE_DICT] = {}
if use_debug: # pragma: no cover
@ -301,7 +298,7 @@ def setup(hass, config):
def node_added(node):
"""Called when a node is added on the network."""
entity = ZWaveNodeEntity(node)
entity = ZWaveNodeEntity(node, network)
node_config = device_config.get(entity.entity_id)
if node_config.get(CONF_IGNORED):
_LOGGER.info(
@ -354,49 +351,49 @@ def setup(hass, config):
def add_node(service):
"""Switch into inclusion mode."""
_LOGGER.info("Zwave add_node have been initialized.")
NETWORK.controller.add_node()
network.controller.add_node()
def add_node_secure(service):
"""Switch into secure inclusion mode."""
_LOGGER.info("Zwave add_node_secure have been initialized.")
NETWORK.controller.add_node(True)
network.controller.add_node(True)
def remove_node(service):
"""Switch into exclusion mode."""
_LOGGER.info("Zwave remove_node have been initialized.")
NETWORK.controller.remove_node()
network.controller.remove_node()
def cancel_command(service):
"""Cancel a running controller command."""
_LOGGER.info("Cancel running ZWave command.")
NETWORK.controller.cancel_command()
network.controller.cancel_command()
def heal_network(service):
"""Heal the network."""
_LOGGER.info("ZWave heal running.")
NETWORK.heal()
network.heal()
def soft_reset(service):
"""Soft reset the controller."""
_LOGGER.info("Zwave soft_reset have been initialized.")
NETWORK.controller.soft_reset()
network.controller.soft_reset()
def test_network(service):
"""Test the network by sending commands to all the nodes."""
_LOGGER.info("Zwave test_network have been initialized.")
NETWORK.test()
network.test()
def stop_network(_service_or_event):
"""Stop Z-Wave network."""
_LOGGER.info("Stopping ZWave network.")
NETWORK.stop()
network.stop()
if hass.state == CoreState.running:
hass.bus.fire(const.EVENT_NETWORK_STOP)
def rename_node(service):
"""Rename a node."""
node_id = service.data.get(const.ATTR_NODE_ID)
node = NETWORK.nodes[node_id]
node = hass.data[ZWAVE_NETWORK].nodes[node_id]
name = service.data.get(const.ATTR_NAME)
node.name = name
_LOGGER.info(
@ -406,18 +403,18 @@ def setup(hass, config):
"""Remove failed node."""
node_id = service.data.get(const.ATTR_NODE_ID)
_LOGGER.info('Trying to remove zwave node %d', node_id)
NETWORK.controller.remove_failed_node(node_id)
network.controller.remove_failed_node(node_id)
def replace_failed_node(service):
"""Replace failed node."""
node_id = service.data.get(const.ATTR_NODE_ID)
_LOGGER.info('Trying to replace zwave node %d', node_id)
NETWORK.controller.replace_failed_node(node_id)
network.controller.replace_failed_node(node_id)
def set_config_parameter(service):
"""Set a config parameter to a node."""
node_id = service.data.get(const.ATTR_NODE_ID)
node = NETWORK.nodes[node_id]
node = network.nodes[node_id]
param = service.data.get(const.ATTR_CONFIG_PARAMETER)
selection = service.data.get(const.ATTR_CONFIG_VALUE)
size = service.data.get(const.ATTR_CONFIG_SIZE, 2)
@ -446,7 +443,7 @@ def setup(hass, config):
def print_config_parameter(service):
"""Print a config parameter from a node."""
node_id = service.data.get(const.ATTR_NODE_ID)
node = NETWORK.nodes[node_id]
node = network.nodes[node_id]
param = service.data.get(const.ATTR_CONFIG_PARAMETER)
_LOGGER.info("Config parameter %s on Node %s : %s",
param, node_id, get_config_value(node, param))
@ -454,13 +451,13 @@ def setup(hass, config):
def print_node(service):
"""Print all information about z-wave node."""
node_id = service.data.get(const.ATTR_NODE_ID)
node = NETWORK.nodes[node_id]
node = network.nodes[node_id]
nice_print_node(node)
def set_wakeup(service):
"""Set wake-up interval of a node."""
node_id = service.data.get(const.ATTR_NODE_ID)
node = NETWORK.nodes[node_id]
node = network.nodes[node_id]
value = service.data.get(const.ATTR_CONFIG_VALUE)
if node.can_wake_up():
for value_id in node.get_values(
@ -478,7 +475,7 @@ def setup(hass, config):
group = service.data.get(const.ATTR_GROUP)
instance = service.data.get(const.ATTR_INSTANCE)
node = ZWaveGroup(group, NETWORK, node_id)
node = ZWaveGroup(group, network, node_id)
if association_type == 'add':
node.add_association(target_node_id, instance)
_LOGGER.info("Adding association for node:%s in group:%s "
@ -500,13 +497,13 @@ def setup(hass, config):
def refresh_node(service):
"""Refresh all node info."""
node_id = service.data.get(const.ATTR_NODE_ID)
node = NETWORK.nodes[node_id]
node = network.nodes[node_id]
node.refresh_info()
def start_zwave(_service_or_event):
"""Startup Z-Wave network."""
_LOGGER.info("Starting ZWave network.")
NETWORK.start()
network.start()
hass.bus.fire(const.EVENT_NETWORK_START)
# Need to be in STATE_AWAKED before talking to nodes.
@ -514,8 +511,9 @@ def setup(hass, config):
# to be ready.
for i in range(const.NETWORK_READY_WAIT_SECS):
_LOGGER.debug(
"network state: %d %s", NETWORK.state, NETWORK.state_str)
if NETWORK.state >= NETWORK.STATE_AWAKED:
"network state: %d %s", hass.data[ZWAVE_NETWORK].state,
network.state_str)
if network.state >= network.STATE_AWAKED:
_LOGGER.info("zwave ready after %d seconds", i)
break
time.sleep(1)
@ -524,14 +522,15 @@ def setup(hass, config):
"zwave not ready after %d seconds, continuing anyway",
const.NETWORK_READY_WAIT_SECS)
_LOGGER.info(
"final network state: %d %s", NETWORK.state, NETWORK.state_str)
"final network state: %d %s", network.state,
network.state_str)
polling_interval = convert(
config[DOMAIN].get(CONF_POLLING_INTERVAL), int)
if polling_interval is not None:
NETWORK.set_poll_interval(polling_interval, False)
network.set_poll_interval(polling_interval, False)
poll_interval = NETWORK.get_poll_interval()
poll_interval = network.get_poll_interval()
_LOGGER.info("zwave polling interval set to %d ms", poll_interval)
hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, stop_network)

View file

@ -22,6 +22,10 @@ _REQUIRED_ATTRIBUTES = [
ATTR_QUERY_STAGE, ATTR_AWAKE, ATTR_READY, ATTR_FAILED,
'is_info_received', 'max_baud_rate', 'is_zwave_plus']
_OPTIONAL_ATTRIBUTES = ['capabilities', 'neighbors', 'location']
_COMM_ATTRIBUTES = [
'sentCnt', 'sentFailed', 'retries', 'receivedCnt', 'receivedDups',
'receivedUnsolicited', 'sentTS', 'receivedTS', 'lastRequestRTT',
'averageRequestRTT', 'lastResponseRTT', 'averageResponseRTT']
ATTRIBUTES = _REQUIRED_ATTRIBUTES + _OPTIONAL_ATTRIBUTES
@ -65,12 +69,13 @@ def sub_status(status, stage):
class ZWaveNodeEntity(ZWaveBaseEntity):
"""Representation of a Z-Wave node."""
def __init__(self, node):
def __init__(self, node, network):
"""Initialize node."""
# pylint: disable=import-error
super().__init__()
from openzwave.network import ZWaveNetwork
from pydispatch import dispatcher
self._network = network
self.node = node
self.node_id = self.node.node_id
self._name = node_name(self.node)
@ -95,13 +100,22 @@ class ZWaveNodeEntity(ZWaveBaseEntity):
return
self.node_changed()
def get_node_statistics(self):
"""Retrieve statistics from the node."""
return self._network.manager.getNodeStatistics(self._network.home_id,
self.node_id)
def node_changed(self):
"""Update node properties."""
self._attributes = {}
stats = self.get_node_statistics()
for attr in ATTRIBUTES:
value = getattr(self.node, attr)
if attr in _REQUIRED_ATTRIBUTES or value:
self._attributes[attr] = value
for attr in _COMM_ATTRIBUTES:
self._attributes[attr] = stats[attr]
if self.node.can_wake_up():
for value in self.node.get_values(COMMAND_CLASS_WAKE_UP).values():
@ -152,4 +166,5 @@ class ZWaveNodeEntity(ZWaveBaseEntity):
attrs[ATTR_BATTERY_LEVEL] = self.battery_level
if self.wakeup_interval is not None:
attrs[ATTR_WAKEUP] = self.wakeup_interval
return attrs

View file

@ -1,5 +1,5 @@
"""Test Z-Wave cover devices."""
from unittest.mock import patch
from unittest.mock import MagicMock
from homeassistant.components.cover import zwave, SUPPORT_OPEN, SUPPORT_CLOSE
from homeassistant.components.zwave import const
@ -8,58 +8,66 @@ from tests.mock.zwave import (
MockNode, MockValue, MockEntityValues, value_changed)
def test_get_device_detects_none(mock_openzwave):
def test_get_device_detects_none(hass, mock_openzwave):
"""Test device returns none."""
node = MockNode()
value = MockValue(data=0, node=node)
values = MockEntityValues(primary=value, node=node)
device = zwave.get_device(node=node, values=values, node_config={})
device = zwave.get_device(hass=hass, node=node, values=values,
node_config={})
assert device is None
def test_get_device_detects_rollershutter(mock_openzwave):
def test_get_device_detects_rollershutter(hass, mock_openzwave):
"""Test device returns rollershutter."""
hass.data[zwave.zwave.ZWAVE_NETWORK] = MagicMock()
node = MockNode()
value = MockValue(data=0, node=node,
command_class=const.COMMAND_CLASS_SWITCH_MULTILEVEL)
values = MockEntityValues(primary=value, open=None, close=None, node=node)
device = zwave.get_device(node=node, values=values, node_config={})
device = zwave.get_device(hass=hass, node=node, values=values,
node_config={})
assert isinstance(device, zwave.ZwaveRollershutter)
def test_get_device_detects_garagedoor(mock_openzwave):
def test_get_device_detects_garagedoor(hass, mock_openzwave):
"""Test device returns garage door."""
node = MockNode()
value = MockValue(data=0, node=node,
command_class=const.COMMAND_CLASS_BARRIER_OPERATOR)
values = MockEntityValues(primary=value, node=node)
device = zwave.get_device(node=node, values=values, node_config={})
device = zwave.get_device(hass=hass, node=node, values=values,
node_config={})
assert isinstance(device, zwave.ZwaveGarageDoor)
assert device.device_class == "garage"
assert device.supported_features == SUPPORT_OPEN | SUPPORT_CLOSE
def test_roller_no_position_workaround(mock_openzwave):
def test_roller_no_position_workaround(hass, mock_openzwave):
"""Test position changed."""
hass.data[zwave.zwave.ZWAVE_NETWORK] = MagicMock()
node = MockNode(manufacturer_id='0047', product_type='5a52')
value = MockValue(data=45, node=node,
command_class=const.COMMAND_CLASS_SWITCH_MULTILEVEL)
values = MockEntityValues(primary=value, open=None, close=None, node=node)
device = zwave.get_device(node=node, values=values, node_config={})
device = zwave.get_device(hass=hass, node=node, values=values,
node_config={})
assert device.current_cover_position is None
def test_roller_value_changed(mock_openzwave):
def test_roller_value_changed(hass, mock_openzwave):
"""Test position changed."""
hass.data[zwave.zwave.ZWAVE_NETWORK] = MagicMock()
node = MockNode()
value = MockValue(data=None, node=node,
command_class=const.COMMAND_CLASS_SWITCH_MULTILEVEL)
values = MockEntityValues(primary=value, open=None, close=None, node=node)
device = zwave.get_device(node=node, values=values, node_config={})
device = zwave.get_device(hass=hass, node=node, values=values,
node_config={})
assert device.current_cover_position is None
assert device.is_closed is None
@ -83,9 +91,9 @@ def test_roller_value_changed(mock_openzwave):
assert not device.is_closed
@patch('homeassistant.components.zwave.NETWORK')
def test_roller_commands(mock_network, mock_openzwave):
def test_roller_commands(hass, mock_openzwave):
"""Test position changed."""
mock_network = hass.data[zwave.zwave.ZWAVE_NETWORK] = MagicMock()
node = MockNode()
value = MockValue(data=50, node=node,
command_class=const.COMMAND_CLASS_SWITCH_MULTILEVEL)
@ -93,7 +101,8 @@ def test_roller_commands(mock_network, mock_openzwave):
close_value = MockValue(data=False, node=node)
values = MockEntityValues(primary=value, open=open_value,
close=close_value, node=node)
device = zwave.get_device(node=node, values=values, node_config={})
device = zwave.get_device(hass=hass, node=node, values=values,
node_config={})
device.set_cover_position(25)
assert node.set_dimmer.called
@ -117,9 +126,9 @@ def test_roller_commands(mock_network, mock_openzwave):
assert value_id == open_value.value_id
@patch('homeassistant.components.zwave.NETWORK')
def test_roller_reverse_open_close(mock_network, mock_openzwave):
def test_roller_reverse_open_close(hass, mock_openzwave):
"""Test position changed."""
mock_network = hass.data[zwave.zwave.ZWAVE_NETWORK] = MagicMock()
node = MockNode()
value = MockValue(data=50, node=node,
command_class=const.COMMAND_CLASS_SWITCH_MULTILEVEL)
@ -128,6 +137,7 @@ def test_roller_reverse_open_close(mock_network, mock_openzwave):
values = MockEntityValues(primary=value, open=open_value,
close=close_value, node=node)
device = zwave.get_device(
hass=hass,
node=node,
values=values,
node_config={zwave.zwave.CONF_INVERT_OPENCLOSE_BUTTONS: True})
@ -148,13 +158,14 @@ def test_roller_reverse_open_close(mock_network, mock_openzwave):
assert value_id == close_value.value_id
def test_garage_value_changed(mock_openzwave):
def test_garage_value_changed(hass, mock_openzwave):
"""Test position changed."""
node = MockNode()
value = MockValue(data=False, node=node,
command_class=const.COMMAND_CLASS_BARRIER_OPERATOR)
values = MockEntityValues(primary=value, node=node)
device = zwave.get_device(node=node, values=values, node_config={})
device = zwave.get_device(hass=hass, node=node, values=values,
node_config={})
assert device.is_closed
@ -164,13 +175,14 @@ def test_garage_value_changed(mock_openzwave):
assert not device.is_closed
def test_garage_commands(mock_openzwave):
def test_garage_commands(hass, mock_openzwave):
"""Test position changed."""
node = MockNode()
value = MockValue(data=False, node=node,
command_class=const.COMMAND_CLASS_BARRIER_OPERATOR)
values = MockEntityValues(primary=value, node=node)
device = zwave.get_device(node=node, values=values, node_config={})
device = zwave.get_device(hass=hass, node=node, values=values,
node_config={})
assert value.data is False
device.open_cover()

View file

@ -171,6 +171,7 @@ def test_lock_alarm_level(mock_openzwave):
@asyncio.coroutine
def test_lock_set_usercode_service(hass, mock_openzwave):
"""Test the zwave lock set_usercode service."""
mock_network = hass.data[zwave.zwave.ZWAVE_NETWORK] = MagicMock()
node = MockNode(node_id=12)
value0 = MockValue(data=None, node=node, index=0)
value1 = MockValue(data=None, node=node, index=1)
@ -182,7 +183,6 @@ def test_lock_set_usercode_service(hass, mock_openzwave):
value1.value_id: value1,
}
with patch.object(zwave.zwave, 'NETWORK') as mock_network:
mock_network.nodes = {
node.node_id: node
}
@ -196,7 +196,6 @@ def test_lock_set_usercode_service(hass, mock_openzwave):
assert value1.data == '1234'
with patch.object(zwave.zwave, 'NETWORK') as mock_network:
mock_network.nodes = {
node.node_id: node
}
@ -214,6 +213,7 @@ def test_lock_set_usercode_service(hass, mock_openzwave):
@asyncio.coroutine
def test_lock_get_usercode_service(hass, mock_openzwave):
"""Test the zwave lock get_usercode service."""
mock_network = hass.data[zwave.zwave.ZWAVE_NETWORK] = MagicMock()
node = MockNode(node_id=12)
value0 = MockValue(data=None, node=node, index=0)
value1 = MockValue(data='1234', node=node, index=1)
@ -225,18 +225,14 @@ def test_lock_get_usercode_service(hass, mock_openzwave):
value1.value_id: value1,
}
with patch.object(zwave.zwave, 'NETWORK') as mock_network:
with patch.object(zwave, '_LOGGER') as mock_logger:
mock_network.nodes = {
node.node_id: node
}
mock_network.nodes = {node.node_id: node}
yield from hass.services.async_call(
zwave.DOMAIN, zwave.SERVICE_GET_USERCODE, {
const.ATTR_NODE_ID: node.node_id,
zwave.ATTR_CODE_SLOT: 1,
})
yield from hass.async_block_till_done()
# This service only seems to write to the log
assert mock_logger.info.called
assert len(mock_logger.info.mock_calls) == 1
@ -246,6 +242,7 @@ def test_lock_get_usercode_service(hass, mock_openzwave):
@asyncio.coroutine
def test_lock_clear_usercode_service(hass, mock_openzwave):
"""Test the zwave lock clear_usercode service."""
mock_network = hass.data[zwave.zwave.ZWAVE_NETWORK] = MagicMock()
node = MockNode(node_id=12)
value0 = MockValue(data=None, node=node, index=0)
value1 = MockValue(data='123', node=node, index=1)
@ -257,7 +254,6 @@ def test_lock_clear_usercode_service(hass, mock_openzwave):
value1.value_id: value1,
}
with patch.object(zwave.zwave, 'NETWORK') as mock_network:
mock_network.nodes = {
node.node_id: node
}

View file

@ -7,7 +7,7 @@ from homeassistant.const import ATTR_ENTITY_ID, EVENT_HOMEASSISTANT_START
from homeassistant.components import zwave
from homeassistant.components.binary_sensor.zwave import get_device
from homeassistant.components.zwave import (
const, CONFIG_SCHEMA, CONF_DEVICE_CONFIG_GLOB)
const, CONFIG_SCHEMA, CONF_DEVICE_CONFIG_GLOB, ZWAVE_NETWORK)
from homeassistant.setup import setup_component
import pytest
@ -70,10 +70,10 @@ def test_config_access_error():
@asyncio.coroutine
@patch.object(zwave, 'NETWORK')
def test_setup_platform(mock_network, hass, mock_openzwave):
def test_setup_platform(hass, mock_openzwave):
"""Test invalid device config."""
mock_device = MagicMock()
hass.data[ZWAVE_NETWORK] = MagicMock()
hass.data[zwave.DATA_ZWAVE_DICT] = {456: mock_device}
async_add_devices = MagicMock()
@ -104,7 +104,7 @@ def test_zwave_ready_wait(hass, mock_openzwave):
with patch.object(zwave.time, 'sleep') as mock_sleep:
with patch.object(zwave, '_LOGGER') as mock_logger:
zwave.NETWORK.state = MockNetwork.STATE_STARTED
hass.data[ZWAVE_NETWORK].state = MockNetwork.STATE_STARTED
hass.bus.async_fire(EVENT_HOMEASSISTANT_START)
yield from hass.async_block_till_done()
@ -473,12 +473,15 @@ class TestZWaveServices(unittest.TestCase):
# Initialize zwave
setup_component(self.hass, 'zwave', {'zwave': {}})
self.hass.block_till_done()
zwave.NETWORK.state = MockNetwork.STATE_READY
self.zwave_network = self.hass.data[ZWAVE_NETWORK]
self.zwave_network.state = MockNetwork.STATE_READY
self.hass.bus.fire(EVENT_HOMEASSISTANT_START)
self.hass.block_till_done()
def tearDown(self): # pylint: disable=invalid-name
"""Stop everything that was started."""
self.hass.services.call('zwave', 'stop_network', {})
self.hass.block_till_done()
self.hass.stop()
def test_add_node(self):
@ -486,58 +489,62 @@ class TestZWaveServices(unittest.TestCase):
self.hass.services.call('zwave', 'add_node', {})
self.hass.block_till_done()
assert zwave.NETWORK.controller.add_node.called
assert len(zwave.NETWORK.controller.add_node.mock_calls) == 1
assert len(zwave.NETWORK.controller.add_node.mock_calls[0][1]) == 0
assert self.zwave_network.controller.add_node.called
assert len(self.zwave_network.controller
.add_node.mock_calls) == 1
assert len(self.zwave_network.controller
.add_node.mock_calls[0][1]) == 0
def test_add_node_secure(self):
"""Test zwave add_node_secure service."""
self.hass.services.call('zwave', 'add_node_secure', {})
self.hass.block_till_done()
assert zwave.NETWORK.controller.add_node.called
assert len(zwave.NETWORK.controller.add_node.mock_calls) == 1
assert zwave.NETWORK.controller.add_node.mock_calls[0][1][0] is True
assert self.zwave_network.controller.add_node.called
assert len(self.zwave_network.controller.add_node.mock_calls) == 1
assert (self.zwave_network.controller
.add_node.mock_calls[0][1][0] is True)
def test_remove_node(self):
"""Test zwave remove_node service."""
self.hass.services.call('zwave', 'remove_node', {})
self.hass.block_till_done()
assert zwave.NETWORK.controller.remove_node.called
assert len(zwave.NETWORK.controller.remove_node.mock_calls) == 1
assert self.zwave_network.controller.remove_node.called
assert len(self.zwave_network.controller.remove_node.mock_calls) == 1
def test_cancel_command(self):
"""Test zwave cancel_command service."""
self.hass.services.call('zwave', 'cancel_command', {})
self.hass.block_till_done()
assert zwave.NETWORK.controller.cancel_command.called
assert len(zwave.NETWORK.controller.cancel_command.mock_calls) == 1
assert self.zwave_network.controller.cancel_command.called
assert len(self.zwave_network.controller
.cancel_command.mock_calls) == 1
def test_heal_network(self):
"""Test zwave heal_network service."""
self.hass.services.call('zwave', 'heal_network', {})
self.hass.block_till_done()
assert zwave.NETWORK.heal.called
assert len(zwave.NETWORK.heal.mock_calls) == 1
assert self.zwave_network.heal.called
assert len(self.zwave_network.heal.mock_calls) == 1
def test_soft_reset(self):
"""Test zwave soft_reset service."""
self.hass.services.call('zwave', 'soft_reset', {})
self.hass.block_till_done()
assert zwave.NETWORK.controller.soft_reset.called
assert len(zwave.NETWORK.controller.soft_reset.mock_calls) == 1
assert self.zwave_network.controller.soft_reset.called
assert len(self.zwave_network.controller.soft_reset.mock_calls) == 1
def test_test_network(self):
"""Test zwave test_network service."""
self.hass.services.call('zwave', 'test_network', {})
self.hass.block_till_done()
assert zwave.NETWORK.test.called
assert len(zwave.NETWORK.test.mock_calls) == 1
assert self.zwave_network.test.called
assert len(self.zwave_network.test.mock_calls) == 1
def test_stop_network(self):
"""Test zwave stop_network service."""
@ -545,22 +552,22 @@ class TestZWaveServices(unittest.TestCase):
self.hass.services.call('zwave', 'stop_network', {})
self.hass.block_till_done()
assert zwave.NETWORK.stop.called
assert len(zwave.NETWORK.stop.mock_calls) == 1
assert self.zwave_network.stop.called
assert len(self.zwave_network.stop.mock_calls) == 1
assert mock_fire.called
assert len(mock_fire.mock_calls) == 2
assert mock_fire.mock_calls[0][1][0] == const.EVENT_NETWORK_STOP
def test_rename_node(self):
"""Test zwave rename_node service."""
zwave.NETWORK.nodes = {11: MagicMock()}
self.zwave_network.nodes = {11: MagicMock()}
self.hass.services.call('zwave', 'rename_node', {
const.ATTR_NODE_ID: 11,
const.ATTR_NAME: 'test_name',
})
self.hass.block_till_done()
assert zwave.NETWORK.nodes[11].name == 'test_name'
assert self.zwave_network.nodes[11].name == 'test_name'
def test_remove_failed_node(self):
"""Test zwave remove_failed_node service."""
@ -569,7 +576,7 @@ class TestZWaveServices(unittest.TestCase):
})
self.hass.block_till_done()
remove_failed_node = zwave.NETWORK.controller.remove_failed_node
remove_failed_node = self.zwave_network.controller.remove_failed_node
assert remove_failed_node.called
assert len(remove_failed_node.mock_calls) == 1
assert remove_failed_node.mock_calls[0][1][0] == 12
@ -581,7 +588,7 @@ class TestZWaveServices(unittest.TestCase):
})
self.hass.block_till_done()
replace_failed_node = zwave.NETWORK.controller.replace_failed_node
replace_failed_node = self.zwave_network.controller.replace_failed_node
assert replace_failed_node.called
assert len(replace_failed_node.mock_calls) == 1
assert replace_failed_node.mock_calls[0][1][0] == 13
@ -600,7 +607,7 @@ class TestZWaveServices(unittest.TestCase):
)
node = MockNode(node_id=14)
node.get_values.return_value = {12: value, 13: value_list}
zwave.NETWORK.nodes = {14: node}
self.zwave_network.nodes = {14: node}
self.hass.services.call('zwave', 'set_config_parameter', {
const.ATTR_NODE_ID: 14,
@ -655,7 +662,7 @@ class TestZWaveServices(unittest.TestCase):
)
node = MockNode(node_id=14)
node.values = {12: value1, 13: value2}
zwave.NETWORK.nodes = {14: node}
self.zwave_network.nodes = {14: node}
with patch.object(zwave, '_LOGGER') as mock_logger:
self.hass.services.call('zwave', 'print_config_parameter', {
@ -674,7 +681,7 @@ class TestZWaveServices(unittest.TestCase):
"""Test zwave print_config_parameter service."""
node1 = MockNode(node_id=14)
node2 = MockNode(node_id=15)
zwave.NETWORK.nodes = {14: node1, 15: node2}
self.zwave_network.nodes = {14: node1, 15: node2}
with patch.object(zwave, 'pprint') as mock_pprint:
self.hass.services.call('zwave', 'print_node', {
@ -695,7 +702,7 @@ class TestZWaveServices(unittest.TestCase):
node = MockNode(node_id=14)
node.values = {12: value}
node.get_values.return_value = node.values
zwave.NETWORK.nodes = {14: node}
self.zwave_network.nodes = {14: node}
self.hass.services.call('zwave', 'set_wakeup', {
const.ATTR_NODE_ID: 14,
@ -727,7 +734,7 @@ class TestZWaveServices(unittest.TestCase):
node = MockNode(node_id=14)
node.values = {12: value}
node.get_values.return_value = node.values
zwave.NETWORK.nodes = {14: node}
self.zwave_network.nodes = {14: node}
self.hass.services.call('zwave', 'change_association', {
const.ATTR_ASSOCIATION: 'add',
@ -760,7 +767,7 @@ class TestZWaveServices(unittest.TestCase):
node = MockNode(node_id=14)
node.values = {12: value}
node.get_values.return_value = node.values
zwave.NETWORK.nodes = {14: node}
self.zwave_network.nodes = {14: node}
self.hass.services.call('zwave', 'change_association', {
const.ATTR_ASSOCIATION: 'remove',
@ -808,7 +815,7 @@ class TestZWaveServices(unittest.TestCase):
def test_refresh_node(self):
"""Test zwave refresh_node service."""
node = MockNode(node_id=14)
zwave.NETWORK.nodes = {14: node}
self.zwave_network.nodes = {14: node}
self.hass.services.call('zwave', 'refresh_node', {
const.ATTR_NODE_ID: 14,
})

View file

@ -1,7 +1,7 @@
"""Test Z-Wave node entity."""
import asyncio
import unittest
from unittest.mock import patch
from unittest.mock import patch, MagicMock
import tests.mock.zwave as mock_zwave
import pytest
from homeassistant.components.zwave import node_entity
@ -36,11 +36,13 @@ class TestZWaveNodeEntity(unittest.TestCase):
def setUp(self):
"""Initialize values for this testcase class."""
self.zwave_network = MagicMock()
self.node = mock_zwave.MockNode(
query_stage='Dynamic', is_awake=True, is_ready=False,
is_failed=False, is_info_received=True, max_baud_rate=40000,
is_zwave_plus=False, capabilities=[], neighbors=[], location=None)
self.entity = node_entity.ZWaveNodeEntity(self.node)
self.entity = node_entity.ZWaveNodeEntity(self.node,
self.zwave_network)
def test_network_node_changed_from_value(self):
"""Test for network_node_changed."""
@ -76,14 +78,61 @@ class TestZWaveNodeEntity(unittest.TestCase):
def test_node_changed(self):
"""Test node_changed function."""
self.maxDiff = None
self.assertEqual({'node_id': self.node.node_id},
self.entity.device_state_attributes)
self.node.get_values.return_value = {
1: mock_zwave.MockValue(data=1800)
}
self.zwave_network.manager.getNodeStatistics.return_value = {
"receivedCnt": 4, "ccData": [{"receivedCnt": 0,
"commandClassId": 134,
"sentCnt": 0},
{"receivedCnt": 1,
"commandClassId": 133,
"sentCnt": 1},
{"receivedCnt": 1,
"commandClassId": 115,
"sentCnt": 1},
{"receivedCnt": 0,
"commandClassId": 114,
"sentCnt": 0},
{"receivedCnt": 0,
"commandClassId": 112,
"sentCnt": 0},
{"receivedCnt": 1,
"commandClassId": 32,
"sentCnt": 1},
{"receivedCnt": 0,
"commandClassId": 0,
"sentCnt": 0}],
"receivedUnsolicited": 0,
"sentTS": "2017-03-27 15:38:15:620 ", "averageRequestRTT": 2462,
"lastResponseRTT": 3679, "retries": 0, "sentFailed": 1,
"sentCnt": 7, "quality": 0, "lastRequestRTT": 1591,
"lastReceivedMessage": [0, 4, 0, 15, 3, 32, 3, 0, 221, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0], "receivedDups": 1,
"averageResponseRTT": 2443,
"receivedTS": "2017-03-27 15:38:19:298 "}
self.entity.node_changed()
self.assertEqual(
{'node_id': self.node.node_id,
'query_stage': 'Dynamic',
@ -94,7 +143,19 @@ class TestZWaveNodeEntity(unittest.TestCase):
'max_baud_rate': 40000,
'is_zwave_plus': False,
'battery_level': 42,
'wake_up_interval': 1800},
'wake_up_interval': 1800,
'averageRequestRTT': 2462,
'averageResponseRTT': 2443,
'lastRequestRTT': 1591,
'lastResponseRTT': 3679,
'receivedCnt': 4,
'receivedDups': 1,
'receivedTS': '2017-03-27 15:38:19:298 ',
'receivedUnsolicited': 0,
'retries': 0,
'sentCnt': 7,
'sentFailed': 1,
'sentTS': '2017-03-27 15:38:15:620 '},
self.entity.device_state_attributes)
self.node.can_wake_up_value = False