soco.events module
Classes to handle Sonos UPnP Events and Subscriptions.
The Subscription
class from this module will be used in
soco.services
unless config.EVENTS_MODULE
is set to
point to soco.events_twisted
, in which case
soco.events_twisted.Subscription
will be used. See the
Example in soco.events_twisted
.
Example
Run this code, and change your volume, tracks etc:
from queue import Empty
import logging
logging.basicConfig()
import soco
from pprint import pprint
from soco.events import event_listener
# pick a device at random and use it to get
# the group coordinator
device = soco.discover().pop().group.coordinator
print (device.player_name)
sub = device.renderingControl.subscribe()
sub2 = device.avTransport.subscribe()
while True:
try:
event = sub.events.get(timeout=0.5)
pprint (event.variables)
except Empty:
pass
try:
event = sub2.events.get(timeout=0.5)
pprint (event.variables)
except Empty:
pass
except KeyboardInterrupt:
sub.unsubscribe()
sub2.unsubscribe()
event_listener.stop()
break
- class soco.events.EventServer(server_address, RequestHandlerClass, bind_and_activate=True)[source]
A TCP server which handles each new request in a new thread.
Constructor. May be extended, do not override.
- class soco.events.EventNotifyHandler(*args, **kwargs)[source]
Handles HTTP
NOTIFY
Verbs sent to the listener server. Inherits fromsoco.events_base.EventNotifyHandlerBase
.- do_NOTIFY()[source]
Serve a
NOTIFY
request by callinghandle_notification
with the headers and content.
- log_message(fmt, *args)[source]
Log an arbitrary message.
This is used by all other logging functions. Override it if you have specific logging wishes.
The first argument, FORMAT, is a format string for the message to be logged. If the format string contains any % escapes requiring parameters, they should be specified as subsequent arguments (it’s just like printf!).
The client ip and current date/time are prefixed to every message.
Unicode control characters are replaced with escaped hex before writing the output to stderr.
- class soco.events.EventServerThread(server)[source]
The thread in which the event listener server will run.
- Parameters
address (tuple) – The (ip, port) address on which the server should listen.
- stop_flag
Used to signal that the server should stop.
- Type
- run()[source]
Start the server
Handling of requests is delegated to an instance of the
EventNotifyHandler
class.
- class soco.events.EventListener[source]
The Event Listener.
Runs an http server in a thread which is an endpoint for
NOTIFY
requests from Sonos devices. Inherits fromsoco.events_base.EventListenerBase
.- listen(ip_address)[source]
Start the event listener listening on the local machine at port 1400 (default). If this port is unavailable, the listener will attempt to listen on the next available port, within a range of 100.
Make sure that your firewall allows connections to this port.
This method is called by
soco.events_base.EventListenerBase.start
- Parameters
ip_address (str) – The local network interface on which the server should start listening.
- Returns
requested_port_number
. Included for compatibility withsoco.events_twisted.EventListener.listen
- Return type
Note
The port on which the event listener listens is configurable. See
config.EVENT_LISTENER_PORT
- class soco.events.Subscription(service, event_queue=None)[source]
A class representing the subscription to a UPnP event. Inherits from
soco.events_base.SubscriptionBase
.- Parameters
- subscribe(requested_timeout=None, auto_renew=False, strict=True)[source]
Subscribe to the service.
If requested_timeout is provided, a subscription valid for that number of seconds will be requested, but not guaranteed. Check
timeout
on return to find out what period of validity is actually allocated.This method calls
events_base.SubscriptionBase.subscribe
.Note
SoCo will try to unsubscribe any subscriptions which are still subscribed on program termination, but it is good practice for you to clean up by making sure that you call
unsubscribe()
yourself.- Parameters
requested_timeout (int, optional) – The timeout to be requested.
auto_renew (bool, optional) – If
True
, renew the subscription automatically shortly before timeout. DefaultFalse
.strict (bool, optional) – If True and an Exception occurs during execution, the Exception will be raised or, if False, the Exception will be logged and the Subscription instance will be returned. Default
True
.
- Returns
The Subscription instance.
- Return type
- renew(requested_timeout=None)[source]
Renew the event subscription. You should not try to renew a subscription which has been unsubscribed, or once it has expired.
This method calls
events_base.SubscriptionBase.renew
.- Parameters
requested_timeout (int, optional) – The period for which a renewal request should be made. If None (the default), use the timeout requested on subscription.
is_autorenew (bool, optional) – Whether this is an autorenewal. Default ‘False’.
strict (bool, optional) – If True and an Exception occurs during execution, the Exception will be raised or, if False, the Exception will be logged and the Subscription instance will be returned. Default
True
.
- Returns
The Subscription instance.
- Return type
- unsubscribe()[source]
Unsubscribe from the service’s events. Once unsubscribed, a Subscription instance should not be reused
This method calls
events_base.SubscriptionBase.unsubscribe
.
soco.events_base module
Base classes used by soco.events
and
soco.events_twisted
.
- soco.events_base.parse_event_xml(xml_event)[source]
Parse the body of a UPnP event.
- Parameters
xml_event (bytes) – bytes containing the body of the event encoded with utf-8.
- Returns
A dict with keys representing the evented variables. The relevant value will usually be a string representation of the variable’s value, but may on occasion be:
a dict (eg when the volume changes, the value will itself be a dict containing the volume for each channel:
{'Volume': {'LF': '100', 'RF': '100', 'Master': '36'}}
)an instance of a
DidlObject
subclass (eg if it represents track metadata).a
SoCoFault
(if a variable contains illegal metadata)
- Return type
- class soco.events_base.Event(sid, seq, service, timestamp, variables=None)[source]
A read-only object representing a received event.
The values of the evented variables can be accessed via the
variables
dict, or as attributes on the instance itself. You should treat all attributes as read-only.- Parameters
sid (str) – the subscription id.
seq (str) – the event sequence number for that subscription.
timestamp (str) – the time that the event was received (from Python’s
time.time
function).service (str) – the service which is subscribed to the event.
variables (dict, optional) – contains the
{names: values}
of the evented variables. Defaults toNone
. The values may beSoCoFault
objects if the metadata could not be parsed.
- Raises
AttributeError – Not all attributes are returned with each event. An
AttributeError
will be raised if you attempt to access as an attribute a variable which was not returned in the event.
Example
>>> print event.variables['transport_state'] 'STOPPED' >>> print event.transport_state 'STOPPED'
- class soco.events_base.EventNotifyHandlerBase[source]
Base class for
soco.events.EventNotifyHandler
andsoco.events_twisted.EventNotifyHandler
.- handle_notification(headers, content)[source]
Handle a
NOTIFY
request by building anEvent
object and sending it to the relevant Subscription object.A
NOTIFY
request will be sent by a Sonos device when a state variable changes. See the UPnP Spec §4.3 [pdf] for details.- Parameters
Note
Each of the
soco.events
and thesoco.events_twisted
modules has a subscriptions_map object which keeps a record of Subscription objects. The get_subscription method of the subscriptions_map object is used to look up the subscription to which the event relates. When the Event Listener runs in a thread (the default), a lock is used by this method for thread safety. The send_event method of the relevant Subscription will first check to see whether the callback variable of the Subscription has been set. If it has been and is callable, then the callback will be called with theEvent
object. Otherwise, theEvent
object will be sent to the event queue of the Subscription object. The callback variable of the Subscription object is intended for use only ifsoco.events_twisted
is being used, as calls to it are not threadsafe.This method calls the log_event method, which must be overridden in the class that inherits from this class.
- class soco.events_base.EventListenerBase[source]
Base class for
soco.events.EventListener
andsoco.events_twisted.EventListener
.- start(any_zone)[source]
Start the event listener listening on the local machine.
- Parameters
any_zone (SoCo) – Any Sonos device on the network. It does not matter which device. It is used only to find a local IP address reachable by the Sonos net.
- listen(ip_address)[source]
Start the event listener listening on the local machine. This method is called by
start
.- Parameters
ip_address (str) – The local network interface on which the server should start listening.
- Returns
The port on which the server is listening.
- Return type
Note
This method must be overridden in the class that inherits from this class.
- class soco.events_base.SubscriptionBase(service, event_queue=None)[source]
Base class for
soco.events.Subscription
andsoco.events_twisted.Subscription
- Parameters
- auto_renew_fail
an optional function to be called if an exception occurs upon autorenewal. This will be called with the exception (or failure, when using
soco.events_twisted
) as its only parameter. This function must be threadsafe (unlesssoco.events_twisted
is being used).- Type
function
- subscribe(requested_timeout=None, auto_renew=False)[source]
Subscribe to the service.
If requested_timeout is provided, a subscription valid for that number of seconds will be requested, but not guaranteed. Check
timeout
on return to find out what period of validity is actually allocated.Note
SoCo will try to unsubscribe any subscriptions which are still subscribed on program termination, but it is good practice for you to clean up by making sure that you call
unsubscribe()
yourself.
- renew(requested_timeout=None)[source]
Renew the event subscription. You should not try to renew a subscription which has been unsubscribed, or once it has expired.
- unsubscribe()[source]
Unsubscribe from the service’s events. Once unsubscribed, a Subscription instance should not be reused
- send_event(event)[source]
Send an
Event
to self.callback or self.events. If self.callback is set and is callable, it will be called with theEvent
as the only parameter. Otherwise theEvent
will be sent to self.events. As self.callback is not threadsafe, it should be set only ifsoco.events_twisted.Subscription
is being used.
- class soco.events_base.SubscriptionsMap[source]
Maintains a mapping of sids to
soco.events.Subscription
instances and the thread safe lock to go with it. Registers each subscription to be unsubscribed at exit.SubscriptionsMapTwisted
inherits from this class.- subscriptions
Thread safe mapping. Used to store a mapping of sid to subscription
- subscriptions_lock
for use with
subscriptions
- Type
- register(subscription)[source]
Register a subscription by updating local mapping of sid to subscription and registering it to be unsubscribed at exit.
- Parameters
subscription (
soco.events.Subscription
) – the subscription to be registered.
- unregister(subscription)[source]
Unregister a subscription by updating local mapping of sid to subscription instances.
- Parameters
subscription (
soco.events.Subscription
) – the subscription to be unregistered.
When using
soco.events_twisted
, an instance ofsoco.events_twisted.Subscription
will be unregistered.
- get_subscription(sid)[source]
Look up a subscription from a sid.
- Args:
sid(str): The sid from which to look up the subscription.
- Returns:
soco.events.Subscription
: The subscription relating to that sid.
When using
soco.events_twisted
, an instance ofsoco.events_twisted.Subscription
will be returned.
soco.events_twisted module
Classes to handle Sonos UPnP Events and Subscriptions.
The Subscription
class from this module will be used in
soco.services
if config.EVENTS_MODULE
is set
to point to this module.
Example
Run this code, and change your volume, tracks etc:
from __future__ import print_function
import logging
logging.basicConfig()
import soco
from pprint import pprint
from soco import events_twisted
soco.config.EVENTS_MODULE = events_twisted
from twisted.internet import reactor
def print_event(event):
try:
pprint (event.variables)
except Exception as e:
pprint ('There was an error in print_event:', e)
def main():
# pick a device at random and use it to get
# the group coordinator
device = soco.discover().pop().group.coordinator
print (device.player_name)
sub = device.renderingControl.subscribe().subscription
sub2 = device.avTransport.subscribe().subscription
sub.callback = print_event
sub2.callback = print_event
def before_shutdown():
sub.unsubscribe()
sub2.unsubscribe()
events_twisted.event_listener.stop()
reactor.addSystemEventTrigger(
'before', 'shutdown', before_shutdown)
if __name__=='__main__':
reactor.callWhenRunning(main)
reactor.run()
- class soco.events_twisted.EventNotifyHandler[source]
Handles HTTP
NOTIFY
Verbs sent to the listener server. Inherits fromsoco.events_base.EventNotifyHandlerBase
.- render_NOTIFY(request)[source]
Serve a
NOTIFY
request by callinghandle_notification
with the headers and content.
- class soco.events_twisted.EventListener[source]
The Event Listener.
Runs an http server which is an endpoint for
NOTIFY
requests from Sonos devices. Inherits fromsoco.events_base.EventListenerBase
.- listen(ip_address)[source]
Start the event listener listening on the local machine at port 1400 (default). If this port is unavailable, the listener will attempt to listen on the next available port, within a range of 100.
Make sure that your firewall allows connections to this port.
This method is called by
soco.events_base.EventListenerBase.start
Handling of requests is delegated to an instance of the
EventNotifyHandler
class.- Parameters
ip_address (str) – The local network interface on which the server should start listening.
- Returns
The port on which the server is listening.
- Return type
Note
The port on which the event listener listens is configurable. See
config.EVENT_LISTENER_PORT
- class soco.events_twisted.Subscription(service, event_queue=None)[source]
A class representing the subscription to a UPnP event. Inherits from
soco.events_base.SubscriptionBase
.- Parameters
- callback
callback function to be called whenever an
Event
is received. If it is set and is callable, the callback function will be called with theEvent
as the only parameter and the Subscription’s event queue won’t be used.- Type
function
- subscribe(requested_timeout=None, auto_renew=False, strict=True)[source]
Subscribe to the service.
If requested_timeout is provided, a subscription valid for that number of seconds will be requested, but not guaranteed. Check
timeout
on return to find out what period of validity is actually allocated.This method calls
events_base.SubscriptionBase.subscribe
.Note
SoCo will try to unsubscribe any subscriptions which are still subscribed on program termination, but it is good practice for you to clean up by making sure that you call
unsubscribe()
yourself.- Parameters
requested_timeout (int, optional) – The timeout to be requested.
auto_renew (bool, optional) – If
True
, renew the subscription automatically shortly before timeout. DefaultFalse
.strict (bool, optional) – If True and an Exception occurs during execution, the returned Deferred will fail with a Failure which will be passed to the applicable errback (if any has been set by the calling code) or, if False, the Failure will be logged and the Subscription instance will be passed to the applicable callback (if any has been set by the calling code). Default
True
.
- Returns
A Deferred the result of which will be the Subscription instance and the subscription property of which will point to the Subscription instance.
- Return type
- renew(requested_timeout=None)[source]
Renew the event subscription. You should not try to renew a subscription which has been unsubscribed, or once it has expired.
This method calls
events_base.SubscriptionBase.renew
.- Parameters
requested_timeout (int, optional) – The period for which a renewal request should be made. If None (the default), use the timeout requested on subscription.
is_autorenew (bool, optional) – Whether this is an autorenewal. Default
False
.strict (bool, optional) – If True and an Exception occurs during execution, the returned Deferred will fail with a Failure which will be passed to the applicable errback (if any has been set by the calling code) or, if False, the Failure will be logged and the Subscription instance will be passed to the applicable callback (if any has been set by the calling code). Default
True
.
- Returns
A Deferred the result of which will be the Subscription instance and the subscription property of which will point to the Subscription instance.
- Return type
- unsubscribe()[source]
Unsubscribe from the service’s events. Once unsubscribed, a Subscription instance should not be reused
This method calls
events_base.SubscriptionBase.unsubscribe
.- Parameters
strict (bool, optional) – If True and an Exception occurs during execution, the returned Deferred will fail with a Failure which will be passed to the applicable errback (if any has been set by the calling code) or, if False, the Failure will be logged and the Subscription instance will be passed to the applicable callback (if any has been set by the calling code). Default
True
.- Returns
A Deferred the result of which will be the Subscription instance and the subscription property of which will point to the Subscription instance.
- Return type
- class soco.events_twisted.SubscriptionsMapTwisted[source]
Maintains a mapping of sids to
soco.events_twisted.Subscription
instances. Registers each subscription to be unsubscribed at exit.Inherits from
soco.events_base.SubscriptionsMap
.- register(subscription)[source]
Register a subscription by updating local mapping of sid to subscription and registering it to be unsubscribed at exit.
- Parameters
subscription (
soco.events_twisted.Subscription
) – the subscription to be registered.
- subscribing()[source]
Called when the
Subscription.subscribe
method commences execution.
- finished_subscribing()[source]
Called when the
Subscription.subscribe
method completes execution.
soco.events_asyncio module
Classes to handle Sonos UPnP Events and Subscriptions using asyncio.
The Subscription
class from this module will be used in
soco.services
if config.EVENTS_MODULE
is set
to point to this module.
Example
Run this code, and change your volume, tracks etc:
import logging
logging.basicConfig()
import soco
import asyncio
from pprint import pprint
from soco import events_asyncio
soco.config.EVENTS_MODULE = events_asyncio
def print_event(event):
try:
pprint(event.variables)
except Exception as e:
print("There was an error in print_event:", e)
def _get_device():
device = soco.discover().pop().group.coordinator
print(device.player_name)
return device
async def main():
# pick a device at random and use it to get
# the group coordinator
loop = asyncio.get_event_loop()
device = await loop.run_in_executor(None, _get_device)
sub = await device.renderingControl.subscribe()
sub2 = await device.avTransport.subscribe()
sub.callback = print_event
sub2.callback = print_event
async def before_shutdown():
await sub.unsubscribe()
await sub2.unsubscribe()
await events_asyncio.event_listener.async_stop()
await asyncio.sleep(1)
print("Renewing subscription..")
await sub.renew()
await asyncio.sleep(100)
await before_shutdown()
if __name__ == "__main__":
asyncio.run(main())
- class soco.events_asyncio.EventNotifyHandler[source]
Handles HTTP
NOTIFY
Verbs sent to the listener server. Inherits fromsoco.events_base.EventNotifyHandlerBase
.- async notify(request)[source]
Serve a
NOTIFY
request by callinghandle_notification
with the headers and content.
- class soco.events_asyncio.EventListener[source]
The Event Listener.
Runs an http server which is an endpoint for
NOTIFY
requests from Sonos devices. Inherits fromsoco.events_base.EventListenerBase
.- async async_start(any_zone)[source]
Start the event listener listening on the local machine under the lock.
- Parameters
any_zone (SoCo) – Any Sonos device on the network. It does not matter which device. It is used only to find a local IP address reachable by the Sonos net.
- async async_listen(ip_address)[source]
Start the event listener listening on the local machine at port 1400 (default). If this port is unavailable, the listener will attempt to listen on the next available port, within a range of 100.
Make sure that your firewall allows connections to this port.
This method is called by
soco.events_base.EventListenerBase.start
Handling of requests is delegated to an instance of the
EventNotifyHandler
class.- Parameters
ip_address (str) – The local network interface on which the server should start listening.
- Returns
The port on which the server is listening.
- Return type
Note
The port on which the event listener listens is configurable. See
config.EVENT_LISTENER_PORT
- class soco.events_asyncio.Subscription(service, callback=None)[source]
A class representing the subscription to a UPnP event. Inherits from
soco.events_base.SubscriptionBase
.- Parameters
- callback
callback function to be called whenever an
Event
is received. If it is set and is callable, the callback function will be called with theEvent
as the only parameter and the Subscription’s event queue won’t be used.- Type
function
- subscribe(requested_timeout=None, auto_renew=False, strict=True)[source]
Subscribe to the service.
If requested_timeout is provided, a subscription valid for that number of seconds will be requested, but not guaranteed. Check
timeout
on return to find out what period of validity is actually allocated.This method calls
events_base.SubscriptionBase.subscribe
.Note
SoCo will try to unsubscribe any subscriptions which are still subscribed on program termination, but it is good practice for you to clean up by making sure that you call
unsubscribe()
yourself.- Parameters
requested_timeout (int, optional) – The timeout to be requested.
auto_renew (bool, optional) – If
True
, renew the subscription automatically shortly before timeout. DefaultFalse
.strict (bool, optional) – If True and an Exception occurs during execution, the Exception will be raised or, if False, the Exception will be logged and the Subscription instance will be returned. Default
True
.
- Returns
The Subscription instance.
- Return type
- async renew(requested_timeout=None)[source]
Renew the event subscription. You should not try to renew a subscription which has been unsubscribed, or once it has expired.
This method calls
events_base.SubscriptionBase.renew
.- Parameters
requested_timeout (int, optional) – The period for which a renewal request should be made. If None (the default), use the timeout requested on subscription.
is_autorenew (bool, optional) – Whether this is an autorenewal. Default
False
.strict (bool, optional) – If True and an Exception occurs during execution, the Exception will be raised or, if False, the Exception will be logged and the Subscription instance will be returned. Default
True
.
- Returns
The Subscription instance.
- Return type
- async unsubscribe()[source]
Unsubscribe from the service’s events. Once unsubscribed, a Subscription instance should not be reused
This method calls
events_base.SubscriptionBase.unsubscribe
.
- class soco.events_asyncio.nullcontext(enter_result=None)[source]
Context manager that does no additional processing.
Backport from python 3.7+ for older pythons.
- class soco.events_asyncio.SubscriptionsMapAio[source]
Maintains a mapping of sids to
soco.events_asyncio.Subscription
instances. Registers each subscription to be unsubscribed at exit.Inherits from
soco.events_base.SubscriptionsMap
.- register(subscription)[source]
Register a subscription by updating local mapping of sid to subscription and registering it to be unsubscribed at exit.
- Parameters
subscription (
soco.events_asyncio.Subscription
) – the subscription to be registered.
- subscribing()[source]
Called when the
Subscription.subscribe
method commences execution.
- finished_subscribing()[source]
Called when the
Subscription.subscribe
method completes execution.