Add service descriptions

This commit is contained in:
Paulus Schoutsen 2015-09-26 23:17:04 -07:00
parent 9a6b2c1831
commit 4e3bd5f2a9
20 changed files with 180 additions and 49 deletions

View file

@ -4,12 +4,15 @@ homeassistant.components.alarm_control_panel
Component to interface with a alarm control panel. Component to interface with a alarm control panel.
""" """
import logging import logging
from homeassistant.helpers.entity import Entity import os
from homeassistant.helpers.entity_component import EntityComponent
from homeassistant.components import verisure from homeassistant.components import verisure
from homeassistant.const import ( from homeassistant.const import (
ATTR_ENTITY_ID, ATTR_ENTITY_ID,
SERVICE_ALARM_DISARM, SERVICE_ALARM_ARM_HOME, SERVICE_ALARM_ARM_AWAY) SERVICE_ALARM_DISARM, SERVICE_ALARM_ARM_HOME, SERVICE_ALARM_ARM_AWAY)
from homeassistant.config import load_yaml_config_file
from homeassistant.helpers.entity import Entity
from homeassistant.helpers.entity_component import EntityComponent
DOMAIN = 'alarm_control_panel' DOMAIN = 'alarm_control_panel'
DEPENDENCIES = [] DEPENDENCIES = []
@ -59,8 +62,12 @@ def setup(hass, config):
for alarm in target_alarms: for alarm in target_alarms:
getattr(alarm, method)(code) getattr(alarm, method)(code)
descriptions = load_yaml_config_file(
os.path.join(os.path.dirname(__file__), 'services.yaml'))
for service in SERVICE_TO_METHOD: for service in SERVICE_TO_METHOD:
hass.services.register(DOMAIN, service, alarm_service_handler) hass.services.register(DOMAIN, service, alarm_service_handler,
descriptions.get(service))
return True return True

View file

@ -60,7 +60,7 @@ def setup(hass, config):
{'camera': { {'camera': {
'platform': 'generic', 'platform': 'generic',
'name': 'IP Camera', 'name': 'IP Camera',
'still_image_url': 'http://194.218.96.92/jpg/image.jpg', 'still_image_url': 'http://home-assistant.io/demo/webcam.jpg',
}}) }})
# Setup scripts # Setup scripts

View file

@ -175,7 +175,10 @@ def setup(hass, config):
ATTR_GPS, ATTR_GPS_ACCURACY, ATTR_BATTERY)} ATTR_GPS, ATTR_GPS_ACCURACY, ATTR_BATTERY)}
tracker.see(**args) tracker.see(**args)
hass.services.register(DOMAIN, SERVICE_SEE, see_service) descriptions = load_yaml_config_file(
os.path.join(os.path.dirname(__file__), 'services.yaml'))
hass.services.register(DOMAIN, SERVICE_SEE, see_service,
descriptions.get(SERVICE_SEE))
return True return True

View file

@ -1,2 +1,2 @@
""" DO NOT MODIFY. Auto-generated by build_frontend script """ """ DO NOT MODIFY. Auto-generated by build_frontend script """
VERSION = "5ba745608f6271b781fc41c1e8f8deb0" VERSION = "1dae3a2fb4ea4ff853d0d0c647f0ac51"

File diff suppressed because one or more lines are too long

@ -1 +1 @@
Subproject commit 78cf25f605724ae84d8e23d0e7ab97845f53725a Subproject commit 72bceff0fcfe7ba440cc1676ec0fe77ac0f6e200

View file

@ -52,14 +52,14 @@ import logging
import os import os
import csv import csv
from homeassistant.helpers.entity_component import EntityComponent from homeassistant.components import group, discovery, wink, isy994
from homeassistant.helpers.entity import ToggleEntity from homeassistant.config import load_yaml_config_file
import homeassistant.util as util
import homeassistant.util.color as color_util
from homeassistant.const import ( from homeassistant.const import (
STATE_ON, SERVICE_TURN_ON, SERVICE_TURN_OFF, ATTR_ENTITY_ID) STATE_ON, SERVICE_TURN_ON, SERVICE_TURN_OFF, ATTR_ENTITY_ID)
from homeassistant.components import group, discovery, wink, isy994 from homeassistant.helpers.entity import ToggleEntity
from homeassistant.helpers.entity_component import EntityComponent
import homeassistant.util as util
import homeassistant.util.color as color_util
DOMAIN = "light" DOMAIN = "light"
@ -275,11 +275,13 @@ def setup(hass, config):
light.update_ha_state(True) light.update_ha_state(True)
# Listen for light on and light off service calls # Listen for light on and light off service calls
hass.services.register(DOMAIN, SERVICE_TURN_ON, descriptions = load_yaml_config_file(
handle_light_service) os.path.join(os.path.dirname(__file__), 'services.yaml'))
hass.services.register(DOMAIN, SERVICE_TURN_ON, handle_light_service,
descriptions.get(SERVICE_TURN_ON))
hass.services.register(DOMAIN, SERVICE_TURN_OFF, hass.services.register(DOMAIN, SERVICE_TURN_OFF, handle_light_service,
handle_light_service) descriptions.get(SERVICE_TURN_OFF))
return True return True

View file

@ -0,0 +1,52 @@
# Describes the format for available light services
turn_on:
description: Turn a light on
fields:
entity_id:
description: Name(s) of entities to turn on
example: 'light.kitchen'
transition:
description: Duration in seconds it takes to get to next state
example: 60
rgb_color:
description: Color for the light in RGB-format
example: '[255, 100, 100]'
xy_color:
description: Color for the light in XY-format
example: '[0.52, 0.43]'
brightness:
description: Number between 0..255 indicating brightness
example: 120
profile:
description: Name of a light profile to use
example: relax
flash:
description: If the light should flash
values:
- short
- long
effect:
description: Light effect
values:
- colorloop
turn_off:
description: Turn a light off
fields:
entity_id:
description: Name(s) of entities to turn off
example: 'light.kitchen'
transition:
description: Duration in seconds it takes to get to next state
example: 60

View file

@ -5,8 +5,10 @@ homeassistant.components.media_player
Component to interface with various media players. Component to interface with various media players.
""" """
import logging import logging
import os
from homeassistant.components import discovery from homeassistant.components import discovery
from homeassistant.config import load_yaml_config_file
from homeassistant.helpers.entity import Entity from homeassistant.helpers.entity import Entity
from homeassistant.helpers.entity_component import EntityComponent from homeassistant.helpers.entity_component import EntityComponent
from homeassistant.const import ( from homeassistant.const import (
@ -186,6 +188,9 @@ def setup(hass, config):
component.setup(config) component.setup(config)
descriptions = load_yaml_config_file(
os.path.join(os.path.dirname(__file__), 'services.yaml'))
def media_player_service_handler(service): def media_player_service_handler(service):
""" Maps services to methods on MediaPlayerDevice. """ """ Maps services to methods on MediaPlayerDevice. """
target_players = component.extract_from_service(service) target_players = component.extract_from_service(service)
@ -199,7 +204,8 @@ def setup(hass, config):
player.update_ha_state(True) player.update_ha_state(True)
for service in SERVICE_TO_METHOD: for service in SERVICE_TO_METHOD:
hass.services.register(DOMAIN, service, media_player_service_handler) hass.services.register(DOMAIN, service, media_player_service_handler,
descriptions.get(service))
def volume_set_service(service): def volume_set_service(service):
""" Set specified volume on the media player. """ """ Set specified volume on the media player. """
@ -216,7 +222,8 @@ def setup(hass, config):
if player.should_poll: if player.should_poll:
player.update_ha_state(True) player.update_ha_state(True)
hass.services.register(DOMAIN, SERVICE_VOLUME_SET, volume_set_service) hass.services.register(DOMAIN, SERVICE_VOLUME_SET, volume_set_service,
descriptions.get(SERVICE_VOLUME_SET))
def volume_mute_service(service): def volume_mute_service(service):
""" Mute (true) or unmute (false) the media player. """ """ Mute (true) or unmute (false) the media player. """
@ -233,7 +240,8 @@ def setup(hass, config):
if player.should_poll: if player.should_poll:
player.update_ha_state(True) player.update_ha_state(True)
hass.services.register(DOMAIN, SERVICE_VOLUME_MUTE, volume_mute_service) hass.services.register(DOMAIN, SERVICE_VOLUME_MUTE, volume_mute_service,
descriptions.get(SERVICE_VOLUME_MUTE))
def media_seek_service(service): def media_seek_service(service):
""" Seek to a position. """ """ Seek to a position. """
@ -250,7 +258,8 @@ def setup(hass, config):
if player.should_poll: if player.should_poll:
player.update_ha_state(True) player.update_ha_state(True)
hass.services.register(DOMAIN, SERVICE_MEDIA_SEEK, media_seek_service) hass.services.register(DOMAIN, SERVICE_MEDIA_SEEK, media_seek_service,
descriptions.get(SERVICE_MEDIA_SEEK))
def play_youtube_video_service(service, media_id=None): def play_youtube_video_service(service, media_id=None):
""" Plays specified media_id on the media player. """ """ Plays specified media_id on the media player. """
@ -268,14 +277,17 @@ def setup(hass, config):
hass.services.register( hass.services.register(
DOMAIN, "start_fireplace", DOMAIN, "start_fireplace",
lambda service: play_youtube_video_service(service, "eyU3bRy2x44")) lambda service: play_youtube_video_service(service, "eyU3bRy2x44"),
descriptions.get('start_fireplace'))
hass.services.register( hass.services.register(
DOMAIN, "start_epic_sax", DOMAIN, "start_epic_sax",
lambda service: play_youtube_video_service(service, "kxopViU98Xo")) lambda service: play_youtube_video_service(service, "kxopViU98Xo"),
descriptions.get('start_epic_sax'))
hass.services.register( hass.services.register(
DOMAIN, SERVICE_YOUTUBE_VIDEO, play_youtube_video_service) DOMAIN, SERVICE_YOUTUBE_VIDEO, play_youtube_video_service,
descriptions.get(SERVICE_YOUTUBE_VIDEO))
return True return True

View file

@ -6,7 +6,9 @@ Provides functionality to notify people.
""" """
from functools import partial from functools import partial
import logging import logging
import os
from homeassistant.config import load_yaml_config_file
from homeassistant.loader import get_component from homeassistant.loader import get_component
from homeassistant.helpers import config_per_platform from homeassistant.helpers import config_per_platform
@ -36,6 +38,9 @@ def setup(hass, config):
""" Sets up notify services. """ """ Sets up notify services. """
success = False success = False
descriptions = load_yaml_config_file(
os.path.join(os.path.dirname(__file__), 'services.yaml'))
for platform, p_config in config_per_platform(config, DOMAIN, _LOGGER): for platform, p_config in config_per_platform(config, DOMAIN, _LOGGER):
# get platform # get platform
notify_implementation = get_component( notify_implementation = get_component(
@ -69,7 +74,8 @@ def setup(hass, config):
# register service # register service
service_call_handler = partial(notify_message, notify_service) service_call_handler = partial(notify_message, notify_service)
service_notify = p_config.get(CONF_NAME, SERVICE_NOTIFY) service_notify = p_config.get(CONF_NAME, SERVICE_NOTIFY)
hass.services.register(DOMAIN, service_notify, service_call_handler) hass.services.register(DOMAIN, service_notify, service_call_handler,
descriptions.get(service_notify))
success = True success = True
return success return success

View file

@ -3,9 +3,11 @@ homeassistant.components.switch
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Component to interface with various switches that can be controlled remotely. Component to interface with various switches that can be controlled remotely.
""" """
import logging
from datetime import timedelta from datetime import timedelta
import logging
import os
from homeassistant.config import load_yaml_config_file
from homeassistant.helpers.entity_component import EntityComponent from homeassistant.helpers.entity_component import EntityComponent
from homeassistant.helpers.entity import ToggleEntity from homeassistant.helpers.entity import ToggleEntity
@ -83,8 +85,12 @@ def setup(hass, config):
if switch.should_poll: if switch.should_poll:
switch.update_ha_state(True) switch.update_ha_state(True)
hass.services.register(DOMAIN, SERVICE_TURN_OFF, handle_switch_service) descriptions = load_yaml_config_file(
hass.services.register(DOMAIN, SERVICE_TURN_ON, handle_switch_service) os.path.join(os.path.dirname(__file__), 'services.yaml'))
hass.services.register(DOMAIN, SERVICE_TURN_OFF, handle_switch_service,
descriptions.get(SERVICE_TURN_OFF))
hass.services.register(DOMAIN, SERVICE_TURN_ON, handle_switch_service,
descriptions.get(SERVICE_TURN_ON))
return True return True

View file

@ -5,9 +5,11 @@ homeassistant.components.thermostat
Provides functionality to interact with thermostats. Provides functionality to interact with thermostats.
""" """
import logging import logging
import os
from homeassistant.helpers.entity_component import EntityComponent from homeassistant.helpers.entity_component import EntityComponent
from homeassistant.config import load_yaml_config_file
import homeassistant.util as util import homeassistant.util as util
from homeassistant.helpers.entity import Entity from homeassistant.helpers.entity import Entity
from homeassistant.helpers.temperature import convert from homeassistant.helpers.temperature import convert
@ -101,11 +103,16 @@ def setup(hass, config):
for thermostat in target_thermostats: for thermostat in target_thermostats:
thermostat.update_ha_state(True) thermostat.update_ha_state(True)
hass.services.register( descriptions = load_yaml_config_file(
DOMAIN, SERVICE_SET_AWAY_MODE, thermostat_service) os.path.join(os.path.dirname(__file__), 'services.yaml'))
hass.services.register( hass.services.register(
DOMAIN, SERVICE_SET_TEMPERATURE, thermostat_service) DOMAIN, SERVICE_SET_AWAY_MODE, thermostat_service,
descriptions.get(SERVICE_SET_AWAY_MODE))
hass.services.register(
DOMAIN, SERVICE_SET_TEMPERATURE, thermostat_service,
descriptions.get(SERVICE_SET_TEMPERATURE))
return True return True

View file

@ -525,6 +525,28 @@ class StateMachine(object):
from_state, to_state) from_state, to_state)
# pylint: disable=too-few-public-methods
class Service(object):
""" Represents a service. """
__slots__ = ['func', 'description', 'fields']
def __init__(self, func, description, fields):
self.func = func
self.description = description or ''
self.fields = fields or {}
def as_dict(self):
""" Return dictionary representation of this service. """
return {
'description': self.description,
'fields': self.fields,
}
def __call__(self, call):
self.func(call)
# pylint: disable=too-few-public-methods # pylint: disable=too-few-public-methods
class ServiceCall(object): class ServiceCall(object):
""" Represents a call to a service. """ """ Represents a call to a service. """
@ -559,20 +581,29 @@ class ServiceRegistry(object):
def services(self): def services(self):
""" Dict with per domain a list of available services. """ """ Dict with per domain a list of available services. """
with self._lock: with self._lock:
return {domain: list(self._services[domain].keys()) return {domain: {key: value.as_dict() for key, value
in self._services[domain].items()}
for domain in self._services} for domain in self._services}
def has_service(self, domain, service): def has_service(self, domain, service):
""" Returns True if specified service exists. """ """ Returns True if specified service exists. """
return service in self._services.get(domain, []) return service in self._services.get(domain, [])
def register(self, domain, service, service_func): def register(self, domain, service, service_func, description=None):
""" Register a service. """ """
Register a service.
Description is a dict containing key 'description' to describe
the service and a key 'fields' to describe the fields.
"""
description = description or {}
service_obj = Service(service_func, description.get('description'),
description.get('fields', {}))
with self._lock: with self._lock:
if domain in self._services: if domain in self._services:
self._services[domain][service] = service_func self._services[domain][service] = service_obj
else: else:
self._services[domain] = {service: service_func} self._services[domain] = {service: service_obj}
self._bus.fire( self._bus.fire(
EVENT_SERVICE_REGISTERED, EVENT_SERVICE_REGISTERED,

View file

@ -441,7 +441,7 @@ class TestServiceRegistry(unittest.TestCase):
def test_services(self): def test_services(self):
expected = { expected = {
'test_domain': ['test_service'] 'test_domain': {'test_service': {'description': '', 'fields': {}}}
} }
self.assertEqual(expected, self.services.services) self.assertEqual(expected, self.services.services)