mirror of
https://github.com/home-assistant/core.git
synced 2025-07-20 19:57:07 +00:00
Merge pull request #911 from rmkraus/service-toggle
Added toggle service
This commit is contained in:
commit
027d97321f
@ -20,7 +20,7 @@ import homeassistant.util as util
|
||||
from homeassistant.helpers import extract_entity_ids
|
||||
from homeassistant.loader import get_component
|
||||
from homeassistant.const import (
|
||||
ATTR_ENTITY_ID, SERVICE_TURN_ON, SERVICE_TURN_OFF)
|
||||
ATTR_ENTITY_ID, SERVICE_TURN_ON, SERVICE_TURN_OFF, SERVICE_TOGGLE)
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
@ -68,6 +68,14 @@ def turn_off(hass, entity_id=None, **service_data):
|
||||
hass.services.call(ha.DOMAIN, SERVICE_TURN_OFF, service_data)
|
||||
|
||||
|
||||
def toggle(hass, entity_id=None, **service_data):
|
||||
""" Toggles specified entity. """
|
||||
if entity_id is not None:
|
||||
service_data[ATTR_ENTITY_ID] = entity_id
|
||||
|
||||
hass.services.call(ha.DOMAIN, SERVICE_TOGGLE, service_data)
|
||||
|
||||
|
||||
def setup(hass, config):
|
||||
""" Setup general services related to homeassistant. """
|
||||
|
||||
@ -105,5 +113,6 @@ def setup(hass, config):
|
||||
|
||||
hass.services.register(ha.DOMAIN, SERVICE_TURN_OFF, handle_turn_service)
|
||||
hass.services.register(ha.DOMAIN, SERVICE_TURN_ON, handle_turn_service)
|
||||
hass.services.register(ha.DOMAIN, SERVICE_TOGGLE, handle_turn_service)
|
||||
|
||||
return True
|
||||
|
@ -13,7 +13,8 @@ import csv
|
||||
from homeassistant.components import group, discovery, wink, isy994, zwave
|
||||
from homeassistant.config import load_yaml_config_file
|
||||
from homeassistant.const import (
|
||||
STATE_ON, SERVICE_TURN_ON, SERVICE_TURN_OFF, ATTR_ENTITY_ID)
|
||||
STATE_ON, SERVICE_TURN_ON, SERVICE_TURN_OFF, SERVICE_TOGGLE,
|
||||
ATTR_ENTITY_ID)
|
||||
from homeassistant.helpers.entity import ToggleEntity
|
||||
from homeassistant.helpers.entity_component import EntityComponent
|
||||
import homeassistant.util as util
|
||||
@ -114,6 +115,18 @@ def turn_off(hass, entity_id=None, transition=None):
|
||||
hass.services.call(DOMAIN, SERVICE_TURN_OFF, data)
|
||||
|
||||
|
||||
def toggle(hass, entity_id=None, transition=None):
|
||||
""" Toggles all or specified light. """
|
||||
data = {
|
||||
key: value for key, value in [
|
||||
(ATTR_ENTITY_ID, entity_id),
|
||||
(ATTR_TRANSITION, transition),
|
||||
] if value is not None
|
||||
}
|
||||
|
||||
hass.services.call(DOMAIN, SERVICE_TOGGLE, data)
|
||||
|
||||
|
||||
# pylint: disable=too-many-branches, too-many-locals, too-many-statements
|
||||
def setup(hass, config):
|
||||
""" Exposes light control via statemachine and services. """
|
||||
@ -165,9 +178,15 @@ def setup(hass, config):
|
||||
if transition is not None:
|
||||
params[ATTR_TRANSITION] = transition
|
||||
|
||||
service_fun = None
|
||||
if service.service == SERVICE_TURN_OFF:
|
||||
service_fun = 'turn_off'
|
||||
elif service.service == SERVICE_TOGGLE:
|
||||
service_fun = 'toggle'
|
||||
|
||||
if service_fun:
|
||||
for light in target_lights:
|
||||
light.turn_off(**params)
|
||||
getattr(light, service_fun)(**params)
|
||||
|
||||
for light in target_lights:
|
||||
if light.should_poll:
|
||||
@ -249,6 +268,9 @@ def setup(hass, config):
|
||||
hass.services.register(DOMAIN, SERVICE_TURN_OFF, handle_light_service,
|
||||
descriptions.get(SERVICE_TURN_OFF))
|
||||
|
||||
hass.services.register(DOMAIN, SERVICE_TOGGLE, handle_light_service,
|
||||
descriptions.get(SERVICE_TOGGLE))
|
||||
|
||||
return True
|
||||
|
||||
|
||||
|
@ -55,3 +55,15 @@ turn_off:
|
||||
transition:
|
||||
description: Duration in seconds it takes to get to next state
|
||||
example: 60
|
||||
|
||||
toggle:
|
||||
description: Toggles a light
|
||||
|
||||
fields:
|
||||
entity_id:
|
||||
description: Name(s) of entities to toggle
|
||||
example: 'light.kitchen'
|
||||
|
||||
transition:
|
||||
description: Duration in seconds it takes to get to next state
|
||||
example: 60
|
||||
|
@ -14,10 +14,10 @@ from homeassistant.config import load_yaml_config_file
|
||||
from homeassistant.helpers.entity import Entity
|
||||
from homeassistant.helpers.entity_component import EntityComponent
|
||||
from homeassistant.const import (
|
||||
STATE_OFF, STATE_UNKNOWN, STATE_PLAYING,
|
||||
STATE_OFF, STATE_UNKNOWN, STATE_PLAYING, STATE_IDLE,
|
||||
ATTR_ENTITY_ID, ATTR_ENTITY_PICTURE, SERVICE_TURN_OFF, SERVICE_TURN_ON,
|
||||
SERVICE_VOLUME_UP, SERVICE_VOLUME_DOWN, SERVICE_VOLUME_SET,
|
||||
SERVICE_VOLUME_MUTE,
|
||||
SERVICE_VOLUME_MUTE, SERVICE_TOGGLE,
|
||||
SERVICE_MEDIA_PLAY_PAUSE, SERVICE_MEDIA_PLAY, SERVICE_MEDIA_PAUSE,
|
||||
SERVICE_MEDIA_NEXT_TRACK, SERVICE_MEDIA_PREVIOUS_TRACK, SERVICE_MEDIA_SEEK)
|
||||
|
||||
@ -79,6 +79,7 @@ YOUTUBE_COVER_URL_FORMAT = 'https://img.youtube.com/vi/{}/1.jpg'
|
||||
SERVICE_TO_METHOD = {
|
||||
SERVICE_TURN_ON: 'turn_on',
|
||||
SERVICE_TURN_OFF: 'turn_off',
|
||||
SERVICE_TOGGLE: 'toggle',
|
||||
SERVICE_VOLUME_UP: 'volume_up',
|
||||
SERVICE_VOLUME_DOWN: 'volume_down',
|
||||
SERVICE_MEDIA_PLAY_PAUSE: 'media_play_pause',
|
||||
@ -131,6 +132,12 @@ def turn_off(hass, entity_id=None):
|
||||
hass.services.call(DOMAIN, SERVICE_TURN_OFF, data)
|
||||
|
||||
|
||||
def toggle(hass, entity_id=None):
|
||||
""" Will toggle specified media player or all. """
|
||||
data = {ATTR_ENTITY_ID: entity_id} if entity_id else {}
|
||||
hass.services.call(DOMAIN, SERVICE_TOGGLE, data)
|
||||
|
||||
|
||||
def volume_up(hass, entity_id=None):
|
||||
""" Send the media player the command for volume up. """
|
||||
data = {ATTR_ENTITY_ID: entity_id} if entity_id else {}
|
||||
@ -532,6 +539,13 @@ class MediaPlayerDevice(Entity):
|
||||
""" Boolean if play media command supported. """
|
||||
return bool(self.supported_media_commands & SUPPORT_PLAY_MEDIA)
|
||||
|
||||
def toggle(self):
|
||||
""" Toggles the power on the media player. """
|
||||
if self.state in [STATE_OFF, STATE_IDLE]:
|
||||
self.turn_on()
|
||||
else:
|
||||
self.turn_off()
|
||||
|
||||
def volume_up(self):
|
||||
""" volume_up media player. """
|
||||
if self.volume_level < 1:
|
||||
|
@ -15,7 +15,8 @@ from homeassistant.helpers.entity_component import EntityComponent
|
||||
from homeassistant.helpers.entity import ToggleEntity
|
||||
|
||||
from homeassistant.const import (
|
||||
STATE_ON, SERVICE_TURN_ON, SERVICE_TURN_OFF, ATTR_ENTITY_ID)
|
||||
STATE_ON, SERVICE_TURN_ON, SERVICE_TURN_OFF, SERVICE_TOGGLE,
|
||||
ATTR_ENTITY_ID)
|
||||
from homeassistant.components import (
|
||||
group, discovery, wink, isy994, verisure, zwave, tellduslive, mysensors)
|
||||
|
||||
@ -71,6 +72,12 @@ def turn_off(hass, entity_id=None):
|
||||
hass.services.call(DOMAIN, SERVICE_TURN_OFF, data)
|
||||
|
||||
|
||||
def toggle(hass, entity_id=None):
|
||||
""" Toggle all or specified switch. """
|
||||
data = {ATTR_ENTITY_ID: entity_id} if entity_id else None
|
||||
hass.services.call(DOMAIN, SERVICE_TOGGLE, data)
|
||||
|
||||
|
||||
def setup(hass, config):
|
||||
""" Track states and offer events for switches. """
|
||||
component = EntityComponent(
|
||||
@ -85,6 +92,8 @@ def setup(hass, config):
|
||||
for switch in target_switches:
|
||||
if service.service == SERVICE_TURN_ON:
|
||||
switch.turn_on()
|
||||
elif service.service == SERVICE_TOGGLE:
|
||||
switch.toggle()
|
||||
else:
|
||||
switch.turn_off()
|
||||
|
||||
@ -97,6 +106,8 @@ def setup(hass, config):
|
||||
descriptions.get(SERVICE_TURN_OFF))
|
||||
hass.services.register(DOMAIN, SERVICE_TURN_ON, handle_switch_service,
|
||||
descriptions.get(SERVICE_TURN_ON))
|
||||
hass.services.register(DOMAIN, SERVICE_TOGGLE, handle_switch_service,
|
||||
descriptions.get(SERVICE_TOGGLE))
|
||||
|
||||
return True
|
||||
|
||||
|
@ -126,6 +126,7 @@ SERVICE_HOMEASSISTANT_STOP = "stop"
|
||||
|
||||
SERVICE_TURN_ON = 'turn_on'
|
||||
SERVICE_TURN_OFF = 'turn_off'
|
||||
SERVICE_TOGGLE = 'toggle'
|
||||
|
||||
SERVICE_VOLUME_UP = "volume_up"
|
||||
SERVICE_VOLUME_DOWN = "volume_down"
|
||||
|
@ -175,3 +175,10 @@ class ToggleEntity(Entity):
|
||||
def turn_off(self, **kwargs):
|
||||
""" Turn the entity off. """
|
||||
pass
|
||||
|
||||
def toggle(self, **kwargs):
|
||||
""" Toggle the entity off. """
|
||||
if self.is_on:
|
||||
self.turn_off(**kwargs)
|
||||
else:
|
||||
self.turn_on(**kwargs)
|
||||
|
@ -9,10 +9,9 @@ import unittest
|
||||
import os
|
||||
|
||||
import homeassistant.loader as loader
|
||||
import homeassistant.util.color as color_util
|
||||
from homeassistant.const import (
|
||||
ATTR_ENTITY_ID, STATE_ON, STATE_OFF, CONF_PLATFORM,
|
||||
SERVICE_TURN_ON, SERVICE_TURN_OFF)
|
||||
SERVICE_TURN_ON, SERVICE_TURN_OFF, SERVICE_TOGGLE)
|
||||
import homeassistant.components.light as light
|
||||
|
||||
from tests.common import mock_service, get_test_home_assistant
|
||||
@ -94,6 +93,23 @@ class TestLight(unittest.TestCase):
|
||||
self.assertEqual('entity_id_val', call.data[ATTR_ENTITY_ID])
|
||||
self.assertEqual('transition_val', call.data[light.ATTR_TRANSITION])
|
||||
|
||||
# Test toggle
|
||||
toggle_calls = mock_service(
|
||||
self.hass, light.DOMAIN, SERVICE_TOGGLE)
|
||||
|
||||
light.toggle(
|
||||
self.hass, entity_id='entity_id_val', transition='transition_val')
|
||||
|
||||
self.hass.pool.block_till_done()
|
||||
|
||||
self.assertEqual(1, len(toggle_calls))
|
||||
call = toggle_calls[-1]
|
||||
|
||||
self.assertEqual(light.DOMAIN, call.domain)
|
||||
self.assertEqual(SERVICE_TOGGLE, call.service)
|
||||
self.assertEqual('entity_id_val', call.data[ATTR_ENTITY_ID])
|
||||
self.assertEqual('transition_val', call.data[light.ATTR_TRANSITION])
|
||||
|
||||
def test_services(self):
|
||||
""" Test the provided services. """
|
||||
platform = loader.get_component('light.test')
|
||||
@ -109,7 +125,7 @@ class TestLight(unittest.TestCase):
|
||||
self.assertFalse(light.is_on(self.hass, dev2.entity_id))
|
||||
self.assertFalse(light.is_on(self.hass, dev3.entity_id))
|
||||
|
||||
# Test basic turn_on, turn_off services
|
||||
# Test basic turn_on, turn_off, toggle services
|
||||
light.turn_off(self.hass, entity_id=dev1.entity_id)
|
||||
light.turn_on(self.hass, entity_id=dev2.entity_id)
|
||||
|
||||
@ -136,6 +152,24 @@ class TestLight(unittest.TestCase):
|
||||
self.assertFalse(light.is_on(self.hass, dev2.entity_id))
|
||||
self.assertFalse(light.is_on(self.hass, dev3.entity_id))
|
||||
|
||||
# toggle all lights
|
||||
light.toggle(self.hass)
|
||||
|
||||
self.hass.pool.block_till_done()
|
||||
|
||||
self.assertTrue(light.is_on(self.hass, dev1.entity_id))
|
||||
self.assertTrue(light.is_on(self.hass, dev2.entity_id))
|
||||
self.assertTrue(light.is_on(self.hass, dev3.entity_id))
|
||||
|
||||
# toggle all lights
|
||||
light.toggle(self.hass)
|
||||
|
||||
self.hass.pool.block_till_done()
|
||||
|
||||
self.assertFalse(light.is_on(self.hass, dev1.entity_id))
|
||||
self.assertFalse(light.is_on(self.hass, dev2.entity_id))
|
||||
self.assertFalse(light.is_on(self.hass, dev3.entity_id))
|
||||
|
||||
# Ensure all attributes process correctly
|
||||
light.turn_on(self.hass, dev1.entity_id,
|
||||
transition=10, brightness=20)
|
||||
|
@ -12,7 +12,8 @@ from homeassistant.const import (
|
||||
STATE_OFF,
|
||||
SERVICE_TURN_ON, SERVICE_TURN_OFF, SERVICE_VOLUME_UP, SERVICE_VOLUME_DOWN,
|
||||
SERVICE_MEDIA_PLAY_PAUSE, SERVICE_MEDIA_PLAY, SERVICE_MEDIA_PAUSE,
|
||||
SERVICE_MEDIA_NEXT_TRACK, SERVICE_MEDIA_PREVIOUS_TRACK, ATTR_ENTITY_ID)
|
||||
SERVICE_MEDIA_NEXT_TRACK, SERVICE_MEDIA_PREVIOUS_TRACK, SERVICE_TOGGLE,
|
||||
ATTR_ENTITY_ID)
|
||||
import homeassistant.components.media_player as media_player
|
||||
from tests.common import mock_service
|
||||
|
||||
@ -45,6 +46,7 @@ class TestMediaPlayer(unittest.TestCase):
|
||||
services = {
|
||||
SERVICE_TURN_ON: media_player.turn_on,
|
||||
SERVICE_TURN_OFF: media_player.turn_off,
|
||||
SERVICE_TOGGLE: media_player.toggle,
|
||||
SERVICE_VOLUME_UP: media_player.volume_up,
|
||||
SERVICE_VOLUME_DOWN: media_player.volume_down,
|
||||
SERVICE_MEDIA_PLAY_PAUSE: media_player.media_play_pause,
|
||||
|
@ -10,7 +10,7 @@ from unittest.mock import patch
|
||||
|
||||
import homeassistant.core as ha
|
||||
from homeassistant.const import (
|
||||
STATE_ON, STATE_OFF, SERVICE_TURN_ON, SERVICE_TURN_OFF)
|
||||
STATE_ON, STATE_OFF, SERVICE_TURN_ON, SERVICE_TURN_OFF, SERVICE_TOGGLE)
|
||||
import homeassistant.components as comps
|
||||
|
||||
from tests.common import get_test_home_assistant
|
||||
@ -61,6 +61,18 @@ class TestComponentsCore(unittest.TestCase):
|
||||
|
||||
self.assertEqual(1, len(runs))
|
||||
|
||||
def test_toggle(self):
|
||||
""" Test toggle method. """
|
||||
runs = []
|
||||
self.hass.services.register(
|
||||
'light', SERVICE_TOGGLE, lambda x: runs.append(1))
|
||||
|
||||
comps.toggle(self.hass, 'light.Bowl')
|
||||
|
||||
self.hass.pool.block_till_done()
|
||||
|
||||
self.assertEqual(1, len(runs))
|
||||
|
||||
@patch('homeassistant.core.ServiceRegistry.call')
|
||||
def test_turn_on_to_not_block_for_domains_without_service(self, mock_call):
|
||||
self.hass.services.register('light', SERVICE_TURN_ON, lambda x: x)
|
||||
|
Loading…
x
Reference in New Issue
Block a user