mirror of
https://github.com/home-assistant/core.git
synced 2025-12-20 02:48:57 +00:00
Add video source reporting to Bang & Olufsen (#158675)
This commit is contained in:
@@ -22,6 +22,7 @@ class BeoSource:
|
||||
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")
|
||||
TV: Final[Source] = Source(name="TV", id="tv")
|
||||
UNKNOWN: Final[Source] = Source(name="Unknown Source", id="unknown")
|
||||
URI_STREAMER: Final[Source] = Source(name="Audio Streamer", id="uriStreamer")
|
||||
|
||||
@@ -55,12 +56,13 @@ BEO_REPEAT_TO_HA: dict[str, RepeatMode] = {
|
||||
class BeoMediaType(StrEnum):
|
||||
"""Bang & Olufsen specific media types."""
|
||||
|
||||
FAVOURITE = "favourite"
|
||||
DEEZER = "deezer"
|
||||
FAVOURITE = "favourite"
|
||||
OVERLAY_TTS = "overlay_tts"
|
||||
RADIO = "radio"
|
||||
TIDAL = "tidal"
|
||||
TTS = "provider"
|
||||
OVERLAY_TTS = "overlay_tts"
|
||||
TV = "tv"
|
||||
|
||||
|
||||
class BeoModel(StrEnum):
|
||||
|
||||
@@ -218,6 +218,7 @@ class BeoMediaPlayer(BeoEntity, MediaPlayerEntity):
|
||||
self._sources: dict[str, str] = {}
|
||||
self._state: str = MediaPlayerState.IDLE
|
||||
self._video_sources: dict[str, str] = {}
|
||||
self._video_source_id_map: dict[str, str] = {}
|
||||
self._sound_modes: dict[str, int] = {}
|
||||
|
||||
# Beolink compatible sources
|
||||
@@ -355,6 +356,9 @@ class BeoMediaPlayer(BeoEntity, MediaPlayerEntity):
|
||||
and menu_item.label != "TV"
|
||||
):
|
||||
self._video_sources[key] = menu_item.label
|
||||
self._video_source_id_map[
|
||||
menu_item.content.content_uri.removeprefix("tv://")
|
||||
] = menu_item.label
|
||||
|
||||
# Combine the source dicts
|
||||
self._sources = self._audio_sources | self._video_sources
|
||||
@@ -627,10 +631,11 @@ class BeoMediaPlayer(BeoEntity, MediaPlayerEntity):
|
||||
def media_content_type(self) -> MediaType | str | None:
|
||||
"""Return the current media type."""
|
||||
content_type = {
|
||||
BeoSource.URI_STREAMER.id: MediaType.URL,
|
||||
BeoSource.DEEZER.id: BeoMediaType.DEEZER,
|
||||
BeoSource.TIDAL.id: BeoMediaType.TIDAL,
|
||||
BeoSource.NET_RADIO.id: BeoMediaType.RADIO,
|
||||
BeoSource.TIDAL.id: BeoMediaType.TIDAL,
|
||||
BeoSource.TV.id: BeoMediaType.TV,
|
||||
BeoSource.URI_STREAMER.id: MediaType.URL,
|
||||
}
|
||||
# Hard to determine content type.
|
||||
if self._source_change.id in content_type:
|
||||
@@ -690,7 +695,11 @@ class BeoMediaPlayer(BeoEntity, MediaPlayerEntity):
|
||||
|
||||
@property
|
||||
def source(self) -> str | None:
|
||||
"""Return the current audio source."""
|
||||
"""Return the current audio/video source."""
|
||||
# Associate TV content ID with a video source
|
||||
if self.media_content_id in self._video_source_id_map:
|
||||
return self._video_source_id_map[self.media_content_id]
|
||||
|
||||
return self._source_change.name
|
||||
|
||||
@property
|
||||
|
||||
@@ -180,6 +180,14 @@ TEST_PLAYBACK_METADATA = PlaybackContentMetadata(
|
||||
track=1,
|
||||
source_internal_id="123",
|
||||
)
|
||||
TEST_PLAYBACK_METADATA_VIDEO = PlaybackContentMetadata(
|
||||
encoding="unknown",
|
||||
organization="HDMI A",
|
||||
title="HDMI A",
|
||||
source_internal_id="hdmi_1",
|
||||
output_channel_processing="TrueImage",
|
||||
output_Channels="5.0.2",
|
||||
)
|
||||
TEST_PLAYBACK_ERROR = PlaybackError(error="Test error")
|
||||
TEST_PLAYBACK_PROGRESS = PlaybackProgress(progress=123)
|
||||
TEST_PLAYBACK_STATE_PAUSED = RenderingState(value="paused")
|
||||
|
||||
@@ -100,6 +100,7 @@ from .const import (
|
||||
TEST_OVERLAY_OFFSET_VOLUME_TTS,
|
||||
TEST_PLAYBACK_ERROR,
|
||||
TEST_PLAYBACK_METADATA,
|
||||
TEST_PLAYBACK_METADATA_VIDEO,
|
||||
TEST_PLAYBACK_PROGRESS,
|
||||
TEST_PLAYBACK_STATE_PAUSED,
|
||||
TEST_PLAYBACK_STATE_PLAYING,
|
||||
@@ -433,6 +434,36 @@ async def test_async_update_source_change(
|
||||
assert (ATTR_MEDIA_CONTENT_ID in states.attributes) == content_id_available
|
||||
|
||||
|
||||
async def test_async_update_source_change_video(
|
||||
hass: HomeAssistant,
|
||||
integration: None,
|
||||
mock_mozart_client: AsyncMock,
|
||||
) -> None:
|
||||
"""Test _async_update_source_change with a video source."""
|
||||
playback_metadata_callback = (
|
||||
mock_mozart_client.get_playback_metadata_notifications.call_args[0][0]
|
||||
)
|
||||
source_change_callback = (
|
||||
mock_mozart_client.get_source_change_notifications.call_args[0][0]
|
||||
)
|
||||
|
||||
assert (states := hass.states.get(TEST_MEDIA_PLAYER_ENTITY_ID))
|
||||
assert ATTR_INPUT_SOURCE not in states.attributes
|
||||
assert states.attributes[ATTR_MEDIA_CONTENT_TYPE] == MediaType.MUSIC
|
||||
|
||||
# Simulate metadata and source change
|
||||
playback_metadata_callback(TEST_PLAYBACK_METADATA_VIDEO)
|
||||
source_change_callback(Source(id="tv", name="TV"))
|
||||
|
||||
assert (states := hass.states.get(TEST_MEDIA_PLAYER_ENTITY_ID))
|
||||
assert states.attributes[ATTR_INPUT_SOURCE] == TEST_PLAYBACK_METADATA_VIDEO.title
|
||||
assert states.attributes[ATTR_MEDIA_CONTENT_TYPE] == BeoMediaType.TV
|
||||
assert (
|
||||
states.attributes[ATTR_MEDIA_CONTENT_ID]
|
||||
== TEST_PLAYBACK_METADATA_VIDEO.source_internal_id
|
||||
)
|
||||
|
||||
|
||||
async def test_async_turn_off(
|
||||
hass: HomeAssistant,
|
||||
integration: None,
|
||||
@@ -819,7 +850,7 @@ async def test_async_select_source(
|
||||
audio_source_call: int,
|
||||
video_source_call: int,
|
||||
) -> None:
|
||||
"""Test async_select_source with an invalid source."""
|
||||
"""Test async_select_source with an invalid source and valid audio and video sources."""
|
||||
with expected_result:
|
||||
await hass.services.async_call(
|
||||
MEDIA_PLAYER_DOMAIN,
|
||||
|
||||
Reference in New Issue
Block a user