Add Sonos discovery of multiple households (#21337)
* Remove confusing device naming * Add discovery of multiple households * Rename SonosDevice to SonosEntity
This commit is contained in:
parent
47220d71a1
commit
a4bb35142c
5 changed files with 89 additions and 88 deletions
|
@ -4,7 +4,7 @@ from homeassistant.helpers import config_entry_flow
|
||||||
|
|
||||||
|
|
||||||
DOMAIN = 'sonos'
|
DOMAIN = 'sonos'
|
||||||
REQUIREMENTS = ['pysonos==0.0.6']
|
REQUIREMENTS = ['pysonos==0.0.7']
|
||||||
|
|
||||||
|
|
||||||
async def async_setup(hass, config):
|
async def async_setup(hass, config):
|
||||||
|
|
|
@ -48,7 +48,7 @@ SERVICE_CLEAR_TIMER = 'sonos_clear_sleep_timer'
|
||||||
SERVICE_UPDATE_ALARM = 'sonos_update_alarm'
|
SERVICE_UPDATE_ALARM = 'sonos_update_alarm'
|
||||||
SERVICE_SET_OPTION = 'sonos_set_option'
|
SERVICE_SET_OPTION = 'sonos_set_option'
|
||||||
|
|
||||||
DATA_SONOS = 'sonos_devices'
|
DATA_SONOS = 'sonos_media_player'
|
||||||
|
|
||||||
SOURCE_LINEIN = 'Line-in'
|
SOURCE_LINEIN = 'Line-in'
|
||||||
SOURCE_TV = 'TV'
|
SOURCE_TV = 'TV'
|
||||||
|
@ -114,7 +114,7 @@ class SonosData:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
"""Initialize the data."""
|
"""Initialize the data."""
|
||||||
self.uids = set()
|
self.uids = set()
|
||||||
self.devices = []
|
self.entities = []
|
||||||
self.topology_lock = threading.Lock()
|
self.topology_lock = threading.Lock()
|
||||||
|
|
||||||
|
|
||||||
|
@ -129,9 +129,9 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
|
||||||
|
|
||||||
async def async_setup_entry(hass, config_entry, async_add_entities):
|
async def async_setup_entry(hass, config_entry, async_add_entities):
|
||||||
"""Set up Sonos from a config entry."""
|
"""Set up Sonos from a config entry."""
|
||||||
def add_entities(devices, update_before_add=False):
|
def add_entities(entities, update_before_add=False):
|
||||||
"""Sync version of async add devices."""
|
"""Sync version of async add entities."""
|
||||||
hass.add_job(async_add_entities, devices, update_before_add)
|
hass.add_job(async_add_entities, entities, update_before_add)
|
||||||
|
|
||||||
hass.async_add_executor_job(
|
hass.async_add_executor_job(
|
||||||
_setup_platform, hass, hass.data[SONOS_DOMAIN].get('media_player', {}),
|
_setup_platform, hass, hass.data[SONOS_DOMAIN].get('media_player', {}),
|
||||||
|
@ -153,7 +153,7 @@ def _setup_platform(hass, config, add_entities, discovery_info):
|
||||||
if discovery_info:
|
if discovery_info:
|
||||||
player = pysonos.SoCo(discovery_info.get('host'))
|
player = pysonos.SoCo(discovery_info.get('host'))
|
||||||
|
|
||||||
# If device already exists by config
|
# If host already exists by config
|
||||||
if player.uid in hass.data[DATA_SONOS].uids:
|
if player.uid in hass.data[DATA_SONOS].uids:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -176,53 +176,54 @@ def _setup_platform(hass, config, add_entities, discovery_info):
|
||||||
_LOGGER.warning("Failed to initialize '%s'", host)
|
_LOGGER.warning("Failed to initialize '%s'", host)
|
||||||
else:
|
else:
|
||||||
players = pysonos.discover(
|
players = pysonos.discover(
|
||||||
interface_addr=config.get(CONF_INTERFACE_ADDR))
|
interface_addr=config.get(CONF_INTERFACE_ADDR),
|
||||||
|
all_households=True)
|
||||||
|
|
||||||
if not players:
|
if not players:
|
||||||
_LOGGER.warning("No Sonos speakers found")
|
_LOGGER.warning("No Sonos speakers found")
|
||||||
return
|
return
|
||||||
|
|
||||||
hass.data[DATA_SONOS].uids.update(p.uid for p in players)
|
hass.data[DATA_SONOS].uids.update(p.uid for p in players)
|
||||||
add_entities(SonosDevice(p) for p in players)
|
add_entities(SonosEntity(p) for p in players)
|
||||||
_LOGGER.debug("Added %s Sonos speakers", len(players))
|
_LOGGER.debug("Added %s Sonos speakers", len(players))
|
||||||
|
|
||||||
def service_handle(service):
|
def service_handle(service):
|
||||||
"""Handle for services."""
|
"""Handle for services."""
|
||||||
entity_ids = service.data.get('entity_id')
|
entity_ids = service.data.get('entity_id')
|
||||||
|
|
||||||
devices = hass.data[DATA_SONOS].devices
|
entities = hass.data[DATA_SONOS].entities
|
||||||
if entity_ids:
|
if entity_ids:
|
||||||
devices = [d for d in devices if d.entity_id in entity_ids]
|
entities = [e for e in entities if e.entity_id in entity_ids]
|
||||||
|
|
||||||
if service.service == SERVICE_JOIN:
|
if service.service == SERVICE_JOIN:
|
||||||
master = [device for device in hass.data[DATA_SONOS].devices
|
master = [e for e in hass.data[DATA_SONOS].entities
|
||||||
if device.entity_id == service.data[ATTR_MASTER]]
|
if e.entity_id == service.data[ATTR_MASTER]]
|
||||||
if master:
|
if master:
|
||||||
with hass.data[DATA_SONOS].topology_lock:
|
with hass.data[DATA_SONOS].topology_lock:
|
||||||
master[0].join(devices)
|
master[0].join(entities)
|
||||||
return
|
return
|
||||||
|
|
||||||
if service.service == SERVICE_UNJOIN:
|
if service.service == SERVICE_UNJOIN:
|
||||||
with hass.data[DATA_SONOS].topology_lock:
|
with hass.data[DATA_SONOS].topology_lock:
|
||||||
for device in devices:
|
for entity in entities:
|
||||||
device.unjoin()
|
entity.unjoin()
|
||||||
return
|
return
|
||||||
|
|
||||||
for device in devices:
|
for entity in entities:
|
||||||
if service.service == SERVICE_SNAPSHOT:
|
if service.service == SERVICE_SNAPSHOT:
|
||||||
device.snapshot(service.data[ATTR_WITH_GROUP])
|
entity.snapshot(service.data[ATTR_WITH_GROUP])
|
||||||
elif service.service == SERVICE_RESTORE:
|
elif service.service == SERVICE_RESTORE:
|
||||||
device.restore(service.data[ATTR_WITH_GROUP])
|
entity.restore(service.data[ATTR_WITH_GROUP])
|
||||||
elif service.service == SERVICE_SET_TIMER:
|
elif service.service == SERVICE_SET_TIMER:
|
||||||
device.set_sleep_timer(service.data[ATTR_SLEEP_TIME])
|
entity.set_sleep_timer(service.data[ATTR_SLEEP_TIME])
|
||||||
elif service.service == SERVICE_CLEAR_TIMER:
|
elif service.service == SERVICE_CLEAR_TIMER:
|
||||||
device.clear_sleep_timer()
|
entity.clear_sleep_timer()
|
||||||
elif service.service == SERVICE_UPDATE_ALARM:
|
elif service.service == SERVICE_UPDATE_ALARM:
|
||||||
device.set_alarm(**service.data)
|
entity.set_alarm(**service.data)
|
||||||
elif service.service == SERVICE_SET_OPTION:
|
elif service.service == SERVICE_SET_OPTION:
|
||||||
device.set_option(**service.data)
|
entity.set_option(**service.data)
|
||||||
|
|
||||||
device.schedule_update_ha_state(True)
|
entity.schedule_update_ha_state(True)
|
||||||
|
|
||||||
hass.services.register(
|
hass.services.register(
|
||||||
DOMAIN, SERVICE_JOIN, service_handle,
|
DOMAIN, SERVICE_JOIN, service_handle,
|
||||||
|
@ -270,9 +271,9 @@ class _ProcessSonosEventQueue:
|
||||||
|
|
||||||
|
|
||||||
def _get_entity_from_soco_uid(hass, uid):
|
def _get_entity_from_soco_uid(hass, uid):
|
||||||
"""Return SonosDevice from SoCo uid."""
|
"""Return SonosEntity from SoCo uid."""
|
||||||
for entity in hass.data[DATA_SONOS].devices:
|
for entity in hass.data[DATA_SONOS].entities:
|
||||||
if uid == entity.soco.uid:
|
if uid == entity.unique_id:
|
||||||
return entity
|
return entity
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@ -303,11 +304,11 @@ def soco_error(errorcodes=None):
|
||||||
def soco_coordinator(funct):
|
def soco_coordinator(funct):
|
||||||
"""Call function on coordinator."""
|
"""Call function on coordinator."""
|
||||||
@ft.wraps(funct)
|
@ft.wraps(funct)
|
||||||
def wrapper(device, *args, **kwargs):
|
def wrapper(entity, *args, **kwargs):
|
||||||
"""Wrap for call to coordinator."""
|
"""Wrap for call to coordinator."""
|
||||||
if device.is_coordinator:
|
if entity.is_coordinator:
|
||||||
return funct(device, *args, **kwargs)
|
return funct(entity, *args, **kwargs)
|
||||||
return funct(device.coordinator, *args, **kwargs)
|
return funct(entity.coordinator, *args, **kwargs)
|
||||||
|
|
||||||
return wrapper
|
return wrapper
|
||||||
|
|
||||||
|
@ -329,11 +330,11 @@ def _is_radio_uri(uri):
|
||||||
return uri.startswith(radio_schemes)
|
return uri.startswith(radio_schemes)
|
||||||
|
|
||||||
|
|
||||||
class SonosDevice(MediaPlayerDevice):
|
class SonosEntity(MediaPlayerDevice):
|
||||||
"""Representation of a Sonos device."""
|
"""Representation of a Sonos entity."""
|
||||||
|
|
||||||
def __init__(self, player):
|
def __init__(self, player):
|
||||||
"""Initialize the Sonos device."""
|
"""Initialize the Sonos entity."""
|
||||||
self._subscriptions = []
|
self._subscriptions = []
|
||||||
self._receives_events = False
|
self._receives_events = False
|
||||||
self._volume_increment = 2
|
self._volume_increment = 2
|
||||||
|
@ -366,7 +367,7 @@ class SonosDevice(MediaPlayerDevice):
|
||||||
|
|
||||||
async def async_added_to_hass(self):
|
async def async_added_to_hass(self):
|
||||||
"""Subscribe sonos events."""
|
"""Subscribe sonos events."""
|
||||||
self.hass.data[DATA_SONOS].devices.append(self)
|
self.hass.data[DATA_SONOS].entities.append(self)
|
||||||
self.hass.async_add_executor_job(self._subscribe_to_player_events)
|
self.hass.async_add_executor_job(self._subscribe_to_player_events)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -376,7 +377,7 @@ class SonosDevice(MediaPlayerDevice):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self):
|
def name(self):
|
||||||
"""Return the name of the device."""
|
"""Return the name of the entity."""
|
||||||
return self._name
|
return self._name
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -394,7 +395,7 @@ class SonosDevice(MediaPlayerDevice):
|
||||||
@property
|
@property
|
||||||
@soco_coordinator
|
@soco_coordinator
|
||||||
def state(self):
|
def state(self):
|
||||||
"""Return the state of the device."""
|
"""Return the state of the entity."""
|
||||||
if self._status in ('PAUSED_PLAYBACK', 'STOPPED'):
|
if self._status in ('PAUSED_PLAYBACK', 'STOPPED'):
|
||||||
return STATE_PAUSED
|
return STATE_PAUSED
|
||||||
if self._status in ('PLAYING', 'TRANSITIONING'):
|
if self._status in ('PLAYING', 'TRANSITIONING'):
|
||||||
|
@ -410,7 +411,7 @@ class SonosDevice(MediaPlayerDevice):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def soco(self):
|
def soco(self):
|
||||||
"""Return soco device."""
|
"""Return soco object."""
|
||||||
return self._player
|
return self._player
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -434,7 +435,7 @@ class SonosDevice(MediaPlayerDevice):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def _set_basic_information(self):
|
def _set_basic_information(self):
|
||||||
"""Set initial device information."""
|
"""Set initial entity information."""
|
||||||
speaker_info = self.soco.get_speaker_info(True)
|
speaker_info = self.soco.get_speaker_info(True)
|
||||||
self._name = speaker_info['zone_name']
|
self._name = speaker_info['zone_name']
|
||||||
self._model = speaker_info['model_name']
|
self._model = speaker_info['model_name']
|
||||||
|
@ -477,8 +478,8 @@ class SonosDevice(MediaPlayerDevice):
|
||||||
self._receives_events = False
|
self._receives_events = False
|
||||||
|
|
||||||
# New player available, build the current group topology
|
# New player available, build the current group topology
|
||||||
for device in self.hass.data[DATA_SONOS].devices:
|
for entity in self.hass.data[DATA_SONOS].entities:
|
||||||
device.update_groups()
|
entity.update_groups()
|
||||||
|
|
||||||
player = self.soco
|
player = self.soco
|
||||||
|
|
||||||
|
@ -554,7 +555,7 @@ class SonosDevice(MediaPlayerDevice):
|
||||||
self.schedule_update_ha_state()
|
self.schedule_update_ha_state()
|
||||||
|
|
||||||
# Also update slaves
|
# Also update slaves
|
||||||
for entity in self.hass.data[DATA_SONOS].devices:
|
for entity in self.hass.data[DATA_SONOS].entities:
|
||||||
coordinator = entity.coordinator
|
coordinator = entity.coordinator
|
||||||
if coordinator and coordinator.unique_id == self.unique_id:
|
if coordinator and coordinator.unique_id == self.unique_id:
|
||||||
entity.schedule_update_ha_state()
|
entity.schedule_update_ha_state()
|
||||||
|
@ -1087,7 +1088,7 @@ class SonosDevice(MediaPlayerDevice):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def device_state_attributes(self):
|
def device_state_attributes(self):
|
||||||
"""Return device specific state attributes."""
|
"""Return entity specific state attributes."""
|
||||||
attributes = {ATTR_SONOS_GROUP: self._sonos_group}
|
attributes = {ATTR_SONOS_GROUP: self._sonos_group}
|
||||||
|
|
||||||
if self._night_sound is not None:
|
if self._night_sound is not None:
|
||||||
|
|
|
@ -1263,7 +1263,7 @@ pysmartthings==0.6.3
|
||||||
pysnmp==4.4.8
|
pysnmp==4.4.8
|
||||||
|
|
||||||
# homeassistant.components.sonos
|
# homeassistant.components.sonos
|
||||||
pysonos==0.0.6
|
pysonos==0.0.7
|
||||||
|
|
||||||
# homeassistant.components.spc
|
# homeassistant.components.spc
|
||||||
pyspcwebgw==0.4.0
|
pyspcwebgw==0.4.0
|
||||||
|
|
|
@ -226,7 +226,7 @@ pysmartapp==0.3.0
|
||||||
pysmartthings==0.6.3
|
pysmartthings==0.6.3
|
||||||
|
|
||||||
# homeassistant.components.sonos
|
# homeassistant.components.sonos
|
||||||
pysonos==0.0.6
|
pysonos==0.0.7
|
||||||
|
|
||||||
# homeassistant.components.spc
|
# homeassistant.components.spc
|
||||||
pyspcwebgw==0.4.0
|
pyspcwebgw==0.4.0
|
||||||
|
|
|
@ -21,7 +21,7 @@ ENTITY_ID = 'media_player.kitchen'
|
||||||
class pysonosDiscoverMock():
|
class pysonosDiscoverMock():
|
||||||
"""Mock class for the pysonos.discover method."""
|
"""Mock class for the pysonos.discover method."""
|
||||||
|
|
||||||
def discover(interface_addr):
|
def discover(interface_addr, all_households=False):
|
||||||
"""Return tuple of pysonos.SoCo objects representing found speakers."""
|
"""Return tuple of pysonos.SoCo objects representing found speakers."""
|
||||||
return {SoCoMock('192.0.2.1')}
|
return {SoCoMock('192.0.2.1')}
|
||||||
|
|
||||||
|
@ -123,10 +123,10 @@ class SoCoMock():
|
||||||
|
|
||||||
|
|
||||||
def add_entities_factory(hass):
|
def add_entities_factory(hass):
|
||||||
"""Add devices factory."""
|
"""Add entities factory."""
|
||||||
def add_entities(devices, update_befor_add=False):
|
def add_entities(entities, update_befor_add=False):
|
||||||
"""Fake add device."""
|
"""Fake add entity."""
|
||||||
hass.data[sonos.DATA_SONOS].devices = devices
|
hass.data[sonos.DATA_SONOS].entities = entities
|
||||||
|
|
||||||
return add_entities
|
return add_entities
|
||||||
|
|
||||||
|
@ -144,14 +144,14 @@ class TestSonosMediaPlayer(unittest.TestCase):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
# Monkey patches
|
# Monkey patches
|
||||||
self.real_available = sonos.SonosDevice.available
|
self.real_available = sonos.SonosEntity.available
|
||||||
sonos.SonosDevice.available = monkey_available
|
sonos.SonosEntity.available = monkey_available
|
||||||
|
|
||||||
# pylint: disable=invalid-name
|
# pylint: disable=invalid-name
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
"""Stop everything that was started."""
|
"""Stop everything that was started."""
|
||||||
# Monkey patches
|
# Monkey patches
|
||||||
sonos.SonosDevice.available = self.real_available
|
sonos.SonosEntity.available = self.real_available
|
||||||
self.hass.stop()
|
self.hass.stop()
|
||||||
|
|
||||||
@mock.patch('pysonos.SoCo', new=SoCoMock)
|
@mock.patch('pysonos.SoCo', new=SoCoMock)
|
||||||
|
@ -162,9 +162,9 @@ class TestSonosMediaPlayer(unittest.TestCase):
|
||||||
'host': '192.0.2.1'
|
'host': '192.0.2.1'
|
||||||
})
|
})
|
||||||
|
|
||||||
devices = list(self.hass.data[sonos.DATA_SONOS].devices)
|
entities = list(self.hass.data[sonos.DATA_SONOS].entities)
|
||||||
assert len(devices) == 1
|
assert len(entities) == 1
|
||||||
assert devices[0].name == 'Kitchen'
|
assert entities[0].name == 'Kitchen'
|
||||||
|
|
||||||
@mock.patch('pysonos.SoCo', new=SoCoMock)
|
@mock.patch('pysonos.SoCo', new=SoCoMock)
|
||||||
@mock.patch('socket.create_connection', side_effect=socket.error())
|
@mock.patch('socket.create_connection', side_effect=socket.error())
|
||||||
|
@ -182,7 +182,7 @@ class TestSonosMediaPlayer(unittest.TestCase):
|
||||||
|
|
||||||
assert setup_component(self.hass, DOMAIN, config)
|
assert setup_component(self.hass, DOMAIN, config)
|
||||||
|
|
||||||
assert len(self.hass.data[sonos.DATA_SONOS].devices) == 1
|
assert len(self.hass.data[sonos.DATA_SONOS].entities) == 1
|
||||||
assert discover_mock.call_count == 1
|
assert discover_mock.call_count == 1
|
||||||
|
|
||||||
@mock.patch('pysonos.SoCo', new=SoCoMock)
|
@mock.patch('pysonos.SoCo', new=SoCoMock)
|
||||||
|
@ -198,9 +198,9 @@ class TestSonosMediaPlayer(unittest.TestCase):
|
||||||
|
|
||||||
assert setup_component(self.hass, DOMAIN, config)
|
assert setup_component(self.hass, DOMAIN, config)
|
||||||
|
|
||||||
devices = self.hass.data[sonos.DATA_SONOS].devices
|
entities = self.hass.data[sonos.DATA_SONOS].entities
|
||||||
assert len(devices) == 1
|
assert len(entities) == 1
|
||||||
assert devices[0].name == 'Kitchen'
|
assert entities[0].name == 'Kitchen'
|
||||||
|
|
||||||
@mock.patch('pysonos.SoCo', new=SoCoMock)
|
@mock.patch('pysonos.SoCo', new=SoCoMock)
|
||||||
@mock.patch('socket.create_connection', side_effect=socket.error())
|
@mock.patch('socket.create_connection', side_effect=socket.error())
|
||||||
|
@ -215,9 +215,9 @@ class TestSonosMediaPlayer(unittest.TestCase):
|
||||||
|
|
||||||
assert setup_component(self.hass, DOMAIN, config)
|
assert setup_component(self.hass, DOMAIN, config)
|
||||||
|
|
||||||
devices = self.hass.data[sonos.DATA_SONOS].devices
|
entities = self.hass.data[sonos.DATA_SONOS].entities
|
||||||
assert len(devices) == 2
|
assert len(entities) == 2
|
||||||
assert devices[0].name == 'Kitchen'
|
assert entities[0].name == 'Kitchen'
|
||||||
|
|
||||||
@mock.patch('pysonos.SoCo', new=SoCoMock)
|
@mock.patch('pysonos.SoCo', new=SoCoMock)
|
||||||
@mock.patch('socket.create_connection', side_effect=socket.error())
|
@mock.patch('socket.create_connection', side_effect=socket.error())
|
||||||
|
@ -232,9 +232,9 @@ class TestSonosMediaPlayer(unittest.TestCase):
|
||||||
|
|
||||||
assert setup_component(self.hass, DOMAIN, config)
|
assert setup_component(self.hass, DOMAIN, config)
|
||||||
|
|
||||||
devices = self.hass.data[sonos.DATA_SONOS].devices
|
entities = self.hass.data[sonos.DATA_SONOS].entities
|
||||||
assert len(devices) == 2
|
assert len(entities) == 2
|
||||||
assert devices[0].name == 'Kitchen'
|
assert entities[0].name == 'Kitchen'
|
||||||
|
|
||||||
@mock.patch('pysonos.SoCo', new=SoCoMock)
|
@mock.patch('pysonos.SoCo', new=SoCoMock)
|
||||||
@mock.patch.object(pysonos, 'discover', new=pysonosDiscoverMock.discover)
|
@mock.patch.object(pysonos, 'discover', new=pysonosDiscoverMock.discover)
|
||||||
|
@ -242,9 +242,9 @@ class TestSonosMediaPlayer(unittest.TestCase):
|
||||||
def test_ensure_setup_sonos_discovery(self, *args):
|
def test_ensure_setup_sonos_discovery(self, *args):
|
||||||
"""Test a single device using the autodiscovery provided by Sonos."""
|
"""Test a single device using the autodiscovery provided by Sonos."""
|
||||||
sonos.setup_platform(self.hass, {}, add_entities_factory(self.hass))
|
sonos.setup_platform(self.hass, {}, add_entities_factory(self.hass))
|
||||||
devices = list(self.hass.data[sonos.DATA_SONOS].devices)
|
entities = list(self.hass.data[sonos.DATA_SONOS].entities)
|
||||||
assert len(devices) == 1
|
assert len(entities) == 1
|
||||||
assert devices[0].name == 'Kitchen'
|
assert entities[0].name == 'Kitchen'
|
||||||
|
|
||||||
@mock.patch('pysonos.SoCo', new=SoCoMock)
|
@mock.patch('pysonos.SoCo', new=SoCoMock)
|
||||||
@mock.patch('socket.create_connection', side_effect=socket.error())
|
@mock.patch('socket.create_connection', side_effect=socket.error())
|
||||||
|
@ -254,10 +254,10 @@ class TestSonosMediaPlayer(unittest.TestCase):
|
||||||
sonos.setup_platform(self.hass, {}, add_entities_factory(self.hass), {
|
sonos.setup_platform(self.hass, {}, add_entities_factory(self.hass), {
|
||||||
'host': '192.0.2.1'
|
'host': '192.0.2.1'
|
||||||
})
|
})
|
||||||
device = list(self.hass.data[sonos.DATA_SONOS].devices)[-1]
|
entity = list(self.hass.data[sonos.DATA_SONOS].entities)[-1]
|
||||||
device.hass = self.hass
|
entity.hass = self.hass
|
||||||
|
|
||||||
device.set_sleep_timer(30)
|
entity.set_sleep_timer(30)
|
||||||
set_sleep_timerMock.assert_called_once_with(30)
|
set_sleep_timerMock.assert_called_once_with(30)
|
||||||
|
|
||||||
@mock.patch('pysonos.SoCo', new=SoCoMock)
|
@mock.patch('pysonos.SoCo', new=SoCoMock)
|
||||||
|
@ -268,10 +268,10 @@ class TestSonosMediaPlayer(unittest.TestCase):
|
||||||
sonos.setup_platform(self.hass, {}, add_entities_factory(self.hass), {
|
sonos.setup_platform(self.hass, {}, add_entities_factory(self.hass), {
|
||||||
'host': '192.0.2.1'
|
'host': '192.0.2.1'
|
||||||
})
|
})
|
||||||
device = list(self.hass.data[sonos.DATA_SONOS].devices)[-1]
|
entity = list(self.hass.data[sonos.DATA_SONOS].entities)[-1]
|
||||||
device.hass = self.hass
|
entity.hass = self.hass
|
||||||
|
|
||||||
device.set_sleep_timer(None)
|
entity.set_sleep_timer(None)
|
||||||
set_sleep_timerMock.assert_called_once_with(None)
|
set_sleep_timerMock.assert_called_once_with(None)
|
||||||
|
|
||||||
@mock.patch('pysonos.SoCo', new=SoCoMock)
|
@mock.patch('pysonos.SoCo', new=SoCoMock)
|
||||||
|
@ -282,8 +282,8 @@ class TestSonosMediaPlayer(unittest.TestCase):
|
||||||
sonos.setup_platform(self.hass, {}, add_entities_factory(self.hass), {
|
sonos.setup_platform(self.hass, {}, add_entities_factory(self.hass), {
|
||||||
'host': '192.0.2.1'
|
'host': '192.0.2.1'
|
||||||
})
|
})
|
||||||
device = list(self.hass.data[sonos.DATA_SONOS].devices)[-1]
|
entity = list(self.hass.data[sonos.DATA_SONOS].entities)[-1]
|
||||||
device.hass = self.hass
|
entity.hass = self.hass
|
||||||
alarm1 = alarms.Alarm(pysonos_mock)
|
alarm1 = alarms.Alarm(pysonos_mock)
|
||||||
alarm1.configure_mock(_alarm_id="1", start_time=None, enabled=False,
|
alarm1.configure_mock(_alarm_id="1", start_time=None, enabled=False,
|
||||||
include_linked_zones=False, volume=100)
|
include_linked_zones=False, volume=100)
|
||||||
|
@ -294,9 +294,9 @@ class TestSonosMediaPlayer(unittest.TestCase):
|
||||||
'include_linked_zones': True,
|
'include_linked_zones': True,
|
||||||
'volume': 0.30,
|
'volume': 0.30,
|
||||||
}
|
}
|
||||||
device.set_alarm(alarm_id=2)
|
entity.set_alarm(alarm_id=2)
|
||||||
alarm1.save.assert_not_called()
|
alarm1.save.assert_not_called()
|
||||||
device.set_alarm(alarm_id=1, **attrs)
|
entity.set_alarm(alarm_id=1, **attrs)
|
||||||
assert alarm1.enabled == attrs['enabled']
|
assert alarm1.enabled == attrs['enabled']
|
||||||
assert alarm1.start_time == attrs['time']
|
assert alarm1.start_time == attrs['time']
|
||||||
assert alarm1.include_linked_zones == \
|
assert alarm1.include_linked_zones == \
|
||||||
|
@ -312,11 +312,11 @@ class TestSonosMediaPlayer(unittest.TestCase):
|
||||||
sonos.setup_platform(self.hass, {}, add_entities_factory(self.hass), {
|
sonos.setup_platform(self.hass, {}, add_entities_factory(self.hass), {
|
||||||
'host': '192.0.2.1'
|
'host': '192.0.2.1'
|
||||||
})
|
})
|
||||||
device = list(self.hass.data[sonos.DATA_SONOS].devices)[-1]
|
entity = list(self.hass.data[sonos.DATA_SONOS].entities)[-1]
|
||||||
device.hass = self.hass
|
entity.hass = self.hass
|
||||||
|
|
||||||
snapshotMock.return_value = True
|
snapshotMock.return_value = True
|
||||||
device.snapshot()
|
entity.snapshot()
|
||||||
assert snapshotMock.call_count == 1
|
assert snapshotMock.call_count == 1
|
||||||
assert snapshotMock.call_args == mock.call()
|
assert snapshotMock.call_args == mock.call()
|
||||||
|
|
||||||
|
@ -330,13 +330,13 @@ class TestSonosMediaPlayer(unittest.TestCase):
|
||||||
sonos.setup_platform(self.hass, {}, add_entities_factory(self.hass), {
|
sonos.setup_platform(self.hass, {}, add_entities_factory(self.hass), {
|
||||||
'host': '192.0.2.1'
|
'host': '192.0.2.1'
|
||||||
})
|
})
|
||||||
device = list(self.hass.data[sonos.DATA_SONOS].devices)[-1]
|
entity = list(self.hass.data[sonos.DATA_SONOS].entities)[-1]
|
||||||
device.hass = self.hass
|
entity.hass = self.hass
|
||||||
|
|
||||||
restoreMock.return_value = True
|
restoreMock.return_value = True
|
||||||
device._snapshot_coordinator = mock.MagicMock()
|
entity._snapshot_coordinator = mock.MagicMock()
|
||||||
device._snapshot_coordinator.soco_device = SoCoMock('192.0.2.17')
|
entity._snapshot_coordinator.soco_entity = SoCoMock('192.0.2.17')
|
||||||
device._soco_snapshot = Snapshot(device._player)
|
entity._soco_snapshot = Snapshot(entity._player)
|
||||||
device.restore()
|
entity.restore()
|
||||||
assert restoreMock.call_count == 1
|
assert restoreMock.call_count == 1
|
||||||
assert restoreMock.call_args == mock.call(False)
|
assert restoreMock.call_args == mock.call(False)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue