You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

151 lines
6.5 KiB

4 years ago
  1. # Copyright (c) 2012-2016, Ferry Boender <ferry.boender@gmail.com>
  2. #
  3. # Permission is hereby granted, free of charge, to any person obtaining a copy
  4. # of this software and associated documentation files (the "Software"), to deal
  5. # in the Software without restriction, including without limitation the rights
  6. # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  7. # copies of the Software, and to permit persons to whom the Software is
  8. # furnished to do so, subject to the following conditions:
  9. #
  10. # The above copyright notice and this permission notice shall be included in
  11. # all copies or substantial portions of the Software.
  12. #
  13. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  14. # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  15. # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  16. # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  17. # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  18. # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  19. # SOFTWARE.
  20. # Todo:
  21. # - Allow persistance of discovered servers.
  22. # - The control point should wait at least the amount of time specified in the
  23. # MX header for responses to arrive from devices.
  24. # - Date/datetime
  25. # - Store all properties
  26. # - SSDP.discover(st): Allow to discover only certain service types
  27. # - .find() method on most classes.
  28. # - async discover (if possible).
  29. # - Read parameter types and verify them when doing a call.
  30. # - Marshall return values to the correct databases.
  31. # - Handle SOAP error:
  32. # <?xml version="1.0"?>
  33. # <s:Envelope
  34. # xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"
  35. # s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
  36. # <s:Body>
  37. # <s:Fault>
  38. # <faultcode>s:Client</faultcode>
  39. # <faultstring>UPnPError</faultstring>
  40. # <detail>
  41. # <UPnPError xmlns="urn:schemas-upnp-org:control-1-0">
  42. # <errorCode xmlns="">714</errorCode>
  43. # <errorDescription xmlns="">No such entry in array</errorDescription>
  44. # </UPnPError>
  45. # </detail>
  46. # </s:Fault>
  47. # </s:Body>
  48. # </s:Envelope>
  49. # - Test params and responses with XML entities in them "<", "&", etc.
  50. # - AllowedValueRange
  51. # <allowedValueRange>
  52. # <minimum>minimum value</minimum>
  53. # <maximum>maximum value</maximum>
  54. # <step>increment value</step>
  55. # </allowedValueRange>
  56. # - Name params as 'NewFoo', or not (See spec)?
  57. """
  58. This module provides an UPnP Control Point (client), and provides an easy
  59. interface to discover and communicate with UPnP servers. It implements SSDP
  60. (Simple Service Discovery Protocol), SCPD (Simple Control Point Definition) and
  61. a minimal SOAP (Simple Object Access Protocol) implementation.
  62. The usual flow for working with UPnP servers is:
  63. - Discover UPnP servers using SSDP.
  64. SSDP is a simple HTTP-over-UDP protocol. An M-SEARCH HTTP request is broad-
  65. casted over the network and any UPnP servers should respond with an HTTP
  66. response. This response includes an URL to an XML file containing information
  67. about the server. The SSDP.discover() method returns a list of Server
  68. instances. If you already know the URL of the XML file, you can skip this
  69. step and instantiate a Server instance directly.
  70. - Inspect Server capabilities using SCPD.
  71. The XML file returned by UPnP servers during discovery is read and information
  72. about the server and the services it offers is stored in a Server instance. The
  73. Server.services property contains a list of Service instances supported by that
  74. server.
  75. - Inspect Services capabilities using SCPD.
  76. Each Server may contain more than one Services. For each Service, a separate
  77. XML file exists. The Service class reads that XML file and determines which
  78. actions a service supports. The Service.actions property contains a list of
  79. Action instances supported by that service.
  80. - Inspect an Action using SCPD.
  81. An Action instance may be inspected to determine which arguments need to be
  82. passed into it and what it returns. Information on the type and possible
  83. values of each argument can also be queried.
  84. - Call an Action using SOAP.
  85. An Action instance may then be called using the Action.call(arguments) method.
  86. The Action class will verify the correctness of arguments, possibly
  87. converting them. A SOAP call is then made to the UPnP server and the results
  88. are returned.
  89. Classes:
  90. * SSDP: Discover UPnP servers using the SSDP class.
  91. * Server: Connect to an UPnP server and retrieve information/capabilities using the Server class.
  92. * Service: Query a Server class instance for the various services it supports.
  93. * Action: Query a Service class instance for the various actions it supports and call them.
  94. Various convenience methods are provided at almost all levels. For instance,
  95. the find_action() methods can directly find a method (by name) in an UPnP
  96. server/service. The call() method can be used at most levels to directly call
  97. an action.
  98. The following example discovers all UPnP servers on the local network and then
  99. dumps all their services and actions:
  100. ------------------------------------------------------------------------------
  101. import upnpclient
  102. ssdp = upnpclient.SSDP()
  103. servers = ssdp.discover()
  104. for server in servers:
  105. print "%s: %s" % (server.friendly_name, server.model_description)
  106. for service in server.services:
  107. print " %s" % (service.service_type)
  108. for action in service.actions:
  109. print " %s" % (action.name)
  110. for arg_name, arg_def in action.argsdef_in:
  111. valid = ', '.join(arg_def['allowed_values']) or '*'
  112. print " in: %s (%s): %s" % (arg_name, arg_def['datatype'], valid)
  113. for arg_name, arg_def in action.argsdef_out:
  114. valid = ', '.join(arg_def['allowed_values']) or '*'
  115. print " out: %s (%s): %s" % (arg_name, arg_def['datatype'], valid)
  116. ------------------------------------------------------------------------------
  117. Useful Links:
  118. * https://embeddedinn.wordpress.com/tutorials/upnp-device-architecture/
  119. * http://upnp.org/specs/arch/UPnP-arch-DeviceArchitecture-v1.1.pdf
  120. """
  121. from upnpclient import const, errors, marshal, soap, ssdp, upnp, util # noqa: F401
  122. from .upnp import (
  123. Device, Action, Service, UPNPError, InvalidActionException, ValidationError, UnexpectedResponse)
  124. from .ssdp import discover
  125. __all__ = [
  126. "Device", "Action", "Service", "UPNPError", "InvalidActionException", "ValidationError",
  127. "discover", "UnexpectedResponse"
  128. ]