From f7c41e694cf431c75fbe749a3efbe768125f9f4e Mon Sep 17 00:00:00 2001 From: Markus Jacobsen Date: Thu, 27 Nov 2025 15:53:43 +0100 Subject: [PATCH] Add media content id attribute to Bang & Olufsen (#156597) --- .../components/bang_olufsen/const.py | 14 ++ .../components/bang_olufsen/media_player.py | 55 +++-- tests/components/bang_olufsen/const.py | 1 + .../snapshots/test_media_player.ambr | 198 +++++++++--------- .../bang_olufsen/test_media_player.py | 47 ++++- 5 files changed, 192 insertions(+), 123 deletions(-) diff --git a/homeassistant/components/bang_olufsen/const.py b/homeassistant/components/bang_olufsen/const.py index 59d7adcfc78..2dd168ff8a1 100644 --- a/homeassistant/components/bang_olufsen/const.py +++ b/homeassistant/components/bang_olufsen/const.py @@ -17,8 +17,12 @@ from homeassistant.components.media_player import ( class BangOlufsenSource: """Class used for associating device source ids with friendly names. May not include all sources.""" + DEEZER: Final[Source] = Source(name="Deezer", id="deezer") LINE_IN: Final[Source] = Source(name="Line-In", id="lineIn") + NET_RADIO: Final[Source] = Source(name="B&O Radio", id="netRadio") SPDIF: Final[Source] = Source(name="Optical", id="spdif") + TIDAL: Final[Source] = Source(name="Tidal", id="tidal") + UNKNOWN: Final[Source] = Source(name="Unknown Source", id="unknown") URI_STREAMER: Final[Source] = Source(name="Audio Streamer", id="uriStreamer") @@ -78,6 +82,16 @@ class BangOlufsenModel(StrEnum): BEOREMOTE_ONE = "Beoremote One" +class BangOlufsenAttribute(StrEnum): + """Enum for extra_state_attribute keys.""" + + BEOLINK = "beolink" + BEOLINK_PEERS = "peers" + BEOLINK_SELF = "self" + BEOLINK_LEADER = "leader" + BEOLINK_LISTENERS = "listeners" + + # Physical "buttons" on devices class BangOlufsenButtons(StrEnum): """Enum for device buttons.""" diff --git a/homeassistant/components/bang_olufsen/media_player.py b/homeassistant/components/bang_olufsen/media_player.py index e3060680c35..618c0f1808d 100644 --- a/homeassistant/components/bang_olufsen/media_player.py +++ b/homeassistant/components/bang_olufsen/media_player.py @@ -82,6 +82,7 @@ from .const import ( FALLBACK_SOURCES, MANUFACTURER, VALID_MEDIA_TYPES, + BangOlufsenAttribute, BangOlufsenMediaType, BangOlufsenSource, WebsocketNotification, @@ -224,7 +225,8 @@ class BangOlufsenMediaPlayer(BangOlufsenEntity, MediaPlayerEntity): # Beolink compatible sources self._beolink_sources: dict[str, bool] = {} self._remote_leader: BeolinkLeader | None = None - # Extra state attributes for showing Beolink: peer(s), listener(s), leader and self + # Extra state attributes: + # Beolink: peer(s), listener(s), leader and self self._beolink_attributes: dict[str, dict[str, dict[str, str]]] = {} async def async_added_to_hass(self) -> None: @@ -436,7 +438,10 @@ class BangOlufsenMediaPlayer(BangOlufsenEntity, MediaPlayerEntity): await self._async_update_beolink() async def _async_update_beolink(self) -> None: - """Update the current Beolink leader, listeners, peers and self.""" + """Update the current Beolink leader, listeners, peers and self. + + Updates Home Assistant state. + """ self._beolink_attributes = {} @@ -445,18 +450,24 @@ class BangOlufsenMediaPlayer(BangOlufsenEntity, MediaPlayerEntity): # Add Beolink self self._beolink_attributes = { - "beolink": {"self": {self.device_entry.name: self._beolink_jid}} + BangOlufsenAttribute.BEOLINK: { + BangOlufsenAttribute.BEOLINK_SELF: { + self.device_entry.name: self._beolink_jid + } + } } # Add Beolink peers peers = await self._client.get_beolink_peers() if len(peers) > 0: - self._beolink_attributes["beolink"]["peers"] = {} + self._beolink_attributes[BangOlufsenAttribute.BEOLINK][ + BangOlufsenAttribute.BEOLINK_PEERS + ] = {} for peer in peers: - self._beolink_attributes["beolink"]["peers"][peer.friendly_name] = ( - peer.jid - ) + self._beolink_attributes[BangOlufsenAttribute.BEOLINK][ + BangOlufsenAttribute.BEOLINK_PEERS + ][peer.friendly_name] = peer.jid # Add Beolink listeners / leader self._remote_leader = self._playback_metadata.remote_leader @@ -477,7 +488,9 @@ class BangOlufsenMediaPlayer(BangOlufsenEntity, MediaPlayerEntity): # Add self group_members.append(self.entity_id) - self._beolink_attributes["beolink"]["leader"] = { + self._beolink_attributes[BangOlufsenAttribute.BEOLINK][ + BangOlufsenAttribute.BEOLINK_LEADER + ] = { self._remote_leader.friendly_name: self._remote_leader.jid, } @@ -514,9 +527,9 @@ class BangOlufsenMediaPlayer(BangOlufsenEntity, MediaPlayerEntity): beolink_listener.jid ) break - self._beolink_attributes["beolink"]["listeners"] = ( - beolink_listeners_attribute - ) + self._beolink_attributes[BangOlufsenAttribute.BEOLINK][ + BangOlufsenAttribute.BEOLINK_LISTENERS + ] = beolink_listeners_attribute self._attr_group_members = group_members @@ -615,11 +628,18 @@ class BangOlufsenMediaPlayer(BangOlufsenEntity, MediaPlayerEntity): return None @property - def media_content_type(self) -> str: + def media_content_type(self) -> MediaType | str | None: """Return the current media type.""" - # Hard to determine content type - if self._source_change.id == BangOlufsenSource.URI_STREAMER.id: - return MediaType.URL + content_type = { + BangOlufsenSource.URI_STREAMER.id: MediaType.URL, + BangOlufsenSource.DEEZER.id: BangOlufsenMediaType.DEEZER, + BangOlufsenSource.TIDAL.id: BangOlufsenMediaType.TIDAL, + BangOlufsenSource.NET_RADIO.id: BangOlufsenMediaType.RADIO, + } + # Hard to determine content type. + if self._source_change.id in content_type: + return content_type[self._source_change.id] + return MediaType.MUSIC @property @@ -632,6 +652,11 @@ class BangOlufsenMediaPlayer(BangOlufsenEntity, MediaPlayerEntity): """Return the current playback progress.""" return self._playback_progress.progress + @property + def media_content_id(self) -> str | None: + """Return internal ID of Deezer, Tidal and radio stations.""" + return self._playback_metadata.source_internal_id + @property def media_image_url(self) -> str | None: """Return URL of the currently playing music.""" diff --git a/tests/components/bang_olufsen/const.py b/tests/components/bang_olufsen/const.py index 4596971a8b1..213c6720b15 100644 --- a/tests/components/bang_olufsen/const.py +++ b/tests/components/bang_olufsen/const.py @@ -168,6 +168,7 @@ TEST_PLAYBACK_METADATA = PlaybackContentMetadata( title="Test title", total_duration_seconds=123, track=1, + source_internal_id="123", ) TEST_PLAYBACK_ERROR = PlaybackError(error="Test error") TEST_PLAYBACK_PROGRESS = PlaybackProgress(progress=123) diff --git a/tests/components/bang_olufsen/snapshots/test_media_player.ambr b/tests/components/bang_olufsen/snapshots/test_media_player.ambr index 4a1688f6a3c..c7fea881345 100644 --- a/tests/components/bang_olufsen/snapshots/test_media_player.ambr +++ b/tests/components/bang_olufsen/snapshots/test_media_player.ambr @@ -2,16 +2,16 @@ # name: test_async_beolink_allstandby StateSnapshot({ 'attributes': ReadOnlyDict({ - 'beolink': dict({ - 'listeners': dict({ + : dict({ + : dict({ 'Bedroom Premiere': '1111.1111111.33333333@products.bang-olufsen.com', 'Lounge room Balance': '1111.1111111.44444444@products.bang-olufsen.com', }), - 'peers': dict({ + : dict({ 'Bedroom Premiere': '1111.1111111.33333333@products.bang-olufsen.com', 'Lounge room Balance': '1111.1111111.44444444@products.bang-olufsen.com', }), - 'self': dict({ + : dict({ 'Living room Balance': '1111.1111111.11111111@products.bang-olufsen.com', }), }), @@ -50,16 +50,16 @@ # name: test_async_beolink_expand[all_discovered-True-None-log_messages0-3] StateSnapshot({ 'attributes': ReadOnlyDict({ - 'beolink': dict({ - 'listeners': dict({ + : dict({ + : dict({ 'Bedroom Premiere': '1111.1111111.33333333@products.bang-olufsen.com', 'Lounge room Balance': '1111.1111111.44444444@products.bang-olufsen.com', }), - 'peers': dict({ + : dict({ 'Bedroom Premiere': '1111.1111111.33333333@products.bang-olufsen.com', 'Lounge room Balance': '1111.1111111.44444444@products.bang-olufsen.com', }), - 'self': dict({ + : dict({ 'Living room Balance': '1111.1111111.11111111@products.bang-olufsen.com', }), }), @@ -71,7 +71,7 @@ 'listener_not_in_hass-1111.1111111.33333333@products.bang-olufsen.com', 'listener_not_in_hass-1111.1111111.44444444@products.bang-olufsen.com', ]), - 'media_content_type': , + 'media_content_type': , 'repeat': , 'shuffle': False, 'sound_mode': 'Test Listening Mode (123)', @@ -99,16 +99,16 @@ # name: test_async_beolink_expand[all_discovered-True-expand_side_effect1-log_messages1-3] StateSnapshot({ 'attributes': ReadOnlyDict({ - 'beolink': dict({ - 'listeners': dict({ + : dict({ + : dict({ 'Bedroom Premiere': '1111.1111111.33333333@products.bang-olufsen.com', 'Lounge room Balance': '1111.1111111.44444444@products.bang-olufsen.com', }), - 'peers': dict({ + : dict({ 'Bedroom Premiere': '1111.1111111.33333333@products.bang-olufsen.com', 'Lounge room Balance': '1111.1111111.44444444@products.bang-olufsen.com', }), - 'self': dict({ + : dict({ 'Living room Balance': '1111.1111111.11111111@products.bang-olufsen.com', }), }), @@ -120,7 +120,7 @@ 'listener_not_in_hass-1111.1111111.33333333@products.bang-olufsen.com', 'listener_not_in_hass-1111.1111111.44444444@products.bang-olufsen.com', ]), - 'media_content_type': , + 'media_content_type': , 'repeat': , 'shuffle': False, 'sound_mode': 'Test Listening Mode (123)', @@ -148,16 +148,16 @@ # name: test_async_beolink_expand[beolink_jids-parameter_value2-None-log_messages2-2] StateSnapshot({ 'attributes': ReadOnlyDict({ - 'beolink': dict({ - 'listeners': dict({ + : dict({ + : dict({ 'Bedroom Premiere': '1111.1111111.33333333@products.bang-olufsen.com', 'Lounge room Balance': '1111.1111111.44444444@products.bang-olufsen.com', }), - 'peers': dict({ + : dict({ 'Bedroom Premiere': '1111.1111111.33333333@products.bang-olufsen.com', 'Lounge room Balance': '1111.1111111.44444444@products.bang-olufsen.com', }), - 'self': dict({ + : dict({ 'Living room Balance': '1111.1111111.11111111@products.bang-olufsen.com', }), }), @@ -169,7 +169,7 @@ 'listener_not_in_hass-1111.1111111.33333333@products.bang-olufsen.com', 'listener_not_in_hass-1111.1111111.44444444@products.bang-olufsen.com', ]), - 'media_content_type': , + 'media_content_type': , 'repeat': , 'shuffle': False, 'sound_mode': 'Test Listening Mode (123)', @@ -197,16 +197,16 @@ # name: test_async_beolink_expand[beolink_jids-parameter_value3-expand_side_effect3-log_messages3-2] StateSnapshot({ 'attributes': ReadOnlyDict({ - 'beolink': dict({ - 'listeners': dict({ + : dict({ + : dict({ 'Bedroom Premiere': '1111.1111111.33333333@products.bang-olufsen.com', 'Lounge room Balance': '1111.1111111.44444444@products.bang-olufsen.com', }), - 'peers': dict({ + : dict({ 'Bedroom Premiere': '1111.1111111.33333333@products.bang-olufsen.com', 'Lounge room Balance': '1111.1111111.44444444@products.bang-olufsen.com', }), - 'self': dict({ + : dict({ 'Living room Balance': '1111.1111111.11111111@products.bang-olufsen.com', }), }), @@ -218,7 +218,7 @@ 'listener_not_in_hass-1111.1111111.33333333@products.bang-olufsen.com', 'listener_not_in_hass-1111.1111111.44444444@products.bang-olufsen.com', ]), - 'media_content_type': , + 'media_content_type': , 'repeat': , 'shuffle': False, 'sound_mode': 'Test Listening Mode (123)', @@ -246,16 +246,16 @@ # name: test_async_beolink_join[service_parameters0-method_parameters0] StateSnapshot({ 'attributes': ReadOnlyDict({ - 'beolink': dict({ - 'listeners': dict({ + : dict({ + : dict({ 'Bedroom Premiere': '1111.1111111.33333333@products.bang-olufsen.com', 'Lounge room Balance': '1111.1111111.44444444@products.bang-olufsen.com', }), - 'peers': dict({ + : dict({ 'Bedroom Premiere': '1111.1111111.33333333@products.bang-olufsen.com', 'Lounge room Balance': '1111.1111111.44444444@products.bang-olufsen.com', }), - 'self': dict({ + : dict({ 'Living room Balance': '1111.1111111.11111111@products.bang-olufsen.com', }), }), @@ -294,16 +294,16 @@ # name: test_async_beolink_join[service_parameters1-method_parameters1] StateSnapshot({ 'attributes': ReadOnlyDict({ - 'beolink': dict({ - 'listeners': dict({ + : dict({ + : dict({ 'Bedroom Premiere': '1111.1111111.33333333@products.bang-olufsen.com', 'Lounge room Balance': '1111.1111111.44444444@products.bang-olufsen.com', }), - 'peers': dict({ + : dict({ 'Bedroom Premiere': '1111.1111111.33333333@products.bang-olufsen.com', 'Lounge room Balance': '1111.1111111.44444444@products.bang-olufsen.com', }), - 'self': dict({ + : dict({ 'Living room Balance': '1111.1111111.11111111@products.bang-olufsen.com', }), }), @@ -342,16 +342,16 @@ # name: test_async_beolink_join[service_parameters2-method_parameters2] StateSnapshot({ 'attributes': ReadOnlyDict({ - 'beolink': dict({ - 'listeners': dict({ + : dict({ + : dict({ 'Bedroom Premiere': '1111.1111111.33333333@products.bang-olufsen.com', 'Lounge room Balance': '1111.1111111.44444444@products.bang-olufsen.com', }), - 'peers': dict({ + : dict({ 'Bedroom Premiere': '1111.1111111.33333333@products.bang-olufsen.com', 'Lounge room Balance': '1111.1111111.44444444@products.bang-olufsen.com', }), - 'self': dict({ + : dict({ 'Living room Balance': '1111.1111111.11111111@products.bang-olufsen.com', }), }), @@ -390,16 +390,16 @@ # name: test_async_beolink_join_invalid[service_parameters0-expected_result0] StateSnapshot({ 'attributes': ReadOnlyDict({ - 'beolink': dict({ - 'listeners': dict({ + : dict({ + : dict({ 'Bedroom Premiere': '1111.1111111.33333333@products.bang-olufsen.com', 'Lounge room Balance': '1111.1111111.44444444@products.bang-olufsen.com', }), - 'peers': dict({ + : dict({ 'Bedroom Premiere': '1111.1111111.33333333@products.bang-olufsen.com', 'Lounge room Balance': '1111.1111111.44444444@products.bang-olufsen.com', }), - 'self': dict({ + : dict({ 'Living room Balance': '1111.1111111.11111111@products.bang-olufsen.com', }), }), @@ -438,16 +438,16 @@ # name: test_async_beolink_join_invalid[service_parameters1-expected_result1] StateSnapshot({ 'attributes': ReadOnlyDict({ - 'beolink': dict({ - 'listeners': dict({ + : dict({ + : dict({ 'Bedroom Premiere': '1111.1111111.33333333@products.bang-olufsen.com', 'Lounge room Balance': '1111.1111111.44444444@products.bang-olufsen.com', }), - 'peers': dict({ + : dict({ 'Bedroom Premiere': '1111.1111111.33333333@products.bang-olufsen.com', 'Lounge room Balance': '1111.1111111.44444444@products.bang-olufsen.com', }), - 'self': dict({ + : dict({ 'Living room Balance': '1111.1111111.11111111@products.bang-olufsen.com', }), }), @@ -486,16 +486,16 @@ # name: test_async_beolink_join_invalid[service_parameters2-expected_result2] StateSnapshot({ 'attributes': ReadOnlyDict({ - 'beolink': dict({ - 'listeners': dict({ + : dict({ + : dict({ 'Bedroom Premiere': '1111.1111111.33333333@products.bang-olufsen.com', 'Lounge room Balance': '1111.1111111.44444444@products.bang-olufsen.com', }), - 'peers': dict({ + : dict({ 'Bedroom Premiere': '1111.1111111.33333333@products.bang-olufsen.com', 'Lounge room Balance': '1111.1111111.44444444@products.bang-olufsen.com', }), - 'self': dict({ + : dict({ 'Living room Balance': '1111.1111111.11111111@products.bang-olufsen.com', }), }), @@ -534,16 +534,16 @@ # name: test_async_beolink_unexpand StateSnapshot({ 'attributes': ReadOnlyDict({ - 'beolink': dict({ - 'listeners': dict({ + : dict({ + : dict({ 'Bedroom Premiere': '1111.1111111.33333333@products.bang-olufsen.com', 'Lounge room Balance': '1111.1111111.44444444@products.bang-olufsen.com', }), - 'peers': dict({ + : dict({ 'Bedroom Premiere': '1111.1111111.33333333@products.bang-olufsen.com', 'Lounge room Balance': '1111.1111111.44444444@products.bang-olufsen.com', }), - 'self': dict({ + : dict({ 'Living room Balance': '1111.1111111.11111111@products.bang-olufsen.com', }), }), @@ -582,16 +582,16 @@ # name: test_async_join_players[group_members0-1-0] StateSnapshot({ 'attributes': ReadOnlyDict({ - 'beolink': dict({ - 'listeners': dict({ + : dict({ + : dict({ 'Bedroom Premiere': '1111.1111111.33333333@products.bang-olufsen.com', 'Lounge room Balance': '1111.1111111.44444444@products.bang-olufsen.com', }), - 'peers': dict({ + : dict({ 'Bedroom Premiere': '1111.1111111.33333333@products.bang-olufsen.com', 'Lounge room Balance': '1111.1111111.44444444@products.bang-olufsen.com', }), - 'self': dict({ + : dict({ 'Living room Balance': '1111.1111111.11111111@products.bang-olufsen.com', }), }), @@ -603,7 +603,7 @@ 'listener_not_in_hass-1111.1111111.33333333@products.bang-olufsen.com', 'listener_not_in_hass-1111.1111111.44444444@products.bang-olufsen.com', ]), - 'media_content_type': , + 'media_content_type': , 'repeat': , 'shuffle': False, 'sound_mode': 'Test Listening Mode (123)', @@ -631,16 +631,16 @@ # name: test_async_join_players[group_members0-1-0].1 StateSnapshot({ 'attributes': ReadOnlyDict({ - 'beolink': dict({ - 'listeners': dict({ + : dict({ + : dict({ 'Bedroom Premiere': '1111.1111111.33333333@products.bang-olufsen.com', 'Lounge room Balance': '1111.1111111.44444444@products.bang-olufsen.com', }), - 'peers': dict({ + : dict({ 'Bedroom Premiere': '1111.1111111.33333333@products.bang-olufsen.com', 'Lounge room Balance': '1111.1111111.44444444@products.bang-olufsen.com', }), - 'self': dict({ + : dict({ 'Living room Balance': '1111.1111111.22222222@products.bang-olufsen.com', }), }), @@ -680,16 +680,16 @@ # name: test_async_join_players[group_members1-0-1] StateSnapshot({ 'attributes': ReadOnlyDict({ - 'beolink': dict({ - 'listeners': dict({ + : dict({ + : dict({ 'Bedroom Premiere': '1111.1111111.33333333@products.bang-olufsen.com', 'Lounge room Balance': '1111.1111111.44444444@products.bang-olufsen.com', }), - 'peers': dict({ + : dict({ 'Bedroom Premiere': '1111.1111111.33333333@products.bang-olufsen.com', 'Lounge room Balance': '1111.1111111.44444444@products.bang-olufsen.com', }), - 'self': dict({ + : dict({ 'Living room Balance': '1111.1111111.11111111@products.bang-olufsen.com', }), }), @@ -701,7 +701,7 @@ 'listener_not_in_hass-1111.1111111.33333333@products.bang-olufsen.com', 'listener_not_in_hass-1111.1111111.44444444@products.bang-olufsen.com', ]), - 'media_content_type': , + 'media_content_type': , 'repeat': , 'shuffle': False, 'sound_mode': 'Test Listening Mode (123)', @@ -729,16 +729,16 @@ # name: test_async_join_players[group_members1-0-1].1 StateSnapshot({ 'attributes': ReadOnlyDict({ - 'beolink': dict({ - 'listeners': dict({ + : dict({ + : dict({ 'Bedroom Premiere': '1111.1111111.33333333@products.bang-olufsen.com', 'Lounge room Balance': '1111.1111111.44444444@products.bang-olufsen.com', }), - 'peers': dict({ + : dict({ 'Bedroom Premiere': '1111.1111111.33333333@products.bang-olufsen.com', 'Lounge room Balance': '1111.1111111.44444444@products.bang-olufsen.com', }), - 'self': dict({ + : dict({ 'Living room Balance': '1111.1111111.22222222@products.bang-olufsen.com', }), }), @@ -778,16 +778,16 @@ # name: test_async_join_players_invalid[source0-group_members0-expected_result0-invalid_source] StateSnapshot({ 'attributes': ReadOnlyDict({ - 'beolink': dict({ - 'listeners': dict({ + : dict({ + : dict({ 'Bedroom Premiere': '1111.1111111.33333333@products.bang-olufsen.com', 'Lounge room Balance': '1111.1111111.44444444@products.bang-olufsen.com', }), - 'peers': dict({ + : dict({ 'Bedroom Premiere': '1111.1111111.33333333@products.bang-olufsen.com', 'Lounge room Balance': '1111.1111111.44444444@products.bang-olufsen.com', }), - 'self': dict({ + : dict({ 'Living room Balance': '1111.1111111.11111111@products.bang-olufsen.com', }), }), @@ -828,16 +828,16 @@ # name: test_async_join_players_invalid[source0-group_members0-expected_result0-invalid_source].1 StateSnapshot({ 'attributes': ReadOnlyDict({ - 'beolink': dict({ - 'listeners': dict({ + : dict({ + : dict({ 'Bedroom Premiere': '1111.1111111.33333333@products.bang-olufsen.com', 'Lounge room Balance': '1111.1111111.44444444@products.bang-olufsen.com', }), - 'peers': dict({ + : dict({ 'Bedroom Premiere': '1111.1111111.33333333@products.bang-olufsen.com', 'Lounge room Balance': '1111.1111111.44444444@products.bang-olufsen.com', }), - 'self': dict({ + : dict({ 'Living room Balance': '1111.1111111.22222222@products.bang-olufsen.com', }), }), @@ -877,16 +877,16 @@ # name: test_async_join_players_invalid[source1-group_members1-expected_result1-invalid_grouping_entity] StateSnapshot({ 'attributes': ReadOnlyDict({ - 'beolink': dict({ - 'listeners': dict({ + : dict({ + : dict({ 'Bedroom Premiere': '1111.1111111.33333333@products.bang-olufsen.com', 'Lounge room Balance': '1111.1111111.44444444@products.bang-olufsen.com', }), - 'peers': dict({ + : dict({ 'Bedroom Premiere': '1111.1111111.33333333@products.bang-olufsen.com', 'Lounge room Balance': '1111.1111111.44444444@products.bang-olufsen.com', }), - 'self': dict({ + : dict({ 'Living room Balance': '1111.1111111.11111111@products.bang-olufsen.com', }), }), @@ -898,7 +898,7 @@ 'listener_not_in_hass-1111.1111111.33333333@products.bang-olufsen.com', 'listener_not_in_hass-1111.1111111.44444444@products.bang-olufsen.com', ]), - 'media_content_type': , + 'media_content_type': , 'repeat': , 'shuffle': False, 'sound_mode': 'Test Listening Mode (123)', @@ -926,16 +926,16 @@ # name: test_async_join_players_invalid[source1-group_members1-expected_result1-invalid_grouping_entity].1 StateSnapshot({ 'attributes': ReadOnlyDict({ - 'beolink': dict({ - 'listeners': dict({ + : dict({ + : dict({ 'Bedroom Premiere': '1111.1111111.33333333@products.bang-olufsen.com', 'Lounge room Balance': '1111.1111111.44444444@products.bang-olufsen.com', }), - 'peers': dict({ + : dict({ 'Bedroom Premiere': '1111.1111111.33333333@products.bang-olufsen.com', 'Lounge room Balance': '1111.1111111.44444444@products.bang-olufsen.com', }), - 'self': dict({ + : dict({ 'Living room Balance': '1111.1111111.22222222@products.bang-olufsen.com', }), }), @@ -975,16 +975,16 @@ # name: test_async_unjoin_player StateSnapshot({ 'attributes': ReadOnlyDict({ - 'beolink': dict({ - 'listeners': dict({ + : dict({ + : dict({ 'Bedroom Premiere': '1111.1111111.33333333@products.bang-olufsen.com', 'Lounge room Balance': '1111.1111111.44444444@products.bang-olufsen.com', }), - 'peers': dict({ + : dict({ 'Bedroom Premiere': '1111.1111111.33333333@products.bang-olufsen.com', 'Lounge room Balance': '1111.1111111.44444444@products.bang-olufsen.com', }), - 'self': dict({ + : dict({ 'Living room Balance': '1111.1111111.11111111@products.bang-olufsen.com', }), }), @@ -1023,15 +1023,15 @@ # name: test_async_update_beolink_listener StateSnapshot({ 'attributes': ReadOnlyDict({ - 'beolink': dict({ - 'leader': dict({ + : dict({ + : dict({ 'Laundry room Core': '1111.1111111.22222222@products.bang-olufsen.com', }), - 'peers': dict({ + : dict({ 'Bedroom Premiere': '1111.1111111.33333333@products.bang-olufsen.com', 'Lounge room Balance': '1111.1111111.44444444@products.bang-olufsen.com', }), - 'self': dict({ + : dict({ 'Living room Balance': '1111.1111111.11111111@products.bang-olufsen.com', }), }), @@ -1069,16 +1069,16 @@ # name: test_async_update_beolink_listener.1 StateSnapshot({ 'attributes': ReadOnlyDict({ - 'beolink': dict({ - 'listeners': dict({ + : dict({ + : dict({ 'Bedroom Premiere': '1111.1111111.33333333@products.bang-olufsen.com', 'Lounge room Balance': '1111.1111111.44444444@products.bang-olufsen.com', }), - 'peers': dict({ + : dict({ 'Bedroom Premiere': '1111.1111111.33333333@products.bang-olufsen.com', 'Lounge room Balance': '1111.1111111.44444444@products.bang-olufsen.com', }), - 'self': dict({ + : dict({ 'Living room Balance': '1111.1111111.22222222@products.bang-olufsen.com', }), }), diff --git a/tests/components/bang_olufsen/test_media_player.py b/tests/components/bang_olufsen/test_media_player.py index a48f9f358ad..e2a72f363f1 100644 --- a/tests/components/bang_olufsen/test_media_player.py +++ b/tests/components/bang_olufsen/test_media_player.py @@ -24,6 +24,7 @@ from homeassistant.components.bang_olufsen.const import ( BANG_OLUFSEN_REPEAT_FROM_HA, BANG_OLUFSEN_STATES, DOMAIN, + BangOlufsenMediaType, BangOlufsenSource, ) from homeassistant.components.media_player import ( @@ -260,6 +261,7 @@ async def test_async_update_playback_metadata( assert ATTR_MEDIA_ALBUM_ARTIST not in states.attributes assert ATTR_MEDIA_TRACK not in states.attributes assert ATTR_MEDIA_CHANNEL not in states.attributes + assert ATTR_MEDIA_CONTENT_ID not in states.attributes # Send the WebSocket event dispatch playback_metadata_callback(TEST_PLAYBACK_METADATA) @@ -276,6 +278,12 @@ async def test_async_update_playback_metadata( ) assert states.attributes[ATTR_MEDIA_TRACK] == TEST_PLAYBACK_METADATA.track assert states.attributes[ATTR_MEDIA_CHANNEL] == TEST_PLAYBACK_METADATA.organization + assert states.attributes[ATTR_MEDIA_CHANNEL] == TEST_PLAYBACK_METADATA.organization + assert ( + states.attributes[ATTR_MEDIA_CONTENT_ID] + == TEST_PLAYBACK_METADATA.source_internal_id + ) + assert states.attributes[ATTR_MEDIA_CONTENT_TYPE] == MediaType.MUSIC async def test_async_update_playback_error( @@ -342,28 +350,47 @@ async def test_async_update_playback_state( @pytest.mark.parametrize( - ("source", "content_type", "progress", "metadata"), + ("source", "content_type", "progress", "metadata", "content_id_available"), [ - # Normal source, music mediatype expected - ( - TEST_SOURCE, - MediaType.MUSIC, - TEST_PLAYBACK_PROGRESS.progress, - PlaybackContentMetadata(), - ), # URI source, url media type expected ( BangOlufsenSource.URI_STREAMER, MediaType.URL, TEST_PLAYBACK_PROGRESS.progress, PlaybackContentMetadata(), + False, ), - # Line-In source,media type expected, progress 0 expected + # Line-In source, music media type expected, progress 0 expected ( BangOlufsenSource.LINE_IN, MediaType.MUSIC, 0, PlaybackContentMetadata(), + False, + ), + # Tidal source, tidal media type expected, media content id expected + ( + BangOlufsenSource.TIDAL, + BangOlufsenMediaType.TIDAL, + TEST_PLAYBACK_PROGRESS.progress, + PlaybackContentMetadata(source_internal_id="123"), + True, + ), + # Deezer source, deezer media type expected, media content id expected + ( + BangOlufsenSource.DEEZER, + BangOlufsenMediaType.DEEZER, + TEST_PLAYBACK_PROGRESS.progress, + PlaybackContentMetadata(source_internal_id="123"), + True, + ), + # Radio source, radio media type expected, media content id expected + ( + BangOlufsenSource.NET_RADIO, + BangOlufsenMediaType.RADIO, + TEST_PLAYBACK_PROGRESS.progress, + PlaybackContentMetadata(source_internal_id="123"), + True, ), ], ) @@ -375,6 +402,7 @@ async def test_async_update_source_change( content_type: MediaType, progress: int, metadata: PlaybackContentMetadata, + content_id_available: bool, ) -> None: """Test _async_update_source_change.""" playback_progress_callback = ( @@ -402,6 +430,7 @@ async def test_async_update_source_change( assert states.attributes[ATTR_INPUT_SOURCE] == source.name assert states.attributes[ATTR_MEDIA_CONTENT_TYPE] == content_type assert states.attributes[ATTR_MEDIA_POSITION] == progress + assert (ATTR_MEDIA_CONTENT_ID in states.attributes) == content_id_available async def test_async_turn_off(