Coder Social home page Coder Social logo

soco / soco Goto Github PK

View Code? Open in Web Editor NEW
1.5K 1.5K 229.0 3.44 MB

SoCo (Sonos Controller) is a Python project that allows you to programmatically control Sonos speakers.

Home Page: http://python-soco.com/

License: MIT License

Python 99.89% Shell 0.04% Makefile 0.05% Batchfile 0.02%

soco's Introduction

SoCo

SoCo (Sonos Controller) is a Python library that allows you to control Sonos speakers programmatically. It was originally created at Music Hack Day Sydney by Rahim Sonawalla and is now developed by a team of people at its GitHub repository

For more background on the project, please see Rahim's blog post.

Visit the SoCo documentation for a more detailed overview of the functionailty.

Join the chat at https://gitter.im/SoCo/SoCo

Build Status

Requirements Status

Latest PyPI version

WARNING

Sonos has changed the way music service account information is available. This means that currently a group of music service will give authentication issues and cannot be used at all. Known members of this group are: Google Play Music, Apple Music, Amazon Music, Spotify and Napster.

Issue #557 is a meta issue for this problem and you can use that to track progress on solving the issues, but please refrain from posting "me too" comments in there. Also, there is no need to open any more separate issue about this. If you have another music service that should be on the list, comment in #557

As of v0.26.0, nascent music service support has been reinstated, with some known issues. Testing and issue reporting would be appreciated.

Installation

SoCo requires Python 3.6 or newer.

Use pip:

pip install soco

SoCo depends on a number of Python packages. If you use pip to install Soco, the dependencies will be installed automatically for you. If not, you can inspect the requirements in the requirements.txt file.

Basic Usage

You can interact with a Sonos Zone Player through a SoCo object. If you know the IP address of a Zone Player, you can create a SoCo object directly:

>>> from soco import SoCo
>>> my_zone = SoCo('192.168.1.101')
>>> my_zone.player_name
Kitchen
>>> my_zone.status_light = True
>>> my_zone.volume = 6

But perhaps the easiest way is to use the module-level discover function. This will find all the Zone Players on your network, and return a python set containing them:

>>> from soco import discover
>>> for zone in discover():
...        print(zone.player_name)
Living Room
Kitchen

If you prefer a list to a set:

>>> zone_list = list(discover())
>>> zone_list
[SoCo("192.168.1.101"), SoCo("192.168.1.102")]
>>> zone_list[0].mute = True

Of course, you can also play music!

#!/usr/bin/env python
from soco import SoCo

if __name__ == '__main__':
    sonos = SoCo('192.168.1.102') # Pass in the IP of your Sonos speaker
    # You could use the discover function instead, if you don't know the IP

    # Pass in a URI to a media file to have it streamed through the Sonos
    # speaker
    sonos.play_uri(
        'http://ia801402.us.archive.org/20/items/TenD2005-07-16.flac16/TenD2005-07-16t10Wonderboy.mp3')

    track = sonos.get_current_track_info()

    print(track['title'])

    sonos.pause()

    # Play a stopped or paused track
    sonos.play()

Support

If you need support for SoCo, feel free to post your question in the SoCo Gitter Room.

Example Applications

To show off what can be made with SoCo, a simple web application is included in the examples folder.

Screenshot of web app

Screenshot of web app

Features

SoCo supports the following controls amongst others:

  • Play, Pause, Stop
  • Next track, Previous track
  • Volume get and set
  • Mute (or unmute)
  • Get current transport information (if speaker is playing, paused or stopped)
  • Get information about the currently playing track
    • Track title
    • Artist
    • Album
    • Album Art (if available)
    • Track length
    • Duration played (for example, 30 seconds into a 3 minute song)
    • Playlist position (for example, item 5 in the playlist)
    • Track URI
  • Receive events when the player state changes
  • Search for and play music items:
    • Local music library
    • Webradio via TuneIn and music services (still unstable)
    • Saved Sonos favorites, favorite radio stations and shows
  • Switch the speaker’s source to line-in or TV input (if the Zone Player supports it)
  • Manage the Sonos queue:
    • Get the items in the queue
    • Add items to the queue
    • Clear the queue
    • Play a specific song from the queue
  • Join or unjoin speakers from a group
  • Put all Sonos speakers in a network into “party mode”.
  • Get or set alarms
  • Get or set sleep timers
  • Enable or disable surround speakers or subwoofer
  • Get information regarding a home theater setup:
    • If surround speakers or a subwoofer are paired
    • Which audio channel a given speaker handles
  • Get or set the speaker’s bass and treble EQ
  • Toggle the speaker’s loudness compensation, night mode and dialog mode
  • Toggle the white status light on the unit
  • Get the speaker’s information
    • Zone Name
    • Zone Icon
    • UID (usually something like RINCON_XXXXXXXXXXXXXXXXX)
    • Serial Number
    • Software version
    • Hardware version
    • MAC Address
  • Set the speaker’s Zone Name
  • Start a music library update and determine if one is in progress

SoCo also supports lower level access from Python to all Sonos services (e.g. ContentDirectory or RenderingControl).

Socos is a command line tool for controlling Sonos devices. It is developed in conjunction with Soco, but in a separate repository.

SoCo-CLI (soco-cli) is a powerful and fully-featured command line tool suitable for use in scripts, scheduled tasks, etc. It supports time-based and state-based actions, and repeated commands using loops. Audio files on the local filesystem can be played back directly on Sonos from the command line. Multi-household Sonos systems are supported.

Older Projects

More of a Ruby fan? Not a problem, Sam Soffes is building out an awesome Ruby gem.

Looking for a GUI that’s more than just a sample project? Joel Björkman is building a Sonos Controller GUI–great for folks on Linux where there isn’t an official Sonos Controller application! Find, fork, and contribute to it here: https://github.com/labero/SoCo-Tk.

SoCo Gitter Room

There is a SoCo Gitter discussion room. Feel free to drop by for support, ideas or casual conversation related to SoCo.

License

SoCo is released under the MIT license.

soco's People

Contributors

agriffis avatar amelchio avatar americanwookie avatar bdraco avatar bjarniivarsson avatar dajobe avatar daubman avatar doreilly avatar dph avatar dundeemt avatar flavio avatar ghcs27 avatar hugovk avatar jjlawren avatar lawrenceakka avatar michaelotto avatar phut avatar pmatos avatar poirier avatar pwt avatar r0stig avatar rahims avatar relevitt avatar robwebset avatar rytilahti avatar sbelluzzo avatar scottgwaters avatar stefankoegl avatar tzneal avatar xxdede avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

soco's Issues

SonosDiscovery and Windows Python

Hi
I got the regular SoCo class working OK with Windows Python by specifying IP address but the SonosDiscovery class does not seem to work.
A network analyser suggests that the uPnP request isn't being broadcast.
Did anyone else notice this?

Thanks

T

Access speed to music library

Hi Rahim,

Great stuff. Really nice! You should change your name to Sonoswalla!-))

I've written my own Zonos controller, with the long term aim to at least provide the same interface to my computer (aka add it as a virtual Zone player). Having some thoughts on ensuring party-mode would work using frequency analysis and cross-correlation of the sound-track. That's still down the track. Currently, my controller does everything (I've had time to program), but I do have one incy wincy little itemette. Having 18000+ tracks it takes hell-of-a-time to build a list of all tracks (i.e. looping with get_music_lib with 300 items at a time). Now hooking up my iphone, it got the list in a wazzle-dazzle, so there must be a better way of doing it.

Any suggestions?

Cheers

Ken

Boolean not callable

Whenever I try to use a function that takes a boolean as a param I get a type error. Is this a problem on my end, am I doing something wrong, or is this a bug? (I included my code just in case!)

from soco import SoCo

Bridge = SoCo('10.0.1.18')
Den = SoCo('10.0.1.22')
Kitchen = SoCo('10.0.1.19')
MasterBath = SoCo('10.0.1.21')
MasterTV = SoCo('10.0.1.50')

SoCo('10.0.1.19').mute(True)

Discussion about IP addresses etc

I have been thinking about the use of IP addresses and SonosDiscovery generally.

IP addresses

We should in general not care so much about IP addresses.

It seems odd to me that discovery should return an IP address, which the user then has inevitably to use to create a SoCo instance. Similarly, for example, why does get_group_coordinator return an IP address, which is only useful for creating a SoCo instance?

I think it would be better if the discovery process simply returned a created SoCo instance (or list of instances, or a generator) to the user. The group/topology methods could do the same. Asking for the group coordinator of a particular group should return a SoCo instance representing the coordinator, rather than the coordinator's IP. See also the current code for partymode which has to get a list of IP addresses, and turn them into SoCo instances before it can use them.

In short, IP addresses are generally irrelevant to the end user, and we should instead pass and return SoCo instances to and from methods.

i.e.

coordinator = soco.get_group_coordinator('mygroup')
coordinator.play()

rather than

coordinator_ip = soco.get_group_coordinator('mygroup')
coordinator = SoCo(coordinator_ip)
coordinator.play()

Of course, if someone really wanted to know the ip address, it could be available as coordinator.ip_address

SonosDiscovery

At the moment it seems odd to have SonosDiscovery as a class, which will generally only be instantiated once. Would it be better as a module level function, or even as static method of the SoCo class itself? A user could then do something like this:

speakers = SoCo.discover_speakers()
for zone in speakers:
    print zone.player_name

rather than

speaker_ips = SonosDiscovery().get_speaker_ips()
for ip in speaker_ips:
    zone_player = SoCo(ip)
    print zone.player_name

It would be great to hear everyone's views.

Lawrence

Question: Roadmap\How to get involved

I am extremely interested in this project as I have 5 Sonos components currently. I'm wondering what everyone's vision is for this project and I'm how I can get involved to move closer to the vision.

I for one would like to see this library grow to include manipulating the different music services (i.e. Pandora, Spotify, etc). Tighten up the existing library to manage zones and such. And most importantly a creation of a web service that would be available from a browser or XMBC widget running on a Raspberry Pi connect to a TV.

can't play URIs from Amazon Cloud Player

An example, run while playing a track from Amazon Cloud Player:

>>> uri = s.get_current_track_info().get('uri')
>>> uri
'x-sonos-http:amz%3atr%3a8b9f2412-dc3b-455f-a38f-fee879911193.mp4?sid=26&flags=32'
>>> s.stop()
>>> s.play_uri(uri)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "soco/core.py", line 202, in play_uri
    self.__parse_error(response)
  File "soco/core.py", line 979, in __parse_error
    raise SoCoException(int(errorCode))
soco.exceptions.SoCoException: 402

Apologies if I'm asking something dumb. The rest of the library makes sense and I have no problems using it. Also happy to try to be of service in providing code to fix this if someone can explain the issues in play or point me toward additional information.

building fails

I am quite new to Python and thus doesn't really know well all the tools around Python.

I tried to build and install the SoCo (python setup.py install), but get an error:

Extracting soco-0.6-py2.6.egg to /usr/lib/python2.6/site-packages
SyntaxError: ('invalid syntax', ('/usr/lib/python2.6/site-packages/soco-0.6-py2.6.egg/soco/services.py', 237, 39, ' return {i.tag: i.text or "" for i in action_response}\n'))
soco 0.6 is already the active version in easy-install.pth

Is the error on my side?

Thanks for the help...
Mike

Topology Discovery

First of all congratulations on this project, I think it's great and would like to help where necessary.

The first thing that caught my eye while trying it out was the fact that there doesn't seem to be a nice straightforward way to map out a topology. It seems you have to discover all speakers and use the instance method get_group_coordinator on a SoCo instance to find the group controllers, and you need to pass in the group name.

Perhaps it would be interesting to be able to discover only the group coordinators, maybe as a new module level discovery function.

In terms of SoCo instance methods, maybe an is_group_coordinator property would be useful and get_group_coordinator could use the instance's own zone name.

Apologies if I have missed anything obvious or am generally missing the point.
Thanks.

Does add_to_queue work for you with music service url's

Hallo

While writing unit tests I noticed that add_to_queue does not work for me with tracks from the music service that I use (Wimp). The music service does use the queue, and I can retrieve the queue, but if I try to add a second copy of one of the tracks by giving it the url, it returns the upnp error. The url's for the music service looks like this:
x-sonos-http:trackid_7840826.mp4?sid=20&flags=32
whereas the uri for a track from my music library looks like this:
x-file-cifs://TLE-SERVER/share/flac/Agnes%20Obel%20-%20Philharmonics/12%20-%20On%20Powdered%20Ground.flac

I guess the most like explanation is that adding music service track uri's require another "command" to be sent, but I would like to confirm that before I put it on the enhancement list.

Publish 0.7

SoCo/socos#25

A lot of changes have been introduced since 0.6, it would be nice to ( in a simpler fashion ) use them in clients.

I don't know if there's been a discussion on versioning, but I wrote 0.8 as I tend to think odd-number=unstable, even-number=stable. Perhaps both 0.7 and 0.8 can be released with proper categorization?

TODO: rewrite topology methods to use new code

Methods such as SoCo.get_group_coordinator can be rewritten to us UPnP methods. These commands should return all the info needed about all groups and their coordinators (and more besides):

>>> self.zoneGroupTopology = ZoneGroupTopology(self)
>>> self.zoneGroupTopology.GetZoneGroupState()

[Feature request] Get event notifications (song change, pause, etc.)

This is an issue migrated from rahims/SoCo#14 (comment). In a now out-dated branch "https://github.com/rahims/SoCo/tree/sonos-events" there exists a solution that allows to build a listener that allows you to respond to events of interest (TransferStatus changed etc).

Although the internals of SoCo have changed, according to @KennethNielsen, most if the ingredients are now there. So where would one start to implement this?
I am interested in a listener that would let me allow to react to changes on my zones to switch external amps etc.

Firmly defined expected output and use None or '' as default for output strings

Hallo follow SoCo-devs

First of, I would like to make the suggestion, that we make it a design goal that all methods document exactly how many and which strings will be present in the output, also e.g. in output dictionaries and such.

We have one or two methods that will choose to leave certain e.g. keys in a dictionary out, if it was not possible to retrieve the information that corresponded to these keys, but I think that it would make for better programming to define the output exactly.

That then leaves the question of what to do with the information items, that were not present for the current item. Should these strings default to None or to the empty string ''.

The advantage if the empty string is, that it might remove the need for specific check outside of SoCo before using the strings. E.g. if you want to pass the information from the method on to a GUI, then you would probably exactly want to fill it out with a empty string anyway.

The disadvantage of the empty string is, that it will become impossible to tell whether the strings could not be retrieved or whether its value actually was the empty string.

For exactly the last reason, I think it would be better to use None, but I am eager to hear your opinions on the subject.

After discussion I intend to start a conventions page on the wiki with the results.

Regards Kenneth

set_player_name works but raises exception

The set_player_name works but raises an exception. The stack trace is pasted below.

  File "/home/knielsen/code/soco/SoCo/soco/core.py", line 103, in set_player_name
    self.__parse_error(response)
  File "/home/knielsen/code/soco/SoCo/soco/core.py", line 981, in __parse_error
    raise UnknownSoCoException(response)
soco.exceptions.UnknownSoCoException: <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><s:Body><u:SetZoneAttributesResponse xmlns:u="urn:schemas-upnp-org:service:DeviceProperties:1"></u:SetZoneAttributesResponse></s:Body></s:Envelope>

tests in soco_unittest will not work

The tests in soco_unittest will not work as currently written. Both AddToQueue and RemoveFromQueue get the state of the queue (which includes the track URI but also metadata about artist, track length etc), manipulate the queue by adding/removing tracks, and then call SOCO.add_to_queue() passing just a track uri as a parameter. As a result, the other metadata which was in the queue before is lost, and the assertions which comport the before and after state always fail.

Also, the set_state method will not restore the queue state properly, for the same reason.

The fix will be to change the add_to_queue method to accept other metadata beside track uri.

For discussion: Properties

Would it be possible to make some methods into properties. For example, I find this

speaker.volume += 4

to be much less cumbersome and more pythonic than:

vol = speaker.volume()
speaker.volume(vol + 4)

Also:

speaker.mute = True
speaker.status_light = True

seems much better (to me) than

speaker.mute(True)
speaker.status_light("On")

What do you all think? The coding would be relatively easy. Other candidates are of course, bass, treble, loudness, player_name etc. Things which are truly actions/commands (such as play, stop) will stay as methods, but things which are properties should be properties!

Update setup.py

I have updated setup.py as follows:

  1. Remove old cruft - setuptools is now pretty much the default/We can ignore python 2.6 etc

  2. Added a setup.py test command to call pytest. To get this to work, we will need to add ``recursive-include unittest *.py` to MANIFEST.in

  3. Used the new README as the long description so we get a nice(r) homepage on Pypi

  4. Added some trove classifiers for people who browse Pipi

Sorry I can't create a PR at the moment, so I have posted the code below. Could someone make a PR from this?

NB the pypi package only installs soco and the plugins (i.e. no docs and no examples). Is this on purpose?

Lawrence

#!/usr/bin/env python

import sys
import re
import warnings
from setuptools import setup
from setuptools.command.test import test as TestCommand

class PyTest(TestCommand):
    # COde from here: https://pytest.org/latest/goodpractises.html
    def finalize_options(self):
        TestCommand.finalize_options(self)
        self.test_args = []
        self.test_suite = True

    def run_tests(self):
        #import here, cause outside the eggs aren't loaded
        import pytest
        errno = pytest.main(self.test_args)
        sys.exit(errno)


src = open('soco/__init__.py').read()
metadata = dict(re.findall("__([a-z]+)__ = '([^']+)'", src))
docstrings = re.findall('"""([^"]*)"""', src, re.MULTILINE | re.DOTALL)

NAME = 'soco'

PACKAGES = (
        'soco',
        'soco.plugins',
)

REQUIREMENTS = list(open('requirements.txt'))
AUTHOR_EMAIL = metadata['author']
VERSION = metadata['version']
WEBSITE = metadata['website']
LICENSE = metadata['license']
DESCRIPTION = docstrings[0]

with open('README.rst') as file:
    LONG_DESCRIPTION = file.read()

# Extract name and e-mail ("Firstname Lastname <[email protected]>")
AUTHOR, EMAIL = re.match(r'(.*) <(.*)>', AUTHOR_EMAIL).groups()

setup(name=NAME,
      version=VERSION,
      description=DESCRIPTION,
      author=AUTHOR,
      author_email=EMAIL,
      license=LICENSE,
      url=WEBSITE,
      packages=PACKAGES,
      install_requires=REQUIREMENTS,
      long_description=LONG_DESCRIPTION,
      tests_require=['pytest'],
      cmdclass = {'test': PyTest},
      classifiers=[
      'Development Status :: 3 - Alpha',
      'Intended Audience :: Developers',
      'License :: OSI Approved :: MIT License',
      'Operating System :: OS Independent',
      'Programming Language :: Python :: 2',
      'Programming Language :: Python :: 2.7',
      'Programming Language :: Python :: 3',
      'Programming Language :: Python :: 3.2',
      'Programming Language :: Python :: 3.3',
      'Programming Language :: Python :: 3.4',
      'Programming Language :: Python :: Implementation :: PyPy',
      'Topic :: Home Automation',
      'Topic :: Multimedia :: Sound/Audio',
      'Topic :: Multimedia :: Sound/Audio :: Players',
      'Topic :: Software Development :: Libraries :: Python Modules',],
)

Use classes for all the data structure

Hi everyone

I'd like to discuss the idea of using classes for all of our data structures (especially the ones we return from methods). I would propose to implement these data structure classes in such a way, that they behave like the primitive type it logically consist of, so e.g. a list of tracks like that which is returned from get_queue will return a class that can be indexed like a list and each element in it, corresponding to a track, will be an instance of a class that acts like a dict, that way it is now.

Doing it this way not only ensures that we don't break comparability but is also, I think, the logical way to structure this.

The main advantage of this is that it will make it easier for people that may use our library, to identify what it is they are dealing with, without having to read and "parse" a list or a dict.

What do you guys think?

Regards Kenneth

How to list Sonos Playlists

In the official controllers you can save your queue as a Sonos playlist , you can then later list your saved playlists and select one as your new queue ( or add to existing queue ).

I assumed there was a service function for this somewhere, so I started looking into {service}.iter_actions, so far I've found Queue.SaveAsSonosPlaylist and there's a few functions that may or may not be related to these playlists in AVTransport

What I however can not find is anything related to listing the existing saved queues?

some code I wrote to find the functions

from __future__ import print_function
import inspect
from soco import SoCo, services
sonos = SoCo('xxx') 

for service in [
                services.AlarmClock,
                services.MusicServices,
                services.DeviceProperties,
                services.SystemProperties,
                services.ZoneGroupTopology,
                services.GroupManagement,
                services.QPlay,
                services.ContentDirectory,
                services.MS_ConnectionManager,
                services.RenderingControl,
                services.MR_ConnectionManager,
                services.AVTransport,
                services.Queue,
                services.GroupRenderingControl]:
    instance = service(sonos)
    for action, in_args, out_args in instance.iter_actions():
        print("%s.%s " % (instance.__class__.__name__, action))
        #print("in_args: %s out_args: %s" % (in_args, out_args))

SonosDiscovery is deprecated

Hey SoCo developers again!

I just went back to using your soco library (installed it just now so i have the latest version (from this git repo)) and i get an error saying UserWarning: SonosDiscovery is deprecated. Use discover instead.

Here is my code:

import soco

class Sonos:
    def __init__(self):
        self.SD = soco.SonosDiscovery()


Sonos()

As you can see i am using the same usage as on the readthedocs.com so it is in the soco library which is causing the error.

What shall i do to fix this?

Thanks for helping!

If you need it this is the full error

Users/pdeveloper/.virtualenvs/sonos/lib/python2.7/site-packages/soco-0.6-py2.7.egg/soco/core.py:87: UserWarning: SonosDiscovery is deprecated. Use discover instead.

Move the ToDo from the front page to the wiki

Hey everyone

I would like to propose to move the ToDo from the front page to the wiki to make it come more alive. We could add items and people could add theirs names if they are working on a feature etc. What do you think?

Regards Kenneth

Code acceptance/commit criteria

Having moved the code to its own project and having expanded the project group (with rights to merge pull requests), we should be able to process pull requests faster, but that will require that we agree on what the criteria is for when it is ok to pull them.

So how many people needs to agree for the different degrees of how invasive a pull is?
Does @rahims (founder) want to be mandatory in all of them, just the major ones or not necessarily any of them?

My suggestion would be the following.

  1. All code should continue to be reviewed by at least 1 project group member (that isn't the author obviously), the way it has been so far
  2. The criteria acceptance criteria for making a pull request should, for the different types of changes should be
    1. All bug fixes that does not, or only to a minor degree, change functionality, can be accepted by just 1 group member that isn't the author.
    2. Medium level changes like adding in new functionality within the existing structure or making small refactorings that does not change the interface can be accepted by (2 group members of which 1 can be the author/1 group member that is not the author)?
    3. High level changes that expand infrastructure or add design decisions can be accepted by 2 group members of which 1 can be the author (@rahims?)
    4. High level changes that change existing infrastructure or alter the existing designs can be accepted by 2/3? group members of which 1 can be the author (@rahims?)
    5. Disputes (let's hope we don't have any) like competing implementations or disagreements about implementations or designs should be settled by the majority of the group (at least 2 members) and ultimately can be overruled by @rahims

I think it is really important to not kill the momentum, that we do not make it too hard for ourselves (and new contributors), but at the same time it is so much easier to ensure the quality of the code before accepting it than afterwards. Basically I think the suggestion above offers a reasonable compromise, what do you all think?

Regards Kenneth

How do I detect a 'Master' speaker in a Zone?

Is there a way to find a 'Master' speaker in a zone? I'm trying to write code for a dynamically changing speaker configuration. I'd like to find the master speaker and then play something.

TypeError: method expected 2 arguments, got 3

Hi With Python2 everything works flawlessly, however with Python3 I get the following traceback, any ideas of how to solve this issue??

admin@smarthome:/usr/smarthome/Temp/master/examples/commandline$ python3 sonoshell.py 192.168.0.6 Stop
Traceback (most recent call last):
File "sonoshell.py", line 101, in
print(sonos.stop())
File "/usr/local/lib/python3.2/dist-packages/soco-0.6-py3.2.egg/soco/core.py", line 278, in stop
self.avTransport.Stop([
File "/usr/local/lib/python3.2/dist-packages/soco-0.6-py3.2.egg/soco/services.py", line 163, in getattr
method = MethodType(_dispatcher, self, self.class)
TypeError: method expected 2 arguments, got 3
admin@smarthome:/usr/smarthome/Temp/master/examples/commandline$

[question] add_to_queue for spotify tracks / albums

Hi all,

I saw what jasperla build over at soffes/sonos "gotwalt/sonos#26". And tought it would be cool to have it also in SoCo but I think I miss something...

playing a spotify track is no problem:
track = "x-sonos-spotify:spotify%3atrack%3a0GfUZrIeoQ1TVZFnLSZYJY?sid=9&flags=32"
print(sonos.play_uri(track))

But what I want is to alos be able to play albums and playlists. So I wiresharked a little bit to be sure to have a valid URI.

album = "x-rincon-cpcontainer:0004006cspotify%3aalbum%3a4agvS3xuy9p0I7aDMQVFEp"

but this wont work with the play uri method. Jasperla gave me the hint that its not possible to play a album but to queue it, so I tryed to use add_to_queue but I think I miss something because the method wants meta data but has only one arument to pass.
print(sonos.add_to_queue(track))

So how would I call the method correct and how do I get the correct meta data? Just use the meta data logged with wireshark?

maybe someone can see what im missing and point me into the right direction (-:

cheers
Malchio

Tunein Example

I updated my Sonos to latest firmware and now the tunein example return me error 402.
Could you check?
Thks
Sandro

Play iTunes Music

Hey SoCo developers again.

I know i have made a question a few days ago but how would i play a song from my iTunes Library? (I am using a Mac)

remove_from_queue and play_from_queue uses different indexing.

play_from_queue takes a index from 0 to {queue_length}
remove_from_queue takes a index from 1 to {queue_length} - 1

This appears to come from sonos api using one-based lists while SoCo uses zero-based. This is of course not a problem as long as the various api functions in SoCo behave the same way.

I guess the solution is rewriting remove_from_queue line 1010 from:

objid = 'Q:0/' + str(index)

to

objid = 'Q:0/' + str(index + 1)

which would be closer to line 216 inside play_from_queue

('Target', queue_index + 1)

Firmware update from 1/6-13 introduce changes in data synchronization between interface and unit?

Hey

As noticed in issue 16 there was an update to the sonos units on 1/6-13. As noted in that issue there was some changes in the way the tunein radio stations are handled. But what I am really interested in, is that I think there was also a change in the way they synchronize their data structure between the interface we talk to and the core of the unit.

I have been wondering about that for some time while I was writing the unit tests. I noticed that I could programatically set something and then get the new value immediately after. This to me indicates that the communication interface does not wait to confirm that the change has happened at the lower level, but simply sets the new value in its own data structure if the core acknowledges the set request. I noticed it because I ran into a similar issue at work. It is a sub-optimal solution, because that means that you cannot be sure that the value you get, is the actual value of the unit.

However, they may have updated this with the update yesterday. At least I now run into problems with the procedure described above. If you change the state of the unit with e.g. with the pause method, then get_current_transport_info will not immediate report as being on pause.

All of the above about state data synchronization changes is of course pure speculation, but the change in behavior is not. I just wanted to put this info out here, so that anyone that may use the lib is aware of the change.

Regards Kenneth

Question re relative imports

I see relative imports are now used (eg from .utils import ......)

Using Python 2.75 on Windows 7 with Eclipse these give an error unless I remove the dots.Should I need to do this every time?

I have utlis.py in the same directory as core.py

Any advice welcome
Cheers David

NameError: global name 'dom' is not defined

Have a simple test which fails with above error.
I have re-installed my machine - have I missed something

Code:
from soco import SoCo
ip = "192.168.1.82"
zp = SoCo(ip)
print zp.player_name
print zp.get_group_coordinator(zp.player_name)

Output:
Study
Traceback (most recent call last):
File "C:\Users\David\DevSpace\Free Test\sss\scr\main.py", line 14, in
print zp.get_group_coordinator(zp.player_name)
File "C:\Python27\Lib\my-packages\soco\core.py", line 685, in get_group_coordinator
self.__get_topology(refresh=True)
File "C:\Python27\Lib\my-packages\soco\core.py", line 713, in __get_topology
for player in state.iter(dom.find('ZonePlayers')):
NameError: global name 'dom' is not defined

Sorry I can't find how to solve it
Cheers Daivd

Dynamic list of available commands

Great work on the new Services @lawrenceakka really like it.

Has the ability to querry available commands got lost in the implementation?
s = SoCo('192.168.1.101') # Your IP address here
for action, in_args, out_args in soco.QPlay.iter_actions():
.....print action, in_args, out_args

Looks like core doesn't support it - is this an intentional ommision.
I think it would be better to provide it via core

Thoughts - or do I mis-understand?
Cheers David

Text to speech attempt and metadata

All - similar to aProgrammer, I think I am running into metadata problems on a little project I have been working on using SoCo. google.translate has an API that will return a TTS conversion as an MP3 for anything you throw at it. My initial little test program is as follows:

import requests
from soco import SoCo
import sys
import os
lr_sonos = SoCo('192.168.0.148')
tts_string = input('Enter something to say: ')
speech_uri = 'http://translate.google.com/translate_tts?q='+tts_string
lr_sonos.play_uri(uri=speech_uri,meta='')
print('Done!')

However, this isn't working and it seems like the problems are mainly associated with metadata (though I am not completely sure). Error return is as follows:

Enter something to say: hello
Traceback (most recent call last):
File "/Users/rodhall/Dropbox/Python/speaksonos.py", line 9, in
lr_sonos.play_uri(uri=speech_uri,meta='')
File "/Users/rodhall/Dropbox/Python/soco/core.py", line 253, in play_uri
('CurrentURIMetaData', meta)
File "/Users/rodhall/Dropbox/Python/soco/services.py", line 153, in _dispatcher
return self.send_command(action, args)
File "/Users/rodhall/Dropbox/Python/soco/services.py", line 316, in send_command
self.handle_upnp_error(response.text)
File "/Users/rodhall/Dropbox/Python/soco/services.py", line 377, in handle_upnp_error
error_xml=xml_error
soco.exceptions.SoCoUPnPException: UPnP Error 714 received: Illegal MIME-Type from 192.168.0.148

I just think it would be super cool to get my Sonos to talk when various things happen (cameras detect motion, doorbell, etc etc.) however I am a newbie to SoCo and need some advice.

Cannot get get_queue to work (request returns error and therefore get_queue returns empty list)

** Bug report moved here from rahims/SoCo **

Hallo

I'm not quite sure what happened. Yesterday, while I was working on the unittests and using the get_queue method, I decided to merge upstream master into my branch and after that the get_queue method did not work anymore. At first I thought that maybe I had done something wrong (I'm a bit of a git newbie) so then I cloned a fresh copy of upstream and I still have the problem.

Can anyone else confirm if this method works for them with the current upstream master?

The exact data that was used in the request and the return value are as follows:
### ADDRESS
http://192.168.0.110:1400/MediaServer/ContentDirectory/Control
### DATA
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><s:Body><u:Browse xmlns:u="urn:schemas-upnp-org:service:ContentDirectory:1#Browse"><ObjectID>Q:0</ObjectID><BrowseFlag>BrowseDirectChildren</BrowseFlag><Filter>dc:title,res,dc:creator,upnp:artist,upnp:album,upnp:albumArtURI</Filter><StartingIndex>0</StartingIndex><RequestedCount>100</RequestedCount><SortCriteria></SortCriteria></u:Browse></s:Body></s:Envelope>
### HEADERS
{'SOAPACTION': '"urn:schemas-upnp-org:service:ContentDirectory:1#Browse"', 'Content-Type': 'text/xml'}
### RETURN
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><s:Body><s:Fault><faultcode>s:Client</faultcode><faultstring>UPnPError</faultstring><detail><UPnPError xmlns="urn:schemas-upnp-org:control-1-0"><errorCode>402</errorCode></UPnPError></detail></s:Fault></s:Body></s:Envelope>
###

Alternatively I must have seriously messed something up with my computer, because I don't think it is the sonos device that is acting up, because I can read the queue both with the android and web client.

The example tunein.py doesn't work "play_uri()"

SONOS INFO:
uid: RINCON_000E58C5A95E01400
software_version: 24.0-71060
zone_icon: x-rincon-roomicon:living
mac_address: 00:0E:58:C5:A9:5E
hardware_version: 1.8.3.7-2
zone_name: WohnzimmerStereo (L)
serial_number: 00-0E-58-C5-A9-5E:4

Hi,
I tried to use the tunein.py example, but it ended up in an error. I have attached the result RESULT1 (please see below).

It is possible to use clear_queue(), add_to_queue(uri) and play_from_queue() to push the radio stations to the queue and to use them with the sonoshell.py. But after using add_to_queue(uri) I get more than 4 radio stations in the queue (see below RESULT2). I think the reason is that some stations provide more than one uri.
How can I get only one uri per station in the queue?

RESULT1:
python tunein.py 192.168.178.37
returned 4 of a possible 4 radio stations:
Deutschlandfunk
No handlers could be found for logger "soco.services"
Traceback (most recent call last):
File "tunein.py", line 42, in
print mySonos.play_uri( uri, metadata)
File "/usr/local/lib/python2.7/dist-packages/soco-0.6-py2.7.egg/soco/core.py", line 250, in play_uri
('CurrentURIMetaData', meta)
File "/usr/local/lib/python2.7/dist-packages/soco-0.6-py2.7.egg/soco/services.py", line 154, in _dispatcher
return self.send_command(action, args)
File "/usr/local/lib/python2.7/dist-packages/soco-0.6-py2.7.egg/soco/services.py", line 316, in send_command
self.handle_upnp_error(response.text)
File "/usr/local/lib/python2.7/dist-packages/soco-0.6-py2.7.egg/soco/services.py", line 377, in handle_upnp_error
error_xml=xml_error
soco.exceptions.SoCoUPnPException: UPnP Error 402 received: Invalid Args from 192.168.178.37

RESULT2:
returned 4 of a possible 4 radio stations:
Deutschlandfunk
x-sonosapi-stream:s42828?sid=254&flags=32
('Queu Id (mySonos.add_to_queue(uri)): ', 1)
FluxFM Bremen/Stuttgart
x-sonosapi-stream:s142329?sid=254&flags=32
('Queu Id (mySonos.add_to_queue(uri)): ', 5)
Hochschulradio Stuttgart
x-sonosapi-stream:s2151?sid=254&flags=32
('Queu Id (mySonos.add_to_queue(uri)): ', 6)
SWR2 Kulturradio
x-sonosapi-stream:s20292?sid=254&flags=32
('Queu Id (mySonos.add_to_queue(uri)): ', 7)
('Queu (mySonos.get_queue()): ', [{u'album': None, u'artist': None, u'uri': 'x-rincon-mp3radio://stream.dradio.de/7/249/142684/v1/gnl.akacast.akamaistream.net/dradio_mp3_dlf_m', u'album_art': '/getaa?u=x-rincon-mp3radio%3a%2f%2fstream.dradio.de%2f7%2f249%2f142684%2fv1%2fgnl.akacast.akamaistream.net%2fdradio_mp3_dlf_m&v=1', u'title': 'dradio_mp3_dlf_m'}, {u'album': None, u'artist': None, u'uri': 'x-rincon-mp3radio://dradio_mp3_dlf_m.akacast.akamaistream.net/7/249/142684/v1/gnl.akacast.akamaistream.net/dradio_mp3_dlf_m', u'album_art': '/getaa?u=x-rincon-mp3radio%3a%2f%2fdradio_mp3_dlf_m.akacast.akamaistream.net%2f7%2f249%2f142684%2fv1%2fgnl.akacast.akamaistream.net%2fdradio_mp3_dlf_m&v=1', u'title': 'dradio_mp3_dlf_m'}, {u'album': None, u'artist': None, u'uri': 'x-rincon-mp3radio://stream.dradio.de/7/251/142684/v1/gnl.akacast.akamaistream.net/dradio_mp3_dlf_s', u'album_art': '/getaa?u=x-rincon-mp3radio%3a%2f%2fstream.dradio.de%2f7%2f251%2f142684%2fv1%2fgnl.akacast.akamaistream.net%2fdradio_mp3_dlf_s&v=1', u'title': 'dradio_mp3_dlf_s'}, {u'album': None, u'artist': None, u'uri': 'x-rincon-mp3radio://dradio_mp3_dlf_s.akacast.akamaistream.net/7/251/142684/v1/gnl.akacast.akamaistream.net/dradio_mp3_dlf_s', u'album_art': '/getaa?u=x-rincon-mp3radio%3a%2f%2fdradio_mp3_dlf_s.akacast.akamaistream.net%2f7%2f251%2f142684%2fv1%2fgnl.akacast.akamaistream.net%2fdradio_mp3_dlf_s&v=1', u'title': 'dradio_mp3_dlf_s'}, {u'album': None, u'artist': None, u'uri': 'x-rincon-mp3radio://stream.hoerradar.de/fluxfm-bremen', u'album_art': '/getaa?u=x-rincon-mp3radio%3a%2f%2fstream.hoerradar.de%2ffluxfm-bremen&v=1', u'title': 'fluxfm-bremen'}, {u'album': None, u'artist': None, u'uri': 'x-rincon-mp3radio://realserver3.hdm-stuttgart.de:8080/horads', u'album_art': '/getaa?u=x-rincon-mp3radio%3a%2f%2frealserver3.hdm-stuttgart.de%3a8080%2fhorads&v=1', u'title': 'horads'}, {u'album': None, u'artist': None, u'uri': 'x-rincon-mp3radio://swr-mp3-m-swr2.akacast.akamaistream.net/7/721/137135/v1/gnl.akacast.akamaistream.net/swr-mp3-m-swr2', u'album_art': '/getaa?u=x-rincon-mp3radio%3a%2f%2fswr-mp3-m-swr2.akacast.akamaistream.net%2f7%2f721%2f137135%2fv1%2fgnl.akacast.akamaistream.net%2fswr-mp3-m-swr2&v=1', u'title': 'swr-mp3-m-swr2'}, {u'album': None, u'artist': None, u'uri': 'x-rincon-mp3radio://swr-mp3-s-swr2.akacast.akamaistream.net/7/204/137135/v1/gnl.akacast.akamaistream.net/swr-mp3-s-swr2', u'album_art': '/getaa?u=x-rincon-mp3radio%3a%2f%2fswr-mp3-s-swr2.akacast.akamaistream.net%2f7%2f204%2f137135%2fv1%2fgnl.akacast.akamaistream.net%2fswr-mp3-s-swr2&v=1', u'title': 'swr-mp3-s-swr2'}])

How do I add a track to the Queue?

Hi,

I'm trying to add a track from soundcloud to the queue and it does not work. I might not be using the add_to_queue() method right and wanted some guidance.

I'm calling the method my passing it a QueueItem object

queueitem1 = data_structures.QueueItem(https_uri, "testname")
device.add_to_queue(queueitem1)

This return the following error

File "/usr/local/lib/python2.7/dist-packages/soco/core.py", line 1080, in add_to_queue
    raise AttributeError(message)
AttributeError: queueable_item has no attribute didl_metadata

I've also tried adding a track to the queue using the Sonos controller. Getting that item using the get_queue() method, and trying to add that item to the queue again, but I get the same error.

add_to_queue breaks in python3

Try the new ml_* commands from socos to see the problem, it works perfectly in 2.7, but breaks in 3.3 with:

ml_albums % add 18
Traceback (most recent call last):
  File "/home/petter/.virtualenvs/python3.3/bin/socos", line 9, in <module>
    load_entry_point('socos==0.1', 'console_scripts', 'socos')()
  File "/home/petter/.virtualenvs/python3.3/lib/python3.3/site-packages/socos/runner.py", line 22, in main
    shell()
  File "/home/petter/.virtualenvs/python3.3/lib/python3.3/site-packages/socos/core.py", line 165, in shell
    process_cmd(args)
  File "/home/petter/.virtualenvs/python3.3/lib/python3.3/site-packages/socos/core.py", line 75, in process_cmd
    for line in result:
  File "/home/petter/.virtualenvs/python3.3/lib/python3.3/site-packages/socos/music_lib.py", line 158, in albums
    for string in self._search_and_play(sonos, 'albums', *args):
  File "/home/petter/.virtualenvs/python3.3/lib/python3.3/site-packages/socos/music_lib.py", line 221, in _search_and_play
    yield self._play(sonos, data_type, results, *args)
  File "/home/petter/.virtualenvs/python3.3/lib/python3.3/site-packages/socos/music_lib.py", line 304, in _play
    sonos.add_to_queue(item)
  File "/home/petter/.virtualenvs/python3.3/lib/python3.3/site-packages/soco/core.py", line 1150, in add_to_queue
    metadata = metadata.encode('utf-8')
AttributeError: 'bytes' object has no attribute 'encode'

I think the reason is this:

ElementTree.tostring in Python2.7

xml.etree.ElementTree.tostring(element, encoding="us-ascii", method="xml")
Generates a string representation of an XML element, including all subelements. element is an Element instance. encoding [1] is the output encoding (default is US-ASCII). method is either "xml", "html" or "text" (default is "xml"). Returns an encoded string containing the XML data.

same in Python3

xml.etree.ElementTree.tostring(element, encoding="us-ascii", method="xml", *, short_empty_elements=True)
Generates a string representation of an XML element, including all subelements. element is an Element instance. encoding [1] is the output encoding (default is US-ASCII). Use encoding="unicode" to generate a Unicode string (otherwise, a bytestring is generated). method is either "xml", "html" or "text" (default is "xml"). short_empty_elements has the same meaning as in ElementTree.write(). Returns an (optionally) encoded string containing the XML data.

You'll notice the default bytestring output in 3.3

https://github.com/SoCo/SoCo/blob/master/soco/core.py#L1143
https://github.com/SoCo/SoCo/blob/master/soco/core.py#L1149

Album title in French misread!

Fails to read french! "Café de Paris"
No error, but output wrong!

Any thoughts?

zp = SoCo('192.168.xx.xx')
info = zp.get_current_track_info()
print info

{'album': 'Caf\xc3\xa9 de Paris', 'artist': 'Edith Piaf', .........

print info['album']

Café de Paris

Cheers Daivd

Use utf-8 or unicode in text strings

Hallo fellow SoCo-devs

I wanted to start a discussion about whether to use utf-8 or unicode for our text strings. What triggered me to start the discussion was #31, but I think it will become important that we decide on one or the other as a convention, because that will make SoCo easier to use.

So far, it seems that the de-facto standard has been to use utf-8, but whether that was a conscious decision or simply the way things developed I do not know.

One of the problems with using utf-8, is that there is no explicit information about what is in the string. This means, that certain things that expect a certain character set, like output to the terminal will fail if you terminal does not use utf-8 (that was the issue in #31). However, if you pass on a unicode string, then there will be information available to allow encoding to the correct character set, and many modules will do so. So I think that speaks in favor of using unicode.

When you search for this on the internet, it seem that the prevalent advice is:

  • Decode input to unicode as early as possible
  • Use unicode everywhere internally
  • Encode your output as late as possible

This of course raises the question, are our strings output? Since they are returned from methods, they are of course per definition output. However, since SoCo is considered to be a library, then one must expect more python programming around it meaning that the strings continue to be internal and therefore by this recommendation they should remain unicode.

As you might have guessed, I am a proponent for switching to unicode as the standard for all our strings, but I would very much like to hear your opinions on the matter.

After discussion I intend to start a conventions page on the wiki with the results.

Regards Kenneth

Song Queue

Hey SoCo developers!

Since I am having some issue working out how to queue songs could you please tell me how to or if you can make a YouTube series on the SoCo libraries!?

Thanks,
aProgramer

Future of sonoshell as an example

Now that socos is up and running, should we keep sonoshell in examples/commandline ?

We could just replace it with a text file referring to the socks repository.

In any case, I think we should remove colorama from requirements.txt . It is not needed for SoCo, and is optional for sonoshell.

examples/plugins/socoplugins.py breaks on SoCo object has no attribute send_command

Upon testing socoplugins.py I realized it's currently broken as soco/plugins/example.py tries to run 'send_command' directly on self.soco.

$ python socoplugins.py 
Testing Example Plugin for some user
Hi, some user
Traceback (most recent call last):
  File "socoplugins.py", line 47, in <module>
    main()
  File "socoplugins.py", line 29, in main
    myplugin.music_plugin_play()
  File "/usr/local/lib/python2.7/dist-packages/soco-0.6-py2.7.egg/soco/plugins/example.py", line 36, in music_plugin_play
    response = self.soco.send_command(
AttributeError: 'SoCo' object has no attribute 'send_command'

I assume it's meant to call send_command from class Service?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.