Formalize supported_features as entity property (#5794)

* Formalize supported_features as entity property

* Remove extra emulated_hue conditions

* Generate log message in executor
This commit is contained in:
Adam Mills 2017-02-07 23:42:45 -05:00 committed by Paulus Schoutsen
parent 4fa4d7347f
commit ecfe8e0a9a
49 changed files with 193 additions and 165 deletions

View file

@ -8,14 +8,13 @@ from homeassistant import core
from homeassistant.const import (
ATTR_ENTITY_ID, SERVICE_TURN_OFF, SERVICE_TURN_ON, SERVICE_VOLUME_SET,
SERVICE_OPEN_COVER, SERVICE_CLOSE_COVER, STATE_ON, STATE_OFF,
HTTP_BAD_REQUEST, HTTP_NOT_FOUND,
HTTP_BAD_REQUEST, HTTP_NOT_FOUND, ATTR_SUPPORTED_FEATURES,
)
from homeassistant.components.light import (
ATTR_BRIGHTNESS, ATTR_SUPPORTED_FEATURES, SUPPORT_BRIGHTNESS
ATTR_BRIGHTNESS, SUPPORT_BRIGHTNESS
)
from homeassistant.components.media_player import (
ATTR_MEDIA_VOLUME_LEVEL, ATTR_SUPPORTED_MEDIA_COMMANDS,
SUPPORT_VOLUME_SET,
ATTR_MEDIA_VOLUME_LEVEL, SUPPORT_VOLUME_SET,
)
from homeassistant.components.fan import (
ATTR_SPEED, SUPPORT_SET_SPEED, SPEED_OFF, SPEED_LOW,
@ -178,11 +177,10 @@ class HueOneLightChangeView(HomeAssistantView):
# Make sure the entity actually supports brightness
entity_features = entity.attributes.get(ATTR_SUPPORTED_FEATURES, 0)
if (entity_features &
SUPPORT_BRIGHTNESS &
(entity.domain == "light")) == SUPPORT_BRIGHTNESS:
if brightness is not None:
data[ATTR_BRIGHTNESS] = brightness
if entity.domain == "light":
if entity_features & SUPPORT_BRIGHTNESS:
if brightness is not None:
data[ATTR_BRIGHTNESS] = brightness
# If the requested entity is a script add some variables
elif entity.domain == "script":
@ -195,9 +193,7 @@ class HueOneLightChangeView(HomeAssistantView):
# If the requested entity is a media player, convert to volume
elif entity.domain == "media_player":
media_commands = entity.attributes.get(
ATTR_SUPPORTED_MEDIA_COMMANDS, 0)
if media_commands & SUPPORT_VOLUME_SET == SUPPORT_VOLUME_SET:
if entity_features & SUPPORT_VOLUME_SET:
if brightness is not None:
turn_on_needed = True
domain = entity.domain
@ -215,9 +211,7 @@ class HueOneLightChangeView(HomeAssistantView):
# If the requested entity is a fan, convert to speed
elif entity.domain == "fan":
functions = entity.attributes.get(
ATTR_SUPPORTED_FEATURES, 0)
if (functions & SUPPORT_SET_SPEED) == SUPPORT_SET_SPEED:
if entity_features & SUPPORT_SET_SPEED:
if brightness is not None:
domain = entity.domain
# Convert 0-100 to a fan speed
@ -288,9 +282,10 @@ def parse_hue_api_put_light_body(request_json, entity):
# Make sure the entity actually supports brightness
entity_features = entity.attributes.get(ATTR_SUPPORTED_FEATURES, 0)
if (entity_features & SUPPORT_BRIGHTNESS) == SUPPORT_BRIGHTNESS:
report_brightness = True
result = (brightness > 0)
if entity.domain == "light":
if entity_features & SUPPORT_BRIGHTNESS:
report_brightness = True
result = (brightness > 0)
elif (entity.domain == "script" or
entity.domain == "media_player" or
@ -316,8 +311,9 @@ def get_entity_state(config, entity):
# Make sure the entity actually supports brightness
entity_features = entity.attributes.get(ATTR_SUPPORTED_FEATURES, 0)
if (entity_features & SUPPORT_BRIGHTNESS) == SUPPORT_BRIGHTNESS:
pass
if entity.domain == "light":
if entity_features & SUPPORT_BRIGHTNESS:
pass
elif entity.domain == "media_player":
level = entity.attributes.get(

View file

@ -34,7 +34,6 @@ ENTITY_ID_ALL_FANS = group.ENTITY_ID_FORMAT.format(GROUP_NAME_ALL_FANS)
ENTITY_ID_FORMAT = DOMAIN + '.{}'
# Bitfield of features supported by the fan entity
ATTR_SUPPORTED_FEATURES = 'supported_features'
SUPPORT_SET_SPEED = 1
SUPPORT_OSCILLATE = 2
SUPPORT_DIRECTION = 4
@ -60,7 +59,6 @@ PROP_TO_ATTR = {
'speed': ATTR_SPEED,
'speed_list': ATTR_SPEED_LIST,
'oscillating': ATTR_OSCILLATING,
'supported_features': ATTR_SUPPORTED_FEATURES,
'direction': ATTR_DIRECTION,
} # type: dict

View file

@ -35,7 +35,6 @@ ENTITY_ID_ALL_LIGHTS = group.ENTITY_ID_FORMAT.format('all_lights')
ENTITY_ID_FORMAT = DOMAIN + ".{}"
# Bitfield of features supported by the light entity
ATTR_SUPPORTED_FEATURES = 'supported_features'
SUPPORT_BRIGHTNESS = 1
SUPPORT_COLOR_TEMP = 2
SUPPORT_EFFECT = 4
@ -85,7 +84,6 @@ PROP_TO_ATTR = {
'white_value': ATTR_WHITE_VALUE,
'effect_list': ATTR_EFFECT_LIST,
'effect': ATTR_EFFECT,
'supported_features': ATTR_SUPPORTED_FEATURES,
}
# Service call validation schemas
@ -364,8 +362,6 @@ class Light(ToggleEntity):
data[ATTR_RGB_COLOR] = color_util.color_xy_brightness_to_RGB(
data[ATTR_XY_COLOR][0], data[ATTR_XY_COLOR][1],
data[ATTR_BRIGHTNESS])
else:
data[ATTR_SUPPORTED_FEATURES] = self.supported_features
return data

View file

@ -77,7 +77,6 @@ ATTR_MEDIA_CHANNEL = 'media_channel'
ATTR_MEDIA_PLAYLIST = 'media_playlist'
ATTR_APP_ID = 'app_id'
ATTR_APP_NAME = 'app_name'
ATTR_SUPPORTED_MEDIA_COMMANDS = 'supported_media_commands'
ATTR_INPUT_SOURCE = 'source'
ATTR_INPUT_SOURCE_LIST = 'source_list'
ATTR_MEDIA_ENQUEUE = 'enqueue'
@ -183,7 +182,6 @@ ATTR_TO_PROPERTY = [
ATTR_MEDIA_PLAYLIST,
ATTR_APP_ID,
ATTR_APP_NAME,
ATTR_SUPPORTED_MEDIA_COMMANDS,
ATTR_INPUT_SOURCE,
ATTR_INPUT_SOURCE_LIST,
]
@ -523,7 +521,39 @@ class MediaPlayerDevice(Entity):
@property
def supported_media_commands(self):
"""Flag media commands that are supported."""
"""Flag media commands that are supported.
DEPRECATED: Included for temporary custom platform compatibility.
"""
return None
@property
def supported_features(self):
"""Flag media player features that are supported."""
# Begin temporary transition logic
if self.supported_media_commands is not None:
# If this platform is still using supported_media_commands, issue
# a logger warning once with instructions on how to fix it.
if not getattr(self, '_supported_features_warned', False):
def show_warning():
"""Show a deprecation warning in the log for this class."""
import inspect
_LOGGER.warning(
"supported_media_commands is deprecated. Please "
"rename supported_media_commands to "
"supported_features in '%s' to ensure future support.",
inspect.getfile(self.__class__))
# This is a temporary attribute. We don't want to pollute
# __init__ so it can be easily removed.
# pylint: disable=attribute-defined-outside-init
self._supported_features_warned = True
self.hass.add_job(show_warning)
# Return the old property
return self.supported_media_commands
# End temporary transition logic
return 0
def turn_on(self):
@ -686,57 +716,57 @@ class MediaPlayerDevice(Entity):
@property
def support_play(self):
"""Boolean if play is supported."""
return bool(self.supported_media_commands & SUPPORT_PLAY)
return bool(self.supported_features & SUPPORT_PLAY)
@property
def support_pause(self):
"""Boolean if pause is supported."""
return bool(self.supported_media_commands & SUPPORT_PAUSE)
return bool(self.supported_features & SUPPORT_PAUSE)
@property
def support_stop(self):
"""Boolean if stop is supported."""
return bool(self.supported_media_commands & SUPPORT_STOP)
return bool(self.supported_features & SUPPORT_STOP)
@property
def support_seek(self):
"""Boolean if seek is supported."""
return bool(self.supported_media_commands & SUPPORT_SEEK)
return bool(self.supported_features & SUPPORT_SEEK)
@property
def support_volume_set(self):
"""Boolean if setting volume is supported."""
return bool(self.supported_media_commands & SUPPORT_VOLUME_SET)
return bool(self.supported_features & SUPPORT_VOLUME_SET)
@property
def support_volume_mute(self):
"""Boolean if muting volume is supported."""
return bool(self.supported_media_commands & SUPPORT_VOLUME_MUTE)
return bool(self.supported_features & SUPPORT_VOLUME_MUTE)
@property
def support_previous_track(self):
"""Boolean if previous track command supported."""
return bool(self.supported_media_commands & SUPPORT_PREVIOUS_TRACK)
return bool(self.supported_features & SUPPORT_PREVIOUS_TRACK)
@property
def support_next_track(self):
"""Boolean if next track command supported."""
return bool(self.supported_media_commands & SUPPORT_NEXT_TRACK)
return bool(self.supported_features & SUPPORT_NEXT_TRACK)
@property
def support_play_media(self):
"""Boolean if play media command supported."""
return bool(self.supported_media_commands & SUPPORT_PLAY_MEDIA)
return bool(self.supported_features & SUPPORT_PLAY_MEDIA)
@property
def support_select_source(self):
"""Boolean if select source command supported."""
return bool(self.supported_media_commands & SUPPORT_SELECT_SOURCE)
return bool(self.supported_features & SUPPORT_SELECT_SOURCE)
@property
def support_clear_playlist(self):
"""Boolean if clear playlist command supported."""
return bool(self.supported_media_commands & SUPPORT_CLEAR_PLAYLIST)
return bool(self.supported_features & SUPPORT_CLEAR_PLAYLIST)
def toggle(self):
"""Toggle the power on the media player."""
@ -821,14 +851,12 @@ class MediaPlayerDevice(Entity):
def state_attributes(self):
"""Return the state attributes."""
if self.state == STATE_OFF:
state_attr = {
ATTR_SUPPORTED_MEDIA_COMMANDS: self.supported_media_commands,
}
else:
state_attr = {
attr: getattr(self, attr) for attr
in ATTR_TO_PROPERTY if getattr(self, attr) is not None
}
return None
state_attr = {
attr: getattr(self, attr) for attr
in ATTR_TO_PROPERTY if getattr(self, attr) is not None
}
return state_attr

View file

@ -79,8 +79,8 @@ class AnthemAVR(MediaPlayerDevice):
return getattr(self.avr.protocol, propname, dval)
@property
def supported_media_commands(self):
"""Return flag of media commands that are supported."""
def supported_features(self):
"""Flag media player features that are supported."""
return SUPPORT_ANTHEMAV
@property

View file

@ -184,8 +184,8 @@ class AppleTvDevice(MediaPlayerDevice):
return title if title else "No title"
@property
def supported_media_commands(self):
"""Flag of media commands that are supported."""
def supported_features(self):
"""Flag media player features that are supported."""
if self._playing is not None:
if self.state != STATE_IDLE:
return SUPPORT_PAUSE | SUPPORT_PLAY | \

View file

@ -191,8 +191,8 @@ class SharpAquosTVDevice(MediaPlayerDevice):
return self._muted
@property
def supported_media_commands(self):
"""Flag of media commands that are supported."""
def supported_features(self):
"""Flag media player features that are supported."""
return SUPPORT_SHARPTV
@_retry

View file

@ -316,8 +316,8 @@ class BraviaTVDevice(MediaPlayerDevice):
return self._muted
@property
def supported_media_commands(self):
"""Flag of media commands that are supported."""
def supported_features(self):
"""Flag media player features that are supported."""
return SUPPORT_BRAVIA
@property

View file

@ -226,8 +226,8 @@ class CastDevice(MediaPlayerDevice):
return self.cast.app_display_name
@property
def supported_media_commands(self):
"""Flag of media commands that are supported."""
def supported_features(self):
"""Flag media player features that are supported."""
return SUPPORT_CAST
@property

View file

@ -151,8 +151,8 @@ class CmusDevice(MediaPlayerDevice):
return int(volume)/100
@property
def supported_media_commands(self):
"""Flag of media commands that are supported."""
def supported_features(self):
"""Flag media player features that are supported."""
return SUPPORT_CMUS
def turn_off(self):

View file

@ -155,8 +155,8 @@ class DemoYoutubePlayer(AbstractDemoPlayer):
return "YouTube"
@property
def supported_media_commands(self):
"""Flag of media commands that are supported."""
def supported_features(self):
"""Flag media player features that are supported."""
return YOUTUBE_PLAYER_SUPPORT
@property
@ -269,8 +269,8 @@ class DemoMusicPlayer(AbstractDemoPlayer):
return self._cur_track + 1
@property
def supported_media_commands(self):
"""Flag of media commands that are supported."""
def supported_features(self):
"""Flag media player features that are supported."""
support = MUSIC_PLAYER_SUPPORT
if self._cur_track > 0:
@ -364,8 +364,8 @@ class DemoTVShowPlayer(AbstractDemoPlayer):
return self._source
@property
def supported_media_commands(self):
"""Flag of media commands that are supported."""
def supported_features(self):
"""Flag media player features that are supported."""
support = NETFLIX_PLAYER_SUPPORT
if self._cur_episode > 1:

View file

@ -193,8 +193,8 @@ class DenonDevice(MediaPlayerDevice):
return self._mediainfo
@property
def supported_media_commands(self):
"""Flag of media commands that are supported."""
def supported_features(self):
"""Flag media player features that are supported."""
if self._mediasource in MEDIA_MODES.values():
return SUPPORT_DENON | SUPPORT_MEDIA_MODES
else:

View file

@ -167,8 +167,8 @@ class DenonDevice(MediaPlayerDevice):
return self._source_list
@property
def supported_media_commands(self):
"""Flag of media commands that are supported."""
def supported_features(self):
"""Flag media player features that are supported."""
if self._current_source in self._receiver.netaudio_func_list:
return SUPPORT_DENON | SUPPORT_MEDIA_MODES
else:

View file

@ -133,8 +133,8 @@ class DirecTvDevice(MediaPlayerDevice):
return None
@property
def supported_media_commands(self):
"""Flag of media commands that are supported."""
def supported_features(self):
"""Flag media player features that are supported."""
return SUPPORT_DTV
@property

View file

@ -97,8 +97,8 @@ class DuneHDPlayerEntity(MediaPlayerDevice):
return list(self._sources.keys())
@property
def supported_media_commands(self):
"""Flag of media commands that are supported."""
def supported_features(self):
"""Flag media player features that are supported."""
return DUNEHD_PLAYER_SUPPORT
def volume_up(self):

View file

@ -309,8 +309,8 @@ class EmbyClient(MediaPlayerDevice):
return self.now_playing_item['IndexNumber']
@property
def supported_media_commands(self):
"""Flag of media commands that are supported."""
def supported_features(self):
"""Flag media player features that are supported."""
if self.supports_remote_control:
return SUPPORT_EMBY
else:

View file

@ -122,8 +122,8 @@ class FireTVDevice(MediaPlayerDevice):
return True
@property
def supported_media_commands(self):
"""Flag of media commands that are supported."""
def supported_features(self):
"""Flag media player features that are supported."""
return SUPPORT_FIRETV
@property

View file

@ -295,8 +295,8 @@ class GPMDP(MediaPlayerDevice):
return self._name
@property
def supported_media_commands(self):
"""Flag of media commands that are supported."""
def supported_features(self):
"""Flag media player features that are supported."""
return SUPPORT_GPMDP
def media_next_track(self):

View file

@ -158,8 +158,8 @@ class CecPlayerDevice(CecDevice, MediaPlayerDevice):
self.schedule_update_ha_state()
@property
def supported_media_commands(self):
"""Flag media commands that are supported."""
def supported_features(self):
"""Flag media player features that are supported."""
from pycec.const import TYPE_RECORDER, TYPE_PLAYBACK, TYPE_TUNER, \
TYPE_AUDIO
if self.type_id == TYPE_RECORDER or self.type == TYPE_PLAYBACK:

View file

@ -306,8 +306,8 @@ class ItunesDevice(MediaPlayerDevice):
return self.current_playlist
@property
def supported_media_commands(self):
"""Flag of media commands that are supported."""
def supported_features(self):
"""Flag media player features that are supported."""
return SUPPORT_ITUNES
def set_volume_level(self, volume):
@ -425,8 +425,8 @@ class AirPlayDevice(MediaPlayerDevice):
return MEDIA_TYPE_MUSIC
@property
def supported_media_commands(self):
"""Flag of media commands that are supported."""
def supported_features(self):
"""Flag media player features that are supported."""
return SUPPORT_AIRPLAY
def set_volume_level(self, volume):

View file

@ -228,14 +228,14 @@ class KodiDevice(MediaPlayerDevice):
self._item.get('label', self._item.get('file', 'unknown')))
@property
def supported_media_commands(self):
"""Flag of media commands that are supported."""
supported_media_commands = SUPPORT_KODI
def supported_features(self):
"""Flag media player features that are supported."""
supported_features = SUPPORT_KODI
if self._turn_off_action in TURN_OFF_ACTION:
supported_media_commands |= SUPPORT_TURN_OFF
supported_features |= SUPPORT_TURN_OFF
return supported_media_commands
return supported_features
@asyncio.coroutine
def async_turn_off(self):

View file

@ -163,8 +163,8 @@ class LgTVDevice(MediaPlayerDevice):
return self._program_name
@property
def supported_media_commands(self):
"""Flag of media commands that are supported."""
def supported_features(self):
"""Flag media player features that are supported."""
return SUPPORT_LGTV
@property

View file

@ -133,8 +133,8 @@ class LiveboxPlayTvDevice(MediaPlayerDevice):
self._current_program)
@property
def supported_media_commands(self):
"""Flag of media commands that are supported."""
def supported_features(self):
"""Flag media player features that are supported."""
return SUPPORT_LIVEBOXPLAYTV
def refresh_channel_list(self):

View file

@ -126,8 +126,8 @@ class MpcHcDevice(MediaPlayerDevice):
int(duration[2])
@property
def supported_media_commands(self):
"""Flag of media commands that are supported."""
def supported_features(self):
"""Flag media player features that are supported."""
return SUPPORT_MPCHC
def volume_up(self):

View file

@ -184,8 +184,8 @@ class MpdDevice(MediaPlayerDevice):
return int(self.status['volume'])/100
@property
def supported_media_commands(self):
"""Flag of media commands that are supported."""
def supported_features(self):
"""Flag media player features that are supported."""
return SUPPORT_MPD
@property

View file

@ -136,8 +136,8 @@ class NAD(MediaPlayerDevice):
return self._mute
@property
def supported_media_commands(self):
"""Flag of media commands that are supported."""
def supported_features(self):
"""Flag media player features that are supported."""
return SUPPORT_NAD
def turn_off(self):

View file

@ -150,8 +150,8 @@ class OnkyoDevice(MediaPlayerDevice):
return self._muted
@property
def supported_media_commands(self):
"""Flag of media commands that are supported."""
def supported_features(self):
"""Flag media player features that are supported."""
return SUPPORT_ONKYO
@property

View file

@ -123,8 +123,8 @@ class PanasonicVieraTVDevice(MediaPlayerDevice):
return self._muted
@property
def supported_media_commands(self):
"""Flag of media commands that are supported."""
def supported_features(self):
"""Flag media player features that are supported."""
if self._mac:
return SUPPORT_VIERATV | SUPPORT_TURN_ON
return SUPPORT_VIERATV

View file

@ -158,8 +158,8 @@ class PandoraMediaPlayer(MediaPlayerDevice):
self.schedule_update_ha_state()
@property
def supported_media_commands(self):
"""Show what this supports."""
def supported_features(self):
"""Flag media player features that are supported."""
return PANDORA_SUPPORT
@property

View file

@ -86,8 +86,8 @@ class PhilipsTV(MediaPlayerDevice):
return True
@property
def supported_media_commands(self):
"""Flag of media commands that are supported."""
def supported_features(self):
"""Flag media player features that are supported."""
if self._watching_tv:
return SUPPORT_PHILIPS_JS_TV
else:

View file

@ -176,8 +176,8 @@ class PioneerDevice(MediaPlayerDevice):
return self._muted
@property
def supported_media_commands(self):
"""Flag of media commands that are supported."""
def supported_features(self):
"""Flag media player features that are supported."""
return SUPPORT_PIONEER
@property

View file

@ -334,8 +334,8 @@ class PlexClient(MediaPlayerDevice):
return self._convert_na_to_none(self.session.index)
@property
def supported_media_commands(self):
"""Flag of media commands that are supported."""
def supported_features(self):
"""Flag media player features that are supported."""
return SUPPORT_PLEX
def set_volume_level(self, volume):

View file

@ -142,8 +142,8 @@ class RokuDevice(MediaPlayerDevice):
return STATE_UNKNOWN
@property
def supported_media_commands(self):
"""Flag of media commands that are supported."""
def supported_features(self):
"""Flag media player features that are supported."""
return SUPPORT_ROKU
@property

View file

@ -95,8 +95,8 @@ class RussoundRNETDevice(MediaPlayerDevice):
return self._state
@property
def supported_media_commands(self):
"""Flag of media commands that are supported."""
def supported_features(self):
"""Flag media player features that are supported."""
return SUPPORT_RUSSOUND
@property

View file

@ -156,8 +156,8 @@ class SamsungTVDevice(MediaPlayerDevice):
return self._muted
@property
def supported_media_commands(self):
"""Flag of media commands that are supported."""
def supported_features(self):
"""Flag media player features that are supported."""
return SUPPORT_SAMSUNGTV
def turn_off(self):

View file

@ -72,8 +72,8 @@ class SnapcastDevice(MediaPlayerDevice):
return self._client.muted
@property
def supported_media_commands(self):
"""Flag of media commands that are supported."""
def supported_features(self):
"""Flag media player features that are supported."""
return SUPPORT_SNAPCAST
@property

View file

@ -761,10 +761,10 @@ class SonosDevice(MediaPlayerDevice):
return self._media_title
@property
def supported_media_commands(self):
"""Flag of media commands that are supported."""
def supported_features(self):
"""Flag media player features that are supported."""
if self._coordinator:
return self._coordinator.supported_media_commands
return self._coordinator.supported_features
supported = SUPPORT_SONOS

View file

@ -287,8 +287,8 @@ class SoundTouchDevice(MediaPlayerDevice):
return self._volume.muted
@property
def supported_media_commands(self):
"""Flag of media commands that are supported."""
def supported_features(self):
"""Flag media player features that are supported."""
return SUPPORT_SOUNDTOUCH
def turn_off(self):

View file

@ -302,8 +302,8 @@ class SqueezeBoxDevice(MediaPlayerDevice):
return self._status['album']
@property
def supported_media_commands(self):
"""Flag of media commands that are supported."""
def supported_features(self):
"""Flag media player features that are supported."""
return SUPPORT_SQUEEZEBOX
def async_turn_off(self):

View file

@ -17,7 +17,7 @@ from homeassistant.components.media_player import (
ATTR_MEDIA_PLAYLIST, ATTR_MEDIA_SEASON, ATTR_MEDIA_SEEK_POSITION,
ATTR_MEDIA_SERIES_TITLE, ATTR_MEDIA_TITLE, ATTR_MEDIA_TRACK,
ATTR_MEDIA_VOLUME_LEVEL, ATTR_MEDIA_VOLUME_MUTED, ATTR_INPUT_SOURCE_LIST,
ATTR_SUPPORTED_MEDIA_COMMANDS, ATTR_MEDIA_POSITION,
ATTR_MEDIA_POSITION,
ATTR_MEDIA_POSITION_UPDATED_AT, DOMAIN, SERVICE_PLAY_MEDIA,
SUPPORT_TURN_OFF, SUPPORT_TURN_ON, SUPPORT_VOLUME_MUTE, SUPPORT_VOLUME_SET,
SUPPORT_VOLUME_STEP, SUPPORT_SELECT_SOURCE, SUPPORT_CLEAR_PLAYLIST,
@ -29,7 +29,7 @@ from homeassistant.const import (
SERVICE_MEDIA_PREVIOUS_TRACK, SERVICE_MEDIA_SEEK, SERVICE_TURN_OFF,
SERVICE_TURN_ON, SERVICE_VOLUME_DOWN, SERVICE_VOLUME_MUTE,
SERVICE_VOLUME_SET, SERVICE_VOLUME_UP, STATE_IDLE, STATE_OFF, STATE_ON,
SERVICE_MEDIA_STOP)
SERVICE_MEDIA_STOP, ATTR_SUPPORTED_FEATURES)
from homeassistant.helpers.event import async_track_state_change
from homeassistant.helpers.service import async_call_from_config
@ -357,9 +357,9 @@ class UniversalMediaPlayer(MediaPlayerDevice):
return self._override_or_child_attr(ATTR_INPUT_SOURCE_LIST)
@property
def supported_media_commands(self):
"""Flag media commands that are supported."""
flags = self._child_attr(ATTR_SUPPORTED_MEDIA_COMMANDS) or 0
def supported_features(self):
"""Flag media player features that are supported."""
flags = self._child_attr(ATTR_SUPPORTED_FEATURES) or 0
if SERVICE_TURN_ON in self._cmds:
flags |= SUPPORT_TURN_ON

View file

@ -97,8 +97,8 @@ class VlcDevice(MediaPlayerDevice):
return self._muted
@property
def supported_media_commands(self):
"""Flag of media commands that are supported."""
def supported_features(self):
"""Flag media player features that are supported."""
return SUPPORT_VLC
@property

View file

@ -244,8 +244,8 @@ class LgWebOSDevice(MediaPlayerDevice):
return None
@property
def supported_media_commands(self):
"""Flag of media commands that are supported."""
def supported_features(self):
"""Flag media player features that are supported."""
if self._mac:
return SUPPORT_WEBOSTV | SUPPORT_TURN_ON
return SUPPORT_WEBOSTV

View file

@ -181,9 +181,9 @@ class YamahaDevice(MediaPlayerDevice):
return self._source_list
@property
def supported_media_commands(self):
"""Flag of media commands that are supported."""
supported_commands = SUPPORT_YAMAHA
def supported_features(self):
"""Flag media player features that are supported."""
supported_features = SUPPORT_YAMAHA
supports = self._playback_support
mapping = {'play': (SUPPORT_PLAY | SUPPORT_PLAY_MEDIA),
@ -193,8 +193,8 @@ class YamahaDevice(MediaPlayerDevice):
'skip_r': SUPPORT_PREVIOUS_TRACK}
for attr, feature in mapping.items():
if getattr(supports, attr, False):
supported_commands |= feature
return supported_commands
supported_features |= feature
return supported_features
def turn_off(self):
"""Turn off media player."""

View file

@ -286,6 +286,9 @@ ATTR_STATE = 'state'
ATTR_OPTION = 'option'
# Bitfield of supported component features for the entity
ATTR_SUPPORTED_FEATURES = 'supported_features'
# #### SERVICES ####
SERVICE_HOMEASSISTANT_STOP = 'stop'
SERVICE_HOMEASSISTANT_RESTART = 'restart'

View file

@ -10,7 +10,7 @@ from homeassistant.const import (
ATTR_ASSUMED_STATE, ATTR_FRIENDLY_NAME, ATTR_HIDDEN, ATTR_ICON,
ATTR_UNIT_OF_MEASUREMENT, DEVICE_DEFAULT_NAME, STATE_OFF, STATE_ON,
STATE_UNAVAILABLE, STATE_UNKNOWN, TEMP_CELSIUS, TEMP_FAHRENHEIT,
ATTR_ENTITY_PICTURE)
ATTR_ENTITY_PICTURE, ATTR_SUPPORTED_FEATURES)
from homeassistant.core import HomeAssistant, DOMAIN as CORE_DOMAIN
from homeassistant.exceptions import NoEntitySpecifiedError
from homeassistant.util import ensure_unique_string, slugify
@ -148,6 +148,11 @@ class Entity(object):
"""
return False
@property
def supported_features(self) -> int:
"""Flag supported features."""
return None
def update(self):
"""Retrieve latest state.
@ -231,6 +236,8 @@ class Entity(object):
self._attr_setter('entity_picture', str, ATTR_ENTITY_PICTURE, attr)
self._attr_setter('hidden', bool, ATTR_HIDDEN, attr)
self._attr_setter('assumed_state', bool, ATTR_ASSUMED_STATE, attr)
self._attr_setter('supported_features', int, ATTR_SUPPORTED_FEATURES,
attr)
end = timer()

View file

@ -301,7 +301,7 @@ def test_put_light_state_fan(hass_hue, hue_client):
blocking=True)
# Emulated hue converts 0-100% to 0-255.
level = 23
level = 43
brightness = round(level * 255 / 100)
fan_result = yield from perform_put_light_state(

View file

@ -155,28 +155,28 @@ class TestDemoMediaPlayer(unittest.TestCase):
state = self.hass.states.get(entity_id)
assert 1 == state.attributes.get('media_track')
assert 0 == (mp.SUPPORT_PREVIOUS_TRACK &
state.attributes.get('supported_media_commands'))
state.attributes.get('supported_features'))
mp.media_next_track(self.hass, entity_id)
self.hass.block_till_done()
state = self.hass.states.get(entity_id)
assert 2 == state.attributes.get('media_track')
assert 0 < (mp.SUPPORT_PREVIOUS_TRACK &
state.attributes.get('supported_media_commands'))
state.attributes.get('supported_features'))
mp.media_next_track(self.hass, entity_id)
self.hass.block_till_done()
state = self.hass.states.get(entity_id)
assert 3 == state.attributes.get('media_track')
assert 0 < (mp.SUPPORT_PREVIOUS_TRACK &
state.attributes.get('supported_media_commands'))
state.attributes.get('supported_features'))
mp.media_previous_track(self.hass, entity_id)
self.hass.block_till_done()
state = self.hass.states.get(entity_id)
assert 2 == state.attributes.get('media_track')
assert 0 < (mp.SUPPORT_PREVIOUS_TRACK &
state.attributes.get('supported_media_commands'))
state.attributes.get('supported_features'))
assert setup_component(
self.hass, mp.DOMAIN,
@ -185,21 +185,21 @@ class TestDemoMediaPlayer(unittest.TestCase):
state = self.hass.states.get(ent_id)
assert 1 == state.attributes.get('media_episode')
assert 0 == (mp.SUPPORT_PREVIOUS_TRACK &
state.attributes.get('supported_media_commands'))
state.attributes.get('supported_features'))
mp.media_next_track(self.hass, ent_id)
self.hass.block_till_done()
state = self.hass.states.get(ent_id)
assert 2 == state.attributes.get('media_episode')
assert 0 < (mp.SUPPORT_PREVIOUS_TRACK &
state.attributes.get('supported_media_commands'))
state.attributes.get('supported_features'))
mp.media_previous_track(self.hass, ent_id)
self.hass.block_till_done()
state = self.hass.states.get(ent_id)
assert 1 == state.attributes.get('media_episode')
assert 0 == (mp.SUPPORT_PREVIOUS_TRACK &
state.attributes.get('supported_media_commands'))
state.attributes.get('supported_features'))
@patch('homeassistant.components.media_player.demo.DemoYoutubePlayer.'
'media_seek', autospec=True)
@ -211,21 +211,21 @@ class TestDemoMediaPlayer(unittest.TestCase):
ent_id = 'media_player.living_room'
state = self.hass.states.get(ent_id)
assert 0 < (mp.SUPPORT_PLAY_MEDIA &
state.attributes.get('supported_media_commands'))
state.attributes.get('supported_features'))
assert state.attributes.get('media_content_id') is not None
mp.play_media(self.hass, None, 'some_id', ent_id)
self.hass.block_till_done()
state = self.hass.states.get(ent_id)
assert 0 < (mp.SUPPORT_PLAY_MEDIA &
state.attributes.get('supported_media_commands'))
state.attributes.get('supported_features'))
assert not 'some_id' == state.attributes.get('media_content_id')
mp.play_media(self.hass, 'youtube', 'some_id', ent_id)
self.hass.block_till_done()
state = self.hass.states.get(ent_id)
assert 0 < (mp.SUPPORT_PLAY_MEDIA &
state.attributes.get('supported_media_commands'))
state.attributes.get('supported_features'))
assert 'some_id' == state.attributes.get('media_content_id')
assert not mock_seek.called

View file

@ -318,7 +318,7 @@ class TestSoundtouchMediaPlayer(unittest.TestCase):
default_component(),
mock.MagicMock())
self.assertEqual(mocked_sountouch_device.call_count, 1)
self.assertEqual(soundtouch.DEVICES[0].supported_media_commands, 17853)
self.assertEqual(soundtouch.DEVICES[0].supported_features, 17853)
@mock.patch('libsoundtouch.device.SoundTouchDevice.power_off')
@mock.patch('libsoundtouch.device.SoundTouchDevice.volume')

View file

@ -27,7 +27,7 @@ class MockMediaPlayer(media_player.MediaPlayerDevice):
self._volume_level = 0
self._is_volume_muted = False
self._media_title = None
self._supported_media_commands = 0
self._supported_features = 0
self._source = None
self._tracks = 12
self._media_image_url = None
@ -91,9 +91,9 @@ class MockMediaPlayer(media_player.MediaPlayerDevice):
return self._is_volume_muted
@property
def supported_media_commands(self):
"""Supported media commands flag."""
return self._supported_media_commands
def supported_features(self):
"""Flag media player features that are supported."""
return self._supported_features
@property
def media_image_url(self):
@ -502,7 +502,7 @@ class TestMediaPlayer(unittest.TestCase):
self.hass.states.set(self.mock_mute_switch_id, STATE_ON)
self.assertTrue(ump.is_volume_muted)
def test_supported_media_commands_children_only(self):
def test_supported_features_children_only(self):
"""Test supported media commands with only children."""
config = self.config_children_only
universal.validate_config(config)
@ -511,15 +511,15 @@ class TestMediaPlayer(unittest.TestCase):
ump.entity_id = media_player.ENTITY_ID_FORMAT.format(config['name'])
run_coroutine_threadsafe(ump.async_update(), self.hass.loop).result()
self.assertEqual(0, ump.supported_media_commands)
self.assertEqual(0, ump.supported_features)
self.mock_mp_1._supported_media_commands = 512
self.mock_mp_1._supported_features = 512
self.mock_mp_1._state = STATE_PLAYING
self.mock_mp_1.update_ha_state()
run_coroutine_threadsafe(ump.async_update(), self.hass.loop).result()
self.assertEqual(512, ump.supported_media_commands)
self.assertEqual(512, ump.supported_features)
def test_supported_media_commands_children_and_cmds(self):
def test_supported_features_children_and_cmds(self):
"""Test supported media commands with children and attrs."""
config = self.config_children_and_attr
universal.validate_config(config)
@ -543,7 +543,7 @@ class TestMediaPlayer(unittest.TestCase):
| universal.SUPPORT_VOLUME_STEP | universal.SUPPORT_VOLUME_MUTE \
| universal.SUPPORT_SELECT_SOURCE
self.assertEqual(check_flags, ump.supported_media_commands)
self.assertEqual(check_flags, ump.supported_features)
def test_service_call_no_active_child(self):
"""Test a service call to children with no active child."""