示例#1
0
    def get_device_by_name(self, player_name, raise_on_notfound=False):
        try:
            devices = list(soco.discover())
        except TypeError as err:
            self.error(
                f"soco.discover returned None for player: {player_name} err: {err}"
            )
            return None

        for device in devices:
            if device.player_name == player_name.strip():
                return device
        if raise_on_notfound:
            raise adplus.ConfigException(
                f"Could not find Sonos Device named: {player_name}")
        return None
示例#2
0
    def _create_sonos_entities():
        """Discover players and return a list of SonosEntity objects."""
        players = []
        hosts = config.get(CONF_HOSTS)

        if hosts:
            for host in hosts:
                try:
                    players.append(pysonos.SoCo(socket.gethostbyname(host)))
                except (OSError, SoCoException):
                    _LOGGER.warning("Failed to initialize '%s'", host)
        else:
            players = pysonos.discover(
                interface_addr=config.get(CONF_INTERFACE_ADDR),
                all_households=True)

        if not players:
            _LOGGER.warning("No Sonos speakers found")

        return [SonosEntity(p) for p in players]
示例#3
0
    def test_discover(self, monkeypatch):
        # Create a fake socket, whose data is always a certain string
        monkeypatch.setattr('socket.socket', Mock())
        sock = socket.socket.return_value
        sock.recvfrom.return_value = (
            b'SERVER: Linux UPnP/1.0 Sonos/26.1-76230 (ZPS3)', [IP_ADDR]
        )  # (data, # address)
        monkeypatch.setattr(
            'ifaddr.get_adapters',
            Mock(
                side_effect=lambda:
                [MockAdapter(['192.168.1.15']),
                 MockAdapter(['192.168.1.16'])]))
        # Fast-forward through timeouts with all_households=True
        monkeypatch.setattr('time.monotonic', Mock(side_effect=monotonic_time))
        # prevent creation of soco instances
        monkeypatch.setattr('pysonos.config.SOCO_CLASS',
                            Mock(return_value=ZoneMock()))
        # Fake return value for select
        monkeypatch.setattr('select.select',
                            Mock(return_value=([sock], [], [])))

        # set timeout
        TIMEOUT = 2
        discover(timeout=TIMEOUT)
        # Two packets for 192.168.1.15 and two for 192.168.1.16
        assert sock.sendto.call_count == 4
        # select called with the relevant timeout
        select.select.assert_called_with([sock, sock], [], [], 1.6)
        # SoCo should be created with the IP address received
        config.SOCO_CLASS.assert_called_with(IP_ADDR)

        # Now test include_visible parameter. include_invisible=True should
        # result in calling SoCo.all_zones etc
        # Reset interfaces to always return the same values
        monkeypatch.setattr(
            'ifaddr.get_adapters',
            Mock(side_effect=lambda: [MockAdapter('192.168.1.19')]))
        assert discover(include_invisible=True) == {'ALL'}
        assert discover(include_invisible=False) == {'VISIBLE'}

        # if select does not return within timeout SoCo should not be called
        # at all
        # simulate no data being returned within timeout
        monkeypatch.setattr('threading.Thread.join', Mock())
        select.select.return_value = ([], [], [])
        discover(timeout=1)
        # Check no SoCo instance created
        config.SOCO_CLASS.assert_not_called
示例#4
0
    def describe_sonos_system(self, kwargs):
        devices = list(soco.discover())
        favorites = list(
            soco.music_library.MusicLibrary().get_sonos_favorites())
        devices_simple = {}

        def clip(line):
            MAX_LENGTH = 75
            line = str(line)
            if len(line) < MAX_LENGTH:
                return line
            else:
                return line[:MAX_LENGTH - 3] + "..."

        def clipdict(indict):
            return {k: clip(v) for k, v in indict.items()}

        for dev in devices:
            devices_simple[dev.player_name] = {
                "player_name": dev.player_name,
                "ip_address": dev.ip_address,
                "group": str(dev.group),
                "volume": dev.volume,
                "play_mode": dev.play_mode,
                "transport_info": dev.get_current_transport_info(),
                "current_media_info": (dev.get_current_media_info()),
                "current_track_info": (dev.get_current_track_info()),
                # "speaker_info": dev.get_speaker_info()
            }
        data = {
            "devices": devices_simple,
            "favorites":
            [clipdict(favorite.to_dict()) for favorite in favorites],
        }

        logfile = Path(self.config_dir) / "../logs/sonos_data.json"
        with logfile.open("wt") as fp:
            json.dump(data, fp, indent=4)
示例#5
0
def _setup_platform(hass, config, add_entities, discovery_info):
    """Set up the Sonos platform."""
    import pysonos

    if DATA_SONOS not in hass.data:
        hass.data[DATA_SONOS] = SonosData(hass)

    advertise_addr = config.get(CONF_ADVERTISE_ADDR)
    if advertise_addr:
        pysonos.config.EVENT_ADVERTISE_IP = advertise_addr

    players = []
    if discovery_info:
        player = pysonos.SoCo(discovery_info.get('host'))

        # If host already exists by config
        if player.uid in hass.data[DATA_SONOS].uids:
            return

        # If invisible, such as a stereo slave
        if not player.is_visible:
            return

        players.append(player)
    else:
        hosts = config.get(CONF_HOSTS)
        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
            for host in hosts:
                try:
                    players.append(pysonos.SoCo(socket.gethostbyname(host)))
                except OSError:
                    _LOGGER.warning("Failed to initialize '%s'", host)
        else:
            players = pysonos.discover(
                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(SonosEntity(p) for p in players)
    _LOGGER.debug("Added %s Sonos speakers", len(players))

    def _service_to_entities(service):
        """Extract and return entities from service call."""
        entity_ids = service.data.get('entity_id')

        entities = hass.data[DATA_SONOS].entities
        if entity_ids:
            entities = [e for e in entities if e.entity_id in entity_ids]

        return entities

    async def async_service_handle(service):
        """Handle async services."""
        entities = _service_to_entities(service)

        if service.service == SERVICE_JOIN:
            master = [e for e in hass.data[DATA_SONOS].entities
                      if e.entity_id == service.data[ATTR_MASTER]]
            if master:
                await SonosEntity.join_multi(hass, master[0], entities)
        elif service.service == SERVICE_UNJOIN:
            await SonosEntity.unjoin_multi(hass, entities)
        elif service.service == SERVICE_SNAPSHOT:
            await SonosEntity.snapshot_multi(
                hass, entities, service.data[ATTR_WITH_GROUP])
        elif service.service == SERVICE_RESTORE:
            await SonosEntity.restore_multi(
                hass, entities, service.data[ATTR_WITH_GROUP])

    hass.services.register(
        DOMAIN, SERVICE_JOIN, async_service_handle,
        schema=SONOS_JOIN_SCHEMA)

    hass.services.register(
        DOMAIN, SERVICE_UNJOIN, async_service_handle,
        schema=SONOS_SCHEMA)

    hass.services.register(
        DOMAIN, SERVICE_SNAPSHOT, async_service_handle,
        schema=SONOS_STATES_SCHEMA)

    hass.services.register(
        DOMAIN, SERVICE_RESTORE, async_service_handle,
        schema=SONOS_STATES_SCHEMA)

    def service_handle(service):
        """Handle sync services."""
        for entity in _service_to_entities(service):
            if service.service == SERVICE_SET_TIMER:
                entity.set_sleep_timer(service.data[ATTR_SLEEP_TIME])
            elif service.service == SERVICE_CLEAR_TIMER:
                entity.clear_sleep_timer()
            elif service.service == SERVICE_UPDATE_ALARM:
                entity.set_alarm(**service.data)
            elif service.service == SERVICE_SET_OPTION:
                entity.set_option(**service.data)

    hass.services.register(
        DOMAIN, SERVICE_SET_TIMER, service_handle,
        schema=SONOS_SET_TIMER_SCHEMA)

    hass.services.register(
        DOMAIN, SERVICE_CLEAR_TIMER, service_handle,
        schema=SONOS_SCHEMA)

    hass.services.register(
        DOMAIN, SERVICE_UPDATE_ALARM, service_handle,
        schema=SONOS_UPDATE_ALARM_SCHEMA)

    hass.services.register(
        DOMAIN, SERVICE_SET_OPTION, service_handle,
        schema=SONOS_SET_OPTION_SCHEMA)