From e88ea2d48ca0556d20e7b61ee98f36668910ea40 Mon Sep 17 00:00:00 2001 From: Erik Montnemery Date: Mon, 15 Nov 2021 20:13:43 +0100 Subject: [PATCH] Show cast as playing when an app without media support is active (#59714) --- homeassistant/components/cast/media_player.py | 13 ++-- tests/components/cast/test_media_player.py | 62 +++++++++++++------ 2 files changed, 49 insertions(+), 26 deletions(-) diff --git a/homeassistant/components/cast/media_player.py b/homeassistant/components/cast/media_player.py index 310431bb488..cfaf8843865 100644 --- a/homeassistant/components/cast/media_player.py +++ b/homeassistant/components/cast/media_player.py @@ -79,11 +79,7 @@ _LOGGER = logging.getLogger(__name__) CAST_SPLASH = "https://www.home-assistant.io/images/cast/splash.png" -SUPPORT_CAST = ( - SUPPORT_PAUSE | SUPPORT_PLAY | SUPPORT_PLAY_MEDIA | SUPPORT_STOP | SUPPORT_TURN_OFF -) - -STATE_CASTING = "casting" +SUPPORT_CAST = SUPPORT_PLAY_MEDIA | SUPPORT_TURN_OFF ENTITY_SCHEMA = vol.All( vol.Schema( @@ -567,7 +563,7 @@ class CastDevice(MediaPlayerEntity): """Return the state of the player.""" # The lovelace app loops media to prevent timing out, don't show that if self.app_id == CAST_APP_ID_HOMEASSISTANT_LOVELACE: - return STATE_CASTING + return STATE_PLAYING if (media_status := self._media_status()[0]) is not None: if media_status.player_is_playing: return STATE_PLAYING @@ -576,7 +572,7 @@ class CastDevice(MediaPlayerEntity): if media_status.player_is_idle: return STATE_IDLE if self.app_id is not None and self.app_id != pychromecast.IDLE_APP_ID: - return STATE_CASTING + return STATE_PLAYING if self._chromecast is not None and self._chromecast.is_idle: return STATE_OFF return None @@ -701,7 +697,8 @@ class CastDevice(MediaPlayerEntity): ): support |= SUPPORT_VOLUME_MUTE | SUPPORT_VOLUME_SET - if media_status: + if media_status and self.app_id != CAST_APP_ID_HOMEASSISTANT_LOVELACE: + support |= SUPPORT_PAUSE | SUPPORT_PLAY | SUPPORT_STOP if media_status.supports_queue_next: support |= SUPPORT_PREVIOUS_TRACK | SUPPORT_NEXT_TRACK if media_status.supports_seek: diff --git a/tests/components/cast/test_media_player.py b/tests/components/cast/test_media_player.py index 3bb9cbf2316..a038cb34aea 100644 --- a/tests/components/cast/test_media_player.py +++ b/tests/components/cast/test_media_player.py @@ -605,11 +605,9 @@ async def test_entity_cast_status(hass: HomeAssistant): assert state.state == "off" assert entity_id == reg.async_get_entity_id("media_player", "cast", full_info.uuid) + # No media status, pause, play, stop not supported assert state.attributes.get("supported_features") == ( - SUPPORT_PAUSE - | SUPPORT_PLAY - | SUPPORT_PLAY_MEDIA - | SUPPORT_STOP + SUPPORT_PLAY_MEDIA | SUPPORT_TURN_OFF | SUPPORT_TURN_ON | SUPPORT_VOLUME_MUTE @@ -652,17 +650,12 @@ async def test_entity_cast_status(hass: HomeAssistant): await hass.async_block_till_done() state = hass.states.get(entity_id) assert state.attributes.get("supported_features") == ( - SUPPORT_PAUSE - | SUPPORT_PLAY - | SUPPORT_PLAY_MEDIA - | SUPPORT_STOP - | SUPPORT_TURN_OFF - | SUPPORT_TURN_ON + SUPPORT_PLAY_MEDIA | SUPPORT_TURN_OFF | SUPPORT_TURN_ON ) @pytest.mark.parametrize( - "cast_type,supported_features", + "cast_type,supported_features,supported_features_no_media", [ ( pychromecast.const.CAST_TYPE_AUDIO, @@ -673,6 +666,10 @@ async def test_entity_cast_status(hass: HomeAssistant): | SUPPORT_TURN_OFF | SUPPORT_VOLUME_MUTE | SUPPORT_VOLUME_SET, + SUPPORT_PLAY_MEDIA + | SUPPORT_TURN_OFF + | SUPPORT_VOLUME_MUTE + | SUPPORT_VOLUME_SET, ), ( pychromecast.const.CAST_TYPE_CHROMECAST, @@ -684,6 +681,11 @@ async def test_entity_cast_status(hass: HomeAssistant): | SUPPORT_TURN_ON | SUPPORT_VOLUME_MUTE | SUPPORT_VOLUME_SET, + SUPPORT_PLAY_MEDIA + | SUPPORT_TURN_OFF + | SUPPORT_TURN_ON + | SUPPORT_VOLUME_MUTE + | SUPPORT_VOLUME_SET, ), ( pychromecast.const.CAST_TYPE_GROUP, @@ -694,10 +696,16 @@ async def test_entity_cast_status(hass: HomeAssistant): | SUPPORT_TURN_OFF | SUPPORT_VOLUME_MUTE | SUPPORT_VOLUME_SET, + SUPPORT_PLAY_MEDIA + | SUPPORT_TURN_OFF + | SUPPORT_VOLUME_MUTE + | SUPPORT_VOLUME_SET, ), ], ) -async def test_supported_features(hass: HomeAssistant, cast_type, supported_features): +async def test_supported_features( + hass: HomeAssistant, cast_type, supported_features, supported_features_no_media +): """Test supported features.""" entity_id = "media_player.speaker" @@ -705,7 +713,7 @@ async def test_supported_features(hass: HomeAssistant, cast_type, supported_feat chromecast, _ = await async_setup_media_player_cast(hass, info) chromecast.cast_type = cast_type - _, conn_status_cb, _ = get_status_callbacks(chromecast) + _, conn_status_cb, media_status_cb = get_status_callbacks(chromecast) connection_status = MagicMock() connection_status.status = "CONNECTED" @@ -716,7 +724,14 @@ async def test_supported_features(hass: HomeAssistant, cast_type, supported_feat assert state is not None assert state.name == "Speaker" assert state.state == "off" + assert state.attributes.get("supported_features") == supported_features_no_media + media_status = MagicMock(images=None) + media_status.supports_queue_next = False + media_status.supports_seek = False + media_status_cb(media_status) + await hass.async_block_till_done() + state = hass.states.get(entity_id) assert state.attributes.get("supported_features") == supported_features @@ -935,15 +950,23 @@ async def test_entity_control(hass: HomeAssistant): chromecast.cast_type = pychromecast.const.CAST_TYPE_CHROMECAST _, conn_status_cb, media_status_cb = get_status_callbacks(chromecast) + # Fake connection status connection_status = MagicMock() connection_status.status = "CONNECTED" conn_status_cb(connection_status) await hass.async_block_till_done() + # Fake media status + media_status = MagicMock(images=None) + media_status.supports_queue_next = False + media_status.supports_seek = False + media_status_cb(media_status) + await hass.async_block_till_done() + state = hass.states.get(entity_id) assert state is not None assert state.name == "Speaker" - assert state.state == "off" + assert state.state == "playing" assert entity_id == reg.async_get_entity_id("media_player", "cast", full_info.uuid) assert state.attributes.get("supported_features") == ( @@ -1119,28 +1142,31 @@ async def test_entity_media_states_lovelace_app(hass: HomeAssistant): cast_status_cb(cast_status) await hass.async_block_till_done() state = hass.states.get(entity_id) - assert state.state == "casting" + assert state.state == "playing" + assert state.attributes.get("supported_features") == ( + SUPPORT_PLAY_MEDIA | SUPPORT_TURN_OFF | SUPPORT_VOLUME_MUTE | SUPPORT_VOLUME_SET + ) media_status = MagicMock(images=None) media_status.player_is_playing = True media_status_cb(media_status) await hass.async_block_till_done() state = hass.states.get(entity_id) - assert state.state == "casting" + assert state.state == "playing" media_status.player_is_playing = False media_status.player_is_paused = True media_status_cb(media_status) await hass.async_block_till_done() state = hass.states.get(entity_id) - assert state.state == "casting" + assert state.state == "playing" media_status.player_is_paused = False media_status.player_is_idle = True media_status_cb(media_status) await hass.async_block_till_done() state = hass.states.get(entity_id) - assert state.state == "casting" + assert state.state == "playing" chromecast.app_id = pychromecast.IDLE_APP_ID media_status.player_is_idle = False