mirror of
https://github.com/home-assistant/core.git
synced 2026-09-26 17:31:15 -04:00
Add Smartthings soundmode using networkaudio (#168698)
This commit is contained in:
@@ -70,6 +70,17 @@ REPEAT_MODE_TO_HA = {
|
||||
|
||||
HA_REPEAT_MODE_TO_SMARTTHINGS = {v: k for k, v in REPEAT_MODE_TO_HA.items()}
|
||||
|
||||
NETWORK_AUDIO_VENDOR_IDS = ["VD-NetworkAudio-002S"]
|
||||
|
||||
SOUND_MODE_TO_HA = {
|
||||
"standard": "standard",
|
||||
"surround": "surround",
|
||||
"game": "game",
|
||||
"adaptive sound": "adaptive_sound",
|
||||
}
|
||||
|
||||
HA_TO_SOUND_MODE = {v: k for k, v in SOUND_MODE_TO_HA.items()}
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
@@ -104,6 +115,7 @@ class SmartThingsMediaPlayer(SmartThingsEntity, MediaPlayerEntity):
|
||||
Capability.AUDIO_MUTE,
|
||||
Capability.AUDIO_TRACK_DATA,
|
||||
Capability.AUDIO_VOLUME,
|
||||
Capability.EXECUTE,
|
||||
Capability.MEDIA_INPUT_SOURCE,
|
||||
Capability.MEDIA_PLAYBACK,
|
||||
Capability.MEDIA_PLAYBACK_REPEAT,
|
||||
@@ -120,6 +132,9 @@ class SmartThingsMediaPlayer(SmartThingsEntity, MediaPlayerEntity):
|
||||
)
|
||||
self._source_to_smartthings_id: dict[str, str] = {}
|
||||
|
||||
if self._supports_samsung_network_audio_sound_mode():
|
||||
self._attr_sound_mode_list = list(SOUND_MODE_TO_HA.values())
|
||||
|
||||
@override
|
||||
def _update_attr(self) -> None:
|
||||
"""Update the attributes."""
|
||||
@@ -157,6 +172,11 @@ class SmartThingsMediaPlayer(SmartThingsEntity, MediaPlayerEntity):
|
||||
)
|
||||
return None
|
||||
|
||||
def _supports_samsung_network_audio_sound_mode(self) -> bool:
|
||||
"""Return True if the device is a Samsung network audio soundbar."""
|
||||
ocf = self.device.device.ocf
|
||||
return ocf is not None and ocf.vendor_id in NETWORK_AUDIO_VENDOR_IDS
|
||||
|
||||
def _determine_features(self) -> MediaPlayerEntityFeature:
|
||||
flags = (
|
||||
MediaPlayerEntityFeature.VOLUME_SET
|
||||
@@ -189,6 +209,8 @@ class SmartThingsMediaPlayer(SmartThingsEntity, MediaPlayerEntity):
|
||||
flags |= MediaPlayerEntityFeature.SHUFFLE_SET
|
||||
if self.supports_capability(Capability.MEDIA_PLAYBACK_REPEAT):
|
||||
flags |= MediaPlayerEntityFeature.REPEAT_SET
|
||||
if self._supports_samsung_network_audio_sound_mode():
|
||||
flags |= MediaPlayerEntityFeature.SELECT_SOUND_MODE
|
||||
return flags
|
||||
|
||||
@override
|
||||
@@ -316,6 +338,20 @@ class SmartThingsMediaPlayer(SmartThingsEntity, MediaPlayerEntity):
|
||||
argument=HA_REPEAT_MODE_TO_SMARTTHINGS[repeat],
|
||||
)
|
||||
|
||||
@override
|
||||
async def async_select_sound_mode(self, sound_mode: str) -> None:
|
||||
"""Select sound mode."""
|
||||
await self.execute_device_command(
|
||||
Capability.EXECUTE,
|
||||
Command.EXECUTE,
|
||||
argument=[
|
||||
"/sec/networkaudio/soundmode",
|
||||
{"x.com.samsung.networkaudio.soundmode": HA_TO_SOUND_MODE[sound_mode]},
|
||||
],
|
||||
)
|
||||
self._attr_sound_mode = sound_mode
|
||||
self.async_write_ha_state()
|
||||
|
||||
@property
|
||||
@override
|
||||
def media_title(self) -> str | None:
|
||||
|
||||
@@ -193,6 +193,14 @@
|
||||
"media_player": {
|
||||
"media_player": {
|
||||
"state_attributes": {
|
||||
"sound_mode": {
|
||||
"state": {
|
||||
"adaptive_sound": "Adaptive sound",
|
||||
"game": "Game",
|
||||
"standard": "Standard",
|
||||
"surround": "Surround"
|
||||
}
|
||||
},
|
||||
"source": {
|
||||
"state": {
|
||||
"am": "AM",
|
||||
|
||||
@@ -247,6 +247,12 @@
|
||||
]),
|
||||
'area_id': None,
|
||||
'capabilities': dict({
|
||||
<MediaPlayerEntityCapabilityAttribute.SOUND_MODE_LIST: 'sound_mode_list'>: list([
|
||||
'standard',
|
||||
'surround',
|
||||
'game',
|
||||
'adaptive_sound',
|
||||
]),
|
||||
}),
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
@@ -272,7 +278,7 @@
|
||||
'platform': 'smartthings',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': <MediaPlayerEntityFeature: 21901>,
|
||||
'supported_features': <MediaPlayerEntityFeature: 87437>,
|
||||
'translation_key': 'media_player',
|
||||
'unique_id': '0d94e5db-8501-2355-eb4f-214163702cac_main',
|
||||
'unit_of_measurement': None,
|
||||
@@ -286,8 +292,14 @@
|
||||
<MediaPlayerEntityStateAttribute.MEDIA_VOLUME_MUTED: 'is_volume_muted'>: False,
|
||||
<MediaPlayerEntityStateAttribute.MEDIA_ARTIST: 'media_artist'>: '',
|
||||
<MediaPlayerEntityStateAttribute.MEDIA_TITLE: 'media_title'>: '',
|
||||
<MediaPlayerEntityCapabilityAttribute.SOUND_MODE_LIST: 'sound_mode_list'>: list([
|
||||
'standard',
|
||||
'surround',
|
||||
'game',
|
||||
'adaptive_sound',
|
||||
]),
|
||||
<MediaPlayerEntityStateAttribute.INPUT_SOURCE: 'source'>: 'hdmi1',
|
||||
<EntityStateAttribute.SUPPORTED_FEATURES: 'supported_features'>: <MediaPlayerEntityFeature: 21901>,
|
||||
<EntityStateAttribute.SUPPORTED_FEATURES: 'supported_features'>: <MediaPlayerEntityFeature: 87437>,
|
||||
<MediaPlayerEntityStateAttribute.MEDIA_VOLUME_LEVEL: 'volume_level'>: 0.17,
|
||||
}),
|
||||
'context': <ANY>,
|
||||
|
||||
@@ -13,7 +13,10 @@ from homeassistant.components.media_player import (
|
||||
ATTR_MEDIA_SHUFFLE,
|
||||
ATTR_MEDIA_VOLUME_LEVEL,
|
||||
ATTR_MEDIA_VOLUME_MUTED,
|
||||
ATTR_SOUND_MODE,
|
||||
ATTR_SOUND_MODE_LIST,
|
||||
DOMAIN as MEDIA_PLAYER_DOMAIN,
|
||||
SERVICE_SELECT_SOUND_MODE,
|
||||
SERVICE_SELECT_SOURCE,
|
||||
MediaPlayerEntityFeature,
|
||||
RepeatMode,
|
||||
@@ -513,6 +516,60 @@ async def test_media_repeat_mode(
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("device_fixture", ["vd_network_audio_002s"])
|
||||
async def test_select_sound_mode(
|
||||
hass: HomeAssistant,
|
||||
devices: AsyncMock,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
) -> None:
|
||||
"""Test media player select sound mode command."""
|
||||
await setup_integration(hass, mock_config_entry)
|
||||
|
||||
await hass.services.async_call(
|
||||
MEDIA_PLAYER_DOMAIN,
|
||||
SERVICE_SELECT_SOUND_MODE,
|
||||
{
|
||||
ATTR_ENTITY_ID: "media_player.theater_soundbar_living",
|
||||
ATTR_SOUND_MODE: "adaptive_sound",
|
||||
},
|
||||
blocking=True,
|
||||
)
|
||||
devices.execute_device_command.assert_called_once_with(
|
||||
"0d94e5db-8501-2355-eb4f-214163702cac",
|
||||
Capability.EXECUTE,
|
||||
Command.EXECUTE,
|
||||
MAIN,
|
||||
argument=[
|
||||
"/sec/networkaudio/soundmode",
|
||||
{"x.com.samsung.networkaudio.soundmode": "adaptive sound"},
|
||||
],
|
||||
)
|
||||
assert (
|
||||
hass.states.get("media_player.theater_soundbar_living").attributes[
|
||||
ATTR_SOUND_MODE
|
||||
]
|
||||
== "adaptive_sound"
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("device_fixture", ["im_speaker_ai_0001"])
|
||||
async def test_no_sound_mode_on_non_soundbar(
|
||||
hass: HomeAssistant,
|
||||
devices: AsyncMock,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
) -> None:
|
||||
"""Test non-soundbar network audio devices don't expose sound mode."""
|
||||
await setup_integration(hass, mock_config_entry)
|
||||
|
||||
state = hass.states.get("media_player.galaxy_home_mini")
|
||||
assert state is not None
|
||||
assert ATTR_SOUND_MODE_LIST not in state.attributes
|
||||
assert not (
|
||||
state.attributes[ATTR_SUPPORTED_FEATURES]
|
||||
& MediaPlayerEntityFeature.SELECT_SOUND_MODE
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("device_fixture", ["hw_q80r_soundbar"])
|
||||
async def test_state_update(
|
||||
hass: HomeAssistant,
|
||||
|
||||
Reference in New Issue
Block a user