Add volume_step property to MediaPlayerEntity (#105574)

* Add volume_step property to MediaPlayerEntity

* Improve tests

* Address review comments
This commit is contained in:
Erik Montnemery 2023-12-13 17:26:34 +01:00 committed by GitHub
parent 4e9b9add29
commit 4f9f548929
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 61 additions and 6 deletions

View file

@ -454,6 +454,7 @@ class MediaPlayerEntityDescription(EntityDescription):
"""A class that describes media player entities."""
device_class: MediaPlayerDeviceClass | None = None
volume_step: float | None = None
class MediaPlayerEntity(Entity):
@ -505,6 +506,7 @@ class MediaPlayerEntity(Entity):
_attr_state: MediaPlayerState | None = None
_attr_supported_features: MediaPlayerEntityFeature = MediaPlayerEntityFeature(0)
_attr_volume_level: float | None = None
_attr_volume_step: float
# Implement these for your media player
@property
@ -533,6 +535,18 @@ class MediaPlayerEntity(Entity):
"""Volume level of the media player (0..1)."""
return self._attr_volume_level
@property
def volume_step(self) -> float:
"""Return the step to be used by the volume_up and volume_down services."""
if hasattr(self, "_attr_volume_step"):
return self._attr_volume_step
if (
hasattr(self, "entity_description")
and (volume_step := self.entity_description.volume_step) is not None
):
return volume_step
return 0.1
@property
def is_volume_muted(self) -> bool | None:
"""Boolean if volume is currently muted."""
@ -956,7 +970,9 @@ class MediaPlayerEntity(Entity):
and self.volume_level < 1
and self.supported_features & MediaPlayerEntityFeature.VOLUME_SET
):
await self.async_set_volume_level(min(1, self.volume_level + 0.1))
await self.async_set_volume_level(
min(1, self.volume_level + self.volume_step)
)
async def async_volume_down(self) -> None:
"""Turn volume down for media player.
@ -972,7 +988,9 @@ class MediaPlayerEntity(Entity):
and self.volume_level > 0
and self.supported_features & MediaPlayerEntityFeature.VOLUME_SET
):
await self.async_set_volume_level(max(0, self.volume_level - 0.1))
await self.async_set_volume_level(
max(0, self.volume_level - self.volume_step)
)
async def async_media_play_pause(self) -> None:
"""Play or pause the media player."""

View file

@ -10,6 +10,7 @@ from homeassistant.const import (
STATE_PLAYING,
STATE_STANDBY,
)
from homeassistant.core import HomeAssistant
class ExtendedMediaPlayer(mp.MediaPlayerEntity):
@ -148,28 +149,64 @@ class SimpleMediaPlayer(mp.MediaPlayerEntity):
self._state = STATE_STANDBY
class AttrMediaPlayer(SimpleMediaPlayer):
"""Media player setting properties via _attr_*."""
_attr_volume_step = 0.2
class DescrMediaPlayer(SimpleMediaPlayer):
"""Media player setting properties via entity description."""
entity_description = mp.MediaPlayerEntityDescription(key="test", volume_step=0.3)
@pytest.fixture(params=[ExtendedMediaPlayer, SimpleMediaPlayer])
def player(hass, request):
"""Return a media player."""
return request.param(hass)
async def test_volume_up(player) -> None:
@pytest.mark.parametrize(
("player_class", "volume_step"),
[
(ExtendedMediaPlayer, 0.1),
(SimpleMediaPlayer, 0.1),
(AttrMediaPlayer, 0.2),
(DescrMediaPlayer, 0.3),
],
)
async def test_volume_up(
hass: HomeAssistant, player_class: type[mp.MediaPlayerEntity], volume_step: float
) -> None:
"""Test the volume_up and set volume methods."""
player = player_class(hass)
assert player.volume_level == 0
await player.async_set_volume_level(0.5)
assert player.volume_level == 0.5
await player.async_volume_up()
assert player.volume_level == 0.6
assert player.volume_level == 0.5 + volume_step
async def test_volume_down(player) -> None:
@pytest.mark.parametrize(
("player_class", "volume_step"),
[
(ExtendedMediaPlayer, 0.1),
(SimpleMediaPlayer, 0.1),
(AttrMediaPlayer, 0.2),
(DescrMediaPlayer, 0.3),
],
)
async def test_volume_down(
hass: HomeAssistant, player_class: type[mp.MediaPlayerEntity], volume_step: float
) -> None:
"""Test the volume_down and set volume methods."""
player = player_class(hass)
assert player.volume_level == 0
await player.async_set_volume_level(0.5)
assert player.volume_level == 0.5
await player.async_volume_down()
assert player.volume_level == 0.4
assert player.volume_level == 0.5 - volume_step
async def test_media_play_pause(player) -> None: