Add mute support to Russound RIO (#134118)
parent
6edf06f8a4
commit
aceb1b39ba
|
@ -3,9 +3,6 @@
|
|||
import asyncio
|
||||
|
||||
from aiorussound import CommandError
|
||||
from aiorussound.const import FeatureFlag
|
||||
|
||||
from homeassistant.components.media_player import MediaPlayerEntityFeature
|
||||
|
||||
DOMAIN = "russound_rio"
|
||||
|
||||
|
@ -15,7 +12,3 @@ RUSSOUND_RIO_EXCEPTIONS = (
|
|||
TimeoutError,
|
||||
asyncio.CancelledError,
|
||||
)
|
||||
|
||||
MP_FEATURES_BY_FLAG = {
|
||||
FeatureFlag.COMMANDS_ZONE_MUTE_OFF_ON: MediaPlayerEntityFeature.VOLUME_MUTE
|
||||
}
|
||||
|
|
|
@ -22,7 +22,6 @@ from homeassistant.core import HomeAssistant
|
|||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
from . import RussoundConfigEntry
|
||||
from .const import MP_FEATURES_BY_FLAG
|
||||
from .entity import RussoundBaseEntity, command
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
@ -54,6 +53,7 @@ class RussoundZoneDevice(RussoundBaseEntity, MediaPlayerEntity):
|
|||
_attr_supported_features = (
|
||||
MediaPlayerEntityFeature.VOLUME_SET
|
||||
| MediaPlayerEntityFeature.VOLUME_STEP
|
||||
| MediaPlayerEntityFeature.VOLUME_MUTE
|
||||
| MediaPlayerEntityFeature.TURN_ON
|
||||
| MediaPlayerEntityFeature.TURN_OFF
|
||||
| MediaPlayerEntityFeature.SELECT_SOURCE
|
||||
|
@ -69,9 +69,6 @@ class RussoundZoneDevice(RussoundBaseEntity, MediaPlayerEntity):
|
|||
self._sources = sources
|
||||
self._attr_name = _zone.name
|
||||
self._attr_unique_id = f"{self._primary_mac_address}-{_zone.device_str}"
|
||||
for flag, feature in MP_FEATURES_BY_FLAG.items():
|
||||
if flag in self._client.supported_features:
|
||||
self._attr_supported_features |= feature
|
||||
|
||||
@property
|
||||
def _zone(self) -> ZoneControlSurface:
|
||||
|
@ -150,6 +147,11 @@ class RussoundZoneDevice(RussoundBaseEntity, MediaPlayerEntity):
|
|||
"""
|
||||
return self._zone.volume / 50.0
|
||||
|
||||
@property
|
||||
def is_volume_muted(self) -> bool:
|
||||
"""Return whether zone is muted."""
|
||||
return self._zone.is_mute
|
||||
|
||||
@command
|
||||
async def async_turn_off(self) -> None:
|
||||
"""Turn off the zone."""
|
||||
|
@ -184,3 +186,16 @@ class RussoundZoneDevice(RussoundBaseEntity, MediaPlayerEntity):
|
|||
async def async_volume_down(self) -> None:
|
||||
"""Step the volume down."""
|
||||
await self._zone.volume_down()
|
||||
|
||||
@command
|
||||
async def async_mute_volume(self, mute: bool) -> None:
|
||||
"""Mute the media player."""
|
||||
if FeatureFlag.COMMANDS_ZONE_MUTE_OFF_ON in self._client.supported_features:
|
||||
if mute:
|
||||
await self._zone.mute()
|
||||
else:
|
||||
await self._zone.unmute()
|
||||
return
|
||||
|
||||
if mute != self.is_volume_muted:
|
||||
await self._zone.toggle_mute()
|
||||
|
|
|
@ -75,6 +75,9 @@ def mock_russound_client() -> Generator[AsyncMock]:
|
|||
zone.zone_on = AsyncMock()
|
||||
zone.zone_off = AsyncMock()
|
||||
zone.select_source = AsyncMock()
|
||||
zone.mute = AsyncMock()
|
||||
zone.unmute = AsyncMock()
|
||||
zone.toggle_mute = AsyncMock()
|
||||
|
||||
client.controllers = {
|
||||
1: Controller(
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
from unittest.mock import AsyncMock
|
||||
|
||||
from aiorussound.const import FeatureFlag
|
||||
from aiorussound.exceptions import CommandError
|
||||
from aiorussound.models import PlayStatus
|
||||
import pytest
|
||||
|
@ -9,6 +10,7 @@ import pytest
|
|||
from homeassistant.components.media_player import (
|
||||
ATTR_INPUT_SOURCE,
|
||||
ATTR_MEDIA_VOLUME_LEVEL,
|
||||
ATTR_MEDIA_VOLUME_MUTED,
|
||||
DOMAIN as MP_DOMAIN,
|
||||
SERVICE_SELECT_SOURCE,
|
||||
)
|
||||
|
@ -17,6 +19,7 @@ from homeassistant.const import (
|
|||
SERVICE_TURN_OFF,
|
||||
SERVICE_TURN_ON,
|
||||
SERVICE_VOLUME_DOWN,
|
||||
SERVICE_VOLUME_MUTE,
|
||||
SERVICE_VOLUME_SET,
|
||||
SERVICE_VOLUME_UP,
|
||||
STATE_BUFFERING,
|
||||
|
@ -106,6 +109,59 @@ async def test_media_volume(
|
|||
)
|
||||
|
||||
|
||||
async def test_volume_mute(
|
||||
hass: HomeAssistant,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
mock_russound_client: AsyncMock,
|
||||
) -> None:
|
||||
"""Test mute service."""
|
||||
await setup_integration(hass, mock_config_entry)
|
||||
|
||||
# Test mute (w/ toggle mute support)
|
||||
await hass.services.async_call(
|
||||
MP_DOMAIN,
|
||||
SERVICE_VOLUME_MUTE,
|
||||
{ATTR_ENTITY_ID: ENTITY_ID_ZONE_1, ATTR_MEDIA_VOLUME_MUTED: True},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
mock_russound_client.controllers[1].zones[1].toggle_mute.assert_called_once()
|
||||
mock_russound_client.controllers[1].zones[1].toggle_mute.reset_mock()
|
||||
|
||||
mock_russound_client.controllers[1].zones[1].is_mute = True
|
||||
|
||||
# Test mute when already muted (w/ toggle mute support)
|
||||
await hass.services.async_call(
|
||||
MP_DOMAIN,
|
||||
SERVICE_VOLUME_MUTE,
|
||||
{ATTR_ENTITY_ID: ENTITY_ID_ZONE_1, ATTR_MEDIA_VOLUME_MUTED: True},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
mock_russound_client.controllers[1].zones[1].toggle_mute.assert_not_called()
|
||||
mock_russound_client.supported_features = [FeatureFlag.COMMANDS_ZONE_MUTE_OFF_ON]
|
||||
|
||||
# Test mute (w/ dedicated commands)
|
||||
await hass.services.async_call(
|
||||
MP_DOMAIN,
|
||||
SERVICE_VOLUME_MUTE,
|
||||
{ATTR_ENTITY_ID: ENTITY_ID_ZONE_1, ATTR_MEDIA_VOLUME_MUTED: True},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
mock_russound_client.controllers[1].zones[1].mute.assert_called_once()
|
||||
|
||||
# Test unmute (w/ dedicated commands)
|
||||
await hass.services.async_call(
|
||||
MP_DOMAIN,
|
||||
SERVICE_VOLUME_MUTE,
|
||||
{ATTR_ENTITY_ID: ENTITY_ID_ZONE_1, ATTR_MEDIA_VOLUME_MUTED: False},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
mock_russound_client.controllers[1].zones[1].unmute.assert_called_once()
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("source_name", "source_id"),
|
||||
[
|
||||
|
|
Loading…
Reference in New Issue