diff --git a/homeassistant/components/sonos/__init__.py b/homeassistant/components/sonos/__init__.py index 69d5a9bfc33..bcac4ce272c 100644 --- a/homeassistant/components/sonos/__init__.py +++ b/homeassistant/components/sonos/__init__.py @@ -4,7 +4,7 @@ from homeassistant.helpers import config_entry_flow DOMAIN = 'sonos' -REQUIREMENTS = ['pysonos==0.0.6'] +REQUIREMENTS = ['pysonos==0.0.7'] async def async_setup(hass, config): diff --git a/homeassistant/components/sonos/media_player.py b/homeassistant/components/sonos/media_player.py index 2a7eafaf835..ee2f9e6b4dc 100644 --- a/homeassistant/components/sonos/media_player.py +++ b/homeassistant/components/sonos/media_player.py @@ -48,7 +48,7 @@ SERVICE_CLEAR_TIMER = 'sonos_clear_sleep_timer' SERVICE_UPDATE_ALARM = 'sonos_update_alarm' SERVICE_SET_OPTION = 'sonos_set_option' -DATA_SONOS = 'sonos_devices' +DATA_SONOS = 'sonos_media_player' SOURCE_LINEIN = 'Line-in' SOURCE_TV = 'TV' @@ -114,7 +114,7 @@ class SonosData: def __init__(self): """Initialize the data.""" self.uids = set() - self.devices = [] + self.entities = [] 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): """Set up Sonos from a config entry.""" - def add_entities(devices, update_before_add=False): - """Sync version of async add devices.""" - hass.add_job(async_add_entities, devices, update_before_add) + def add_entities(entities, update_before_add=False): + """Sync version of async add entities.""" + hass.add_job(async_add_entities, entities, update_before_add) hass.async_add_executor_job( _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: 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: return @@ -176,53 +176,54 @@ def _setup_platform(hass, config, add_entities, discovery_info): _LOGGER.warning("Failed to initialize '%s'", host) else: players = pysonos.discover( - interface_addr=config.get(CONF_INTERFACE_ADDR)) + interface_addr=config.get(CONF_INTERFACE_ADDR), + all_households=True) if not players: _LOGGER.warning("No Sonos speakers found") return 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)) def service_handle(service): """Handle for services.""" entity_ids = service.data.get('entity_id') - devices = hass.data[DATA_SONOS].devices + entities = hass.data[DATA_SONOS].entities 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: - master = [device for device in hass.data[DATA_SONOS].devices - if device.entity_id == service.data[ATTR_MASTER]] + master = [e for e in hass.data[DATA_SONOS].entities + if e.entity_id == service.data[ATTR_MASTER]] if master: with hass.data[DATA_SONOS].topology_lock: - master[0].join(devices) + master[0].join(entities) return if service.service == SERVICE_UNJOIN: with hass.data[DATA_SONOS].topology_lock: - for device in devices: - device.unjoin() + for entity in entities: + entity.unjoin() return - for device in devices: + for entity in entities: if service.service == SERVICE_SNAPSHOT: - device.snapshot(service.data[ATTR_WITH_GROUP]) + entity.snapshot(service.data[ATTR_WITH_GROUP]) 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: - device.set_sleep_timer(service.data[ATTR_SLEEP_TIME]) + entity.set_sleep_timer(service.data[ATTR_SLEEP_TIME]) elif service.service == SERVICE_CLEAR_TIMER: - device.clear_sleep_timer() + entity.clear_sleep_timer() elif service.service == SERVICE_UPDATE_ALARM: - device.set_alarm(**service.data) + entity.set_alarm(**service.data) 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( DOMAIN, SERVICE_JOIN, service_handle, @@ -270,9 +271,9 @@ class _ProcessSonosEventQueue: def _get_entity_from_soco_uid(hass, uid): - """Return SonosDevice from SoCo uid.""" - for entity in hass.data[DATA_SONOS].devices: - if uid == entity.soco.uid: + """Return SonosEntity from SoCo uid.""" + for entity in hass.data[DATA_SONOS].entities: + if uid == entity.unique_id: return entity return None @@ -303,11 +304,11 @@ def soco_error(errorcodes=None): def soco_coordinator(funct): """Call function on coordinator.""" @ft.wraps(funct) - def wrapper(device, *args, **kwargs): + def wrapper(entity, *args, **kwargs): """Wrap for call to coordinator.""" - if device.is_coordinator: - return funct(device, *args, **kwargs) - return funct(device.coordinator, *args, **kwargs) + if entity.is_coordinator: + return funct(entity, *args, **kwargs) + return funct(entity.coordinator, *args, **kwargs) return wrapper @@ -329,11 +330,11 @@ def _is_radio_uri(uri): return uri.startswith(radio_schemes) -class SonosDevice(MediaPlayerDevice): - """Representation of a Sonos device.""" +class SonosEntity(MediaPlayerDevice): + """Representation of a Sonos entity.""" def __init__(self, player): - """Initialize the Sonos device.""" + """Initialize the Sonos entity.""" self._subscriptions = [] self._receives_events = False self._volume_increment = 2 @@ -366,7 +367,7 @@ class SonosDevice(MediaPlayerDevice): async def async_added_to_hass(self): """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) @property @@ -376,7 +377,7 @@ class SonosDevice(MediaPlayerDevice): @property def name(self): - """Return the name of the device.""" + """Return the name of the entity.""" return self._name @property @@ -394,7 +395,7 @@ class SonosDevice(MediaPlayerDevice): @property @soco_coordinator def state(self): - """Return the state of the device.""" + """Return the state of the entity.""" if self._status in ('PAUSED_PLAYBACK', 'STOPPED'): return STATE_PAUSED if self._status in ('PLAYING', 'TRANSITIONING'): @@ -410,7 +411,7 @@ class SonosDevice(MediaPlayerDevice): @property def soco(self): - """Return soco device.""" + """Return soco object.""" return self._player @property @@ -434,7 +435,7 @@ class SonosDevice(MediaPlayerDevice): return False def _set_basic_information(self): - """Set initial device information.""" + """Set initial entity information.""" speaker_info = self.soco.get_speaker_info(True) self._name = speaker_info['zone_name'] self._model = speaker_info['model_name'] @@ -477,8 +478,8 @@ class SonosDevice(MediaPlayerDevice): self._receives_events = False # New player available, build the current group topology - for device in self.hass.data[DATA_SONOS].devices: - device.update_groups() + for entity in self.hass.data[DATA_SONOS].entities: + entity.update_groups() player = self.soco @@ -554,7 +555,7 @@ class SonosDevice(MediaPlayerDevice): self.schedule_update_ha_state() # Also update slaves - for entity in self.hass.data[DATA_SONOS].devices: + for entity in self.hass.data[DATA_SONOS].entities: coordinator = entity.coordinator if coordinator and coordinator.unique_id == self.unique_id: entity.schedule_update_ha_state() @@ -1087,7 +1088,7 @@ class SonosDevice(MediaPlayerDevice): @property def device_state_attributes(self): - """Return device specific state attributes.""" + """Return entity specific state attributes.""" attributes = {ATTR_SONOS_GROUP: self._sonos_group} if self._night_sound is not None: diff --git a/requirements_all.txt b/requirements_all.txt index d3fae557be7..d885b3004ca 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1263,7 +1263,7 @@ pysmartthings==0.6.3 pysnmp==4.4.8 # homeassistant.components.sonos -pysonos==0.0.6 +pysonos==0.0.7 # homeassistant.components.spc pyspcwebgw==0.4.0 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 64c28534046..f3b8e6ac03e 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -226,7 +226,7 @@ pysmartapp==0.3.0 pysmartthings==0.6.3 # homeassistant.components.sonos -pysonos==0.0.6 +pysonos==0.0.7 # homeassistant.components.spc pyspcwebgw==0.4.0 diff --git a/tests/components/sonos/test_media_player.py b/tests/components/sonos/test_media_player.py index 55ff96f202a..d57c730a9f8 100644 --- a/tests/components/sonos/test_media_player.py +++ b/tests/components/sonos/test_media_player.py @@ -21,7 +21,7 @@ ENTITY_ID = 'media_player.kitchen' class pysonosDiscoverMock(): """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 {SoCoMock('192.0.2.1')} @@ -123,10 +123,10 @@ class SoCoMock(): def add_entities_factory(hass): - """Add devices factory.""" - def add_entities(devices, update_befor_add=False): - """Fake add device.""" - hass.data[sonos.DATA_SONOS].devices = devices + """Add entities factory.""" + def add_entities(entities, update_befor_add=False): + """Fake add entity.""" + hass.data[sonos.DATA_SONOS].entities = entities return add_entities @@ -144,14 +144,14 @@ class TestSonosMediaPlayer(unittest.TestCase): return True # Monkey patches - self.real_available = sonos.SonosDevice.available - sonos.SonosDevice.available = monkey_available + self.real_available = sonos.SonosEntity.available + sonos.SonosEntity.available = monkey_available # pylint: disable=invalid-name def tearDown(self): """Stop everything that was started.""" # Monkey patches - sonos.SonosDevice.available = self.real_available + sonos.SonosEntity.available = self.real_available self.hass.stop() @mock.patch('pysonos.SoCo', new=SoCoMock) @@ -162,9 +162,9 @@ class TestSonosMediaPlayer(unittest.TestCase): 'host': '192.0.2.1' }) - devices = list(self.hass.data[sonos.DATA_SONOS].devices) - assert len(devices) == 1 - assert devices[0].name == 'Kitchen' + entities = list(self.hass.data[sonos.DATA_SONOS].entities) + assert len(entities) == 1 + assert entities[0].name == 'Kitchen' @mock.patch('pysonos.SoCo', new=SoCoMock) @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 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 @mock.patch('pysonos.SoCo', new=SoCoMock) @@ -198,9 +198,9 @@ class TestSonosMediaPlayer(unittest.TestCase): assert setup_component(self.hass, DOMAIN, config) - devices = self.hass.data[sonos.DATA_SONOS].devices - assert len(devices) == 1 - assert devices[0].name == 'Kitchen' + entities = self.hass.data[sonos.DATA_SONOS].entities + assert len(entities) == 1 + assert entities[0].name == 'Kitchen' @mock.patch('pysonos.SoCo', new=SoCoMock) @mock.patch('socket.create_connection', side_effect=socket.error()) @@ -215,9 +215,9 @@ class TestSonosMediaPlayer(unittest.TestCase): assert setup_component(self.hass, DOMAIN, config) - devices = self.hass.data[sonos.DATA_SONOS].devices - assert len(devices) == 2 - assert devices[0].name == 'Kitchen' + entities = self.hass.data[sonos.DATA_SONOS].entities + assert len(entities) == 2 + assert entities[0].name == 'Kitchen' @mock.patch('pysonos.SoCo', new=SoCoMock) @mock.patch('socket.create_connection', side_effect=socket.error()) @@ -232,9 +232,9 @@ class TestSonosMediaPlayer(unittest.TestCase): assert setup_component(self.hass, DOMAIN, config) - devices = self.hass.data[sonos.DATA_SONOS].devices - assert len(devices) == 2 - assert devices[0].name == 'Kitchen' + entities = self.hass.data[sonos.DATA_SONOS].entities + assert len(entities) == 2 + assert entities[0].name == 'Kitchen' @mock.patch('pysonos.SoCo', new=SoCoMock) @mock.patch.object(pysonos, 'discover', new=pysonosDiscoverMock.discover) @@ -242,9 +242,9 @@ class TestSonosMediaPlayer(unittest.TestCase): def test_ensure_setup_sonos_discovery(self, *args): """Test a single device using the autodiscovery provided by Sonos.""" sonos.setup_platform(self.hass, {}, add_entities_factory(self.hass)) - devices = list(self.hass.data[sonos.DATA_SONOS].devices) - assert len(devices) == 1 - assert devices[0].name == 'Kitchen' + entities = list(self.hass.data[sonos.DATA_SONOS].entities) + assert len(entities) == 1 + assert entities[0].name == 'Kitchen' @mock.patch('pysonos.SoCo', new=SoCoMock) @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), { 'host': '192.0.2.1' }) - device = list(self.hass.data[sonos.DATA_SONOS].devices)[-1] - device.hass = self.hass + entity = list(self.hass.data[sonos.DATA_SONOS].entities)[-1] + entity.hass = self.hass - device.set_sleep_timer(30) + entity.set_sleep_timer(30) set_sleep_timerMock.assert_called_once_with(30) @mock.patch('pysonos.SoCo', new=SoCoMock) @@ -268,10 +268,10 @@ class TestSonosMediaPlayer(unittest.TestCase): sonos.setup_platform(self.hass, {}, add_entities_factory(self.hass), { 'host': '192.0.2.1' }) - device = list(self.hass.data[sonos.DATA_SONOS].devices)[-1] - device.hass = self.hass + entity = list(self.hass.data[sonos.DATA_SONOS].entities)[-1] + entity.hass = self.hass - device.set_sleep_timer(None) + entity.set_sleep_timer(None) set_sleep_timerMock.assert_called_once_with(None) @mock.patch('pysonos.SoCo', new=SoCoMock) @@ -282,8 +282,8 @@ class TestSonosMediaPlayer(unittest.TestCase): sonos.setup_platform(self.hass, {}, add_entities_factory(self.hass), { 'host': '192.0.2.1' }) - device = list(self.hass.data[sonos.DATA_SONOS].devices)[-1] - device.hass = self.hass + entity = list(self.hass.data[sonos.DATA_SONOS].entities)[-1] + entity.hass = self.hass alarm1 = alarms.Alarm(pysonos_mock) alarm1.configure_mock(_alarm_id="1", start_time=None, enabled=False, include_linked_zones=False, volume=100) @@ -294,9 +294,9 @@ class TestSonosMediaPlayer(unittest.TestCase): 'include_linked_zones': True, 'volume': 0.30, } - device.set_alarm(alarm_id=2) + entity.set_alarm(alarm_id=2) 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.start_time == attrs['time'] assert alarm1.include_linked_zones == \ @@ -312,11 +312,11 @@ class TestSonosMediaPlayer(unittest.TestCase): sonos.setup_platform(self.hass, {}, add_entities_factory(self.hass), { 'host': '192.0.2.1' }) - device = list(self.hass.data[sonos.DATA_SONOS].devices)[-1] - device.hass = self.hass + entity = list(self.hass.data[sonos.DATA_SONOS].entities)[-1] + entity.hass = self.hass snapshotMock.return_value = True - device.snapshot() + entity.snapshot() assert snapshotMock.call_count == 1 assert snapshotMock.call_args == mock.call() @@ -330,13 +330,13 @@ class TestSonosMediaPlayer(unittest.TestCase): sonos.setup_platform(self.hass, {}, add_entities_factory(self.hass), { 'host': '192.0.2.1' }) - device = list(self.hass.data[sonos.DATA_SONOS].devices)[-1] - device.hass = self.hass + entity = list(self.hass.data[sonos.DATA_SONOS].entities)[-1] + entity.hass = self.hass restoreMock.return_value = True - device._snapshot_coordinator = mock.MagicMock() - device._snapshot_coordinator.soco_device = SoCoMock('192.0.2.17') - device._soco_snapshot = Snapshot(device._player) - device.restore() + entity._snapshot_coordinator = mock.MagicMock() + entity._snapshot_coordinator.soco_entity = SoCoMock('192.0.2.17') + entity._soco_snapshot = Snapshot(entity._player) + entity.restore() assert restoreMock.call_count == 1 assert restoreMock.call_args == mock.call(False)