diff --git a/soco/core.py b/soco/core.py index ef30af0a0..75a90176c 100755 --- a/soco/core.py +++ b/soco/core.py @@ -197,6 +197,7 @@ class SoCo(_SocoSingletonBase): balance night_mode dialog_mode + trueplay status_light .. rubric:: Playlists and Favorites @@ -954,6 +955,45 @@ 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` + both when getting and setting the property.. + """ + response = self.renderingControl.GetRoomCalibrationStatus([("InstanceID", 0)]) + if response["RoomCalibrationAvailable"] == "0": + raise NotSupportedException + return response["RoomCalibrationEnabled"] == "1" + + @trueplay.setter + def trueplay(self, trueplay): + """Switch on/off 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. + """ + if not int( + self.renderingControl.GetRoomCalibrationStatus([("InstanceID", 0)])[ + "RoomCalibrationAvailable" + ] + ): + raise NotSupportedException + trueplay_value = "1" if trueplay else "0" + self.renderingControl.SetRoomCalibrationStatus( + [ + ("InstanceID", 0), + ("RoomCalibrationEnabled", trueplay_value), + ] + ) + def _parse_zone_group_state(self): """The Zone Group State contains a lot of useful information. diff --git a/tests/test_core.py b/tests/test_core.py index 9a1c1a09c..778fe8010 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -6,7 +6,7 @@ from soco import SoCo from soco.data_structures import DidlMusicTrack, to_didl_string -from soco.exceptions import SoCoSlaveException, SoCoUPnPException +from soco.exceptions import SoCoSlaveException, SoCoUPnPException, NotSupportedException from soco.groups import ZoneGroup from soco.xml import XML @@ -1148,6 +1148,31 @@ def test_soco_loudness(self, moco): [("InstanceID", 0), ("Channel", "Master"), ("DesiredLoudness", "0")] ) + def test_soco_trueplay(self, moco): + moco.renderingControl.GetRoomCalibrationStatus.return_value = { + "RoomCalibrationAvailable": "1", + "RoomCalibrationEnabled": "1", + } + assert moco.trueplay + moco.renderingControl.GetRoomCalibrationStatus.assert_called_once_with( + [("InstanceID", 0)] + ) + moco.trueplay = False + moco.renderingControl.GetRoomCalibrationStatus.assert_called_with( + [("InstanceID", 0)] + ) + moco.renderingControl.SetRoomCalibrationStatus.assert_called_once_with( + [("InstanceID", 0), ("RoomCalibrationEnabled", "0")] + ) + moco.renderingControl.GetRoomCalibrationStatus.return_value = { + "RoomCalibrationAvailable": "0", + "RoomCalibrationEnabled": "0", + } + with pytest.raises(NotSupportedException): + assert not moco.trueplay + with pytest.raises(NotSupportedException): + moco.trueplay = True + def test_soco_balance(self, moco): # GetVolume is called twice, once for each of the left # and right channels