Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add 'trueplay' property to SoCo #775

Merged
merged 4 commits into from Dec 27, 2020
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
43 changes: 43 additions & 0 deletions soco/core.py
Expand Up @@ -201,6 +201,7 @@ class SoCo(_SocoSingletonBase):
dialog_mode
supports_fixed_volume
fixed_volume
trueplay
status_light
buttons_enabled

Expand Down Expand Up @@ -960,6 +961,48 @@ def dialog_mode(self, dialog_mode):
]
)

@property
def trueplay(self):
"""bool: Whether Trueplay is enabled on this device.
True if on, False if off.

Devices that do not support Trueplay, or which do not have
a current Trueplay calibration, will raise a `NotSupportedException`
when both getting and setting the property.

Can only be set on visible devices. Attempting to set on non-visible
devices will raise a `SoCoNotVisibleException`.
"""
response = self.renderingControl.GetRoomCalibrationStatus([("InstanceID", 0)])
if response["RoomCalibrationAvailable"] == "0":
raise NotSupportedException
return response["RoomCalibrationEnabled"] == "1"
pwt marked this conversation as resolved.
Show resolved Hide resolved

@trueplay.setter
def trueplay(self, trueplay):
"""Toggle the device's TruePlay setting. Only available to
Sonos speakers, not the Connect, Amp, etc., and only available to
speakers that have a current Trueplay calibration.

:param trueplay: Enable or disable Trueplay.
:type trueplay: bool
:raises NotSupportedException: If the device does not support
Trueplay or doesn't have a current calibration.
:raises SoCoNotVisibleException: If the device is not visible.
"""
response = self.renderingControl.GetRoomCalibrationStatus([("InstanceID", 0)])
if response["RoomCalibrationAvailable"] == "0":
raise NotSupportedException
if not self.is_visible:
raise SoCoNotVisibleException
trueplay_value = "1" if trueplay else "0"
self.renderingControl.SetRoomCalibrationStatus(
[
("InstanceID", 0),
("RoomCalibrationEnabled", trueplay_value),
]
)

@property
def supports_fixed_volume(self):
"""bool: Whether the device supports fixed volume output."""
Expand Down
47 changes: 44 additions & 3 deletions tests/test_core.py
Expand Up @@ -6,14 +6,12 @@

from soco import SoCo
from soco.data_structures import DidlMusicTrack, to_didl_string

from soco.exceptions import (
SoCoSlaveException,
SoCoUPnPException,
SoCoNotVisibleException,
NotSupportedException,
)

from soco.groups import ZoneGroup
from soco.xml import XML

Expand Down Expand Up @@ -1155,6 +1153,50 @@ def test_soco_loudness(self, moco):
[("InstanceID", 0), ("Channel", "Master"), ("DesiredLoudness", "0")]
)

def test_soco_trueplay(self, moco):
moco.renderingControl.GetRoomCalibrationStatus.return_value = {
"RoomCalibrationAvailable": "0",
"RoomCalibrationEnabled": "0",
}
with pytest.raises(NotSupportedException):
assert not moco.trueplay
moco.renderingControl.GetRoomCalibrationStatus.assert_called_with(
[("InstanceID", 0)]
)
moco.renderingControl.GetRoomCalibrationStatus.return_value = {
"RoomCalibrationAvailable": "1",
"RoomCalibrationEnabled": "1",
}
assert moco.trueplay
moco.renderingControl.GetRoomCalibrationStatus.assert_called_with(
[("InstanceID", 0)]
)
# Setter tests for 'is_visible' property, so this needs to be
# mocked.
with mock.patch(
"soco.SoCo.is_visible", new_callable=mock.PropertyMock
) as mock_is_visible:
mock_is_visible.return_value = True
moco.trueplay = False
moco.renderingControl.SetRoomCalibrationStatus.assert_called_with(
[
("InstanceID", 0),
("RoomCalibrationEnabled", "0"),
]
)
moco.trueplay = True
moco.renderingControl.SetRoomCalibrationStatus.assert_called_with(
[
("InstanceID", 0),
("RoomCalibrationEnabled", "1"),
]
)
# Check for exception if attempt to set the property on a
# non-visible speaker.
mock_is_visible.return_value = False
with pytest.raises(SoCoNotVisibleException):
moco.trueplay = True

def test_soco_fixed_volume(self, moco):
moco.renderingControl.GetSupportsOutputFixed.return_value = {
"CurrentSupportsFixed": "1"
Expand All @@ -1170,7 +1212,6 @@ def test_soco_fixed_volume(self, moco):
moco.renderingControl.GetSupportsOutputFixed.assert_called_with(
[("InstanceID", 0)]
)

moco.renderingControl.GetOutputFixed.return_value = {"CurrentFixed": "1"}
assert moco.fixed_volume
moco.renderingControl.GetOutputFixed.assert_called_once_with(
Expand Down