1.. _examples:
2
3Examples
4========
5
6This page contains collection of small examples to show of the features of
7*SoCo* and hopefully get you well started with the library.
8
9All examples are shown as if entered in the Python interpreter (as apposed to
10executed from a file) because that makes it easy to incorporate output in the
11code listings.
12
13All the examples from :ref:`examples_playback_control` and forward
14assume that you have followed one of the examples in
15:ref:`examples_getting_your_devices` and therefore already have a
16variable named ``device`` that points to a :class:`soco.SoCo`
17instance.
18
19.. _examples_getting_your_devices:
20
21Getting your devices
22--------------------
23
24Getting all your devices
25^^^^^^^^^^^^^^^^^^^^^^^^
26
27To get all your devices use the :func:`soco.discover` function::
28
29  >>> import soco
30  >>> devices = soco.discover()
31  >>> devices
32  set([SoCo("192.168.0.10"), SoCo("192.168.0.30"), SoCo("192.168.0.17")])
33  >>> device = devices.pop()
34  >>> device
35  SoCo("192.168.0.16")
36
37Getting any device
38^^^^^^^^^^^^^^^^^^
39
40To get any device use the :func:`soco.discovery.any_soco` function. This can be
41useful for cases where you really do not care which one you get, you just need
42one e.g. to query for music library information::
43
44  >>> import soco
45  >>> device = soco.discovery.any_soco()
46  >>> device
47  SoCo("192.168.0.16")
48
49Getting a named device
50^^^^^^^^^^^^^^^^^^^^^^
51
52Getting a device by player name can be done with the
53:func:`soco.discovery.by_name` function::
54
55  >>> from soco.discovery import by_name
56  >>> device = by_name("Living Room")
57  >>> device
58  SoCo("192.168.1.18")
59
60
61.. _examples_handle_group:
62
63Handling groups of devices
64--------------------------
65
66Information about a group
67^^^^^^^^^^^^^^^^^^^^^^^^^
68
69To get information about a group, pick a device and use the :attr:`~soco.core.SoCo.all_groups`
70property::
71
72  >>> import soco
73  >>> devices = {device.player_name: device for device in soco.discover()}
74  >>> devices
75  {'Living Room': SoCo("192.168.1.47"), 'Office': SoCo("192.168.1.48")}
76
77  >>> devices['Living Room'].all_groups
78  {ZoneGroup(uid='RINCON_347E5C68F04001400:2900176654', coordinator=SoCo("192.168.1.48"), members={SoCo("192.168.1.48")}),
79   ZoneGroup(uid='RINCON_7828CAF58E6E01400:3613865501', coordinator=SoCo("192.168.1.47"), members={SoCo("192.168.1.47")})}
80
81In the case above, there are two independent devices, one group for each device with the device as its only member.
82
83Join/unjoin devices
84^^^^^^^^^^^^^^^^^^^
85
86You can use the :meth:`~soco.core.SoCo.join` method to join a device to another 'master' device::
87
88  >>> devices['Office'].join(devices['Living Room'])
89  >>> devices['Living Room'].all_groups
90  {ZoneGroup(uid='RINCON_7828CAF58E6E01400:3613865501', coordinator=SoCo("192.168.1.47"), members={SoCo("192.168.1.47"), SoCo("192.168.1.48")})}
91
92Now, there is a single group composed of the two devices, with the Living Room device as the coordinator of the group.
93
94Use the :meth:`~soco.core.SoCo.unjoin` method to unjoin a device in a group::
95
96  >>> devices['Living Room'].unjoin()
97  >>> devices['Living Room'].all_groups
98  {ZoneGroup(uid='RINCON_7828CAF58E6E01400:3613865501', coordinator=SoCo("192.168.1.48"), members={SoCo("192.168.1.48")}),
99   ZoneGroup(uid='RINCON_7828CAF58E6E01400:3613865502', coordinator=SoCo("192.168.1.47"), members={SoCo("192.168.1.47")})}
100
101Party mode
102^^^^^^^^^^
103
104Use the :meth:`~soco.core.SoCo.partymode` method to join all the devices in your network into a single group, in one command::
105
106  >>> devices['Living Room'].partymode()
107  >>> devices['Living Room'].all_groups
108  {ZoneGroup(uid='RINCON_7828CAF58E6E01400:3613865501', coordinator=SoCo("192.168.1.47"), members={SoCo("192.168.1.47"), SoCo("192.168.1.48")})}
109
110
111.. _examples_playback_control:
112
113Playback control
114----------------
115
116Play, pause and stop
117^^^^^^^^^^^^^^^^^^^^
118
119The normal play, pause and stop functionality is provided with
120similarly named methods (:meth:`~soco.core.SoCo.play`,
121:meth:`~soco.core.SoCo.pause` and :meth:`~soco.core.SoCo.stop`) on the
122:class:`~soco.core.SoCo` instance and the current state is included in the
123output of :meth:`~soco.core.SoCo.get_current_transport_info`::
124
125  >>> device.get_current_transport_info()['current_transport_state']
126  'STOPPED'
127  >>> device.play()
128  >>> device.get_current_transport_info()['current_transport_state']
129  'PLAYING'
130  >>> device.pause()
131  >>> device.get_current_transport_info()['current_transport_state']
132  'PAUSED_PLAYBACK'
133
134More playback control with next, previous and seek
135^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
136
137Navigating to the next or previous track is similarly done with
138methods of the same name (:meth:`~soco.core.SoCo.next` and
139:meth:`~soco.core.SoCo.previous`) and information about the current
140position in the queue is contained in the output from
141:meth:`~soco.core.SoCo.get_current_track_info`::
142
143  >>> device.get_current_track_info()['playlist_position']
144  '29'
145  >>> device.next()
146  >>> device.get_current_track_info()['playlist_position']
147  '30'
148  >>> device.previous()
149  >>> device.get_current_track_info()['playlist_position']
150  '29'
151
152Seeking is done with the :meth:`~soco.core.SoCo.seek` method. Note
153that the input for that method is a string on the form "HH:MM:SS" or
154"H:MM:SS". The current position is also contained in
155:meth:`~soco.core.SoCo.get_current_track_info`::
156
157  >>> device.get_current_track_info()['position']
158  '0:02:59'
159  >>> device.seek("0:00:30")
160  >>> device.get_current_track_info()['position']
161  '0:00:31'
162
163Control of a group
164^^^^^^^^^^^^^^^^^^
165
166Only the coordinator of a group can control playback (play, pause, stop, next,
167previous, seek commands) and manage the queue (add or remove track, clear the queue).
168A :class:`~soco.exceptions.SoCoSlaveException` exception will be raised if a
169master-only command is called on a non-coordinator device.
170
171Other commands like volume, loudness and treble, mute, night mode can be controlled on each
172individual player in the group.
173
174You can use the :attr:`~soco.core.SoCo.is_coordinator` property to see if a device is the
175coordinator::
176
177  >>> devices['Living Room'].is_coordinator
178  True
179
180From a device, you can get the coordinator of a group by using the
181:attr:`~soco.core.SoCo.group` property of the :class:`~soco.core.SoCo` instance,
182which returns a :class:`~soco.groups.ZoneGroup` instance allowing access to its
183:attr:`~soco.groups.ZoneGroup.coordinator` property::
184
185  >>> devices['Living Room'].group.coordinator
186  SoCo("192.168.1.47")
187  >>> devices['Office'].group.coordinator
188  SoCo("192.168.1.47")
189
190To set a group volume, use the :attr:`~soco.groups.ZoneGroup.volume` property or the
191:meth:`~soco.groups.ZoneGroup.set_relative_volume` method::
192
193  >>> # let's define some aliases ...
194  >>> lr = devices['Living Room']
195  >>> of = devices['Office']
196  >>> lr.volume, of.volume
197  (17, 10)
198  >>> g = lr.group  # alias to the group
199  >>> g.volume
200  13
201  >>> g.volume = 20
202  >>> lr.volume, of.volume
203  (27, 13)
204
205
206Seeing and manipulating the queue
207---------------------------------
208
209Getting the queue
210^^^^^^^^^^^^^^^^^
211
212Getting the queue is done with the :meth:`~soco.core.SoCo.get_queue` method::
213
214  >>> queue = device.get_queue()
215  >>> queue
216  Queue(items=[<DidlMusicTrack 'b'Blackened'' at 0x7f2237006dd8>, ..., <DidlMusicTrack 'b'Dyers Eve'' at 0x7f2237006828>])
217
218The returned :class:`~soco.data_structures.Queue` object is a sequence
219of items from the queue, meaning that it can be iterated over and its
220length aquired with :func:`len`::
221
222  >>> len(queue)
223  9
224  >>> for item in queue:
225  ...     print(item.title)
226  ...
227  Blackened
228  ...and Justice for All
229  Eye of the Beholder
230  One
231  The Shortest Straw
232  Harvester of Sorrow
233  The Frayed Ends of Sanity
234  To Live Is to Die
235  Dyers Eve
236
237The queue object also has :attr:`~.ListOfMusicInfoItems.total_matches`
238and :attr:`~.ListOfMusicInfoItems.number_returned` attributes, which
239are used to figure out whether paging is required in order to get all
240elements of the queue. See the :class:`~.ListOfMusicInfoItems`
241docstring for details.
242
243Clearing the queue
244^^^^^^^^^^^^^^^^^^
245
246Clearing the queue is done with the
247:meth:`~soco.core.SoCo.clear_queue` method as follows::
248
249  >>> queue = device.get_queue()
250  >>> len(queue)
251  9
252  >>> device.clear_queue()
253  >>> queue = device.get_queue()
254  >>> len(queue)
255  0
256
257Listing and deleting music library shares
258-----------------------------------------
259
260Music library shares are the local network drive shares connected to
261Sonos, which host the audio content in the Sonos Music Library.
262
263To list the shares connected to Sonos, use the
264:meth:`~soco.music_library.MusicLibrary.list_library_shares` method as follows::
265
266  >>> device.music_library.list_library_shares()
267  ['//share_host_01/music', '//share_host_02/music']
268
269The result is a list of network share locations.
270
271To delete a network share, use the
272:meth:`~soco.music_library.MusicLibrary.delete_library_share` method as follows::
273
274  >>> device.music_library.delete_library_share('//share_host_01/music')
275
276You may want to check that the deletion has succeeded, by waiting a few seconds,
277then confirming that the share has disappeared from the list of shares.
278