Discover UPnP Devices

The UPnP protocol is used to discover certain devices in the local network and to a certain extend also to interact with them.

The discovery mechanism is to send a multicast request which gets answered by UPnP devices in the HTTP format. The combination of devices in potential stand-by mode and multicast let the discovery fail infrequently. For that reason a retry is strongly recommended to make sure to get answers from all UPnP device in the network. Also the service type which is included in the request matters for some devices, it is recommended to use the most specific service type, if known, for a device as some devices answers differently depending on the service type. Recommendation is to use after a broader discover() the more specific discoverParticularHost() again for every device you are interested in as that method do some magic to find all the information’s which a device can provide.

The discovery mechanism is the only way to gather the URL to the device specifications, which is needed if you like to interact with a device. Not all UPnP devices support an interaction based on the standard and provide only a proprietary way for which you need the vendor documentation.

This library provides an sheell command ‘upnp_tools’ which shows how to use the library for the different use cases.

See also

The scripts which have been provided with this library shows good use of the full library.

Additional short explanation of the UPnP protocol

Protocol

This example illustrates what the library sends and receives during a discovery process, whereas the example is given for a specific service type.

Request:

A discovery request is send via IP multicast on 239.255.255.250:1900.

M-SEARCH * HTTP/1.1\r\n
MX: 5\r\n
MAN: "ssdp:discover"\r\n
HOST: 239.255.255.250:1900\r\n
ST: urn:dslforum-org:device:InternetGatewayDevice:1\r\n
\r\n
Response:
HTTP/1.1 200 OK\r\n
LOCATION: http://192.168.178.1:49000/tr64desc.xml\r\n
SERVER: FRITZ!Box Fon WLAN 7390 UPnP/1.0 AVM FRITZ!Box Fon WLAN 7390 84.06.30\r\n
CACHE-CONTROL: max-age=1800\r\n
EXT:\r\n
ST: urn:dslforum-org:device:InternetGatewayDevice:1\r\n
USN: uuid:739f2419-bccb-40e7-8e6c-BC254222D5C4::urn:dslforum-org:device:InternetGatewayDevice:1\r\n
\r\n

Classes

class simpletr64.Discover

This class provides several static methods to discover UPnP devices.

static discover(service='ssdp:all', timeout=1, retries=2, ipAddress='239.255.255.250', port=1900)

Discovers UPnP devices in the local network.

Try to discover all devices in the local network which do support UPnP. The discovery process can fail for various reasons and it is recommended to do at least two discoveries, which you can specify with the retries parameter.

The default service parameter tries to address all devices also if you know which kind of service type you are looking for you should set it as some devices do not respond or respond differently otherwise.

Parameters:
  • service (str or list[str]) – the service type or list of service types of devices you look for
  • timeout (float) – the socket timeout for each try
  • retries (int) – how often should be a discovery request send
  • ipAddress (str) – the multicast ip address to use
  • port (int) – the port to use
Returns:

a list of DiscoveryResponse objects or empty if no device was found

Return type:

list[DiscoveryResponse]

Example:
results = discover()
for result in results:
    print("Host: " + result.locationHost + " Port: " + result.locationPort + " Device definitions: " + \
        result.location)
static discoverParticularHost(host, service='ssdp:all', deviceDefinitionURL=None, timeout=1, retries=2, ipAddress='239.255.255.250', port=1900, proxies=None)

Discover a particular host and find the best response.

This tries to find the most specific discovery result for the given host. Only the discovery result contains the URL to the XML tree which initializes the device definition. If an URL is already known it should be provided to avoid additional latency for a broader first device discovery. This method also do some magic to find the best result for the given host as UPnP devices behave sometimes strangely. This call is costly the result if any should be cached.

Parameters:
  • host (str) – the host to find
  • service (str or list[str]) – the service type or list of service types if known to search for
  • deviceDefinitionURL (str) – if provided it is used to skip a first device discovery
  • timeout (float) – the time to wait for each retry
  • retries (int) – the amount of times how often the device is tried to discover
  • ipAddress (str) – the multicast ip address to discover devices
  • port (int) – the port to discover devices
  • proxies (str) – proxy definition as defined here: Proxy definition
Returns:

If the device have been found the response is returned otherwise None

Return type:

DiscoveryResponse

Raises:
  • ValueError – if problems with reading or parsing the xml device definition occurs
  • requests.exceptions.ConnectionError – when the device definitions can not be downloaded
  • requests.exceptions.ConnectTimeout – when download time out
Example:
proxies = {"http": "http://localhost:8888"}
result = discoverParticularHost("192.168.0.1", proxies=proxies)
if result is not None:
    print("Host: " + result.locationHost + " Port: " + result.locationPort + " Device definitions: " + \
        result.location)
static rateServiceTypeInResult(discoveryResponse)

Gives a quality rating for a given service type in a result, higher is better.

Several UpnP devices reply to a discovery request with multiple responses with different service type announcements. To find the most specific one we need to be able rate the service types against each other. Usually this is an internal method and just exported for convenience reasons.

Parameters:discoveryResponse (DiscoveryResponse) – the response to rate
Returns:a rating of the quality of the given service type
Return type:int

class simpletr64.DiscoveryResponse(data)

A helper class for results of discovery requests.

static create(location, service='uuid:none', usn='none')

Factory method to create an DiscoverResponse object with dedicated parameters.

Parameters:
  • location (str) – the location of the new object
  • service (str) – which service should be used
  • usn (str) – the device id which should be used
Returns:

the newly created object

Return type:

DiscoveryResponse

getheaders()

Return all headers from the response

This gives the ability to access all HTTP headers of a discovery response.

Returns:dict[str, str]
location

Return the location of the discovery response which points to the device definitions.

The location usually is a full URL to an XML device definition, example http://192.168.0.24:49000/tr64desc.xml

Returns:the location
Return type:str
locationHost

Returns the host or IP address of the location URL.

For the given example: http://192.168.0.24:49000/tr64desc.xml the result would be 192.168.0.24

Returns:the extracted host part of the location URL
Return type:str
locationPath

Returns the URI path of the location URL.

For the given example: http://192.168.0.24:49000/tr64desc.xml the result would be /tr64desc.xml

Returns:the extracted URI of the location URL
Return type:str
locationPort

Returns the port of the location URL.

For the given example: http://192.168.0.24:49000/tr64desc.xml the result would be 49000. If no port was given the port is assumed based on the protocol.

Returns:the extracted port of the location URL
Return type:int
locationProtocol

Returns the protocol of the location URL.

For the given example: http://192.168.0.24:49000/tr64desc.xml the result would be http

Returns:the extracted protocol of the location URL
Return type:str
service

Returns the service which was announced by the device response.

Example: urn:dslforum-org:device:InternetGatewayDevice:1

Returns:the service type
Return type:str
usn

Return the device id of the device which responded.

Example: uuid:739f2419-bccb-40e7-8e6c-BC254222D5C4::urn:dslforum-org:device:InternetGatewayDevice:1

Returns:the device id
Return type:str