diff --git a/homeassistant/components/cast/media_player.py b/homeassistant/components/cast/media_player.py index d8eacfeede41fdb303e996136ca0cbf967d73d62..dc3d20188e7458131812152d1850c3363fec1b36 100644 --- a/homeassistant/components/cast/media_player.py +++ b/homeassistant/components/cast/media_player.py @@ -46,6 +46,7 @@ from homeassistant.components.media_player.const import ( from homeassistant.components.plex.const import PLEX_URI_SCHEME from homeassistant.components.plex.services import lookup_plex_media from homeassistant.const import ( + CAST_APP_ID_HOMEASSISTANT_LOVELACE, CAST_APP_ID_HOMEASSISTANT_MEDIA, EVENT_HOMEASSISTANT_STOP, STATE_IDLE, @@ -87,6 +88,7 @@ SUPPORT_CAST = ( | SUPPORT_TURN_ON ) +STATE_CASTING = "casting" ENTITY_SCHEMA = vol.All( vol.Schema( @@ -568,14 +570,18 @@ class CastDevice(MediaPlayerEntity): @property def state(self): """Return the state of the player.""" - if (media_status := self._media_status()[0]) is None: - return None - if media_status.player_is_playing: - return STATE_PLAYING - if media_status.player_is_paused: - return STATE_PAUSED - if media_status.player_is_idle: - return STATE_IDLE + # 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 + if (media_status := self._media_status()[0]) is not None: + if media_status.player_is_playing: + return STATE_PLAYING + if media_status.player_is_paused: + return STATE_PAUSED + 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 if self._chromecast is not None and self._chromecast.is_idle: return STATE_OFF return None @@ -583,12 +589,18 @@ class CastDevice(MediaPlayerEntity): @property def media_content_id(self): """Content ID of current playing media.""" + # The lovelace app loops media to prevent timing out, don't show that + if self.app_id == CAST_APP_ID_HOMEASSISTANT_LOVELACE: + return None media_status = self._media_status()[0] return media_status.content_id if media_status else None @property def media_content_type(self): """Content type of current playing media.""" + # The lovelace app loops media to prevent timing out, don't show that + if self.app_id == CAST_APP_ID_HOMEASSISTANT_LOVELACE: + return None if (media_status := self._media_status()[0]) is None: return None if media_status.media_is_tvshow: @@ -602,6 +614,9 @@ class CastDevice(MediaPlayerEntity): @property def media_duration(self): """Duration of current playing media in seconds.""" + # The lovelace app loops media to prevent timing out, don't show that + if self.app_id == CAST_APP_ID_HOMEASSISTANT_LOVELACE: + return None media_status = self._media_status()[0] return media_status.duration if media_status else None @@ -699,6 +714,9 @@ class CastDevice(MediaPlayerEntity): @property def media_position(self): """Position of current playing media in seconds.""" + # The lovelace app loops media to prevent timing out, don't show that + if self.app_id == CAST_APP_ID_HOMEASSISTANT_LOVELACE: + return None media_status = self._media_status()[0] if media_status is None or not ( media_status.player_is_playing @@ -714,6 +732,8 @@ class CastDevice(MediaPlayerEntity): Returns value from homeassistant.util.dt.utcnow(). """ + if self.app_id == CAST_APP_ID_HOMEASSISTANT_LOVELACE: + return None media_status_recevied = self._media_status()[1] return media_status_recevied diff --git a/tests/components/cast/test_media_player.py b/tests/components/cast/test_media_player.py index 3bb2b895c1abff156273b1b35bbc5b2e9135f88e..48ed54cb76e7078bf307579a183a2acd667afe10 100644 --- a/tests/components/cast/test_media_player.py +++ b/tests/components/cast/test_media_player.py @@ -45,6 +45,7 @@ FakeGroupUUID = UUID("57355bce-9364-4aa6-ac1e-eb849dccf9e3") def get_fake_chromecast(info: ChromecastInfo): """Generate a Fake Chromecast object with the specified arguments.""" mock = MagicMock(uuid=info.uuid) + mock.app_id = None mock.media_controller.status = None return mock @@ -565,7 +566,7 @@ async def test_entity_availability(hass: HomeAssistant): conn_status_cb(connection_status) await hass.async_block_till_done() state = hass.states.get(entity_id) - assert state.state == "unknown" + assert state.state == "off" connection_status = MagicMock() connection_status.status = "DISCONNECTED" @@ -596,7 +597,7 @@ async def test_entity_cast_status(hass: HomeAssistant): state = hass.states.get(entity_id) assert state is not None assert state.name == "Speaker" - assert state.state == "unknown" + assert state.state == "off" assert entity_id == reg.async_get_entity_id("media_player", "cast", full_info.uuid) assert state.attributes.get("supported_features") == ( @@ -610,6 +611,17 @@ async def test_entity_cast_status(hass: HomeAssistant): | SUPPORT_VOLUME_SET ) + cast_status = MagicMock() + cast_status.volume_level = 0.5 + cast_status.volume_muted = False + cast_status_cb(cast_status) + await hass.async_block_till_done() + state = hass.states.get(entity_id) + # Volume hidden if no app is active + assert state.attributes.get("volume_level") is None + assert not state.attributes.get("is_volume_muted") + + chromecast.app_id = "1234" cast_status = MagicMock() cast_status.volume_level = 0.5 cast_status.volume_muted = False @@ -665,7 +677,7 @@ async def test_entity_play_media(hass: HomeAssistant): state = hass.states.get(entity_id) assert state is not None assert state.name == "Speaker" - assert state.state == "unknown" + assert state.state == "off" assert entity_id == reg.async_get_entity_id("media_player", "cast", full_info.uuid) # Play_media @@ -694,7 +706,7 @@ async def test_entity_play_media_cast(hass: HomeAssistant, quick_play_mock): state = hass.states.get(entity_id) assert state is not None assert state.name == "Speaker" - assert state.state == "unknown" + assert state.state == "off" assert entity_id == reg.async_get_entity_id("media_player", "cast", full_info.uuid) # Play_media - cast with app ID @@ -739,7 +751,7 @@ async def test_entity_play_media_cast_invalid(hass, caplog, quick_play_mock): state = hass.states.get(entity_id) assert state is not None assert state.name == "Speaker" - assert state.state == "unknown" + assert state.state == "off" assert entity_id == reg.async_get_entity_id("media_player", "cast", full_info.uuid) # play_media - media_type cast with invalid JSON @@ -812,7 +824,7 @@ async def test_entity_media_content_type(hass: HomeAssistant): state = hass.states.get(entity_id) assert state is not None assert state.name == "Speaker" - assert state.state == "unknown" + assert state.state == "off" assert entity_id == reg.async_get_entity_id("media_player", "cast", full_info.uuid) media_status = MagicMock(images=None) @@ -866,7 +878,7 @@ async def test_entity_control(hass: HomeAssistant): state = hass.states.get(entity_id) assert state is not None assert state.name == "Speaker" - assert state.state == "unknown" + assert state.state == "off" assert entity_id == reg.async_get_entity_id("media_player", "cast", full_info.uuid) assert state.attributes.get("supported_features") == ( @@ -975,7 +987,7 @@ async def test_entity_media_states(hass: HomeAssistant): state = hass.states.get(entity_id) assert state is not None assert state.name == "Speaker" - assert state.state == "unknown" + assert state.state == "off" assert entity_id == reg.async_get_entity_id("media_player", "cast", full_info.uuid) media_status = MagicMock(images=None) @@ -1036,7 +1048,7 @@ async def test_group_media_states(hass, mz_mock): state = hass.states.get(entity_id) assert state is not None assert state.name == "Speaker" - assert state.state == "unknown" + assert state.state == "off" assert entity_id == reg.async_get_entity_id("media_player", "cast", full_info.uuid) group_media_status = MagicMock(images=None) @@ -1090,7 +1102,7 @@ async def test_group_media_control(hass, mz_mock): state = hass.states.get(entity_id) assert state is not None assert state.name == "Speaker" - assert state.state == "unknown" + assert state.state == "off" assert entity_id == reg.async_get_entity_id("media_player", "cast", full_info.uuid) group_media_status = MagicMock(images=None)