mirror of
https://github.com/home-assistant/core.git
synced 2025-07-23 13:17:32 +00:00
Add subwoofer crossover support to Sonos Amp devices (#106290)
This commit is contained in:
parent
5d2ddcb1d2
commit
0ae4d017b9
@ -21,6 +21,7 @@ LEVEL_TYPES = {
|
|||||||
"bass": (-10, 10),
|
"bass": (-10, 10),
|
||||||
"balance": (-100, 100),
|
"balance": (-100, 100),
|
||||||
"treble": (-10, 10),
|
"treble": (-10, 10),
|
||||||
|
"sub_crossover": (50, 110),
|
||||||
"sub_gain": (-15, 15),
|
"sub_gain": (-15, 15),
|
||||||
"surround_level": (-15, 15),
|
"surround_level": (-15, 15),
|
||||||
"music_surround_level": (-15, 15),
|
"music_surround_level": (-15, 15),
|
||||||
|
@ -154,6 +154,7 @@ class SonosSpeaker:
|
|||||||
self.dialog_level: bool | None = None
|
self.dialog_level: bool | None = None
|
||||||
self.night_mode: bool | None = None
|
self.night_mode: bool | None = None
|
||||||
self.sub_enabled: bool | None = None
|
self.sub_enabled: bool | None = None
|
||||||
|
self.sub_crossover: int | None = None
|
||||||
self.sub_gain: int | None = None
|
self.sub_gain: int | None = None
|
||||||
self.surround_enabled: bool | None = None
|
self.surround_enabled: bool | None = None
|
||||||
self.surround_mode: bool | None = None
|
self.surround_mode: bool | None = None
|
||||||
@ -561,6 +562,7 @@ class SonosSpeaker:
|
|||||||
"audio_delay",
|
"audio_delay",
|
||||||
"bass",
|
"bass",
|
||||||
"treble",
|
"treble",
|
||||||
|
"sub_crossover",
|
||||||
"sub_gain",
|
"sub_gain",
|
||||||
"surround_level",
|
"surround_level",
|
||||||
"music_surround_level",
|
"music_surround_level",
|
||||||
|
@ -36,6 +36,9 @@
|
|||||||
"treble": {
|
"treble": {
|
||||||
"name": "Treble"
|
"name": "Treble"
|
||||||
},
|
},
|
||||||
|
"sub_crossover": {
|
||||||
|
"name": "Sub crossover frequency"
|
||||||
|
},
|
||||||
"sub_gain": {
|
"sub_gain": {
|
||||||
"name": "Sub gain"
|
"name": "Sub gain"
|
||||||
},
|
},
|
||||||
|
@ -108,8 +108,26 @@ def config_entry_fixture():
|
|||||||
class MockSoCo(MagicMock):
|
class MockSoCo(MagicMock):
|
||||||
"""Mock the Soco Object."""
|
"""Mock the Soco Object."""
|
||||||
|
|
||||||
|
uid = "RINCON_test"
|
||||||
|
play_mode = "NORMAL"
|
||||||
|
mute = False
|
||||||
|
night_mode = True
|
||||||
|
dialog_level = True
|
||||||
|
loudness = True
|
||||||
|
volume = 19
|
||||||
audio_delay = 2
|
audio_delay = 2
|
||||||
|
balance = (61, 100)
|
||||||
|
bass = 1
|
||||||
|
treble = -1
|
||||||
|
mic_enabled = False
|
||||||
|
sub_crossover = None # Default to None for non-Amp devices
|
||||||
|
sub_enabled = False
|
||||||
sub_gain = 5
|
sub_gain = 5
|
||||||
|
surround_enabled = True
|
||||||
|
surround_mode = True
|
||||||
|
surround_level = 3
|
||||||
|
music_surround_level = 4
|
||||||
|
soundbar_audio_input_format = "Dolby 5.1"
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def visible_zones(self):
|
def visible_zones(self):
|
||||||
@ -143,10 +161,7 @@ class SoCoMockFactory:
|
|||||||
mock_soco.mock_add_spec(SoCo)
|
mock_soco.mock_add_spec(SoCo)
|
||||||
mock_soco.ip_address = ip_address
|
mock_soco.ip_address = ip_address
|
||||||
if ip_address != "192.168.42.2":
|
if ip_address != "192.168.42.2":
|
||||||
mock_soco.uid = f"RINCON_test_{ip_address}"
|
mock_soco.uid += f"_{ip_address}"
|
||||||
else:
|
|
||||||
mock_soco.uid = "RINCON_test"
|
|
||||||
mock_soco.play_mode = "NORMAL"
|
|
||||||
mock_soco.music_library = self.music_library
|
mock_soco.music_library = self.music_library
|
||||||
mock_soco.get_current_track_info.return_value = self.current_track_info
|
mock_soco.get_current_track_info.return_value = self.current_track_info
|
||||||
mock_soco.music_source_from_uri = SoCo.music_source_from_uri
|
mock_soco.music_source_from_uri = SoCo.music_source_from_uri
|
||||||
@ -161,23 +176,6 @@ class SoCoMockFactory:
|
|||||||
mock_soco.contentDirectory = SonosMockService("ContentDirectory", ip_address)
|
mock_soco.contentDirectory = SonosMockService("ContentDirectory", ip_address)
|
||||||
mock_soco.deviceProperties = SonosMockService("DeviceProperties", ip_address)
|
mock_soco.deviceProperties = SonosMockService("DeviceProperties", ip_address)
|
||||||
mock_soco.alarmClock = self.alarm_clock
|
mock_soco.alarmClock = self.alarm_clock
|
||||||
mock_soco.mute = False
|
|
||||||
mock_soco.night_mode = True
|
|
||||||
mock_soco.dialog_level = True
|
|
||||||
mock_soco.loudness = True
|
|
||||||
mock_soco.volume = 19
|
|
||||||
mock_soco.audio_delay = 2
|
|
||||||
mock_soco.balance = (61, 100)
|
|
||||||
mock_soco.bass = 1
|
|
||||||
mock_soco.treble = -1
|
|
||||||
mock_soco.mic_enabled = False
|
|
||||||
mock_soco.sub_enabled = False
|
|
||||||
mock_soco.sub_gain = 5
|
|
||||||
mock_soco.surround_enabled = True
|
|
||||||
mock_soco.surround_mode = True
|
|
||||||
mock_soco.surround_level = 3
|
|
||||||
mock_soco.music_surround_level = 4
|
|
||||||
mock_soco.soundbar_audio_input_format = "Dolby 5.1"
|
|
||||||
mock_soco.get_battery_info.return_value = self.battery_info
|
mock_soco.get_battery_info.return_value = self.battery_info
|
||||||
mock_soco.all_zones = {mock_soco}
|
mock_soco.all_zones = {mock_soco}
|
||||||
mock_soco.group.coordinator = mock_soco
|
mock_soco.group.coordinator = mock_soco
|
||||||
|
@ -6,6 +6,8 @@ from homeassistant.const import ATTR_ENTITY_ID
|
|||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.helpers import entity_registry as er
|
from homeassistant.helpers import entity_registry as er
|
||||||
|
|
||||||
|
CROSSOVER_ENTITY = "number.zone_a_sub_crossover_frequency"
|
||||||
|
|
||||||
|
|
||||||
async def test_number_entities(
|
async def test_number_entities(
|
||||||
hass: HomeAssistant, async_autosetup_sonos, soco, entity_registry: er.EntityRegistry
|
hass: HomeAssistant, async_autosetup_sonos, soco, entity_registry: er.EntityRegistry
|
||||||
@ -62,3 +64,32 @@ async def test_number_entities(
|
|||||||
blocking=True,
|
blocking=True,
|
||||||
)
|
)
|
||||||
mock_sub_gain.assert_called_once_with(-8)
|
mock_sub_gain.assert_called_once_with(-8)
|
||||||
|
|
||||||
|
# sub_crossover is only available on Sonos Amp devices, see test_amp_number_entities
|
||||||
|
assert CROSSOVER_ENTITY not in entity_registry.entities
|
||||||
|
|
||||||
|
|
||||||
|
async def test_amp_number_entities(
|
||||||
|
hass: HomeAssistant, async_setup_sonos, soco, entity_registry: er.EntityRegistry
|
||||||
|
) -> None:
|
||||||
|
"""Test the sub_crossover feature only available on Sonos Amp devices.
|
||||||
|
|
||||||
|
The sub_crossover value will be None on all other device types.
|
||||||
|
"""
|
||||||
|
with patch.object(soco, "sub_crossover", 50):
|
||||||
|
await async_setup_sonos()
|
||||||
|
|
||||||
|
sub_crossover_number = entity_registry.entities[CROSSOVER_ENTITY]
|
||||||
|
sub_crossover_state = hass.states.get(sub_crossover_number.entity_id)
|
||||||
|
assert sub_crossover_state.state == "50"
|
||||||
|
|
||||||
|
with patch.object(
|
||||||
|
type(soco), "sub_crossover", new_callable=PropertyMock
|
||||||
|
) as mock_sub_crossover:
|
||||||
|
await hass.services.async_call(
|
||||||
|
NUMBER_DOMAIN,
|
||||||
|
SERVICE_SET_VALUE,
|
||||||
|
{ATTR_ENTITY_ID: sub_crossover_number.entity_id, "value": 110},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
mock_sub_crossover.assert_called_once_with(110)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user