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)
| File | Size | Uploaded | |
|---|---|---|---|
| upnpclient-2.0.3.tar.gz | 89.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| 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 logRelease 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