hass-core/homeassistant/helpers/entity_component.py

150 lines
5.2 KiB
Python
Raw Normal View History

2016-01-30 18:55:52 -08:00
"""Provides helpers for components that manage entities."""
2015-11-28 15:55:01 -08:00
from threading import Lock
from homeassistant.bootstrap import prepare_setup_platform
from homeassistant.helpers import config_per_platform
from homeassistant.helpers.entity import generate_entity_id
from homeassistant.helpers.event import track_utc_time_change
from homeassistant.helpers.service import extract_entity_ids
from homeassistant.components import group, discovery
from homeassistant.const import ATTR_ENTITY_ID
DEFAULT_SCAN_INTERVAL = 15
class EntityComponent(object):
2016-01-30 18:55:52 -08:00
"""Helper class that will help a component manage its entities."""
# pylint: disable=too-many-instance-attributes
# pylint: disable=too-many-arguments
def __init__(self, logger, domain, hass,
scan_interval=DEFAULT_SCAN_INTERVAL,
discovery_platforms=None, group_name=None):
2016-01-30 18:55:52 -08:00
"""Initialize an entity component."""
self.logger = logger
self.hass = hass
self.domain = domain
self.entity_id_format = domain + '.{}'
self.scan_interval = scan_interval
self.discovery_platforms = discovery_platforms
self.group_name = group_name
self.entities = {}
self.group = None
self.is_polling = False
2015-05-14 21:36:12 -07:00
self.config = None
2015-11-28 15:55:01 -08:00
self.lock = Lock()
2015-05-14 21:36:12 -07:00
def setup(self, config):
"""
2016-01-30 18:55:52 -08:00
Set up a full entity component.
Loads the platforms from the config and will listen for supported
discovered platforms.
"""
2015-05-14 21:36:12 -07:00
self.config = config
# Look in config for Domain, Domain 2, Domain 3 etc and load them
for p_type, p_config in \
config_per_platform(config, self.domain, self.logger):
2015-05-14 21:36:12 -07:00
self._setup_platform(p_type, p_config)
if self.discovery_platforms:
2016-01-30 18:55:52 -08:00
discovery.listen(
self.hass, self.discovery_platforms.keys(),
lambda service, info:
self._setup_platform(self.discovery_platforms[service], {},
info))
def add_entities(self, new_entities):
"""
2016-01-30 18:55:52 -08:00
Add new entities to this component.
For each entity will see if it already exists. If not, will add it,
set it up and push the first state.
"""
2015-11-28 15:55:01 -08:00
with self.lock:
for entity in new_entities:
if entity is None or entity in self.entities.values():
continue
entity.hass = self.hass
2015-10-28 12:24:33 -07:00
if getattr(entity, 'entity_id', None) is None:
entity.entity_id = generate_entity_id(
self.entity_id_format, entity.name,
self.entities.keys())
self.entities[entity.entity_id] = entity
entity.update_ha_state()
2015-11-28 15:55:01 -08:00
if self.group is None and self.group_name is not None:
self.group = group.Group(self.hass, self.group_name,
user_defined=False)
if self.group is not None:
self.group.update_tracked_entity_ids(self.entities.keys())
2015-11-28 15:55:01 -08:00
if self.is_polling or \
not any(entity.should_poll for entity
in self.entities.values()):
return
2015-11-28 15:55:01 -08:00
self.is_polling = True
track_utc_time_change(
self.hass, self._update_entity_states,
second=range(0, 60, self.scan_interval))
def extract_from_service(self, service):
"""
2016-01-30 18:55:52 -08:00
Extract all known entities from a service call.
Will return all entities if no entities specified in call.
Will return an empty list if entities specified but unknown.
"""
2015-11-28 15:55:01 -08:00
with self.lock:
if ATTR_ENTITY_ID not in service.data:
return list(self.entities.values())
return [self.entities[entity_id] for entity_id
in extract_entity_ids(self.hass, service)
if entity_id in self.entities]
def _update_entity_states(self, now):
2016-01-30 18:55:52 -08:00
"""Update the states of all the polling entities."""
2015-12-22 02:19:55 -08:00
with self.lock:
# We copy the entities because new entities might be detected
# during state update causing deadlocks.
entities = list(entity for entity in self.entities.values()
if entity.should_poll)
self.logger.info("Updating %s entities", self.domain)
2015-12-22 02:19:55 -08:00
for entity in entities:
entity.update_ha_state(True)
2015-05-14 21:36:12 -07:00
def _setup_platform(self, platform_type, platform_config,
discovery_info=None):
2016-01-30 18:55:52 -08:00
"""Setup a platform for this component."""
platform = prepare_setup_platform(
2015-05-14 21:36:12 -07:00
self.hass, self.config, self.domain, platform_type)
if platform is None:
return
try:
platform.setup_platform(
self.hass, platform_config, self.add_entities, discovery_info)
except Exception: # pylint: disable=broad-except
self.logger.exception(
2015-05-11 22:23:38 -07:00
'Error while setting up platform %s', platform_type)
2015-09-09 23:37:15 -07:00
return
platform_name = '{}.{}'.format(self.domain, platform_type)
self.hass.config.components.append(platform_name)