diff --git a/homeassistant/components/demo/media_player.py b/homeassistant/components/demo/media_player.py index 661e218a1ad..f3046a6f807 100644 --- a/homeassistant/components/demo/media_player.py +++ b/homeassistant/components/demo/media_player.py @@ -10,24 +10,7 @@ from homeassistant.components.media_player.const import ( MEDIA_TYPE_MUSIC, MEDIA_TYPE_TVSHOW, REPEAT_MODE_OFF, - SUPPORT_CLEAR_PLAYLIST, - SUPPORT_GROUPING, - SUPPORT_NEXT_TRACK, - SUPPORT_PAUSE, - SUPPORT_PLAY, - SUPPORT_PLAY_MEDIA, - SUPPORT_PREVIOUS_TRACK, - SUPPORT_REPEAT_SET, - SUPPORT_SEEK, - SUPPORT_SELECT_SOUND_MODE, - SUPPORT_SELECT_SOURCE, - SUPPORT_SHUFFLE_SET, - SUPPORT_STOP, - SUPPORT_TURN_OFF, - SUPPORT_TURN_ON, - SUPPORT_VOLUME_MUTE, - SUPPORT_VOLUME_SET, - SUPPORT_VOLUME_STEP, + MediaPlayerEntityFeature, ) from homeassistant.config_entries import ConfigEntry from homeassistant.const import STATE_OFF, STATE_PAUSED, STATE_PLAYING @@ -75,48 +58,48 @@ SOUND_MODE_LIST = ["Music", "Movie"] DEFAULT_SOUND_MODE = "Music" YOUTUBE_PLAYER_SUPPORT = ( - SUPPORT_PAUSE - | SUPPORT_VOLUME_SET - | SUPPORT_VOLUME_MUTE - | SUPPORT_TURN_ON - | SUPPORT_TURN_OFF - | SUPPORT_PLAY_MEDIA - | SUPPORT_PLAY - | SUPPORT_SHUFFLE_SET - | SUPPORT_SELECT_SOUND_MODE - | SUPPORT_SEEK - | SUPPORT_STOP + MediaPlayerEntityFeature.PAUSE + | MediaPlayerEntityFeature.VOLUME_SET + | MediaPlayerEntityFeature.VOLUME_MUTE + | MediaPlayerEntityFeature.TURN_ON + | MediaPlayerEntityFeature.TURN_OFF + | MediaPlayerEntityFeature.PLAY_MEDIA + | MediaPlayerEntityFeature.PLAY + | MediaPlayerEntityFeature.SHUFFLE_SET + | MediaPlayerEntityFeature.SELECT_SOUND_MODE + | MediaPlayerEntityFeature.SEEK + | MediaPlayerEntityFeature.STOP ) MUSIC_PLAYER_SUPPORT = ( - SUPPORT_PAUSE - | SUPPORT_VOLUME_SET - | SUPPORT_VOLUME_MUTE - | SUPPORT_TURN_ON - | SUPPORT_TURN_OFF - | SUPPORT_CLEAR_PLAYLIST - | SUPPORT_GROUPING - | SUPPORT_PLAY - | SUPPORT_SHUFFLE_SET - | SUPPORT_REPEAT_SET - | SUPPORT_VOLUME_STEP - | SUPPORT_PREVIOUS_TRACK - | SUPPORT_NEXT_TRACK - | SUPPORT_SELECT_SOUND_MODE - | SUPPORT_STOP + MediaPlayerEntityFeature.PAUSE + | MediaPlayerEntityFeature.VOLUME_SET + | MediaPlayerEntityFeature.VOLUME_MUTE + | MediaPlayerEntityFeature.TURN_ON + | MediaPlayerEntityFeature.TURN_OFF + | MediaPlayerEntityFeature.CLEAR_PLAYLIST + | MediaPlayerEntityFeature.GROUPING + | MediaPlayerEntityFeature.PLAY + | MediaPlayerEntityFeature.SHUFFLE_SET + | MediaPlayerEntityFeature.REPEAT_SET + | MediaPlayerEntityFeature.VOLUME_STEP + | MediaPlayerEntityFeature.PREVIOUS_TRACK + | MediaPlayerEntityFeature.NEXT_TRACK + | MediaPlayerEntityFeature.SELECT_SOUND_MODE + | MediaPlayerEntityFeature.STOP ) NETFLIX_PLAYER_SUPPORT = ( - SUPPORT_PAUSE - | SUPPORT_TURN_ON - | SUPPORT_TURN_OFF - | SUPPORT_SELECT_SOURCE - | SUPPORT_PLAY - | SUPPORT_SHUFFLE_SET - | SUPPORT_PREVIOUS_TRACK - | SUPPORT_NEXT_TRACK - | SUPPORT_SELECT_SOUND_MODE - | SUPPORT_STOP + MediaPlayerEntityFeature.PAUSE + | MediaPlayerEntityFeature.TURN_ON + | MediaPlayerEntityFeature.TURN_OFF + | MediaPlayerEntityFeature.SELECT_SOURCE + | MediaPlayerEntityFeature.PLAY + | MediaPlayerEntityFeature.SHUFFLE_SET + | MediaPlayerEntityFeature.PREVIOUS_TRACK + | MediaPlayerEntityFeature.NEXT_TRACK + | MediaPlayerEntityFeature.SELECT_SOUND_MODE + | MediaPlayerEntityFeature.STOP ) diff --git a/homeassistant/components/media_player/__init__.py b/homeassistant/components/media_player/__init__.py index 99d493a75c4..8cd8cad2956 100644 --- a/homeassistant/components/media_player/__init__.py +++ b/homeassistant/components/media_player/__init__.py @@ -126,6 +126,7 @@ from .const import ( # noqa: F401 SUPPORT_VOLUME_MUTE, SUPPORT_VOLUME_SET, SUPPORT_VOLUME_STEP, + MediaPlayerEntityFeature, ) from .errors import BrowseError @@ -241,52 +242,61 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: await component.async_setup(config) component.async_register_entity_service( - SERVICE_TURN_ON, {}, "async_turn_on", [SUPPORT_TURN_ON] + SERVICE_TURN_ON, {}, "async_turn_on", [MediaPlayerEntityFeature.TURN_ON] ) component.async_register_entity_service( - SERVICE_TURN_OFF, {}, "async_turn_off", [SUPPORT_TURN_OFF] + SERVICE_TURN_OFF, {}, "async_turn_off", [MediaPlayerEntityFeature.TURN_OFF] ) component.async_register_entity_service( - SERVICE_TOGGLE, {}, "async_toggle", [SUPPORT_TURN_OFF | SUPPORT_TURN_ON] + SERVICE_TOGGLE, + {}, + "async_toggle", + [MediaPlayerEntityFeature.TURN_OFF | MediaPlayerEntityFeature.TURN_ON], ) component.async_register_entity_service( SERVICE_VOLUME_UP, {}, "async_volume_up", - [SUPPORT_VOLUME_SET, SUPPORT_VOLUME_STEP], + [MediaPlayerEntityFeature.VOLUME_SET, MediaPlayerEntityFeature.VOLUME_STEP], ) component.async_register_entity_service( SERVICE_VOLUME_DOWN, {}, "async_volume_down", - [SUPPORT_VOLUME_SET, SUPPORT_VOLUME_STEP], + [MediaPlayerEntityFeature.VOLUME_SET, MediaPlayerEntityFeature.VOLUME_STEP], ) component.async_register_entity_service( SERVICE_MEDIA_PLAY_PAUSE, {}, "async_media_play_pause", - [SUPPORT_PLAY | SUPPORT_PAUSE], + [MediaPlayerEntityFeature.PLAY | MediaPlayerEntityFeature.PAUSE], ) component.async_register_entity_service( - SERVICE_MEDIA_PLAY, {}, "async_media_play", [SUPPORT_PLAY] + SERVICE_MEDIA_PLAY, {}, "async_media_play", [MediaPlayerEntityFeature.PLAY] ) component.async_register_entity_service( - SERVICE_MEDIA_PAUSE, {}, "async_media_pause", [SUPPORT_PAUSE] + SERVICE_MEDIA_PAUSE, {}, "async_media_pause", [MediaPlayerEntityFeature.PAUSE] ) component.async_register_entity_service( - SERVICE_MEDIA_STOP, {}, "async_media_stop", [SUPPORT_STOP] + SERVICE_MEDIA_STOP, {}, "async_media_stop", [MediaPlayerEntityFeature.STOP] ) component.async_register_entity_service( - SERVICE_MEDIA_NEXT_TRACK, {}, "async_media_next_track", [SUPPORT_NEXT_TRACK] + SERVICE_MEDIA_NEXT_TRACK, + {}, + "async_media_next_track", + [MediaPlayerEntityFeature.NEXT_TRACK], ) component.async_register_entity_service( SERVICE_MEDIA_PREVIOUS_TRACK, {}, "async_media_previous_track", - [SUPPORT_PREVIOUS_TRACK], + [MediaPlayerEntityFeature.PREVIOUS_TRACK], ) component.async_register_entity_service( - SERVICE_CLEAR_PLAYLIST, {}, "async_clear_playlist", [SUPPORT_CLEAR_PLAYLIST] + SERVICE_CLEAR_PLAYLIST, + {}, + "async_clear_playlist", + [MediaPlayerEntityFeature.CLEAR_PLAYLIST], ) component.async_register_entity_service( SERVICE_VOLUME_SET, @@ -297,7 +307,7 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: _rename_keys(volume=ATTR_MEDIA_VOLUME_LEVEL), ), "async_set_volume_level", - [SUPPORT_VOLUME_SET], + [MediaPlayerEntityFeature.VOLUME_SET], ) component.async_register_entity_service( SERVICE_VOLUME_MUTE, @@ -308,7 +318,7 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: _rename_keys(mute=ATTR_MEDIA_VOLUME_MUTED), ), "async_mute_volume", - [SUPPORT_VOLUME_MUTE], + [MediaPlayerEntityFeature.VOLUME_MUTE], ) component.async_register_entity_service( SERVICE_MEDIA_SEEK, @@ -319,25 +329,25 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: _rename_keys(position=ATTR_MEDIA_SEEK_POSITION), ), "async_media_seek", - [SUPPORT_SEEK], + [MediaPlayerEntityFeature.SEEK], ) component.async_register_entity_service( SERVICE_JOIN, {vol.Required(ATTR_GROUP_MEMBERS): vol.All(cv.ensure_list, [cv.entity_id])}, "async_join_players", - [SUPPORT_GROUPING], + [MediaPlayerEntityFeature.GROUPING], ) component.async_register_entity_service( SERVICE_SELECT_SOURCE, {vol.Required(ATTR_INPUT_SOURCE): cv.string}, "async_select_source", - [SUPPORT_SELECT_SOURCE], + [MediaPlayerEntityFeature.SELECT_SOURCE], ) component.async_register_entity_service( SERVICE_SELECT_SOUND_MODE, {vol.Required(ATTR_SOUND_MODE): cv.string}, "async_select_sound_mode", - [SUPPORT_SELECT_SOUND_MODE], + [MediaPlayerEntityFeature.SELECT_SOUND_MODE], ) component.async_register_entity_service( SERVICE_PLAY_MEDIA, @@ -350,23 +360,23 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: ), ), "async_play_media", - [SUPPORT_PLAY_MEDIA], + [MediaPlayerEntityFeature.PLAY_MEDIA], ) component.async_register_entity_service( SERVICE_SHUFFLE_SET, {vol.Required(ATTR_MEDIA_SHUFFLE): cv.boolean}, "async_set_shuffle", - [SUPPORT_SHUFFLE_SET], + [MediaPlayerEntityFeature.SHUFFLE_SET], ) component.async_register_entity_service( - SERVICE_UNJOIN, {}, "async_unjoin_player", [SUPPORT_GROUPING] + SERVICE_UNJOIN, {}, "async_unjoin_player", [MediaPlayerEntityFeature.GROUPING] ) component.async_register_entity_service( SERVICE_REPEAT_SET, {vol.Required(ATTR_MEDIA_REPEAT): vol.In(REPEAT_MODES)}, "async_set_repeat", - [SUPPORT_REPEAT_SET], + [MediaPlayerEntityFeature.REPEAT_SET], ) return True @@ -766,72 +776,74 @@ class MediaPlayerEntity(Entity): @property def support_play(self): """Boolean if play is supported.""" - return bool(self.supported_features & SUPPORT_PLAY) + return bool(self.supported_features & MediaPlayerEntityFeature.PLAY) @property def support_pause(self): """Boolean if pause is supported.""" - return bool(self.supported_features & SUPPORT_PAUSE) + return bool(self.supported_features & MediaPlayerEntityFeature.PAUSE) @property def support_stop(self): """Boolean if stop is supported.""" - return bool(self.supported_features & SUPPORT_STOP) + return bool(self.supported_features & MediaPlayerEntityFeature.STOP) @property def support_seek(self): """Boolean if seek is supported.""" - return bool(self.supported_features & SUPPORT_SEEK) + return bool(self.supported_features & MediaPlayerEntityFeature.SEEK) @property def support_volume_set(self): """Boolean if setting volume is supported.""" - return bool(self.supported_features & SUPPORT_VOLUME_SET) + return bool(self.supported_features & MediaPlayerEntityFeature.VOLUME_SET) @property def support_volume_mute(self): """Boolean if muting volume is supported.""" - return bool(self.supported_features & SUPPORT_VOLUME_MUTE) + return bool(self.supported_features & MediaPlayerEntityFeature.VOLUME_MUTE) @property def support_previous_track(self): """Boolean if previous track command supported.""" - return bool(self.supported_features & SUPPORT_PREVIOUS_TRACK) + return bool(self.supported_features & MediaPlayerEntityFeature.PREVIOUS_TRACK) @property def support_next_track(self): """Boolean if next track command supported.""" - return bool(self.supported_features & SUPPORT_NEXT_TRACK) + return bool(self.supported_features & MediaPlayerEntityFeature.NEXT_TRACK) @property def support_play_media(self): """Boolean if play media command supported.""" - return bool(self.supported_features & SUPPORT_PLAY_MEDIA) + return bool(self.supported_features & MediaPlayerEntityFeature.PLAY_MEDIA) @property def support_select_source(self): """Boolean if select source command supported.""" - return bool(self.supported_features & SUPPORT_SELECT_SOURCE) + return bool(self.supported_features & MediaPlayerEntityFeature.SELECT_SOURCE) @property def support_select_sound_mode(self): """Boolean if select sound mode command supported.""" - return bool(self.supported_features & SUPPORT_SELECT_SOUND_MODE) + return bool( + self.supported_features & MediaPlayerEntityFeature.SELECT_SOUND_MODE + ) @property def support_clear_playlist(self): """Boolean if clear playlist command supported.""" - return bool(self.supported_features & SUPPORT_CLEAR_PLAYLIST) + return bool(self.supported_features & MediaPlayerEntityFeature.CLEAR_PLAYLIST) @property def support_shuffle_set(self): """Boolean if shuffle is supported.""" - return bool(self.supported_features & SUPPORT_SHUFFLE_SET) + return bool(self.supported_features & MediaPlayerEntityFeature.SHUFFLE_SET) @property def support_grouping(self): """Boolean if player grouping is supported.""" - return bool(self.supported_features & SUPPORT_GROUPING) + return bool(self.supported_features & MediaPlayerEntityFeature.GROUPING) async def async_toggle(self): """Toggle the power on the media player.""" @@ -853,7 +865,10 @@ class MediaPlayerEntity(Entity): await self.hass.async_add_executor_job(self.volume_up) return - if self.volume_level < 1 and self.supported_features & SUPPORT_VOLUME_SET: + if ( + self.volume_level < 1 + and self.supported_features & MediaPlayerEntityFeature.VOLUME_SET + ): await self.async_set_volume_level(min(1, self.volume_level + 0.1)) async def async_volume_down(self): @@ -865,7 +880,10 @@ class MediaPlayerEntity(Entity): await self.hass.async_add_executor_job(self.volume_down) return - if self.volume_level > 0 and self.supported_features & SUPPORT_VOLUME_SET: + if ( + self.volume_level > 0 + and self.supported_features & MediaPlayerEntityFeature.VOLUME_SET + ): await self.async_set_volume_level(max(0, self.volume_level - 0.1)) async def async_media_play_pause(self): @@ -907,12 +925,12 @@ class MediaPlayerEntity(Entity): supported_features = self.supported_features or 0 data = {} - if supported_features & SUPPORT_SELECT_SOURCE and ( + if supported_features & MediaPlayerEntityFeature.SELECT_SOURCE and ( source_list := self.source_list ): data[ATTR_INPUT_SOURCE_LIST] = source_list - if supported_features & SUPPORT_SELECT_SOUND_MODE and ( + if supported_features & MediaPlayerEntityFeature.SELECT_SOUND_MODE and ( sound_mode_list := self.sound_mode_list ): data[ATTR_SOUND_MODE_LIST] = sound_mode_list @@ -1147,7 +1165,7 @@ async def websocket_browse_media(hass, connection, msg): connection.send_error(msg["id"], "entity_not_found", "Entity not found") return - if not player.supported_features & SUPPORT_BROWSE_MEDIA: + if not player.supported_features & MediaPlayerEntityFeature.BROWSE_MEDIA: connection.send_message( websocket_api.error_message( msg["id"], ERR_NOT_SUPPORTED, "Player does not support browsing media" diff --git a/homeassistant/components/media_player/const.py b/homeassistant/components/media_player/const.py index e7b16f6ac88..fcb706250cc 100644 --- a/homeassistant/components/media_player/const.py +++ b/homeassistant/components/media_player/const.py @@ -1,4 +1,6 @@ """Provides the constants needed for component.""" +from enum import IntEnum + # How long our auth signature on the content should be valid for CONTENT_AUTH_EXPIRY_TIME = 3600 * 24 @@ -89,6 +91,34 @@ REPEAT_MODE_OFF = "off" REPEAT_MODE_ONE = "one" REPEAT_MODES = [REPEAT_MODE_OFF, REPEAT_MODE_ALL, REPEAT_MODE_ONE] + +class MediaPlayerEntityFeature(IntEnum): + """Supported features of the media player entity.""" + + PAUSE = 1 + SEEK = 2 + VOLUME_SET = 4 + VOLUME_MUTE = 8 + PREVIOUS_TRACK = 16 + NEXT_TRACK = 32 + + TURN_ON = 128 + TURN_OFF = 256 + PLAY_MEDIA = 512 + VOLUME_STEP = 1024 + SELECT_SOURCE = 2048 + STOP = 4096 + CLEAR_PLAYLIST = 8192 + PLAY = 16384 + SHUFFLE_SET = 32768 + SELECT_SOUND_MODE = 65536 + BROWSE_MEDIA = 131072 + REPEAT_SET = 262144 + GROUPING = 524288 + + +# These SUPPORT_* constants are deprecated as of Home Assistant 2022.5. +# Please use the MediaPlayerEntityFeature enum instead. SUPPORT_PAUSE = 1 SUPPORT_SEEK = 2 SUPPORT_VOLUME_SET = 4 diff --git a/tests/components/demo/test_media_player.py b/tests/components/demo/test_media_player.py index 4a40795613f..dc54b27a2c2 100644 --- a/tests/components/demo/test_media_player.py +++ b/tests/components/demo/test_media_player.py @@ -336,7 +336,11 @@ async def test_play_media(hass): ent_id = "media_player.living_room" state = hass.states.get(ent_id) - assert mp.SUPPORT_PLAY_MEDIA & state.attributes.get(ATTR_SUPPORTED_FEATURES) > 0 + assert ( + mp.MediaPlayerEntityFeature.PLAY_MEDIA + & state.attributes.get(ATTR_SUPPORTED_FEATURES) + > 0 + ) assert state.attributes.get(mp.ATTR_MEDIA_CONTENT_ID) is not None with pytest.raises(vol.Invalid): @@ -347,7 +351,11 @@ async def test_play_media(hass): blocking=True, ) state = hass.states.get(ent_id) - assert mp.SUPPORT_PLAY_MEDIA & state.attributes.get(ATTR_SUPPORTED_FEATURES) > 0 + assert ( + mp.MediaPlayerEntityFeature.PLAY_MEDIA + & state.attributes.get(ATTR_SUPPORTED_FEATURES) + > 0 + ) assert state.attributes.get(mp.ATTR_MEDIA_CONTENT_ID) != "some_id" await hass.services.async_call( @@ -361,7 +369,11 @@ async def test_play_media(hass): blocking=True, ) state = hass.states.get(ent_id) - assert mp.SUPPORT_PLAY_MEDIA & state.attributes.get(ATTR_SUPPORTED_FEATURES) > 0 + assert ( + mp.MediaPlayerEntityFeature.PLAY_MEDIA + & state.attributes.get(ATTR_SUPPORTED_FEATURES) + > 0 + ) assert state.attributes.get(mp.ATTR_MEDIA_CONTENT_ID) == "some_id" @@ -374,7 +386,7 @@ async def test_seek(hass, mock_media_seek): ent_id = "media_player.living_room" state = hass.states.get(ent_id) - assert state.attributes[ATTR_SUPPORTED_FEATURES] & mp.SUPPORT_SEEK + assert state.attributes[ATTR_SUPPORTED_FEATURES] & mp.MediaPlayerEntityFeature.SEEK assert not mock_media_seek.called with pytest.raises(vol.Invalid): diff --git a/tests/components/media_player/test_async_helpers.py b/tests/components/media_player/test_async_helpers.py index dac35c71515..53c80bfc8de 100644 --- a/tests/components/media_player/test_async_helpers.py +++ b/tests/components/media_player/test_async_helpers.py @@ -34,12 +34,12 @@ class ExtendedMediaPlayer(mp.MediaPlayerEntity): 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 + mp.const.MediaPlayerEntityFeature.VOLUME_SET + | mp.const.MediaPlayerEntityFeature.VOLUME_STEP + | mp.const.MediaPlayerEntityFeature.PLAY + | mp.const.MediaPlayerEntityFeature.PAUSE + | mp.const.MediaPlayerEntityFeature.TURN_OFF + | mp.const.MediaPlayerEntityFeature.TURN_ON ) def set_volume_level(self, volume): @@ -110,12 +110,12 @@ class SimpleMediaPlayer(mp.MediaPlayerEntity): 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 + mp.const.MediaPlayerEntityFeature.VOLUME_SET + | mp.const.MediaPlayerEntityFeature.VOLUME_STEP + | mp.const.MediaPlayerEntityFeature.PLAY + | mp.const.MediaPlayerEntityFeature.PAUSE + | mp.const.MediaPlayerEntityFeature.TURN_OFF + | mp.const.MediaPlayerEntityFeature.TURN_ON ) def set_volume_level(self, volume): diff --git a/tests/components/media_player/test_init.py b/tests/components/media_player/test_init.py index a725129bed6..aa5e1b164f4 100644 --- a/tests/components/media_player/test_init.py +++ b/tests/components/media_player/test_init.py @@ -164,7 +164,7 @@ async def test_media_browse(hass, hass_ws_client): with patch( "homeassistant.components.demo.media_player.YOUTUBE_PLAYER_SUPPORT", - media_player.SUPPORT_BROWSE_MEDIA, + media_player.MediaPlayerEntityFeature.BROWSE_MEDIA, ), patch( "homeassistant.components.media_player.MediaPlayerEntity.async_browse_media", return_value=BrowseMedia( @@ -207,7 +207,7 @@ async def test_media_browse(hass, hass_ws_client): with patch( "homeassistant.components.demo.media_player.YOUTUBE_PLAYER_SUPPORT", - media_player.SUPPORT_BROWSE_MEDIA, + media_player.MediaPlayerEntityFeature.BROWSE_MEDIA, ), patch( "homeassistant.components.media_player.MediaPlayerEntity.async_browse_media", return_value={"bla": "yo"}, @@ -238,7 +238,8 @@ async def test_group_members_available_when_off(hass): # Fake group support for DemoYoutubePlayer with patch( "homeassistant.components.demo.media_player.YOUTUBE_PLAYER_SUPPORT", - media_player.SUPPORT_GROUPING | media_player.SUPPORT_TURN_OFF, + media_player.MediaPlayerEntityFeature.GROUPING + | media_player.MediaPlayerEntityFeature.TURN_OFF, ): await hass.services.async_call( "media_player",