Entity registry (#11979)

* Entity#unique_id defaults to None

* Initial commit entity registry

* Clean up unique_id property

* Lint

* Add tests to entity component

* Lint

* Restore some unique ids

* Spelling

* Remove use of IP address for unique ID

* Add tests

* Add tests

* Fix tests

* Add some docs

* Add one more test

* Fix new test…
This commit is contained in:
Paulus Schoutsen 2018-01-30 01:39:39 -08:00 committed by Pascal Vizeli
parent 8e441ba03b
commit e51427b284
47 changed files with 471 additions and 230 deletions

View file

@ -8,10 +8,9 @@ from homeassistant.setup import async_prepare_setup_platform
from homeassistant.const import (
ATTR_ENTITY_ID, CONF_SCAN_INTERVAL, CONF_ENTITY_NAMESPACE,
DEVICE_DEFAULT_NAME)
from homeassistant.core import callback, valid_entity_id
from homeassistant.core import callback, valid_entity_id, split_entity_id
from homeassistant.exceptions import HomeAssistantError, PlatformNotReady
from homeassistant.helpers import config_per_platform, discovery
from homeassistant.helpers.entity import async_generate_entity_id
from homeassistant.helpers.event import (
async_track_time_interval, async_track_point_in_time)
from homeassistant.helpers.service import extract_entity_ids
@ -19,11 +18,13 @@ from homeassistant.util import slugify
from homeassistant.util.async import (
run_callback_threadsafe, run_coroutine_threadsafe)
import homeassistant.util.dt as dt_util
from .entity_registry import EntityRegistry
DEFAULT_SCAN_INTERVAL = timedelta(seconds=15)
SLOW_SETUP_WARNING = 10
SLOW_SETUP_MAX_WAIT = 60
PLATFORM_NOT_READY_RETRIES = 10
DATA_REGISTRY = 'entity_registry'
class EntityComponent(object):
@ -357,12 +358,20 @@ class EntityPlatform(object):
if not new_entities:
return
hass = self.component.hass
component_entities = set(entity.entity_id for entity
in self.component.entities)
registry = hass.data.get(DATA_REGISTRY)
if registry is None:
registry = hass.data[DATA_REGISTRY] = EntityRegistry(hass)
yield from registry.async_ensure_loaded()
tasks = [
self._async_add_entity(entity, update_before_add,
component_entities)
component_entities, registry)
for entity in new_entities]
yield from asyncio.wait(tasks, loop=self.component.hass.loop)
@ -378,15 +387,12 @@ class EntityPlatform(object):
)
@asyncio.coroutine
def _async_add_entity(self, entity, update_before_add, component_entities):
def _async_add_entity(self, entity, update_before_add, component_entities,
registry):
"""Helper method to add an entity to the platform."""
if entity is None:
raise ValueError('Entity cannot be None')
# Do nothing if entity has already been added based on unique id.
if entity in self.component.entities:
return
entity.hass = self.component.hass
entity.platform = self
entity.parallel_updates = self.parallel_updates
@ -400,17 +406,39 @@ class EntityPlatform(object):
"%s: Error on device update!", self.platform)
return
# Write entity_id to entity
if getattr(entity, 'entity_id', None) is None:
object_id = entity.name or DEVICE_DEFAULT_NAME
suggested_object_id = None
# Get entity_id from unique ID registration
if entity.unique_id is not None:
if entity.entity_id is not None:
suggested_object_id = split_entity_id(entity.entity_id)[1]
else:
suggested_object_id = entity.name
entry = registry.async_get_or_create(
self.component.domain, self.platform, entity.unique_id,
suggested_object_id=suggested_object_id)
entity.entity_id = entry.entity_id
# We won't generate an entity ID if the platform has already set one
# We will however make sure that platform cannot pick a registered ID
elif (entity.entity_id is not None and
registry.async_is_registered(entity.entity_id)):
# If entity already registered, convert entity id to suggestion
suggested_object_id = split_entity_id(entity.entity_id)[1]
entity.entity_id = None
# Generate entity ID
if entity.entity_id is None:
suggested_object_id = \
suggested_object_id or entity.name or DEVICE_DEFAULT_NAME
if self.entity_namespace is not None:
object_id = '{} {}'.format(self.entity_namespace,
object_id)
suggested_object_id = '{} {}'.format(self.entity_namespace,
suggested_object_id)
entity.entity_id = async_generate_entity_id(
self.component.entity_id_format, object_id,
component_entities)
entity.entity_id = registry.async_generate_entity_id(
self.component.domain, suggested_object_id)
# Make sure it is valid in case an entity set the value themselves
if not valid_entity_id(entity.entity_id):