Beispiel #1
0
    def _create_visible_speakers(self, ip_address: str) -> None:
        """Create all visible SonosSpeaker instances with the provided seed IP."""
        try:
            soco = SoCo(ip_address)
            visible_zones = soco.visible_zones
            self._known_invisible = soco.all_zones - visible_zones
        except (OSError, SoCoException) as ex:
            _LOGGER.warning("Failed to request visible zones from %s: %s",
                            ip_address, ex)
            return

        for zone in visible_zones:
            if zone.uid not in self.data.discovered:
                self._add_speaker(zone)
Beispiel #2
0
 def _discovered_player(self, soco: SoCo) -> None:
     """Handle a (re)discovered player."""
     try:
         speaker_info = soco.get_speaker_info(True)
         _LOGGER.debug("Adding new speaker: %s", speaker_info)
         speaker = SonosSpeaker(self.hass, soco, speaker_info)
         self.data.discovered[soco.uid] = speaker
         for coordinator, coord_dict in (
             (SonosAlarms, self.data.alarms),
             (SonosFavorites, self.data.favorites),
         ):
             if soco.household_id not in coord_dict:
                 new_coordinator = coordinator(self.hass, soco.household_id)
                 new_coordinator.setup(soco)
                 coord_dict[soco.household_id] = new_coordinator
         speaker.setup()
     except (OSError, SoCoException):
         _LOGGER.warning("Failed to add SonosSpeaker using %s", soco, exc_info=True)
Beispiel #3
0
    def _create_soco(self, ip_address: str,
                     source: SoCoCreationSource) -> SoCo | None:
        """Create a soco instance and return if successful."""
        if ip_address in self.data.discovery_ignored:
            return None

        try:
            soco = SoCo(ip_address)
            # Ensure that the player is available and UID is cached
            uid = soco.uid
            _ = soco.volume
            return soco
        except NotSupportedException as exc:
            _LOGGER.debug("Device %s is not supported, ignoring: %s", uid, exc)
            self.data.discovery_ignored.add(ip_address)
        except (OSError, SoCoException) as ex:
            _LOGGER.warning("Failed to connect to %s player '%s': %s",
                            source.value, ip_address, ex)
        return None
 def _add_speaker(self, soco: SoCo) -> None:
     """Create and set up a new SonosSpeaker instance."""
     try:
         speaker_info = soco.get_speaker_info(True)
         if soco.uid not in self.data.boot_counts:
             self.data.boot_counts[soco.uid] = soco.boot_seqnum
         _LOGGER.debug("Adding new speaker: %s", speaker_info)
         speaker = SonosSpeaker(self.hass, soco, speaker_info)
         self.data.discovered[soco.uid] = speaker
         for coordinator, coord_dict in (
             (SonosAlarms, self.data.alarms),
             (SonosFavorites, self.data.favorites),
         ):
             if soco.household_id not in coord_dict:
                 new_coordinator = coordinator(self.hass, soco.household_id)
                 new_coordinator.setup(soco)
                 coord_dict[soco.household_id] = new_coordinator
         speaker.setup(self.entry)
     except (OSError, SoCoException):
         _LOGGER.warning("Failed to add SonosSpeaker using %s", soco, exc_info=True)
Beispiel #5
0
    def _get_account_xml(soco):
        """Fetch the account data from a Sonos device.

        Args:
            soco (SoCo): a SoCo instance to query. If soco is none, a
                random device will be used.

        Returns:
            (str): a byte string containing the account data xml

        """
        # It is likely that the same information is available over UPnP as well
        # via a call to
        # systemProperties.GetStringX([('VariableName','R_SvcAccounts')]))
        # This returns an encrypted string, and, so far, we cannot decrypt it
        device = soco or SoCo.any_soco()
        log.debug("Fetching account data from %s", device)
        settings_url = "http://{0}:1400/status/accounts".format(
            device.ip_address)
        result = requests.get(settings_url).content
        log.debug("Account data: %s", result)
        return result
Beispiel #6
0
    def _get_account_xml(soco):
        """Fetch the account data from a Sonos device.

        Args:
            soco (SoCo): a SoCo instance to query. If soco is none, a
                random device will be used.

        Returns:
            (str): a byte string containing the account data xml

        """
        # It is likely that the same information is available over UPnP as well
        # via a call to
        # systemProperties.GetStringX([('VariableName','R_SvcAccounts')]))
        # This returns an encrypted string, and, so far, we cannot decrypt it
        device = soco or SoCo.any_soco()
        log.debug("Fetching account data from %s", device)
        settings_url = "http://{0}:1400/status/accounts".format(
            device.ip_address)
        result = requests.get(settings_url).content
        log.debug("Account data: %s", result)
        return result
 def _poll_manual_hosts(self, now: datetime.datetime | None = None) -> None:
     """Add and maintain Sonos devices from a manual configuration."""
     for host in self.hosts:
         ip_addr = socket.gethostbyname(host)
         soco = SoCo(ip_addr)
         try:
             visible_zones = soco.visible_zones
         except OSError:
             _LOGGER.warning("Could not get visible Sonos devices from %s", ip_addr)
         else:
             if new_hosts := {
                 x.ip_address
                 for x in visible_zones
                 if x.ip_address not in self.hosts
             }:
                 _LOGGER.debug("Adding to manual hosts: %s", new_hosts)
                 self.hosts.update(new_hosts)
             dispatcher_send(
                 self.hass,
                 f"{SONOS_SPEAKER_ACTIVITY}-{soco.uid}",
                 "manual zone scan",
             )
             break
Beispiel #8
0
 async def _async_handle_discovery_message(self, uid: str,
                                           discovered_ip: str,
                                           boot_seqnum: int) -> None:
     """Handle discovered player creation and activity."""
     async with self.discovery_lock:
         if not self.data.discovered:
             # Initial discovery, attempt to add all visible zones
             await self.hass.async_add_executor_job(
                 self._create_visible_speakers,
                 discovered_ip,
             )
         elif uid not in self.data.discovered:
             if self.is_device_invisible(discovered_ip):
                 return
             await self.hass.async_add_executor_job(self._add_speaker,
                                                    SoCo(discovered_ip))
         elif boot_seqnum and boot_seqnum > self.data.boot_counts[uid]:
             self.data.boot_counts[uid] = boot_seqnum
             async_dispatcher_send(self.hass, f"{SONOS_REBOOTED}-{uid}")
         else:
             async_dispatcher_send(self.hass,
                                   f"{SONOS_SPEAKER_ACTIVITY}-{uid}",
                                   "discovery")
Beispiel #9
0
#!/usr/bin/env python

import status_wrapper

from soco.core import SoCo

sonos = SoCo("10.0.0.11")


def wrap(j):
    # Truncate music titles
    j[1]["short_text"] = j[1]["full_text"][:160] + "..."

    try:
        block = {"name": "sonos"}
        volume = sonos.volume
        mute = sonos.mute
        icon = "♫"
        if mute:
            icon = "✕"
            block["color"] = status_wrapper.color_degraded
        block["full_text"] = "{} {}%".format(icon, volume)
        j.insert(0, block)
    except:
        pass

    return j


status_wrapper.mainloop(wrap)
Beispiel #10
0
 def _set_device_volume(self, device: SoCo, volume: int):
     device.volume = volume
     logger.info('Volume of Sonos device with name \'%s\' changed to %d.',
                 device.player_name, device.volume)
Beispiel #11
0
#!/usr/bin/env python3

from soco.core import SoCo
from sys import argv

sonos = SoCo("10.0.0.11")
vol_step = 5

if argv[1] == "line_in":
    sonos.switch_to_line_in()
    sonos.play()

if argv[1] == "+":
    sonos.volume = (int(sonos.volume / vol_step) + 1) * vol_step

if argv[1] == "-":
    sonos.volume = (int(sonos.volume / vol_step) - 1) * vol_step

if argv[1] == "set":
    sonos.volume = int(argv[2])

if argv[1] == "mute":
    sonos.mute = not (sonos.mute)