|
# Copyright (c) 2012-2016, Ferry Boender <ferry.boender@gmail.com>
|
|
#
|
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
# of this software and associated documentation files (the "Software"), to deal
|
|
# in the Software without restriction, including without limitation the rights
|
|
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
# copies of the Software, and to permit persons to whom the Software is
|
|
# furnished to do so, subject to the following conditions:
|
|
#
|
|
# The above copyright notice and this permission notice shall be included in
|
|
# all copies or substantial portions of the Software.
|
|
#
|
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
# SOFTWARE.
|
|
|
|
# Todo:
|
|
# - Allow persistance of discovered servers.
|
|
# - The control point should wait at least the amount of time specified in the
|
|
# MX header for responses to arrive from devices.
|
|
# - Date/datetime
|
|
# - Store all properties
|
|
# - SSDP.discover(st): Allow to discover only certain service types
|
|
# - .find() method on most classes.
|
|
# - async discover (if possible).
|
|
# - Read parameter types and verify them when doing a call.
|
|
# - Marshall return values to the correct databases.
|
|
# - Handle SOAP error:
|
|
# <?xml version="1.0"?>
|
|
# <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 xmlns="">714</errorCode>
|
|
# <errorDescription xmlns="">No such entry in array</errorDescription>
|
|
# </UPnPError>
|
|
# </detail>
|
|
# </s:Fault>
|
|
# </s:Body>
|
|
# </s:Envelope>
|
|
# - Test params and responses with XML entities in them "<", "&", etc.
|
|
# - AllowedValueRange
|
|
# <allowedValueRange>
|
|
# <minimum>minimum value</minimum>
|
|
# <maximum>maximum value</maximum>
|
|
# <step>increment value</step>
|
|
# </allowedValueRange>
|
|
# - Name params as 'NewFoo', or not (See spec)?
|
|
|
|
"""
|
|
This module provides an UPnP Control Point (client), and provides an easy
|
|
interface to discover and communicate with UPnP servers. It implements SSDP
|
|
(Simple Service Discovery Protocol), SCPD (Simple Control Point Definition) and
|
|
a minimal SOAP (Simple Object Access Protocol) implementation.
|
|
|
|
The usual flow for working with UPnP servers is:
|
|
|
|
- Discover UPnP servers using SSDP.
|
|
|
|
SSDP is a simple HTTP-over-UDP protocol. An M-SEARCH HTTP request is broad-
|
|
casted over the network and any UPnP servers should respond with an HTTP
|
|
response. This response includes an URL to an XML file containing information
|
|
about the server. The SSDP.discover() method returns a list of Server
|
|
instances. If you already know the URL of the XML file, you can skip this
|
|
step and instantiate a Server instance directly.
|
|
|
|
- Inspect Server capabilities using SCPD.
|
|
|
|
The XML file returned by UPnP servers during discovery is read and information
|
|
about the server and the services it offers is stored in a Server instance. The
|
|
Server.services property contains a list of Service instances supported by that
|
|
server.
|
|
|
|
- Inspect Services capabilities using SCPD.
|
|
|
|
Each Server may contain more than one Services. For each Service, a separate
|
|
XML file exists. The Service class reads that XML file and determines which
|
|
actions a service supports. The Service.actions property contains a list of
|
|
Action instances supported by that service.
|
|
|
|
- Inspect an Action using SCPD.
|
|
|
|
An Action instance may be inspected to determine which arguments need to be
|
|
passed into it and what it returns. Information on the type and possible
|
|
values of each argument can also be queried.
|
|
|
|
- Call an Action using SOAP.
|
|
|
|
An Action instance may then be called using the Action.call(arguments) method.
|
|
The Action class will verify the correctness of arguments, possibly
|
|
converting them. A SOAP call is then made to the UPnP server and the results
|
|
are returned.
|
|
|
|
Classes:
|
|
|
|
* SSDP: Discover UPnP servers using the SSDP class.
|
|
* Server: Connect to an UPnP server and retrieve information/capabilities using the Server class.
|
|
* Service: Query a Server class instance for the various services it supports.
|
|
* Action: Query a Service class instance for the various actions it supports and call them.
|
|
|
|
Various convenience methods are provided at almost all levels. For instance,
|
|
the find_action() methods can directly find a method (by name) in an UPnP
|
|
server/service. The call() method can be used at most levels to directly call
|
|
an action.
|
|
|
|
The following example discovers all UPnP servers on the local network and then
|
|
dumps all their services and actions:
|
|
|
|
------------------------------------------------------------------------------
|
|
import upnpclient
|
|
|
|
ssdp = upnpclient.SSDP()
|
|
servers = ssdp.discover()
|
|
|
|
for server in servers:
|
|
print "%s: %s" % (server.friendly_name, server.model_description)
|
|
for service in server.services:
|
|
print " %s" % (service.service_type)
|
|
for action in service.actions:
|
|
print " %s" % (action.name)
|
|
for arg_name, arg_def in action.argsdef_in:
|
|
valid = ', '.join(arg_def['allowed_values']) or '*'
|
|
print " in: %s (%s): %s" % (arg_name, arg_def['datatype'], valid)
|
|
for arg_name, arg_def in action.argsdef_out:
|
|
valid = ', '.join(arg_def['allowed_values']) or '*'
|
|
print " out: %s (%s): %s" % (arg_name, arg_def['datatype'], valid)
|
|
------------------------------------------------------------------------------
|
|
|
|
Useful Links:
|
|
|
|
* https://embeddedinn.wordpress.com/tutorials/upnp-device-architecture/
|
|
* http://upnp.org/specs/arch/UPnP-arch-DeviceArchitecture-v1.1.pdf
|
|
"""
|
|
from upnpclient import const, errors, marshal, soap, ssdp, upnp, util # noqa: F401
|
|
from .upnp import (
|
|
Device, Action, Service, UPNPError, InvalidActionException, ValidationError, UnexpectedResponse)
|
|
from .ssdp import discover
|
|
|
|
__all__ = [
|
|
"Device", "Action", "Service", "UPNPError", "InvalidActionException", "ValidationError",
|
|
"discover", "UnexpectedResponse"
|
|
]
|