Sonos specify IP for event subscription (#4177)

pull/4669/head
Lewis Juggins 2016-12-02 06:22:03 +00:00 committed by Paulus Schoutsen
parent b0a800cc6d
commit 83a108b20a
2 changed files with 106 additions and 13 deletions

View File

@ -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.')

View File

@ -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)