Skip to main content

CI PyPI Python License Downloads

uPnPclient

uPnP client library for Python 3.

This library can be used to discover and consume uPnP devices and their services.

It's originally based on Ferry Boender's work and his blog post entitled Exploring UPnP with Python.

Requirements

Python 3.9+

Installation

pip install upnpclient

Usage

Typical usage:

In [1]: import upnpclient

In [2]: devices = upnpclient.discover()

In [3]: devices
Out[3]: 
[<Device 'OpenWRT router'>,
 <Device 'Harmony Hub'>,
 <Device 'walternate: root'>]

In [4]: d = devices[0]

In [5]: d.WANIPConn1.GetStatusInfo()
Out[5]: 
{'NewConnectionStatus': 'Connected',
 'NewLastConnectionError': 'ERROR_NONE',
 'NewUptime': 14851479}

In [6]: d.WANIPConn1.GetNATRSIPStatus()
Out[6]: {'NewNATEnabled': True, 'NewRSIPAvailable': False}

In [7]: d.WANIPConn1.GetExternalIPAddress()
Out[7]: {'NewExternalIPAddress': '123.123.123.123'}

If you know the URL for the device description XML, you can access it directly.

In [1]: import upnpclient

In [2]: d = upnpclient.Device("http://192.168.1.1:5000/rootDesc.xml")

In [3]: d.services
Out[3]: 
[<Service service_id='urn:upnp-org:serviceId:Layer3Forwarding1'>,
 <Service service_id='urn:upnp-org:serviceId:WANCommonIFC1'>,
 <Service service_id='urn:upnp-org:serviceId:WANIPConn1'>]

In [4]: d.Layer3Forwarding1.actions
Out[4]: 
[<Action 'SetDefaultConnectionService'>,
 <Action 'GetDefaultConnectionService'>]

In [5]: d.Layer3Forwarding1.GetDefaultConnectionService()
Out[5]: {'NewDefaultConnectionService': 'uuid:46cb370a-d7f2-490f-ac01-fb0db6c8b22b:WANConnectionDevice:1,urn:upnp-org:serviceId:WANIPConn1'}

Sometimes the service or action name isn't a valid property name. In which case, service and actions can be accessed other ways:

In [1]: d["Layer3Forwarding1"]["GetDefaultConnectionService"]()
Out[1]: {'NewDefaultConnectionService': 'uuid:46cb370a-d7f2-490f-ac01-fb0db6c8b22b:WANConnectionDevice:1,urn:upnp-org:serviceId:WANIPConn1'}

To view the arguments required to call a given action:

In [1]: d.WANIPConn1.AddPortMapping.argsdef_in
Out[1]: 
[('NewRemoteHost',
  {'allowed_values': set(), 'datatype': 'string', 'name': 'RemoteHost'}),
 ('NewExternalPort',
  {'allowed_values': set(), 'datatype': 'ui2', 'name': 'ExternalPort'}),
 ('NewProtocol',
  {'allowed_values': {'TCP', 'UDP'},
   'datatype': 'string',
   'name': 'PortMappingProtocol'}),
 ('NewInternalPort',
  {'allowed_values': set(), 'datatype': 'ui2', 'name': 'InternalPort'}),
 ('NewInternalClient',
  {'allowed_values': set(), 'datatype': 'string', 'name': 'InternalClient'}),
 ('NewEnabled',
  {'allowed_values': set(),
   'datatype': 'boolean',
   'name': 'PortMappingEnabled'}),
 ('NewPortMappingDescription',
  {'allowed_values': set(),
   'datatype': 'string',
   'name': 'PortMappingDescription'}),
 ('NewLeaseDuration',
  {'allowed_values': set(),
   'datatype': 'ui4',
   'name': 'PortMappingLeaseDuration'})]

and then to call the action using those arguments:

In [1]: d.WANIPConn1.AddPortMapping(
   ...:     NewRemoteHost='0.0.0.0',
   ...:     NewExternalPort=12345,
   ...:     NewProtocol='TCP',
   ...:     NewInternalPort=12345,
   ...:     NewInternalClient='192.168.1.10',
   ...:     NewEnabled='1',
   ...:     NewPortMappingDescription='Testing',
   ...:     NewLeaseDuration=10000)
Out[1]: {}

Similarly, the arguments you can expect to receive in response are listed:

In [1]: d.WANIPConn1.GetGenericPortMappingEntry.argsdef_out
Out[1]: 
[('NewRemoteHost',
  {'allowed_values': set(), 'datatype': 'string', 'name': 'RemoteHost'}),
 ('NewExternalPort',
  {'allowed_values': set(), 'datatype': 'ui2', 'name': 'ExternalPort'}),
 ('NewProtocol',
  {'allowed_values': {'TCP', 'UDP'},
   'datatype': 'string',
   'name': 'PortMappingProtocol'}),
 ('NewInternalPort',
  {'allowed_values': set(), 'datatype': 'ui2', 'name': 'InternalPort'}),
 ('NewInternalClient',
  {'allowed_values': set(), 'datatype': 'string', 'name': 'InternalClient'}),
 ('NewEnabled',
  {'allowed_values': set(),
   'datatype': 'boolean',
   'name': 'PortMappingEnabled'}),
 ('NewPortMappingDescription',
  {'allowed_values': set(),
   'datatype': 'string',
   'name': 'PortMappingDescription'}),
 ('NewLeaseDuration',
  {'allowed_values': set(),
   'datatype': 'ui4',
   'name': 'PortMappingLeaseDuration'})]

HTTP Auth/Headers

You may pass a requests compatible authentication object and/or a dictionary containing headers to use on the HTTP calls to your uPnP device.

These may be set on the Device itself on creation for use with every HTTP call:

device = upnpclient.Device(
    "http://192.168.1.1:5000/rootDesc.xml"
    http_auth=('myusername', 'mypassword'),
    http_headers={'Some-Required-Header': 'somevalue'}
)

Or on a per-call basis:

device.Layer3Forwarding1.GetDefaultConnectionService(
    http_auth=('myusername', 'mypassword'),
    http_headers={'Some-Required-Header': 'somevalue'}
)

If you've set either at Device level, they can be overridden per-call by setting them to None.

Release files for upnpclient 2.0.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for upnpclient 2.0.3
File Size Uploaded
upnpclient-2.0.3.tar.gz 89.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for upnpclient 2.0.3
File Interpreter ABI Platform
upnpclient-2.0.3-py3-none-any.whl Python 3 none any Details

Total release size: 107.4 kB

Release files / upnpclient-2.0.3.tar.gz

Download URL upnpclient-2.0.3.tar.gz
Size 89.1 kB
Tags Source
SHA-256 checksum
How to use checksums
acf66781a194f268539fbca52ebfa1b10de12174c7150902053d9fd0a2a02c5c
BLAKE2b-256 checksum
How to use checksums
3fce347724075ddbd768c11dec1f7c89fa7d03364ae1bf3317c5651277617946
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Apr 7, 2026.

Transparency log

Release files / upnpclient-2.0.3-py3-none-any.whl

Download URL upnpclient-2.0.3-py3-none-any.whl
Size 18.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
01b5930a16799f5ca2096b520207fa0ae85ecd2627529fc7f96a8e02c4d0e656
BLAKE2b-256 checksum
How to use checksums
d185a96e21ceca5d612852d0f319a689da827f7be93b26b39faf3224d02847d1
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Apr 7, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

2.0.3 This release

2 release files

2.0.2

2 release files

2.0.1

2 release files

2.0.0

2 release files

1.0.3

2 release files

0.0.8

1 release file

0.0.7

1 release file

0.0.6

1 release file

0.0.5

1 release file

0.0.4

1 release file

0.0.3

1 release file

0.0.1

1 release file

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page