More entity service (#15998)

* Camera use entity service

* Convert climate services

* Convert light

* Convert media player

* Migrate fan
pull/16000/head
Paulus Schoutsen 2018-08-16 14:28:59 +02:00 committed by GitHub
parent e4d41fe313
commit 1ff1639cef
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 252 additions and 442 deletions

View File

@ -189,74 +189,26 @@ async def async_setup(hass, config):
hass.helpers.event.async_track_time_interval( hass.helpers.event.async_track_time_interval(
update_tokens, TOKEN_CHANGE_INTERVAL) update_tokens, TOKEN_CHANGE_INTERVAL)
async def async_handle_camera_service(service): component.async_register_entity_service(
"""Handle calls to the camera services.""" SERVICE_ENABLE_MOTION, CAMERA_SERVICE_SCHEMA,
target_cameras = component.async_extract_from_service(service) 'async_enable_motion_detection'
)
update_tasks = [] component.async_register_entity_service(
for camera in target_cameras: SERVICE_DISABLE_MOTION, CAMERA_SERVICE_SCHEMA,
if service.service == SERVICE_ENABLE_MOTION: 'async_disable_motion_detection'
await camera.async_enable_motion_detection() )
elif service.service == SERVICE_DISABLE_MOTION: component.async_register_entity_service(
await camera.async_disable_motion_detection() SERVICE_TURN_OFF, CAMERA_SERVICE_SCHEMA,
elif service.service == SERVICE_TURN_OFF and \ 'async_turn_off'
camera.supported_features & SUPPORT_ON_OFF: )
await camera.async_turn_off() component.async_register_entity_service(
elif service.service == SERVICE_TURN_ON and \ SERVICE_TURN_ON, CAMERA_SERVICE_SCHEMA,
camera.supported_features & SUPPORT_ON_OFF: 'async_turn_on'
await camera.async_turn_on() )
component.async_register_entity_service(
if not camera.should_poll: SERVICE_SNAPSHOT, CAMERA_SERVICE_SNAPSHOT,
continue async_handle_snapshot_service
update_tasks.append(camera.async_update_ha_state(True)) )
if update_tasks:
await asyncio.wait(update_tasks, loop=hass.loop)
async def async_handle_snapshot_service(service):
"""Handle snapshot services calls."""
target_cameras = component.async_extract_from_service(service)
filename = service.data[ATTR_FILENAME]
filename.hass = hass
for camera in target_cameras:
snapshot_file = filename.async_render(
variables={ATTR_ENTITY_ID: camera})
# check if we allow to access to that file
if not hass.config.is_allowed_path(snapshot_file):
_LOGGER.error(
"Can't write %s, no access to path!", snapshot_file)
continue
image = await camera.async_camera_image()
def _write_image(to_file, image_data):
"""Executor helper to write image."""
with open(to_file, 'wb') as img_file:
img_file.write(image_data)
try:
await hass.async_add_job(
_write_image, snapshot_file, image)
except OSError as err:
_LOGGER.error("Can't write image to file: %s", err)
hass.services.async_register(
DOMAIN, SERVICE_TURN_OFF, async_handle_camera_service,
schema=CAMERA_SERVICE_SCHEMA)
hass.services.async_register(
DOMAIN, SERVICE_TURN_ON, async_handle_camera_service,
schema=CAMERA_SERVICE_SCHEMA)
hass.services.async_register(
DOMAIN, SERVICE_ENABLE_MOTION, async_handle_camera_service,
schema=CAMERA_SERVICE_SCHEMA)
hass.services.async_register(
DOMAIN, SERVICE_DISABLE_MOTION, async_handle_camera_service,
schema=CAMERA_SERVICE_SCHEMA)
hass.services.async_register(
DOMAIN, SERVICE_SNAPSHOT, async_handle_snapshot_service,
schema=CAMERA_SERVICE_SNAPSHOT)
return True return True
@ -553,3 +505,32 @@ def websocket_camera_thumbnail(hass, connection, msg):
msg['id'], 'image_fetch_failed', 'Unable to fetch image')) msg['id'], 'image_fetch_failed', 'Unable to fetch image'))
hass.async_add_job(send_camera_still()) hass.async_add_job(send_camera_still())
async def async_handle_snapshot_service(camera, service):
"""Handle snapshot services calls."""
hass = camera.hass
filename = service.data[ATTR_FILENAME]
filename.hass = hass
snapshot_file = filename.async_render(
variables={ATTR_ENTITY_ID: camera})
# check if we allow to access to that file
if not hass.config.is_allowed_path(snapshot_file):
_LOGGER.error(
"Can't write %s, no access to path!", snapshot_file)
return
image = await camera.async_camera_image()
def _write_image(to_file, image_data):
"""Executor helper to write image."""
with open(to_file, 'wb') as img_file:
img_file.write(image_data)
try:
await hass.async_add_executor_job(
_write_image, snapshot_file, image)
except OSError as err:
_LOGGER.error("Can't write image to file: %s", err)

View File

@ -4,7 +4,6 @@ Provides functionality to interact with climate devices.
For more details about this component, please refer to the documentation at For more details about this component, please refer to the documentation at
https://home-assistant.io/components/climate/ https://home-assistant.io/components/climate/
""" """
import asyncio
from datetime import timedelta from datetime import timedelta
import logging import logging
import functools as ft import functools as ft
@ -250,209 +249,46 @@ async def async_setup(hass, config):
EntityComponent(_LOGGER, DOMAIN, hass, SCAN_INTERVAL) EntityComponent(_LOGGER, DOMAIN, hass, SCAN_INTERVAL)
await component.async_setup(config) await component.async_setup(config)
async def async_away_mode_set_service(service): component.async_register_entity_service(
"""Set away mode on target climate devices.""" SERVICE_SET_AWAY_MODE, SET_AWAY_MODE_SCHEMA,
target_climate = component.async_extract_from_service(service) async_service_away_mode
)
away_mode = service.data.get(ATTR_AWAY_MODE) component.async_register_entity_service(
SERVICE_SET_HOLD_MODE, SET_HOLD_MODE_SCHEMA,
update_tasks = [] 'async_set_hold_mode'
for climate in target_climate: )
if away_mode: component.async_register_entity_service(
await climate.async_turn_away_mode_on() SERVICE_SET_AUX_HEAT, SET_AUX_HEAT_SCHEMA,
else: async_service_aux_heat
await climate.async_turn_away_mode_off() )
component.async_register_entity_service(
if not climate.should_poll: SERVICE_SET_TEMPERATURE, SET_TEMPERATURE_SCHEMA,
continue async_service_temperature_set
update_tasks.append(climate.async_update_ha_state(True)) )
component.async_register_entity_service(
if update_tasks: SERVICE_SET_HUMIDITY, SET_HUMIDITY_SCHEMA,
await asyncio.wait(update_tasks, loop=hass.loop) 'async_set_humidity'
)
hass.services.async_register( component.async_register_entity_service(
DOMAIN, SERVICE_SET_AWAY_MODE, async_away_mode_set_service, SERVICE_SET_FAN_MODE, SET_FAN_MODE_SCHEMA,
schema=SET_AWAY_MODE_SCHEMA) 'async_set_fan_mode'
)
async def async_hold_mode_set_service(service): component.async_register_entity_service(
"""Set hold mode on target climate devices.""" SERVICE_SET_OPERATION_MODE, SET_OPERATION_MODE_SCHEMA,
target_climate = component.async_extract_from_service(service) 'async_set_operation_mode'
)
hold_mode = service.data.get(ATTR_HOLD_MODE) component.async_register_entity_service(
SERVICE_SET_SWING_MODE, SET_SWING_MODE_SCHEMA,
update_tasks = [] 'async_set_swing_mode'
for climate in target_climate: )
await climate.async_set_hold_mode(hold_mode) component.async_register_entity_service(
SERVICE_TURN_OFF, ON_OFF_SERVICE_SCHEMA,
if not climate.should_poll: 'async_turn_off'
continue )
update_tasks.append(climate.async_update_ha_state(True)) component.async_register_entity_service(
SERVICE_TURN_ON, ON_OFF_SERVICE_SCHEMA,
if update_tasks: 'async_turn_on'
await asyncio.wait(update_tasks, loop=hass.loop) )
hass.services.async_register(
DOMAIN, SERVICE_SET_HOLD_MODE, async_hold_mode_set_service,
schema=SET_HOLD_MODE_SCHEMA)
async def async_aux_heat_set_service(service):
"""Set auxiliary heater on target climate devices."""
target_climate = component.async_extract_from_service(service)
aux_heat = service.data.get(ATTR_AUX_HEAT)
update_tasks = []
for climate in target_climate:
if aux_heat:
await climate.async_turn_aux_heat_on()
else:
await climate.async_turn_aux_heat_off()
if not climate.should_poll:
continue
update_tasks.append(climate.async_update_ha_state(True))
if update_tasks:
await asyncio.wait(update_tasks, loop=hass.loop)
hass.services.async_register(
DOMAIN, SERVICE_SET_AUX_HEAT, async_aux_heat_set_service,
schema=SET_AUX_HEAT_SCHEMA)
async def async_temperature_set_service(service):
"""Set temperature on the target climate devices."""
target_climate = component.async_extract_from_service(service)
update_tasks = []
for climate in target_climate:
kwargs = {}
for value, temp in service.data.items():
if value in CONVERTIBLE_ATTRIBUTE:
kwargs[value] = convert_temperature(
temp,
hass.config.units.temperature_unit,
climate.temperature_unit
)
else:
kwargs[value] = temp
await climate.async_set_temperature(**kwargs)
if not climate.should_poll:
continue
update_tasks.append(climate.async_update_ha_state(True))
if update_tasks:
await asyncio.wait(update_tasks, loop=hass.loop)
hass.services.async_register(
DOMAIN, SERVICE_SET_TEMPERATURE, async_temperature_set_service,
schema=SET_TEMPERATURE_SCHEMA)
async def async_humidity_set_service(service):
"""Set humidity on the target climate devices."""
target_climate = component.async_extract_from_service(service)
humidity = service.data.get(ATTR_HUMIDITY)
update_tasks = []
for climate in target_climate:
await climate.async_set_humidity(humidity)
if not climate.should_poll:
continue
update_tasks.append(climate.async_update_ha_state(True))
if update_tasks:
await asyncio.wait(update_tasks, loop=hass.loop)
hass.services.async_register(
DOMAIN, SERVICE_SET_HUMIDITY, async_humidity_set_service,
schema=SET_HUMIDITY_SCHEMA)
async def async_fan_mode_set_service(service):
"""Set fan mode on target climate devices."""
target_climate = component.async_extract_from_service(service)
fan = service.data.get(ATTR_FAN_MODE)
update_tasks = []
for climate in target_climate:
await climate.async_set_fan_mode(fan)
if not climate.should_poll:
continue
update_tasks.append(climate.async_update_ha_state(True))
if update_tasks:
await asyncio.wait(update_tasks, loop=hass.loop)
hass.services.async_register(
DOMAIN, SERVICE_SET_FAN_MODE, async_fan_mode_set_service,
schema=SET_FAN_MODE_SCHEMA)
async def async_operation_set_service(service):
"""Set operating mode on the target climate devices."""
target_climate = component.async_extract_from_service(service)
operation_mode = service.data.get(ATTR_OPERATION_MODE)
update_tasks = []
for climate in target_climate:
await climate.async_set_operation_mode(operation_mode)
if not climate.should_poll:
continue
update_tasks.append(climate.async_update_ha_state(True))
if update_tasks:
await asyncio.wait(update_tasks, loop=hass.loop)
hass.services.async_register(
DOMAIN, SERVICE_SET_OPERATION_MODE, async_operation_set_service,
schema=SET_OPERATION_MODE_SCHEMA)
async def async_swing_set_service(service):
"""Set swing mode on the target climate devices."""
target_climate = component.async_extract_from_service(service)
swing_mode = service.data.get(ATTR_SWING_MODE)
update_tasks = []
for climate in target_climate:
await climate.async_set_swing_mode(swing_mode)
if not climate.should_poll:
continue
update_tasks.append(climate.async_update_ha_state(True))
if update_tasks:
await asyncio.wait(update_tasks, loop=hass.loop)
hass.services.async_register(
DOMAIN, SERVICE_SET_SWING_MODE, async_swing_set_service,
schema=SET_SWING_MODE_SCHEMA)
async def async_on_off_service(service):
"""Handle on/off calls."""
target_climate = component.async_extract_from_service(service)
update_tasks = []
for climate in target_climate:
if service.service == SERVICE_TURN_ON:
await climate.async_turn_on()
elif service.service == SERVICE_TURN_OFF:
await climate.async_turn_off()
if not climate.should_poll:
continue
update_tasks.append(climate.async_update_ha_state(True))
if update_tasks:
await asyncio.wait(update_tasks, loop=hass.loop)
hass.services.async_register(
DOMAIN, SERVICE_TURN_OFF, async_on_off_service,
schema=ON_OFF_SERVICE_SCHEMA)
hass.services.async_register(
DOMAIN, SERVICE_TURN_ON, async_on_off_service,
schema=ON_OFF_SERVICE_SCHEMA)
return True return True
@ -812,3 +648,37 @@ class ClimateDevice(Entity):
def max_humidity(self): def max_humidity(self):
"""Return the maximum humidity.""" """Return the maximum humidity."""
return DEFAULT_MAX_HUMIDITY return DEFAULT_MAX_HUMIDITY
async def async_service_away_mode(entity, service):
"""Handle away mode service."""
if service.data[ATTR_AWAY_MODE]:
await entity.async_turn_away_mode_on()
else:
await entity.async_turn_away_mode_off()
async def async_service_aux_heat(entity, service):
"""Handle aux heat service."""
if service.data[ATTR_AUX_HEAT]:
await entity.async_turn_aux_heat_on()
else:
await entity.async_turn_aux_heat_off()
async def async_service_temperature_set(entity, service):
"""Handle set temperature service."""
hass = entity.hass
kwargs = {}
for value, temp in service.data.items():
if value in CONVERTIBLE_ATTRIBUTE:
kwargs[value] = convert_temperature(
temp,
hass.config.units.temperature_unit,
entity.temperature_unit
)
else:
kwargs[value] = temp
await entity.async_set_temperature(**kwargs)

View File

@ -89,33 +89,6 @@ FAN_SET_DIRECTION_SCHEMA = vol.Schema({
vol.Optional(ATTR_DIRECTION): cv.string vol.Optional(ATTR_DIRECTION): cv.string
}) # type: dict }) # type: dict
SERVICE_TO_METHOD = {
SERVICE_TURN_ON: {
'method': 'async_turn_on',
'schema': FAN_TURN_ON_SCHEMA,
},
SERVICE_TURN_OFF: {
'method': 'async_turn_off',
'schema': FAN_TURN_OFF_SCHEMA,
},
SERVICE_TOGGLE: {
'method': 'async_toggle',
'schema': FAN_TOGGLE_SCHEMA,
},
SERVICE_SET_SPEED: {
'method': 'async_set_speed',
'schema': FAN_SET_SPEED_SCHEMA,
},
SERVICE_OSCILLATE: {
'method': 'async_oscillate',
'schema': FAN_OSCILLATE_SCHEMA,
},
SERVICE_SET_DIRECTION: {
'method': 'async_set_direction',
'schema': FAN_SET_DIRECTION_SCHEMA,
},
}
@bind_hass @bind_hass
def is_on(hass, entity_id: str = None) -> bool: def is_on(hass, entity_id: str = None) -> bool:
@ -204,30 +177,30 @@ def async_setup(hass, config: dict):
yield from component.async_setup(config) yield from component.async_setup(config)
@asyncio.coroutine component.async_register_entity_service(
def async_handle_fan_service(service): SERVICE_TURN_ON, FAN_TURN_ON_SCHEMA,
"""Handle service call for fans.""" 'async_turn_on'
method = SERVICE_TO_METHOD.get(service.service) )
params = service.data.copy() component.async_register_entity_service(
SERVICE_TURN_OFF, FAN_TURN_OFF_SCHEMA,
# Convert the entity ids to valid fan ids 'async_turn_off'
target_fans = component.async_extract_from_service(service) )
params.pop(ATTR_ENTITY_ID, None) component.async_register_entity_service(
SERVICE_TOGGLE, FAN_TOGGLE_SCHEMA,
update_tasks = [] 'async_toggle'
for fan in target_fans: )
yield from getattr(fan, method['method'])(**params) component.async_register_entity_service(
if not fan.should_poll: SERVICE_SET_SPEED, FAN_SET_SPEED_SCHEMA,
continue 'async_set_speed'
update_tasks.append(fan.async_update_ha_state(True)) )
component.async_register_entity_service(
if update_tasks: SERVICE_OSCILLATE, FAN_OSCILLATE_SCHEMA,
yield from asyncio.wait(update_tasks, loop=hass.loop) 'async_oscillate'
)
for service_name in SERVICE_TO_METHOD: component.async_register_entity_service(
schema = SERVICE_TO_METHOD[service_name].get('schema') SERVICE_SET_DIRECTION, FAN_SET_DIRECTION_SCHEMA,
hass.services.async_register( 'async_set_direction'
DOMAIN, service_name, async_handle_fan_service, schema=schema) )
return True return True

View File

@ -332,8 +332,8 @@ async def async_setup(hass, config):
if not profiles_valid: if not profiles_valid:
return False return False
async def async_handle_light_service(service): async def async_handle_light_on_service(service):
"""Handle a turn light on or off service call.""" """Handle a turn light on service call."""
# Get the validated data # Get the validated data
params = service.data.copy() params = service.data.copy()
@ -345,17 +345,12 @@ async def async_setup(hass, config):
update_tasks = [] update_tasks = []
for light in target_lights: for light in target_lights:
if service.service == SERVICE_TURN_ON: pars = params
pars = params if not pars:
if not pars: pars = params.copy()
pars = params.copy() pars[ATTR_PROFILE] = Profiles.get_default(light.entity_id)
pars[ATTR_PROFILE] = Profiles.get_default(light.entity_id) preprocess_turn_on_alternatives(pars)
preprocess_turn_on_alternatives(pars) await light.async_turn_on(**pars)
await light.async_turn_on(**pars)
elif service.service == SERVICE_TURN_OFF:
await light.async_turn_off(**params)
else:
await light.async_toggle(**params)
if not light.should_poll: if not light.should_poll:
continue continue
@ -368,16 +363,18 @@ async def async_setup(hass, config):
# Listen for light on and light off service calls. # Listen for light on and light off service calls.
hass.services.async_register( hass.services.async_register(
DOMAIN, SERVICE_TURN_ON, async_handle_light_service, DOMAIN, SERVICE_TURN_ON, async_handle_light_on_service,
schema=LIGHT_TURN_ON_SCHEMA) schema=LIGHT_TURN_ON_SCHEMA)
hass.services.async_register( component.async_register_entity_service(
DOMAIN, SERVICE_TURN_OFF, async_handle_light_service, SERVICE_TURN_OFF, LIGHT_TURN_OFF_SCHEMA,
schema=LIGHT_TURN_OFF_SCHEMA) 'async_turn_off'
)
hass.services.async_register( component.async_register_entity_service(
DOMAIN, SERVICE_TOGGLE, async_handle_light_service, SERVICE_TOGGLE, LIGHT_TOGGLE_SCHEMA,
schema=LIGHT_TOGGLE_SCHEMA) 'async_toggle'
)
hass.helpers.intent.async_register(SetIntentHandler()) hass.helpers.intent.async_register(SetIntentHandler())

View File

@ -151,42 +151,6 @@ MEDIA_PLAYER_SET_SHUFFLE_SCHEMA = MEDIA_PLAYER_SCHEMA.extend({
vol.Required(ATTR_MEDIA_SHUFFLE): cv.boolean, vol.Required(ATTR_MEDIA_SHUFFLE): cv.boolean,
}) })
SERVICE_TO_METHOD = {
SERVICE_TURN_ON: {'method': 'async_turn_on'},
SERVICE_TURN_OFF: {'method': 'async_turn_off'},
SERVICE_TOGGLE: {'method': 'async_toggle'},
SERVICE_VOLUME_UP: {'method': 'async_volume_up'},
SERVICE_VOLUME_DOWN: {'method': 'async_volume_down'},
SERVICE_MEDIA_PLAY_PAUSE: {'method': 'async_media_play_pause'},
SERVICE_MEDIA_PLAY: {'method': 'async_media_play'},
SERVICE_MEDIA_PAUSE: {'method': 'async_media_pause'},
SERVICE_MEDIA_STOP: {'method': 'async_media_stop'},
SERVICE_MEDIA_NEXT_TRACK: {'method': 'async_media_next_track'},
SERVICE_MEDIA_PREVIOUS_TRACK: {'method': 'async_media_previous_track'},
SERVICE_CLEAR_PLAYLIST: {'method': 'async_clear_playlist'},
SERVICE_VOLUME_SET: {
'method': 'async_set_volume_level',
'schema': MEDIA_PLAYER_SET_VOLUME_SCHEMA},
SERVICE_VOLUME_MUTE: {
'method': 'async_mute_volume',
'schema': MEDIA_PLAYER_MUTE_VOLUME_SCHEMA},
SERVICE_MEDIA_SEEK: {
'method': 'async_media_seek',
'schema': MEDIA_PLAYER_MEDIA_SEEK_SCHEMA},
SERVICE_SELECT_SOURCE: {
'method': 'async_select_source',
'schema': MEDIA_PLAYER_SELECT_SOURCE_SCHEMA},
SERVICE_SELECT_SOUND_MODE: {
'method': 'async_select_sound_mode',
'schema': MEDIA_PLAYER_SELECT_SOUND_MODE_SCHEMA},
SERVICE_PLAY_MEDIA: {
'method': 'async_play_media',
'schema': MEDIA_PLAYER_PLAY_MEDIA_SCHEMA},
SERVICE_SHUFFLE_SET: {
'method': 'async_set_shuffle',
'schema': MEDIA_PLAYER_SET_SHUFFLE_SCHEMA},
}
ATTR_TO_PROPERTY = [ ATTR_TO_PROPERTY = [
ATTR_MEDIA_VOLUME_LEVEL, ATTR_MEDIA_VOLUME_LEVEL,
ATTR_MEDIA_VOLUME_MUTED, ATTR_MEDIA_VOLUME_MUTED,
@ -409,50 +373,89 @@ async def async_setup(hass, config):
await component.async_setup(config) await component.async_setup(config)
async def async_service_handler(service): component.async_register_entity_service(
"""Map services to methods on MediaPlayerDevice.""" SERVICE_TURN_ON, MEDIA_PLAYER_SCHEMA,
method = SERVICE_TO_METHOD.get(service.service) 'async_turn_on'
if not method: )
return component.async_register_entity_service(
SERVICE_TURN_OFF, MEDIA_PLAYER_SCHEMA,
params = {} 'async_turn_off'
if service.service == SERVICE_VOLUME_SET: )
params['volume'] = service.data.get(ATTR_MEDIA_VOLUME_LEVEL) component.async_register_entity_service(
elif service.service == SERVICE_VOLUME_MUTE: SERVICE_TOGGLE, MEDIA_PLAYER_SCHEMA,
params['mute'] = service.data.get(ATTR_MEDIA_VOLUME_MUTED) 'async_toggle'
elif service.service == SERVICE_MEDIA_SEEK: )
params['position'] = service.data.get(ATTR_MEDIA_SEEK_POSITION) component.async_register_entity_service(
elif service.service == SERVICE_SELECT_SOURCE: SERVICE_VOLUME_UP, MEDIA_PLAYER_SCHEMA,
params['source'] = service.data.get(ATTR_INPUT_SOURCE) 'async_volume_up'
elif service.service == SERVICE_SELECT_SOUND_MODE: )
params['sound_mode'] = service.data.get(ATTR_SOUND_MODE) component.async_register_entity_service(
elif service.service == SERVICE_PLAY_MEDIA: SERVICE_VOLUME_DOWN, MEDIA_PLAYER_SCHEMA,
params['media_type'] = \ 'async_volume_down'
service.data.get(ATTR_MEDIA_CONTENT_TYPE) )
params['media_id'] = service.data.get(ATTR_MEDIA_CONTENT_ID) component.async_register_entity_service(
params[ATTR_MEDIA_ENQUEUE] = \ SERVICE_MEDIA_PLAY_PAUSE, MEDIA_PLAYER_SCHEMA,
service.data.get(ATTR_MEDIA_ENQUEUE) 'async_media_play_pause'
elif service.service == SERVICE_SHUFFLE_SET: )
params[ATTR_MEDIA_SHUFFLE] = \ component.async_register_entity_service(
service.data.get(ATTR_MEDIA_SHUFFLE) SERVICE_MEDIA_PLAY, MEDIA_PLAYER_SCHEMA,
target_players = component.async_extract_from_service(service) 'async_media_play'
)
update_tasks = [] component.async_register_entity_service(
for player in target_players: SERVICE_MEDIA_PAUSE, MEDIA_PLAYER_SCHEMA,
await getattr(player, method['method'])(**params) 'async_media_pause'
if not player.should_poll: )
continue component.async_register_entity_service(
update_tasks.append(player.async_update_ha_state(True)) SERVICE_MEDIA_STOP, MEDIA_PLAYER_SCHEMA,
'async_media_stop'
if update_tasks: )
await asyncio.wait(update_tasks, loop=hass.loop) component.async_register_entity_service(
SERVICE_MEDIA_NEXT_TRACK, MEDIA_PLAYER_SCHEMA,
for service in SERVICE_TO_METHOD: 'async_media_next_track'
schema = SERVICE_TO_METHOD[service].get( )
'schema', MEDIA_PLAYER_SCHEMA) component.async_register_entity_service(
hass.services.async_register( SERVICE_MEDIA_PREVIOUS_TRACK, MEDIA_PLAYER_SCHEMA,
DOMAIN, service, async_service_handler, 'async_media_previous_track'
schema=schema) )
component.async_register_entity_service(
SERVICE_CLEAR_PLAYLIST, MEDIA_PLAYER_SCHEMA,
'async_clear_playlist'
)
component.async_register_entity_service(
SERVICE_VOLUME_SET, MEDIA_PLAYER_SET_VOLUME_SCHEMA,
lambda entity, call: entity.async_set_volume_level(
volume=call.data[ATTR_MEDIA_VOLUME_LEVEL])
)
component.async_register_entity_service(
SERVICE_VOLUME_MUTE, MEDIA_PLAYER_MUTE_VOLUME_SCHEMA,
lambda entity, call: entity.async_mute_volume(
mute=call.data[ATTR_MEDIA_VOLUME_MUTED])
)
component.async_register_entity_service(
SERVICE_MEDIA_SEEK, MEDIA_PLAYER_MEDIA_SEEK_SCHEMA,
lambda entity, call: entity.async_media_seek(
position=call.data[ATTR_MEDIA_SEEK_POSITION])
)
component.async_register_entity_service(
SERVICE_SELECT_SOURCE, MEDIA_PLAYER_SELECT_SOURCE_SCHEMA,
'async_select_source'
)
component.async_register_entity_service(
SERVICE_SELECT_SOUND_MODE, MEDIA_PLAYER_SELECT_SOUND_MODE_SCHEMA,
'async_select_sound_mode'
)
component.async_register_entity_service(
SERVICE_PLAY_MEDIA, MEDIA_PLAYER_PLAY_MEDIA_SCHEMA,
lambda entity, call: entity.async_play_media(
media_type=call.data[ATTR_MEDIA_CONTENT_TYPE],
media_id=call.data[ATTR_MEDIA_CONTENT_ID],
enqueue=call.data.get(ATTR_MEDIA_ENQUEUE)
)
)
component.async_register_entity_service(
SERVICE_SHUFFLE_SET, MEDIA_PLAYER_SET_SHUFFLE_SCHEMA,
'async_set_shuffle'
)
return True return True

View File

@ -1,5 +1,5 @@
"""The tests for local file camera component.""" """The tests for local file camera component."""
from unittest.mock import mock_open, patch, PropertyMock from unittest.mock import mock_open, patch
import pytest import pytest
@ -67,19 +67,6 @@ async def test_turn_off_invalid_camera(hass, demo_camera):
assert demo_camera.state == STATE_STREAMING assert demo_camera.state == STATE_STREAMING
async def test_turn_off_unsupport_camera(hass, demo_camera):
"""Turn off unsupported camera should quietly fail."""
assert demo_camera.state == STATE_STREAMING
with patch('homeassistant.components.camera.demo.DemoCamera'
'.supported_features', new_callable=PropertyMock) as m:
m.return_value = 0
await camera.async_turn_off(hass, demo_camera.entity_id)
await hass.async_block_till_done()
assert demo_camera.state == STATE_STREAMING
async def test_motion_detection(hass): async def test_motion_detection(hass):
"""Test motion detection services.""" """Test motion detection services."""
# Setup platform # Setup platform

View File

@ -356,11 +356,10 @@ def test_signal_repetitions_cancelling(hass, monkeypatch):
yield from hass.async_block_till_done() yield from hass.async_block_till_done()
print(protocol.send_command_ack.call_args_list) assert protocol.send_command_ack.call_args_list[0][0][1] == 'on'
assert protocol.send_command_ack.call_args_list[0][0][1] == 'off' assert protocol.send_command_ack.call_args_list[1][0][1] == 'off'
assert protocol.send_command_ack.call_args_list[1][0][1] == 'on' assert protocol.send_command_ack.call_args_list[2][0][1] == 'off'
assert protocol.send_command_ack.call_args_list[2][0][1] == 'on' assert protocol.send_command_ack.call_args_list[3][0][1] == 'off'
assert protocol.send_command_ack.call_args_list[3][0][1] == 'on'
@asyncio.coroutine @asyncio.coroutine