mirror of
https://github.com/home-assistant/core.git
synced 2025-04-23 16:57:53 +00:00
Add HEOS group volume down/up actions (#138801)
Add group volume down/up actions
This commit is contained in:
parent
1579e90d58
commit
6613b46071
@ -4,5 +4,7 @@ ATTR_PASSWORD = "password"
|
||||
ATTR_USERNAME = "username"
|
||||
DOMAIN = "heos"
|
||||
SERVICE_GROUP_VOLUME_SET = "group_volume_set"
|
||||
SERVICE_GROUP_VOLUME_DOWN = "group_volume_down"
|
||||
SERVICE_GROUP_VOLUME_UP = "group_volume_up"
|
||||
SERVICE_SIGN_IN = "sign_in"
|
||||
SERVICE_SIGN_OUT = "sign_out"
|
||||
|
@ -3,6 +3,12 @@
|
||||
"group_volume_set": {
|
||||
"service": "mdi:volume-medium"
|
||||
},
|
||||
"group_volume_down": {
|
||||
"service": "mdi:volume-low"
|
||||
},
|
||||
"group_volume_up": {
|
||||
"service": "mdi:volume-high"
|
||||
},
|
||||
"sign_in": {
|
||||
"service": "mdi:login"
|
||||
},
|
||||
|
@ -45,7 +45,12 @@ from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
from homeassistant.helpers.update_coordinator import CoordinatorEntity
|
||||
from homeassistant.util.dt import utcnow
|
||||
|
||||
from .const import DOMAIN as HEOS_DOMAIN, SERVICE_GROUP_VOLUME_SET
|
||||
from .const import (
|
||||
DOMAIN as HEOS_DOMAIN,
|
||||
SERVICE_GROUP_VOLUME_DOWN,
|
||||
SERVICE_GROUP_VOLUME_SET,
|
||||
SERVICE_GROUP_VOLUME_UP,
|
||||
)
|
||||
from .coordinator import HeosConfigEntry, HeosCoordinator
|
||||
|
||||
PARALLEL_UPDATES = 0
|
||||
@ -106,6 +111,12 @@ async def async_setup_entry(
|
||||
{vol.Required(ATTR_MEDIA_VOLUME_LEVEL): cv.small_float},
|
||||
"async_set_group_volume_level",
|
||||
)
|
||||
platform.async_register_entity_service(
|
||||
SERVICE_GROUP_VOLUME_DOWN, None, "async_group_volume_down"
|
||||
)
|
||||
platform.async_register_entity_service(
|
||||
SERVICE_GROUP_VOLUME_UP, None, "async_group_volume_up"
|
||||
)
|
||||
|
||||
def add_entities_callback(players: Sequence[HeosPlayer]) -> None:
|
||||
"""Add entities for each player."""
|
||||
@ -372,6 +383,28 @@ class HeosMediaPlayer(CoordinatorEntity[HeosCoordinator], MediaPlayerEntity):
|
||||
self._player.group_id, int(volume_level * 100)
|
||||
)
|
||||
|
||||
@catch_action_error("group volume down")
|
||||
async def async_group_volume_down(self) -> None:
|
||||
"""Turn group volume down for media player."""
|
||||
if self._player.group_id is None:
|
||||
raise ServiceValidationError(
|
||||
translation_domain=HEOS_DOMAIN,
|
||||
translation_key="entity_not_grouped",
|
||||
translation_placeholders={"entity_id": self.entity_id},
|
||||
)
|
||||
await self.coordinator.heos.group_volume_down(self._player.group_id)
|
||||
|
||||
@catch_action_error("group volume up")
|
||||
async def async_group_volume_up(self) -> None:
|
||||
"""Turn group volume up for media player."""
|
||||
if self._player.group_id is None:
|
||||
raise ServiceValidationError(
|
||||
translation_domain=HEOS_DOMAIN,
|
||||
translation_key="entity_not_grouped",
|
||||
translation_placeholders={"entity_id": self.entity_id},
|
||||
)
|
||||
await self.coordinator.heos.group_volume_up(self._player.group_id)
|
||||
|
||||
@catch_action_error("join players")
|
||||
async def async_join_players(self, group_members: list[str]) -> None:
|
||||
"""Join `group_members` as a player group with the current player."""
|
||||
|
@ -12,6 +12,18 @@ group_volume_set:
|
||||
max: 1
|
||||
step: 0.01
|
||||
|
||||
group_volume_down:
|
||||
target:
|
||||
entity:
|
||||
integration: heos
|
||||
domain: media_player
|
||||
|
||||
group_volume_up:
|
||||
target:
|
||||
entity:
|
||||
integration: heos
|
||||
domain: media_player
|
||||
|
||||
sign_in:
|
||||
fields:
|
||||
username:
|
||||
|
@ -81,6 +81,14 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"group_volume_down": {
|
||||
"name": "Turn down group volume",
|
||||
"description": "Turns down the group volume."
|
||||
},
|
||||
"group_volume_up": {
|
||||
"name": "Turn up group volume",
|
||||
"description": "Turns up the group volume."
|
||||
},
|
||||
"sign_in": {
|
||||
"name": "Sign in",
|
||||
"description": "Signs in to a HEOS account.",
|
||||
|
@ -20,6 +20,8 @@ class MockHeos(Heos):
|
||||
self.get_input_sources: AsyncMock = AsyncMock()
|
||||
self.get_playlists: AsyncMock = AsyncMock()
|
||||
self.get_players: AsyncMock = AsyncMock()
|
||||
self.group_volume_down: AsyncMock = AsyncMock()
|
||||
self.group_volume_up: AsyncMock = AsyncMock()
|
||||
self.load_players: AsyncMock = AsyncMock()
|
||||
self.play_media: AsyncMock = AsyncMock()
|
||||
self.play_preset_station: AsyncMock = AsyncMock()
|
||||
|
@ -22,7 +22,12 @@ import pytest
|
||||
from syrupy.assertion import SnapshotAssertion
|
||||
from syrupy.filters import props
|
||||
|
||||
from homeassistant.components.heos.const import DOMAIN, SERVICE_GROUP_VOLUME_SET
|
||||
from homeassistant.components.heos.const import (
|
||||
DOMAIN,
|
||||
SERVICE_GROUP_VOLUME_DOWN,
|
||||
SERVICE_GROUP_VOLUME_SET,
|
||||
SERVICE_GROUP_VOLUME_UP,
|
||||
)
|
||||
from homeassistant.components.media_player import (
|
||||
ATTR_GROUP_MEMBERS,
|
||||
ATTR_INPUT_SOURCE,
|
||||
@ -780,6 +785,64 @@ async def test_group_volume_set_not_grouped_error(
|
||||
controller.set_group_volume.assert_not_called()
|
||||
|
||||
|
||||
async def test_group_volume_down(
|
||||
hass: HomeAssistant, config_entry: MockConfigEntry, controller: MockHeos
|
||||
) -> None:
|
||||
"""Test the group volume down service."""
|
||||
config_entry.add_to_hass(hass)
|
||||
await hass.config_entries.async_setup(config_entry.entry_id)
|
||||
await hass.services.async_call(
|
||||
DOMAIN,
|
||||
SERVICE_GROUP_VOLUME_DOWN,
|
||||
{ATTR_ENTITY_ID: "media_player.test_player"},
|
||||
blocking=True,
|
||||
)
|
||||
controller.group_volume_down.assert_called_with(999)
|
||||
|
||||
|
||||
async def test_group_volume_up(
|
||||
hass: HomeAssistant, config_entry: MockConfigEntry, controller: MockHeos
|
||||
) -> None:
|
||||
"""Test the group volume up service."""
|
||||
config_entry.add_to_hass(hass)
|
||||
await hass.config_entries.async_setup(config_entry.entry_id)
|
||||
await hass.services.async_call(
|
||||
DOMAIN,
|
||||
SERVICE_GROUP_VOLUME_UP,
|
||||
{ATTR_ENTITY_ID: "media_player.test_player"},
|
||||
blocking=True,
|
||||
)
|
||||
controller.group_volume_up.assert_called_with(999)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"service", [SERVICE_GROUP_VOLUME_DOWN, SERVICE_GROUP_VOLUME_UP]
|
||||
)
|
||||
async def test_group_volume_down_up_ungrouped_raises(
|
||||
hass: HomeAssistant,
|
||||
config_entry: MockConfigEntry,
|
||||
controller: MockHeos,
|
||||
service: str,
|
||||
) -> None:
|
||||
"""Test the group volume down and up service raise if player ungrouped."""
|
||||
config_entry.add_to_hass(hass)
|
||||
await hass.config_entries.async_setup(config_entry.entry_id)
|
||||
player = controller.players[1]
|
||||
player.group_id = None
|
||||
with pytest.raises(
|
||||
ServiceValidationError,
|
||||
match=re.escape("Entity media_player.test_player is not joined to a group"),
|
||||
):
|
||||
await hass.services.async_call(
|
||||
DOMAIN,
|
||||
service,
|
||||
{ATTR_ENTITY_ID: "media_player.test_player"},
|
||||
blocking=True,
|
||||
)
|
||||
controller.group_volume_down.assert_not_called()
|
||||
controller.group_volume_up.assert_not_called()
|
||||
|
||||
|
||||
async def test_select_favorite(
|
||||
hass: HomeAssistant,
|
||||
config_entry: MockConfigEntry,
|
||||
|
Loading…
x
Reference in New Issue
Block a user