From 8fdf2d608afa36b4c4436c652a8b123056d44348 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 13 Apr 2014 12:59:45 -0700 Subject: [PATCH] Cleanup of core services --- homeassistant/bootstrap.py | 2 +- homeassistant/components/__init__.py | 96 +++++++++---------- homeassistant/components/chromecast.py | 7 ++ .../components/device_sun_light_trigger.py | 7 +- homeassistant/components/group.py | 58 ++++++----- 5 files changed, 82 insertions(+), 88 deletions(-) diff --git a/homeassistant/bootstrap.py b/homeassistant/bootstrap.py index c0a8a902f26..7aee8aa0add 100644 --- a/homeassistant/bootstrap.py +++ b/homeassistant/bootstrap.py @@ -152,7 +152,7 @@ def from_config_file(config_path): add_status("Downloader", downloader.setup( bus, get_opt("downloader", "download_dir"))) - add_status("Core components", components.setup(bus)) + add_status("Core components", components.setup(bus, statemachine)) if has_section('browser'): add_status("Browser", load_module('browser').setup(bus)) diff --git a/homeassistant/components/__init__.py b/homeassistant/components/__init__.py index e3dd0efefc8..7fa4b5d1299 100644 --- a/homeassistant/components/__init__.py +++ b/homeassistant/components/__init__.py @@ -14,13 +14,13 @@ format ".". Each component should publish services only under its own domain. """ - +import itertools as it import importlib import homeassistant as ha import homeassistant.util as util -# String that contains an entity id or a comma seperated list of entity ids +# Contains one string or a list of strings, each being an entity id ATTR_ENTITY_ID = 'entity_id' # String with a friendly name for the entity @@ -69,7 +69,12 @@ def _get_component(component): def is_on(statemachine, entity_id=None): """ Loads up the module to call the is_on method. If there is no entity id given we will check all. """ - entity_ids = [entity_id] if entity_id else statemachine.entity_ids + if entity_id: + group = _get_component('group') + + entity_ids = group.expand_entity_ids([entity_id]) + else: + entity_ids = statemachine.entity_ids for entity_id in entity_ids: domain = util.split_entity_id(entity_id)[0] @@ -87,34 +92,14 @@ def is_on(statemachine, entity_id=None): return False -def turn_on(bus, entity_id=None): +def turn_on(bus, **service_data): """ Turns specified entity on if possible. """ - # If there is no entity_id we do not know which domain to call. - if not entity_id: - return - - domain = util.split_entity_id(entity_id)[0] - - try: - bus.call_service(domain, SERVICE_TURN_ON, {ATTR_ENTITY_ID: entity_id}) - except ha.ServiceDoesNotExistError: - # turn_on service does not exist - pass + bus.call_service(ha.DOMAIN, SERVICE_TURN_ON, service_data) -def turn_off(bus, entity_id=None): +def turn_off(bus, **service_data): """ Turns specified entity off. """ - # If there is no entity_id we do not know which domain to call. - if not entity_id: - return - - domain = util.split_entity_id(entity_id)[0] - - try: - bus.call_service(domain, SERVICE_TURN_OFF, {ATTR_ENTITY_ID: entity_id}) - except ha.ServiceDoesNotExistError: - # turn_off service does not exist - pass + bus.call_service(ha.DOMAIN, SERVICE_TURN_OFF, service_data) def extract_entity_ids(statemachine, service): @@ -134,37 +119,44 @@ def extract_entity_ids(statemachine, service): else: ent_ids = [service_ent_id] - for entity_id in ent_ids: - try: - # If entity_id points at a group, expand it - domain, _ = util.split_entity_id(entity_id) - - if domain == group.DOMAIN: - entity_ids.extend( - ent_id for ent_id - in group.get_entity_ids(statemachine, entity_id) - if ent_id not in entity_ids) - - else: - if entity_id not in entity_ids: - entity_ids.append(entity_id) - - except AttributeError: - # Raised by util.split_entity_id if entity_id is not a string - pass + entity_ids.extend( + ent_id for ent_id + in group.expand_entity_ids(statemachine, ent_ids) + if ent_id not in entity_ids) return entity_ids -def setup(bus): +def setup(bus, statemachine): """ Setup general services related to homeassistant. """ - bus.register_service(ha.DOMAIN, SERVICE_TURN_OFF, - lambda service: - turn_off(bus, service.data.get(ATTR_ENTITY_ID))) + def handle_turn_service(service): + """ Method to handle calls to homeassistant.turn_on/off. """ - bus.register_service(ha.DOMAIN, SERVICE_TURN_ON, - lambda service: - turn_on(bus, service.data.get(ATTR_ENTITY_ID))) + entity_ids = extract_entity_ids(statemachine, service) + + # Generic turn on/off method requires entity id + if not entity_ids: + return + + # Group entity_ids by domain. groupby requires sorted data. + by_domain = it.groupby(sorted(entity_ids), + lambda item: util.split_entity_id(item)[0]) + + for domain, ent_ids in by_domain: + # Create a new dict for this call + data = dict(service.data) + + # ent_ids is a generator, convert it to a list. + data[ATTR_ENTITY_ID] = list(ent_ids) + + try: + bus.call_service(domain, service.service, data) + except ha.ServiceDoesNotExistError: + # turn_on service does not exist + pass + + bus.register_service(ha.DOMAIN, SERVICE_TURN_OFF, handle_turn_service) + bus.register_service(ha.DOMAIN, SERVICE_TURN_ON, handle_turn_service) return True diff --git a/homeassistant/components/chromecast.py b/homeassistant/components/chromecast.py index 3cf4f08dd63..abad1919169 100644 --- a/homeassistant/components/chromecast.py +++ b/homeassistant/components/chromecast.py @@ -45,6 +45,13 @@ def is_on(statemachine, entity_id=None): for entity_id in entity_ids) +def turn_off(bus, entity_id=None): + """ Will turn off specified Chromecast or all. """ + data = {components.ATTR_ENTITY_ID: entity_id} if entity_id else {} + + bus.call_service(DOMAIN, components.SERVICE_TURN_OFF, data) + + def volume_up(bus, entity_id=None): """ Send the chromecast the command for volume up. """ data = {components.ATTR_ENTITY_ID: entity_id} if entity_id else {} diff --git a/homeassistant/components/device_sun_light_trigger.py b/homeassistant/components/device_sun_light_trigger.py index cee60279f4c..52b42b5416e 100644 --- a/homeassistant/components/device_sun_light_trigger.py +++ b/homeassistant/components/device_sun_light_trigger.py @@ -117,11 +117,8 @@ def setup(bus, statemachine, "Home coming event for {}. Turning lights on". format(entity)) - # Turn on lights directly instead of calling group.turn_on - # So we skip fetching the entity ids again. - for light_id in light_ids: - light.turn_on(bus, light_id, - profile=light_profile) + light.turn_on(bus, light_ids, + profile=light_profile) # Are we in the time span were we would turn on the lights # if someone would be home? diff --git a/homeassistant/components/group.py b/homeassistant/components/group.py index be467c4b602..9072a60977f 100644 --- a/homeassistant/components/group.py +++ b/homeassistant/components/group.py @@ -8,11 +8,9 @@ Provides functionality to group devices that can be turned on or off. import logging import homeassistant as ha +import homeassistant.util as util from homeassistant.components import (STATE_ON, STATE_OFF, STATE_HOME, STATE_NOT_HOME, - SERVICE_TURN_ON, SERVICE_TURN_OFF, - turn_on as comp_turn_on, - turn_off as comp_turn_off, ATTR_ENTITY_ID) DOMAIN = "group" @@ -50,6 +48,33 @@ def is_on(statemachine, entity_id): return False +def expand_entity_ids(statemachine, entity_ids): + """ Returns the given list of entity ids and expands group ids into + the entity ids it represents if found. """ + found_ids = [] + + for entity_id in entity_ids: + try: + # If entity_id points at a group, expand it + domain, _ = util.split_entity_id(entity_id) + + if domain == DOMAIN: + found_ids.extend( + ent_id for ent_id + in get_entity_ids(statemachine, entity_id) + if ent_id not in found_ids) + + else: + if entity_id not in found_ids: + found_ids.append(entity_id) + + except AttributeError: + # Raised by util.split_entity_id if entity_id is not a string + pass + + return found_ids + + def get_entity_ids(statemachine, entity_id): """ Get the entity ids that make up this group. """ try: @@ -141,33 +166,6 @@ def setup(bus, statemachine, name, entity_ids): for entity_id in entity_ids: ha.track_state_change(bus, entity_id, update_group_state) - # group.setup is called to setup each group. Only the first time will we - # register a turn_on and turn_off method for groups. - - if not bus.has_service(DOMAIN, SERVICE_TURN_ON): - def turn_group_on_service(service): - """ Call components.turn_on for each entity_id from this group. """ - for entity_id in get_entity_ids(statemachine, - service.data.get( - ATTR_ENTITY_ID)): - - comp_turn_on(bus, entity_id) - - bus.register_service(DOMAIN, SERVICE_TURN_ON, - turn_group_on_service) - - if not bus.has_service(DOMAIN, SERVICE_TURN_OFF): - def turn_group_off_service(service): - """ Call components.turn_off for each entity_id in this group. """ - for entity_id in get_entity_ids(statemachine, - service.data.get( - ATTR_ENTITY_ID)): - - comp_turn_off(bus, entity_id) - - bus.register_service(DOMAIN, SERVICE_TURN_OFF, - turn_group_off_service) - statemachine.set_state(group_entity_id, group_state, state_attr) return True