2013-12-11 00:07:30 -08:00
|
|
|
"""
|
|
|
|
homeassistant.components
|
|
|
|
~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
|
|
|
This package contains components that can be plugged into Home Assistant.
|
2014-01-04 18:24:30 -08:00
|
|
|
|
|
|
|
Component design guidelines:
|
|
|
|
|
|
|
|
Each component defines a constant DOMAIN that is equal to its filename.
|
|
|
|
|
2014-01-19 23:37:40 -08:00
|
|
|
Each component that tracks states should create state entity names in the
|
2014-01-04 18:24:30 -08:00
|
|
|
format "<DOMAIN>.<OBJECT_ID>".
|
|
|
|
|
|
|
|
Each component should publish services only under its own domain.
|
|
|
|
|
2013-12-11 00:07:30 -08:00
|
|
|
"""
|
2014-04-13 12:59:45 -07:00
|
|
|
import itertools as it
|
2014-08-13 14:28:45 +02:00
|
|
|
import logging
|
2014-01-23 23:26:00 -08:00
|
|
|
|
|
|
|
import homeassistant as ha
|
|
|
|
import homeassistant.util as util
|
2014-11-04 23:34:19 -08:00
|
|
|
from homeassistant.loader import get_component
|
2014-01-23 23:26:00 -08:00
|
|
|
|
2014-04-13 12:59:45 -07:00
|
|
|
# Contains one string or a list of strings, each being an entity id
|
2014-01-23 23:26:00 -08:00
|
|
|
ATTR_ENTITY_ID = 'entity_id'
|
2014-03-24 20:34:35 -07:00
|
|
|
|
|
|
|
# String with a friendly name for the entity
|
2014-03-23 12:03:34 -07:00
|
|
|
ATTR_FRIENDLY_NAME = "friendly_name"
|
2014-01-23 23:26:00 -08:00
|
|
|
|
2014-11-02 11:22:22 -08:00
|
|
|
# A picture to represent entity
|
|
|
|
ATTR_ENTITY_PICTURE = "entity_picture"
|
|
|
|
|
2014-11-08 17:45:09 -08:00
|
|
|
# The unit of measurement if applicable
|
|
|
|
ATTR_UNIT_OF_MEASUREMENT = "unit_of_measurement"
|
|
|
|
|
2014-01-23 23:26:00 -08:00
|
|
|
STATE_ON = 'on'
|
|
|
|
STATE_OFF = 'off'
|
|
|
|
STATE_HOME = 'home'
|
2014-04-24 00:40:45 -07:00
|
|
|
STATE_NOT_HOME = 'not_home'
|
2014-01-23 23:26:00 -08:00
|
|
|
|
|
|
|
SERVICE_TURN_ON = 'turn_on'
|
|
|
|
SERVICE_TURN_OFF = 'turn_off'
|
|
|
|
|
2014-03-11 22:45:05 -07:00
|
|
|
SERVICE_VOLUME_UP = "volume_up"
|
|
|
|
SERVICE_VOLUME_DOWN = "volume_down"
|
|
|
|
SERVICE_VOLUME_MUTE = "volume_mute"
|
|
|
|
SERVICE_MEDIA_PLAY_PAUSE = "media_play_pause"
|
2014-04-24 00:40:45 -07:00
|
|
|
SERVICE_MEDIA_PLAY = "media_play"
|
|
|
|
SERVICE_MEDIA_PAUSE = "media_pause"
|
2014-03-11 22:45:05 -07:00
|
|
|
SERVICE_MEDIA_NEXT_TRACK = "media_next_track"
|
|
|
|
SERVICE_MEDIA_PREV_TRACK = "media_prev_track"
|
|
|
|
|
2014-11-08 13:57:08 -08:00
|
|
|
_LOGGER = logging.getLogger(__name__)
|
2014-08-13 14:28:45 +02:00
|
|
|
|
2014-01-23 23:26:00 -08:00
|
|
|
|
2014-04-24 00:40:45 -07:00
|
|
|
def is_on(hass, entity_id=None):
|
2014-01-23 23:26:00 -08:00
|
|
|
""" Loads up the module to call the is_on method.
|
|
|
|
If there is no entity id given we will check all. """
|
2014-04-13 12:59:45 -07:00
|
|
|
if entity_id:
|
2014-11-04 23:34:19 -08:00
|
|
|
group = get_component('group')
|
2014-04-13 12:59:45 -07:00
|
|
|
|
|
|
|
entity_ids = group.expand_entity_ids([entity_id])
|
|
|
|
else:
|
2014-04-24 00:40:45 -07:00
|
|
|
entity_ids = hass.states.entity_ids
|
2014-01-23 23:26:00 -08:00
|
|
|
|
|
|
|
for entity_id in entity_ids:
|
|
|
|
domain = util.split_entity_id(entity_id)[0]
|
|
|
|
|
2014-11-04 23:34:19 -08:00
|
|
|
module = get_component(domain)
|
2014-01-23 23:53:18 -08:00
|
|
|
|
2014-01-23 23:26:00 -08:00
|
|
|
try:
|
2014-04-24 00:40:45 -07:00
|
|
|
if module.is_on(hass, entity_id):
|
2014-01-23 23:26:00 -08:00
|
|
|
return True
|
|
|
|
|
|
|
|
except AttributeError:
|
2014-01-23 23:53:18 -08:00
|
|
|
# module is None or method is_on does not exist
|
2014-11-08 13:57:08 -08:00
|
|
|
_LOGGER.exception("Failed to call %s.is_on for %s",
|
|
|
|
module, entity_id)
|
2014-01-23 23:26:00 -08:00
|
|
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
2014-04-24 00:40:45 -07:00
|
|
|
def turn_on(hass, **service_data):
|
2014-01-23 23:26:00 -08:00
|
|
|
""" Turns specified entity on if possible. """
|
2014-04-24 00:40:45 -07:00
|
|
|
hass.call_service(ha.DOMAIN, SERVICE_TURN_ON, service_data)
|
2014-01-23 23:26:00 -08:00
|
|
|
|
|
|
|
|
2014-04-24 00:40:45 -07:00
|
|
|
def turn_off(hass, **service_data):
|
2014-01-23 23:26:00 -08:00
|
|
|
""" Turns specified entity off. """
|
2014-04-24 00:40:45 -07:00
|
|
|
hass.call_service(ha.DOMAIN, SERVICE_TURN_OFF, service_data)
|
2014-01-23 23:26:00 -08:00
|
|
|
|
|
|
|
|
2014-04-24 00:40:45 -07:00
|
|
|
def extract_entity_ids(hass, service):
|
2014-03-24 20:34:35 -07:00
|
|
|
"""
|
|
|
|
Helper method to extract a list of entity ids from a service call.
|
|
|
|
Will convert group entity ids to the entity ids it represents.
|
|
|
|
"""
|
|
|
|
entity_ids = []
|
|
|
|
|
|
|
|
if service.data and ATTR_ENTITY_ID in service.data:
|
2014-08-13 14:28:45 +02:00
|
|
|
group = get_component('group')
|
2014-03-24 20:34:35 -07:00
|
|
|
|
|
|
|
# Entity ID attr can be a list or a string
|
|
|
|
service_ent_id = service.data[ATTR_ENTITY_ID]
|
|
|
|
if isinstance(service_ent_id, list):
|
|
|
|
ent_ids = service_ent_id
|
|
|
|
else:
|
|
|
|
ent_ids = [service_ent_id]
|
|
|
|
|
2014-04-13 12:59:45 -07:00
|
|
|
entity_ids.extend(
|
|
|
|
ent_id for ent_id
|
2014-04-24 00:40:45 -07:00
|
|
|
in group.expand_entity_ids(hass, ent_ids)
|
2014-04-13 12:59:45 -07:00
|
|
|
if ent_id not in entity_ids)
|
2014-03-24 20:34:35 -07:00
|
|
|
|
2014-04-13 12:59:45 -07:00
|
|
|
return entity_ids
|
2014-03-24 20:34:35 -07:00
|
|
|
|
|
|
|
|
2014-11-09 15:12:23 -08:00
|
|
|
class ToggleDevice(object):
|
|
|
|
""" ABC for devices that can be turned on and off. """
|
|
|
|
# pylint: disable=no-self-use
|
|
|
|
|
|
|
|
entity_id = None
|
|
|
|
|
|
|
|
def get_name(self):
|
|
|
|
""" Returns the name of the device if any. """
|
|
|
|
return None
|
|
|
|
|
|
|
|
def turn_on(self, **kwargs):
|
|
|
|
""" Turn the device on. """
|
|
|
|
pass
|
|
|
|
|
|
|
|
def turn_off(self, **kwargs):
|
|
|
|
""" Turn the device off. """
|
|
|
|
pass
|
|
|
|
|
|
|
|
def is_on(self):
|
|
|
|
""" True if device is on. """
|
|
|
|
return False
|
|
|
|
|
|
|
|
def get_state_attributes(self):
|
|
|
|
""" Returns optional state attributes. """
|
|
|
|
return None
|
|
|
|
|
|
|
|
def update(self):
|
|
|
|
""" Retrieve latest state from the real device. """
|
|
|
|
pass
|
|
|
|
|
|
|
|
def update_ha_state(self, hass, force_refresh=False):
|
|
|
|
"""
|
|
|
|
Updates Home Assistant with current state of device.
|
|
|
|
If force_refresh == True will update device before setting state.
|
|
|
|
"""
|
|
|
|
if self.entity_id is None:
|
|
|
|
raise ha.NoEntitySpecifiedError(
|
|
|
|
"No entity specified for device {}".format(self.get_name()))
|
|
|
|
|
|
|
|
if force_refresh:
|
|
|
|
self.update()
|
|
|
|
|
|
|
|
state = STATE_ON if self.is_on() else STATE_OFF
|
|
|
|
|
|
|
|
return hass.states.set(self.entity_id, state,
|
|
|
|
self.get_state_attributes())
|
|
|
|
|
|
|
|
|
2014-08-13 14:28:45 +02:00
|
|
|
# pylint: disable=unused-argument
|
|
|
|
def setup(hass, config):
|
2014-04-13 12:59:45 -07:00
|
|
|
""" Setup general services related to homeassistant. """
|
2014-03-24 20:34:35 -07:00
|
|
|
|
2014-04-13 12:59:45 -07:00
|
|
|
def handle_turn_service(service):
|
|
|
|
""" Method to handle calls to homeassistant.turn_on/off. """
|
2014-03-24 20:34:35 -07:00
|
|
|
|
2014-04-24 00:40:45 -07:00
|
|
|
entity_ids = extract_entity_ids(hass, service)
|
2014-03-24 20:34:35 -07:00
|
|
|
|
2014-04-13 12:59:45 -07:00
|
|
|
# Generic turn on/off method requires entity id
|
|
|
|
if not entity_ids:
|
2014-11-08 13:57:08 -08:00
|
|
|
_LOGGER.error(
|
|
|
|
"homeassistant/%s cannot be called without entity_id",
|
|
|
|
service.service)
|
2014-04-13 12:59:45 -07:00
|
|
|
return
|
2014-01-23 23:26:00 -08:00
|
|
|
|
2014-04-13 12:59:45 -07:00
|
|
|
# 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)
|
|
|
|
|
2014-04-24 00:40:45 -07:00
|
|
|
hass.call_service(domain, service.service, data)
|
2014-01-23 23:26:00 -08:00
|
|
|
|
2014-04-24 00:40:45 -07:00
|
|
|
hass.services.register(ha.DOMAIN, SERVICE_TURN_OFF, handle_turn_service)
|
|
|
|
hass.services.register(ha.DOMAIN, SERVICE_TURN_ON, handle_turn_service)
|
2014-01-23 23:26:00 -08:00
|
|
|
|
|
|
|
return True
|