Look at registry before pulling zwave config values (#14408)

* Look at registry before deciding on ID for zwave values

* Reuse the new function
pull/14431/head
Andrey 2018-05-13 00:45:36 +03:00 committed by Paulus Schoutsen
parent 7aec098a05
commit d1228d5cf4
5 changed files with 87 additions and 18 deletions

View File

@ -16,10 +16,11 @@ 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.helpers.entity_registry import async_get_registry
from homeassistant.const import (
ATTR_ENTITY_ID, EVENT_HOMEASSISTANT_START, EVENT_HOMEASSISTANT_STOP)
from homeassistant.helpers.entity_values import EntityValues
from homeassistant.helpers.event import track_time_change
from homeassistant.helpers.event import async_track_time_change
from homeassistant.util import convert
import homeassistant.util.dt as dt_util
import homeassistant.helpers.config_validation as cv
@ -218,7 +219,7 @@ async def async_setup_platform(hass, config, async_add_devices,
# pylint: disable=R0914
def setup(hass, config):
async def async_setup(hass, config):
"""Set up Z-Wave.
Will automatically load components to support devices found on the network.
@ -286,7 +287,7 @@ def setup(hass, config):
continue
values = ZWaveDeviceEntityValues(
hass, schema, value, config, device_config)
hass, schema, value, config, device_config, registry)
# We create a new list and update the reference here so that
# the list can be safely iterated over in the main thread
@ -294,6 +295,7 @@ def setup(hass, config):
hass.data[DATA_ENTITY_VALUES] = new_values
component = EntityComponent(_LOGGER, DOMAIN, hass)
registry = await async_get_registry(hass)
def node_added(node):
"""Handle a new node on the network."""
@ -702,9 +704,9 @@ def setup(hass, config):
# Setup autoheal
if autoheal:
_LOGGER.info("Z-Wave network autoheal is enabled")
track_time_change(hass, heal_network, hour=0, minute=0, second=0)
async_track_time_change(hass, heal_network, hour=0, minute=0, second=0)
hass.bus.listen_once(EVENT_HOMEASSISTANT_START, start_zwave)
hass.bus.async_listen_once(EVENT_HOMEASSISTANT_START, start_zwave)
return True
@ -713,7 +715,7 @@ class ZWaveDeviceEntityValues():
"""Manages entity access to the underlying zwave value objects."""
def __init__(self, hass, schema, primary_value, zwave_config,
device_config):
device_config, registry):
"""Initialize the values object with the passed entity schema."""
self._hass = hass
self._zwave_config = zwave_config
@ -722,6 +724,7 @@ class ZWaveDeviceEntityValues():
self._values = {}
self._entity = None
self._workaround_ignore = False
self._registry = registry
for name in self._schema[const.DISC_VALUES].keys():
self._values[name] = None
@ -794,9 +797,13 @@ class ZWaveDeviceEntityValues():
workaround_component, component)
component = workaround_component
value_name = _value_name(self.primary)
generated_id = generate_entity_id(component + '.{}', value_name, [])
node_config = self._device_config.get(generated_id)
entity_id = self._registry.async_get_entity_id(
component, DOMAIN,
compute_value_unique_id(self._node, self.primary))
if entity_id is None:
value_name = _value_name(self.primary)
entity_id = generate_entity_id(component + '.{}', value_name, [])
node_config = self._device_config.get(entity_id)
# Configure node
_LOGGER.debug("Adding Node_id=%s Generic_command_class=%s, "
@ -809,7 +816,7 @@ class ZWaveDeviceEntityValues():
if node_config.get(CONF_IGNORED):
_LOGGER.info(
"Ignoring entity %s due to device settings", generated_id)
"Ignoring entity %s due to device settings", entity_id)
# No entity will be created for this value
self._workaround_ignore = True
return
@ -964,6 +971,10 @@ class ZWaveDeviceEntity(ZWaveBaseEntity):
if (is_node_parsed(self.node) and
self.values.primary.label != "Unknown") or \
self.node.is_ready:
return "{}-{}".format(self.node.node_id,
self.values.primary.object_id)
return compute_value_unique_id(self.node, self.values.primary)
return None
def compute_value_unique_id(node, value):
"""Compute unique_id a value would get if it were to get one."""
return "{}-{}".format(node.node_id, value.object_id)

View File

@ -83,6 +83,15 @@ class EntityRegistry:
"""Check if an entity_id is currently registered."""
return entity_id in self.entities
@callback
def async_get_entity_id(self, domain: str, platform: str, unique_id: str):
"""Check if an entity_id is currently registered."""
for entity in self.entities.values():
if entity.domain == domain and entity.platform == platform and \
entity.unique_id == unique_id:
return entity.entity_id
return None
@callback
def async_generate_entity_id(self, domain, suggested_object_id):
"""Generate an entity ID that does not conflict.
@ -99,10 +108,9 @@ class EntityRegistry:
def async_get_or_create(self, domain, platform, unique_id, *,
suggested_object_id=None):
"""Get entity. Create if it doesn't exist."""
for entity in self.entities.values():
if entity.domain == domain and entity.platform == platform and \
entity.unique_id == unique_id:
return entity
entity_id = self.async_get_entity_id(domain, platform, unique_id)
if entity_id:
return self.entities[entity_id]
entity_id = self.async_generate_entity_id(
domain, suggested_object_id or '{}_{}'.format(platform, unique_id))

View File

@ -13,6 +13,7 @@ from homeassistant.components.binary_sensor.zwave import get_device
from homeassistant.components.zwave import (
const, CONFIG_SCHEMA, CONF_DEVICE_CONFIG_GLOB, DATA_NETWORK)
from homeassistant.setup import setup_component
from tests.common import mock_registry
import pytest
@ -468,6 +469,7 @@ class TestZWaveDeviceEntityValues(unittest.TestCase):
"""Initialize values for this testcase class."""
self.hass = get_test_home_assistant()
self.hass.start()
self.registry = mock_registry(self.hass)
setup_component(self.hass, 'zwave', {'zwave': {}})
self.hass.block_till_done()
@ -487,7 +489,7 @@ class TestZWaveDeviceEntityValues(unittest.TestCase):
const.DISC_OPTIONAL: True,
}}}
self.primary = MockValue(
command_class='mock_primary_class', node=self.node)
command_class='mock_primary_class', node=self.node, value_id=1000)
self.secondary = MockValue(
command_class='mock_secondary_class', node=self.node)
self.duplicate_secondary = MockValue(
@ -521,6 +523,7 @@ class TestZWaveDeviceEntityValues(unittest.TestCase):
primary_value=self.primary,
zwave_config=self.zwave_config,
device_config=self.device_config,
registry=self.registry
)
assert values.primary is self.primary
@ -592,6 +595,7 @@ class TestZWaveDeviceEntityValues(unittest.TestCase):
primary_value=self.primary,
zwave_config=self.zwave_config,
device_config=self.device_config,
registry=self.registry
)
self.hass.block_till_done()
@ -630,6 +634,7 @@ class TestZWaveDeviceEntityValues(unittest.TestCase):
primary_value=self.primary,
zwave_config=self.zwave_config,
device_config=self.device_config,
registry=self.registry
)
values._check_entity_ready()
self.hass.block_till_done()
@ -639,7 +644,7 @@ class TestZWaveDeviceEntityValues(unittest.TestCase):
@patch.object(zwave, 'get_platform')
@patch.object(zwave, 'discovery')
def test_entity_workaround_component(self, discovery, get_platform):
"""Test ignore workaround."""
"""Test component workaround."""
discovery.async_load_platform.return_value = mock_coro()
mock_platform = MagicMock()
get_platform.return_value = mock_platform
@ -666,6 +671,7 @@ class TestZWaveDeviceEntityValues(unittest.TestCase):
primary_value=self.primary,
zwave_config=self.zwave_config,
device_config=self.device_config,
registry=self.registry
)
values._check_entity_ready()
self.hass.block_till_done()
@ -697,6 +703,7 @@ class TestZWaveDeviceEntityValues(unittest.TestCase):
primary_value=self.primary,
zwave_config=self.zwave_config,
device_config=self.device_config,
registry=self.registry
)
values._check_entity_ready()
self.hass.block_till_done()
@ -720,12 +727,42 @@ class TestZWaveDeviceEntityValues(unittest.TestCase):
primary_value=self.primary,
zwave_config=self.zwave_config,
device_config=self.device_config,
registry=self.registry
)
values._check_entity_ready()
self.hass.block_till_done()
assert not discovery.async_load_platform.called
@patch.object(zwave, 'get_platform')
@patch.object(zwave, 'discovery')
def test_entity_config_ignore_with_registry(self, discovery, get_platform):
"""Test ignore config.
The case when the device is in entity registry.
"""
self.node.values = {
self.primary.value_id: self.primary,
self.secondary.value_id: self.secondary,
}
self.device_config = {'mock_component.registry_id': {
zwave.CONF_IGNORED: True
}}
self.registry.async_get_or_create(
'mock_component', zwave.DOMAIN, '567-1000',
suggested_object_id='registry_id')
zwave.ZWaveDeviceEntityValues(
hass=self.hass,
schema=self.mock_schema,
primary_value=self.primary,
zwave_config=self.zwave_config,
device_config=self.device_config,
registry=self.registry
)
self.hass.block_till_done()
assert not discovery.async_load_platform.called
@patch.object(zwave, 'get_platform')
@patch.object(zwave, 'discovery')
def test_entity_platform_ignore(self, discovery, get_platform):
@ -743,6 +780,7 @@ class TestZWaveDeviceEntityValues(unittest.TestCase):
primary_value=self.primary,
zwave_config=self.zwave_config,
device_config=self.device_config,
registry=self.registry
)
self.hass.block_till_done()
@ -770,6 +808,7 @@ class TestZWaveDeviceEntityValues(unittest.TestCase):
primary_value=self.primary,
zwave_config=self.zwave_config,
device_config=self.device_config,
registry=self.registry
)
values._check_entity_ready()
self.hass.block_till_done()

View File

@ -180,3 +180,13 @@ test.disabled_hass:
assert entry_disabled_hass.disabled_by == entity_registry.DISABLED_HASS
assert entry_disabled_user.disabled
assert entry_disabled_user.disabled_by == entity_registry.DISABLED_USER
@asyncio.coroutine
def test_async_get_entity_id(registry):
"""Test that entity_id is returned."""
entry = registry.async_get_or_create('light', 'hue', '1234')
assert entry.entity_id == 'light.hue_1234'
assert registry.async_get_entity_id(
'light', 'hue', '1234') == 'light.hue_1234'
assert registry.async_get_entity_id('light', 'hue', '123') is None

View File

@ -178,6 +178,7 @@ class MockValue(MagicMock):
MockValue._mock_value_id += 1
value_id = MockValue._mock_value_id
self.value_id = value_id
self.object_id = value_id
for attr_name in kwargs:
setattr(self, attr_name, kwargs[attr_name])