diff --git a/homeassistant/components/media_player/sonos.py b/homeassistant/components/media_player/sonos.py index 022e5742ee7..b5367486e38 100644 --- a/homeassistant/components/media_player/sonos.py +++ b/homeassistant/components/media_player/sonos.py @@ -15,9 +15,10 @@ from homeassistant.components.media_player import ( ATTR_MEDIA_ENQUEUE, DOMAIN, MEDIA_TYPE_MUSIC, SUPPORT_NEXT_TRACK, SUPPORT_PAUSE, SUPPORT_PLAY_MEDIA, SUPPORT_PREVIOUS_TRACK, SUPPORT_SEEK, SUPPORT_VOLUME_MUTE, SUPPORT_VOLUME_SET, SUPPORT_CLEAR_PLAYLIST, - SUPPORT_SELECT_SOURCE, MediaPlayerDevice) + SUPPORT_SELECT_SOURCE, MediaPlayerDevice, PLATFORM_SCHEMA) from homeassistant.const import ( - STATE_IDLE, STATE_PAUSED, STATE_PLAYING, STATE_OFF, ATTR_ENTITY_ID) + STATE_IDLE, STATE_PAUSED, STATE_PLAYING, STATE_OFF, ATTR_ENTITY_ID, + CONF_HOSTS) from homeassistant.config import load_yaml_config_file import homeassistant.helpers.config_validation as cv from homeassistant.util.dt import utcnow @@ -49,9 +50,18 @@ SERVICE_CLEAR_TIMER = 'sonos_clear_sleep_timer' SUPPORT_SOURCE_LINEIN = 'Line-in' SUPPORT_SOURCE_TV = 'TV' +CONF_ADVERTISE_ADDR = 'advertise_addr' +CONF_INTERFACE_ADDR = 'interface_addr' + # Service call validation schemas ATTR_SLEEP_TIME = 'sleep_time' +PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ + vol.Optional(CONF_ADVERTISE_ADDR): cv.string, + vol.Optional(CONF_INTERFACE_ADDR): cv.string, + vol.Optional(CONF_HOSTS): cv.ensure_list(cv.string), +}) + SONOS_SCHEMA = vol.Schema({ ATTR_ENTITY_ID: cv.entity_ids, }) @@ -70,6 +80,10 @@ def setup_platform(hass, config, add_devices, discovery_info=None): import soco global DEVICES + advertise_addr = config.get(CONF_ADVERTISE_ADDR, None) + if advertise_addr: + soco.config.EVENT_ADVERTISE_IP = advertise_addr + if discovery_info: player = soco.SoCo(discovery_info) @@ -87,18 +101,18 @@ def setup_platform(hass, config, add_devices, discovery_info=None): return False players = None - hosts = config.get('hosts', None) + hosts = config.get(CONF_HOSTS, None) if hosts: # Support retro compatibility with comma separated list of hosts # from config + hosts = hosts[0] if len(hosts) == 1 else hosts hosts = hosts.split(',') if isinstance(hosts, str) else hosts players = [] for host in hosts: players.append(soco.SoCo(socket.gethostbyname(host))) if not players: - players = soco.discover(interface_addr=config.get('interface_addr', - None)) + players = soco.discover(interface_addr=config.get(CONF_INTERFACE_ADDR)) if not players: _LOGGER.warning('No Sonos speakers found.') diff --git a/tests/components/media_player/test_sonos.py b/tests/components/media_player/test_sonos.py index 5c2911b2235..9835b8d7635 100644 --- a/tests/components/media_player/test_sonos.py +++ b/tests/components/media_player/test_sonos.py @@ -5,7 +5,11 @@ import soco.snapshot from unittest import mock import soco -from homeassistant.components.media_player import sonos +from homeassistant.bootstrap import setup_component +from homeassistant.components.media_player import sonos, DOMAIN +from homeassistant.components.media_player.sonos import CONF_INTERFACE_ADDR, \ + CONF_ADVERTISE_ADDR +from homeassistant.const import CONF_HOSTS, CONF_PLATFORM from tests.common import get_test_home_assistant @@ -134,20 +138,95 @@ class TestSonosMediaPlayer(unittest.TestCase): """Test a single device using the autodiscovery provided by HASS.""" sonos.setup_platform(self.hass, {}, fake_add_device, '192.0.2.1') - # Ensure registration took place (#2558) self.assertEqual(len(sonos.DEVICES), 1) self.assertEqual(sonos.DEVICES[0].name, 'Kitchen') @mock.patch('soco.SoCo', new=SoCoMock) @mock.patch('socket.create_connection', side_effect=socket.error()) - def test_ensure_setup_config(self, *args): - """Test a single address config'd by the HASS config file.""" - sonos.setup_platform(self.hass, - {'hosts': '192.0.2.1'}, - fake_add_device) + @mock.patch('soco.discover') + def test_ensure_setup_config_interface_addr(self, discover_mock, *args): + """Test a interface address config'd by the HASS config file.""" + discover_mock.return_value = {SoCoMock('192.0.2.1')} + + config = { + DOMAIN: { + CONF_PLATFORM: 'sonos', + CONF_INTERFACE_ADDR: '192.0.1.1', + } + } + + assert setup_component(self.hass, DOMAIN, config) - # Ensure registration took place (#2558) self.assertEqual(len(sonos.DEVICES), 1) + self.assertEqual(discover_mock.call_count, 1) + + @mock.patch('soco.SoCo', new=SoCoMock) + @mock.patch('socket.create_connection', side_effect=socket.error()) + @mock.patch('soco.discover') + def test_ensure_setup_config_advertise_addr(self, discover_mock, + *args): + """Test a advertise address config'd by the HASS config file.""" + discover_mock.return_value = {SoCoMock('192.0.2.1')} + + config = { + DOMAIN: { + CONF_PLATFORM: 'sonos', + CONF_ADVERTISE_ADDR: '192.0.1.1', + } + } + + assert setup_component(self.hass, DOMAIN, config) + + self.assertEqual(len(sonos.DEVICES), 1) + self.assertEqual(discover_mock.call_count, 1) + self.assertEqual(soco.config.EVENT_ADVERTISE_IP, '192.0.1.1') + + @mock.patch('soco.SoCo', new=SoCoMock) + @mock.patch('socket.create_connection', side_effect=socket.error()) + def test_ensure_setup_config_hosts_string_single(self, *args): + """Test a single address config'd by the HASS config file.""" + config = { + DOMAIN: { + CONF_PLATFORM: 'sonos', + CONF_HOSTS: ['192.0.2.1'], + } + } + + assert setup_component(self.hass, DOMAIN, config) + + self.assertEqual(len(sonos.DEVICES), 1) + self.assertEqual(sonos.DEVICES[0].name, 'Kitchen') + + @mock.patch('soco.SoCo', new=SoCoMock) + @mock.patch('socket.create_connection', side_effect=socket.error()) + def test_ensure_setup_config_hosts_string_multiple(self, *args): + """Test multiple address string config'd by the HASS config file.""" + config = { + DOMAIN: { + CONF_PLATFORM: 'sonos', + CONF_HOSTS: ['192.0.2.1,192.168.2.2'], + } + } + + assert setup_component(self.hass, DOMAIN, config) + + self.assertEqual(len(sonos.DEVICES), 2) + self.assertEqual(sonos.DEVICES[0].name, 'Kitchen') + + @mock.patch('soco.SoCo', new=SoCoMock) + @mock.patch('socket.create_connection', side_effect=socket.error()) + def test_ensure_setup_config_hosts_list(self, *args): + """Test a multiple address list config'd by the HASS config file.""" + config = { + DOMAIN: { + CONF_PLATFORM: 'sonos', + CONF_HOSTS: ['192.0.2.1', '192.168.2.2'], + } + } + + assert setup_component(self.hass, DOMAIN, config) + + self.assertEqual(len(sonos.DEVICES), 2) self.assertEqual(sonos.DEVICES[0].name, 'Kitchen') @mock.patch('soco.SoCo', new=SoCoMock)