Fix supported features gates in media_player volume up/down services (#23419)

* Correct media player feature gates

* Fix failing test

* Lint...
This commit is contained in:
Andrew Sayre 2019-04-25 23:42:39 -05:00 committed by Paulus Schoutsen
parent eefb9406c2
commit b5725f8f19
4 changed files with 42 additions and 24 deletions

View File

@ -45,7 +45,8 @@ from .const import (
SUPPORT_NEXT_TRACK, SUPPORT_PAUSE, SUPPORT_PLAY, SUPPORT_PLAY_MEDIA, SUPPORT_NEXT_TRACK, SUPPORT_PAUSE, SUPPORT_PLAY, SUPPORT_PLAY_MEDIA,
SUPPORT_PREVIOUS_TRACK, SUPPORT_SEEK, SUPPORT_SELECT_SOUND_MODE, SUPPORT_PREVIOUS_TRACK, SUPPORT_SEEK, SUPPORT_SELECT_SOUND_MODE,
SUPPORT_SELECT_SOURCE, SUPPORT_SHUFFLE_SET, SUPPORT_STOP, SUPPORT_TURN_OFF, SUPPORT_SELECT_SOURCE, SUPPORT_SHUFFLE_SET, SUPPORT_STOP, SUPPORT_TURN_OFF,
SUPPORT_TURN_ON, SUPPORT_VOLUME_MUTE, SUPPORT_VOLUME_SET) SUPPORT_TURN_ON, SUPPORT_VOLUME_MUTE, SUPPORT_VOLUME_SET,
SUPPORT_VOLUME_STEP)
from .reproduce_state import async_reproduce_states # noqa from .reproduce_state import async_reproduce_states # noqa
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -174,77 +175,77 @@ async def async_setup(hass, config):
component.async_register_entity_service( component.async_register_entity_service(
SERVICE_TURN_ON, MEDIA_PLAYER_SCHEMA, SERVICE_TURN_ON, MEDIA_PLAYER_SCHEMA,
'async_turn_on', SUPPORT_TURN_ON 'async_turn_on', [SUPPORT_TURN_ON]
) )
component.async_register_entity_service( component.async_register_entity_service(
SERVICE_TURN_OFF, MEDIA_PLAYER_SCHEMA, SERVICE_TURN_OFF, MEDIA_PLAYER_SCHEMA,
'async_turn_off', SUPPORT_TURN_OFF 'async_turn_off', [SUPPORT_TURN_OFF]
) )
component.async_register_entity_service( component.async_register_entity_service(
SERVICE_TOGGLE, MEDIA_PLAYER_SCHEMA, SERVICE_TOGGLE, MEDIA_PLAYER_SCHEMA,
'async_toggle', SUPPORT_TURN_OFF | SUPPORT_TURN_ON 'async_toggle', [SUPPORT_TURN_OFF | SUPPORT_TURN_ON]
) )
component.async_register_entity_service( component.async_register_entity_service(
SERVICE_VOLUME_UP, MEDIA_PLAYER_SCHEMA, SERVICE_VOLUME_UP, MEDIA_PLAYER_SCHEMA,
'async_volume_up', SUPPORT_VOLUME_SET 'async_volume_up', [SUPPORT_VOLUME_SET, SUPPORT_VOLUME_STEP]
) )
component.async_register_entity_service( component.async_register_entity_service(
SERVICE_VOLUME_DOWN, MEDIA_PLAYER_SCHEMA, SERVICE_VOLUME_DOWN, MEDIA_PLAYER_SCHEMA,
'async_volume_down', SUPPORT_VOLUME_SET 'async_volume_down', [SUPPORT_VOLUME_SET, SUPPORT_VOLUME_STEP]
) )
component.async_register_entity_service( component.async_register_entity_service(
SERVICE_MEDIA_PLAY_PAUSE, MEDIA_PLAYER_SCHEMA, SERVICE_MEDIA_PLAY_PAUSE, MEDIA_PLAYER_SCHEMA,
'async_media_play_pause', SUPPORT_PLAY | SUPPORT_PAUSE 'async_media_play_pause', [SUPPORT_PLAY | SUPPORT_PAUSE]
) )
component.async_register_entity_service( component.async_register_entity_service(
SERVICE_MEDIA_PLAY, MEDIA_PLAYER_SCHEMA, SERVICE_MEDIA_PLAY, MEDIA_PLAYER_SCHEMA,
'async_media_play', SUPPORT_PLAY 'async_media_play', [SUPPORT_PLAY]
) )
component.async_register_entity_service( component.async_register_entity_service(
SERVICE_MEDIA_PAUSE, MEDIA_PLAYER_SCHEMA, SERVICE_MEDIA_PAUSE, MEDIA_PLAYER_SCHEMA,
'async_media_pause', SUPPORT_PAUSE 'async_media_pause', [SUPPORT_PAUSE]
) )
component.async_register_entity_service( component.async_register_entity_service(
SERVICE_MEDIA_STOP, MEDIA_PLAYER_SCHEMA, SERVICE_MEDIA_STOP, MEDIA_PLAYER_SCHEMA,
'async_media_stop', SUPPORT_STOP 'async_media_stop', [SUPPORT_STOP]
) )
component.async_register_entity_service( component.async_register_entity_service(
SERVICE_MEDIA_NEXT_TRACK, MEDIA_PLAYER_SCHEMA, SERVICE_MEDIA_NEXT_TRACK, MEDIA_PLAYER_SCHEMA,
'async_media_next_track', SUPPORT_NEXT_TRACK 'async_media_next_track', [SUPPORT_NEXT_TRACK]
) )
component.async_register_entity_service( component.async_register_entity_service(
SERVICE_MEDIA_PREVIOUS_TRACK, MEDIA_PLAYER_SCHEMA, SERVICE_MEDIA_PREVIOUS_TRACK, MEDIA_PLAYER_SCHEMA,
'async_media_previous_track', SUPPORT_PREVIOUS_TRACK 'async_media_previous_track', [SUPPORT_PREVIOUS_TRACK]
) )
component.async_register_entity_service( component.async_register_entity_service(
SERVICE_CLEAR_PLAYLIST, MEDIA_PLAYER_SCHEMA, SERVICE_CLEAR_PLAYLIST, MEDIA_PLAYER_SCHEMA,
'async_clear_playlist', SUPPORT_CLEAR_PLAYLIST 'async_clear_playlist', [SUPPORT_CLEAR_PLAYLIST]
) )
component.async_register_entity_service( component.async_register_entity_service(
SERVICE_VOLUME_SET, MEDIA_PLAYER_SET_VOLUME_SCHEMA, SERVICE_VOLUME_SET, MEDIA_PLAYER_SET_VOLUME_SCHEMA,
lambda entity, call: entity.async_set_volume_level( lambda entity, call: entity.async_set_volume_level(
volume=call.data[ATTR_MEDIA_VOLUME_LEVEL]), volume=call.data[ATTR_MEDIA_VOLUME_LEVEL]),
SUPPORT_VOLUME_SET [SUPPORT_VOLUME_SET]
) )
component.async_register_entity_service( component.async_register_entity_service(
SERVICE_VOLUME_MUTE, MEDIA_PLAYER_MUTE_VOLUME_SCHEMA, SERVICE_VOLUME_MUTE, MEDIA_PLAYER_MUTE_VOLUME_SCHEMA,
lambda entity, call: entity.async_mute_volume( lambda entity, call: entity.async_mute_volume(
mute=call.data[ATTR_MEDIA_VOLUME_MUTED]), mute=call.data[ATTR_MEDIA_VOLUME_MUTED]),
SUPPORT_VOLUME_MUTE [SUPPORT_VOLUME_MUTE]
) )
component.async_register_entity_service( component.async_register_entity_service(
SERVICE_MEDIA_SEEK, MEDIA_PLAYER_MEDIA_SEEK_SCHEMA, SERVICE_MEDIA_SEEK, MEDIA_PLAYER_MEDIA_SEEK_SCHEMA,
lambda entity, call: entity.async_media_seek( lambda entity, call: entity.async_media_seek(
position=call.data[ATTR_MEDIA_SEEK_POSITION]), position=call.data[ATTR_MEDIA_SEEK_POSITION]),
SUPPORT_SEEK [SUPPORT_SEEK]
) )
component.async_register_entity_service( component.async_register_entity_service(
SERVICE_SELECT_SOURCE, MEDIA_PLAYER_SELECT_SOURCE_SCHEMA, SERVICE_SELECT_SOURCE, MEDIA_PLAYER_SELECT_SOURCE_SCHEMA,
'async_select_source', SUPPORT_SELECT_SOURCE 'async_select_source', [SUPPORT_SELECT_SOURCE]
) )
component.async_register_entity_service( component.async_register_entity_service(
SERVICE_SELECT_SOUND_MODE, MEDIA_PLAYER_SELECT_SOUND_MODE_SCHEMA, SERVICE_SELECT_SOUND_MODE, MEDIA_PLAYER_SELECT_SOUND_MODE_SCHEMA,
'async_select_sound_mode', SUPPORT_SELECT_SOUND_MODE 'async_select_sound_mode', [SUPPORT_SELECT_SOUND_MODE]
) )
component.async_register_entity_service( component.async_register_entity_service(
SERVICE_PLAY_MEDIA, MEDIA_PLAYER_PLAY_MEDIA_SCHEMA, SERVICE_PLAY_MEDIA, MEDIA_PLAYER_PLAY_MEDIA_SCHEMA,
@ -252,11 +253,11 @@ async def async_setup(hass, config):
media_type=call.data[ATTR_MEDIA_CONTENT_TYPE], media_type=call.data[ATTR_MEDIA_CONTENT_TYPE],
media_id=call.data[ATTR_MEDIA_CONTENT_ID], media_id=call.data[ATTR_MEDIA_CONTENT_ID],
enqueue=call.data.get(ATTR_MEDIA_ENQUEUE) enqueue=call.data.get(ATTR_MEDIA_ENQUEUE)
), SUPPORT_PLAY_MEDIA ), [SUPPORT_PLAY_MEDIA]
) )
component.async_register_entity_service( component.async_register_entity_service(
SERVICE_SHUFFLE_SET, MEDIA_PLAYER_SET_SHUFFLE_SCHEMA, SERVICE_SHUFFLE_SET, MEDIA_PLAYER_SET_SHUFFLE_SCHEMA,
'async_set_shuffle', SUPPORT_SHUFFLE_SET 'async_set_shuffle', [SUPPORT_SHUFFLE_SET]
) )
return True return True
@ -701,7 +702,8 @@ class MediaPlayerDevice(Entity):
await self.hass.async_add_job(self.volume_up) await self.hass.async_add_job(self.volume_up)
return return
if self.volume_level < 1: if self.volume_level < 1 \
and self.supported_features & SUPPORT_VOLUME_SET:
await self.async_set_volume_level(min(1, self.volume_level + .1)) await self.async_set_volume_level(min(1, self.volume_level + .1))
async def async_volume_down(self): async def async_volume_down(self):
@ -714,7 +716,8 @@ class MediaPlayerDevice(Entity):
await self.hass.async_add_job(self.volume_down) await self.hass.async_add_job(self.volume_down)
return return
if self.volume_level > 0: if self.volume_level > 0 \
and self.supported_features & SUPPORT_VOLUME_SET:
await self.async_set_volume_level( await self.async_set_volume_level(
max(0, self.volume_level - .1)) max(0, self.volume_level - .1))

View File

@ -327,7 +327,8 @@ async def _handle_service_platform_call(func, data, entities, context,
# Skip entities that don't have the required feature. # Skip entities that don't have the required feature.
if required_features is not None \ if required_features is not None \
and not entity.supported_features & required_features: and not any(entity.supported_features & feature_set
for feature_set in required_features):
continue continue
entity.async_set_context(context) entity.async_set_context(context)

View File

@ -29,6 +29,13 @@ class AsyncMediaPlayer(mp.MediaPlayerDevice):
"""Volume level of the media player (0..1).""" """Volume level of the media player (0..1)."""
return self._volume return self._volume
@property
def supported_features(self):
"""Flag media player features that are supported."""
return mp.const.SUPPORT_VOLUME_SET | mp.const.SUPPORT_PLAY \
| mp.const.SUPPORT_PAUSE | mp.const.SUPPORT_TURN_OFF \
| mp.const.SUPPORT_TURN_ON
@asyncio.coroutine @asyncio.coroutine
def async_set_volume_level(self, volume): def async_set_volume_level(self, volume):
"""Set volume level, range 0..1.""" """Set volume level, range 0..1."""
@ -74,6 +81,13 @@ class SyncMediaPlayer(mp.MediaPlayerDevice):
"""Volume level of the media player (0..1).""" """Volume level of the media player (0..1)."""
return self._volume return self._volume
@property
def supported_features(self):
"""Flag media player features that are supported."""
return mp.const.SUPPORT_VOLUME_SET | mp.const.SUPPORT_VOLUME_STEP \
| mp.const.SUPPORT_PLAY | mp.const.SUPPORT_PAUSE \
| mp.const.SUPPORT_TURN_OFF | mp.const.SUPPORT_TURN_ON
def set_volume_level(self, volume): def set_volume_level(self, volume):
"""Set volume level, range 0..1.""" """Set volume level, range 0..1."""
self._volume = volume self._volume = volume

View File

@ -280,7 +280,7 @@ async def test_call_with_required_features(hass, mock_entities):
Mock(entities=mock_entities) Mock(entities=mock_entities)
], test_service_mock, ha.ServiceCall('test_domain', 'test_service', { ], test_service_mock, ha.ServiceCall('test_domain', 'test_service', {
'entity_id': 'all' 'entity_id': 'all'
}), required_features=1) }), required_features=[1])
assert len(mock_entities) == 2 assert len(mock_entities) == 2
# Called once because only one of the entities had the required features # Called once because only one of the entities had the required features
assert test_service_mock.call_count == 1 assert test_service_mock.call_count == 1