Revbump to SoCo 0.13 and add support for Night Sound and Speech Enhancement. (#10765)
Sonos Playbar and Playbase devices support Night Sound and Speech Enhancement effects when playing from sources such as a TV. Adds a new service "sonos_set_option" whichs accepts boolean options to control these audio features.pull/11180/head
parent
024f1d4882
commit
dfb8b5a3c1
|
@ -215,6 +215,18 @@ sonos_clear_sleep_timer:
|
|||
description: Name(s) of entities that will have the timer cleared.
|
||||
example: 'media_player.living_room_sonos'
|
||||
|
||||
sonos_set_option:
|
||||
description: Set Sonos sound options.
|
||||
fields:
|
||||
entity_id:
|
||||
description: Name(s) of entities that will have options set.
|
||||
example: 'media_player.living_room_sonos'
|
||||
night_sound:
|
||||
description: Enable Night Sound mode
|
||||
example: 'true'
|
||||
speech_enhance:
|
||||
description: Enable Speech Enhancement mode
|
||||
example: 'true'
|
||||
|
||||
soundtouch_play_everywhere:
|
||||
description: Play on all Bose Soundtouch devices.
|
||||
|
|
|
@ -27,7 +27,7 @@ from homeassistant.config import load_yaml_config_file
|
|||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.util.dt import utcnow
|
||||
|
||||
REQUIREMENTS = ['SoCo==0.12']
|
||||
REQUIREMENTS = ['SoCo==0.13']
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
@ -52,6 +52,7 @@ SERVICE_RESTORE = 'sonos_restore'
|
|||
SERVICE_SET_TIMER = 'sonos_set_sleep_timer'
|
||||
SERVICE_CLEAR_TIMER = 'sonos_clear_sleep_timer'
|
||||
SERVICE_UPDATE_ALARM = 'sonos_update_alarm'
|
||||
SERVICE_SET_OPTION = 'sonos_set_option'
|
||||
|
||||
DATA_SONOS = 'sonos'
|
||||
|
||||
|
@ -69,6 +70,8 @@ ATTR_ENABLED = 'enabled'
|
|||
ATTR_INCLUDE_LINKED_ZONES = 'include_linked_zones'
|
||||
ATTR_MASTER = 'master'
|
||||
ATTR_WITH_GROUP = 'with_group'
|
||||
ATTR_NIGHT_SOUND = 'night_sound'
|
||||
ATTR_SPEECH_ENHANCE = 'speech_enhance'
|
||||
|
||||
ATTR_IS_COORDINATOR = 'is_coordinator'
|
||||
|
||||
|
@ -105,6 +108,11 @@ SONOS_UPDATE_ALARM_SCHEMA = SONOS_SCHEMA.extend({
|
|||
vol.Optional(ATTR_INCLUDE_LINKED_ZONES): cv.boolean,
|
||||
})
|
||||
|
||||
SONOS_SET_OPTION_SCHEMA = SONOS_SCHEMA.extend({
|
||||
vol.Optional(ATTR_NIGHT_SOUND): cv.boolean,
|
||||
vol.Optional(ATTR_SPEECH_ENHANCE): cv.boolean,
|
||||
})
|
||||
|
||||
|
||||
def setup_platform(hass, config, add_devices, discovery_info=None):
|
||||
"""Set up the Sonos platform."""
|
||||
|
@ -192,6 +200,8 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
|
|||
device.clear_sleep_timer()
|
||||
elif service.service == SERVICE_UPDATE_ALARM:
|
||||
device.update_alarm(**service.data)
|
||||
elif service.service == SERVICE_SET_OPTION:
|
||||
device.update_option(**service.data)
|
||||
|
||||
device.schedule_update_ha_state(True)
|
||||
|
||||
|
@ -224,6 +234,11 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
|
|||
descriptions.get(SERVICE_UPDATE_ALARM),
|
||||
schema=SONOS_UPDATE_ALARM_SCHEMA)
|
||||
|
||||
hass.services.register(
|
||||
DOMAIN, SERVICE_SET_OPTION, service_handle,
|
||||
descriptions.get(SERVICE_SET_OPTION),
|
||||
schema=SONOS_SET_OPTION_SCHEMA)
|
||||
|
||||
|
||||
def _parse_timespan(timespan):
|
||||
"""Parse a time-span into number of seconds."""
|
||||
|
@ -337,6 +352,8 @@ class SonosDevice(MediaPlayerDevice):
|
|||
self._support_shuffle_set = True
|
||||
self._support_stop = False
|
||||
self._support_pause = False
|
||||
self._night_sound = None
|
||||
self._speech_enhance = None
|
||||
self._current_track_uri = None
|
||||
self._current_track_is_radio_stream = False
|
||||
self._queue = None
|
||||
|
@ -457,6 +474,8 @@ class SonosDevice(MediaPlayerDevice):
|
|||
self._support_shuffle_set = False
|
||||
self._support_stop = False
|
||||
self._support_pause = False
|
||||
self._night_sound = None
|
||||
self._speech_enhance = None
|
||||
self._is_playing_tv = False
|
||||
self._is_playing_line_in = False
|
||||
self._source_name = None
|
||||
|
@ -529,6 +548,9 @@ class SonosDevice(MediaPlayerDevice):
|
|||
media_position_updated_at = None
|
||||
source_name = None
|
||||
|
||||
night_sound = self._player.night_mode
|
||||
speech_enhance = self._player.dialog_mode
|
||||
|
||||
is_radio_stream = \
|
||||
current_media_uri.startswith('x-sonosapi-stream:') or \
|
||||
current_media_uri.startswith('x-rincon-mp3radio:')
|
||||
|
@ -705,6 +727,8 @@ class SonosDevice(MediaPlayerDevice):
|
|||
self._support_shuffle_set = support_shuffle_set
|
||||
self._support_stop = support_stop
|
||||
self._support_pause = support_pause
|
||||
self._night_sound = night_sound
|
||||
self._speech_enhance = speech_enhance
|
||||
self._is_playing_tv = is_playing_tv
|
||||
self._is_playing_line_in = is_playing_line_in
|
||||
self._source_name = source_name
|
||||
|
@ -848,6 +872,16 @@ class SonosDevice(MediaPlayerDevice):
|
|||
|
||||
return self._media_title
|
||||
|
||||
@property
|
||||
def night_sound(self):
|
||||
"""Get status of Night Sound."""
|
||||
return self._night_sound
|
||||
|
||||
@property
|
||||
def speech_enhance(self):
|
||||
"""Get status of Speech Enhancement."""
|
||||
return self._speech_enhance
|
||||
|
||||
@property
|
||||
def supported_features(self):
|
||||
"""Flag media player features that are supported."""
|
||||
|
@ -1179,7 +1213,24 @@ class SonosDevice(MediaPlayerDevice):
|
|||
a.include_linked_zones = data[ATTR_INCLUDE_LINKED_ZONES]
|
||||
a.save()
|
||||
|
||||
@soco_error
|
||||
def update_option(self, **data):
|
||||
"""Modify playback options."""
|
||||
if ATTR_NIGHT_SOUND in data and self.night_sound is not None:
|
||||
self.soco.night_mode = data[ATTR_NIGHT_SOUND]
|
||||
|
||||
if ATTR_SPEECH_ENHANCE in data and self.speech_enhance is not None:
|
||||
self.soco.dialog_mode = data[ATTR_SPEECH_ENHANCE]
|
||||
|
||||
@property
|
||||
def device_state_attributes(self):
|
||||
"""Return device specific state attributes."""
|
||||
return {ATTR_IS_COORDINATOR: self.is_coordinator}
|
||||
attributes = {ATTR_IS_COORDINATOR: self.is_coordinator}
|
||||
|
||||
if self.night_sound is not None:
|
||||
attributes[ATTR_NIGHT_SOUND] = self.night_sound
|
||||
|
||||
if self.speech_enhance is not None:
|
||||
attributes[ATTR_SPEECH_ENHANCE] = self.speech_enhance
|
||||
|
||||
return attributes
|
||||
|
|
|
@ -44,7 +44,7 @@ PyXiaomiGateway==0.6.0
|
|||
RtmAPI==0.7.0
|
||||
|
||||
# homeassistant.components.media_player.sonos
|
||||
SoCo==0.12
|
||||
SoCo==0.13
|
||||
|
||||
# homeassistant.components.sensor.travisci
|
||||
TravisPy==0.3.5
|
||||
|
|
|
@ -24,7 +24,7 @@ freezegun>=0.3.8
|
|||
PyJWT==1.5.3
|
||||
|
||||
# homeassistant.components.media_player.sonos
|
||||
SoCo==0.12
|
||||
SoCo==0.13
|
||||
|
||||
# homeassistant.components.device_tracker.automatic
|
||||
aioautomatic==0.6.4
|
||||
|
|
|
@ -389,3 +389,21 @@ class TestSonosMediaPlayer(unittest.TestCase):
|
|||
device.restore()
|
||||
self.assertEqual(restoreMock.call_count, 1)
|
||||
self.assertEqual(restoreMock.call_args, mock.call(False))
|
||||
|
||||
@mock.patch('soco.SoCo', new=SoCoMock)
|
||||
@mock.patch('socket.create_connection', side_effect=socket.error())
|
||||
def test_sonos_set_option(self, option_mock, *args):
|
||||
"""Ensuring soco methods called for sonos_set_option service."""
|
||||
sonos.setup_platform(self.hass, {}, fake_add_device, {
|
||||
'host': '192.0.2.1'
|
||||
})
|
||||
device = self.hass.data[sonos.DATA_SONOS][-1]
|
||||
device.hass = self.hass
|
||||
|
||||
option_mock.return_value = True
|
||||
device._snapshot_coordinator = mock.MagicMock()
|
||||
device._snapshot_coordinator.soco_device = SoCoMock('192.0.2.17')
|
||||
|
||||
device.update_option(night_sound=True, speech_enhance=True)
|
||||
|
||||
self.assertEqual(option_mock.call_count, 1)
|
||||
|
|
Loading…
Reference in New Issue