onvif-python 0.0.8__tar.gz → 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {onvif_python-0.0.8/onvif_python.egg-info → onvif_python-0.1.0}/PKG-INFO +105 -37
- {onvif_python-0.0.8 → onvif_python-0.1.0}/README.md +104 -33
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/client.py +167 -79
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/operator.py +3 -3
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/services/uplink.py +1 -1
- onvif_python-0.1.0/onvif/utils/wsdl.py +350 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0/onvif_python.egg-info}/PKG-INFO +105 -37
- {onvif_python-0.0.8 → onvif_python-0.1.0}/pyproject.toml +1 -4
- onvif_python-0.0.8/onvif/utils/wsdl.py +0 -297
- {onvif_python-0.0.8 → onvif_python-0.1.0}/LICENSE.md +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/MANIFEST.in +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/__init__.py +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/services/__init__.py +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/services/accesscontrol.py +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/services/accessrules.py +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/services/actionengine.py +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/services/analytics/analytics.py +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/services/analytics/ruleengine.py +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/services/analyticsdevice.py +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/services/appmgmt.py +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/services/authenticationbehavior.py +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/services/credential.py +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/services/deviceio.py +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/services/devicemgmt.py +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/services/display.py +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/services/doorcontrol.py +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/services/events/events.py +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/services/events/notification.py +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/services/events/pullpoint.py +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/services/events/subscription.py +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/services/imaging.py +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/services/media.py +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/services/media2.py +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/services/provisioning.py +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/services/ptz.py +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/services/receiver.py +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/services/recording.py +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/services/replay.py +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/services/schedule.py +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/services/search.py +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/services/security/advancedsecurity.py +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/services/security/authorizationserver.py +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/services/security/dot1x.py +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/services/security/jwt.py +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/services/security/keystore.py +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/services/security/mediasigning.py +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/services/security/tlsserver.py +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/services/thermal.py +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/utils/__init__.py +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/utils/error_handlers.py +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/utils/exceptions.py +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/utils/xml_capture.py +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/utils/zeep.py +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/wsdl/ver10/accesscontrol/wsdl/index.html +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/wsdl/ver10/accessrules/wsdl/accessrules.wsdl +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/wsdl/ver10/accessrules/wsdl/index.html +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/wsdl/ver10/actionengine.wsdl +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/wsdl/ver10/advancedsecurity/wsdl/advancedsecurity.wsdl +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/wsdl/ver10/advancedsecurity/wsdl/index.html +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/wsdl/ver10/analyticsdevice.wsdl +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/wsdl/ver10/appmgmt/wsdl/appmgmt.wsdl +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/wsdl/ver10/appmgmt/wsdl/index.html +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/wsdl/ver10/authenticationbehavior/wsdl/authenticationbehavior.wsdl +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/wsdl/ver10/authenticationbehavior/wsdl/index.html +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/wsdl/ver10/credential/wsdl/credential.wsdl +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/wsdl/ver10/credential/wsdl/index.html +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/wsdl/ver10/device/wsdl/devicemgmt.wsdl +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/wsdl/ver10/deviceio.wsdl +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/wsdl/ver10/display/display.wsdl +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/wsdl/ver10/display/wsdl/index.htm +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/wsdl/ver10/display.wsdl +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/wsdl/ver10/doorcontrol/wsdl/index.html +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/wsdl/ver10/events/wsdl/bw-2-vs-mod.wsdl +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/wsdl/ver10/events/wsdl/event-vs.wsdl +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/wsdl/ver10/events/wsdl/event.wsdl +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/wsdl/ver10/events/wsdl/index.html +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/wsdl/ver10/federatedsearch.wsdl +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/wsdl/ver10/media/wsdl/media.wsdl +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/wsdl/ver10/pacs/accesscontrol.wsdl +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/wsdl/ver10/pacs/doorcontrol.wsdl +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/wsdl/ver10/pacs/types.xsd +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/wsdl/ver10/provisioning/wsdl/provisioning.wsdl +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/wsdl/ver10/receiver.wsdl +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/wsdl/ver10/recording.wsdl +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/wsdl/ver10/replay.wsdl +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/wsdl/ver10/schedule/wsdl/index.html +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/wsdl/ver10/schedule/wsdl/schedule.wsdl +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/wsdl/ver10/schema/common.xsd +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/wsdl/ver10/schema/metadatastream.xsd +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/wsdl/ver10/schema/onvif.xsd +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/wsdl/ver10/search.wsdl +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/wsdl/ver10/thermal/wsdl/index.html +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/wsdl/ver10/thermal/wsdl/thermal.wsdl +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/wsdl/ver10/topics/topicns.xml +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/wsdl/ver10/uplink/wsdl/index.html +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/wsdl/ver10/uplink/wsdl/uplink.wsdl +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/wsdl/ver20/analytics/humanbody.xsd +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/wsdl/ver20/analytics/humanface.xsd +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/wsdl/ver20/analytics/index.html +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/wsdl/ver20/analytics/radiometry.xsd +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/wsdl/ver20/analytics/rules.xsd +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/wsdl/ver20/analytics/wsdl/analytics.wsdl +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/wsdl/ver20/analytics/wsdl/index.html +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/wsdl/ver20/imaging/wsdl/imaging.wsdl +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/wsdl/ver20/media/wsdl/index.html +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/wsdl/ver20/media/wsdl/media.wsdl +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/wsdl/ver20/ptz/wsdl/ptz.wsdl +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/wsdl/ver20/util/federated_search_documentation.html +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/wsdl/ver20/util/fedsearch-docu-viewer.xsl +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/wsdl/ver20/util/onvif-wsdl-viewer.xsl +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif/wsdl/ver20/util/operationIndex.html +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif_python.egg-info/SOURCES.txt +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif_python.egg-info/dependency_links.txt +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif_python.egg-info/requires.txt +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/onvif_python.egg-info/top_level.txt +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/setup.cfg +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/setup.py +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/tests/test_client.py +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/tests/test_core.py +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/tests/test_exceptions.py +0 -0
- {onvif_python-0.0.8 → onvif_python-0.1.0}/tests/test_wsdl_map.py +0 -0
|
@@ -1,14 +1,11 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: onvif-python
|
|
3
|
-
Version: 0.0
|
|
3
|
+
Version: 0.1.0
|
|
4
4
|
Summary: A comprehensive and developer-friendly Python library for working with ONVIF-compliant devices
|
|
5
5
|
Author-email: Nirsimetri Technologies® <open@nirsimetri.com>
|
|
6
6
|
Maintainer: Kaburagi
|
|
7
7
|
License-Expression: MIT
|
|
8
|
-
Project-URL: Homepage, https://github.com/nirsimetri/onvif-python
|
|
9
|
-
Project-URL: Issues, https://github.com/nirsimetri/onvif-python/issues
|
|
10
8
|
Project-URL: Documentation, https://deepwiki.com/nirsimetri/onvif-python
|
|
11
|
-
Project-URL: Repository, https://github.com/nirsimetri/onvif-python.git
|
|
12
9
|
Project-URL: Changelog, https://github.com/nirsimetri/onvif-python/releases
|
|
13
10
|
Keywords: onvif,Camera,onvif-python,ip-camera,cctv,soap,surveillance,cctv cameras,soap-client,onvif-client,onvif-library,onvif-specifications
|
|
14
11
|
Classifier: Development Status :: 5 - Production/Stable
|
|
@@ -43,9 +40,9 @@ Dynamic: license-file
|
|
|
43
40
|
|
|
44
41
|
[](https://github.com/nirsimetri/onvif-python?tab=MIT-1-ov-file)
|
|
45
42
|
[](https://deepwiki.com/nirsimetri/onvif-python)
|
|
46
|
-
[](https://github.com/nirsimetri/onvif-python/releases)
|
|
47
44
|
<br>
|
|
48
|
-
[](https://pypi.org/project/onvif-python/)
|
|
49
46
|
[](https://clickpy.clickhouse.com/dashboard/onvif-python)
|
|
50
47
|
|
|
51
48
|
**This project provides a comprehensive and developer-friendly Python library for working with ONVIF-compliant devices.** It is designed to be reliable, easy to integrate, and flexible enough to support a wide range of ONVIF profiles and services.
|
|
@@ -96,7 +93,14 @@ Create an instance of `ONVIFClient` by providing your device's IP address, port,
|
|
|
96
93
|
```python
|
|
97
94
|
from onvif import ONVIFClient
|
|
98
95
|
|
|
96
|
+
# Basic connection
|
|
99
97
|
client = ONVIFClient("192.168.1.17", 8000, "admin", "admin123")
|
|
98
|
+
|
|
99
|
+
# With custom WSDL directory (optional)
|
|
100
|
+
client = ONVIFClient(
|
|
101
|
+
"192.168.1.17", 8000, "admin", "admin123",
|
|
102
|
+
wsdl_dir="/path/to/custom/wsdl" # Use custom WSDL files in this path
|
|
103
|
+
)
|
|
100
104
|
```
|
|
101
105
|
|
|
102
106
|
**2. Create Service Instance**
|
|
@@ -189,8 +193,9 @@ The `ONVIFClient` class provides various configuration options to customize the
|
|
|
189
193
|
|
|
190
194
|
| Parameter | Type | Required | Default | Description |
|
|
191
195
|
|-----------|------|----------|---------|-------------|
|
|
192
|
-
| `apply_patch` | `bool` | ❌ No | `True` | Enable zeep patching for better `xsd:any` field parsing and automatic flattening |
|
|
193
|
-
| `capture_xml` | `bool` | ❌ No | `False` | Enable XML capture plugin for debugging SOAP requests/responses |
|
|
196
|
+
| `apply_patch` | `bool` | ❌ No | `True` | Enable zeep patching for better `xsd:any` field parsing and automatic flattening, applied at (>= [`v0.0.4`](https://github.com/nirsimetri/onvif-python/releases/tag/v0.0.4)) |
|
|
197
|
+
| `capture_xml` | `bool` | ❌ No | `False` | Enable XML capture plugin for debugging SOAP requests/responses, applied at (>= [`v0.0.6`](https://github.com/nirsimetri/onvif-python/releases/tag/v0.0.6)) |
|
|
198
|
+
| `wsdl_dir` | `str` | ❌ No | `None` | Custom WSDL directory path for using external WSDL files instead of built-in ones (e.g., `/path/to/custom/wsdl`), applied at (>= [`v0.1.0`](https://github.com/nirsimetri/onvif-python/releases/tag/v0.1.0)) |
|
|
194
199
|
|
|
195
200
|
</details>
|
|
196
201
|
|
|
@@ -320,6 +325,33 @@ if client.xml_plugin:
|
|
|
320
325
|
> - `save_to_file(request_file, response_file)` - Save XML to files
|
|
321
326
|
> - `clear_history()` - Clear captured history
|
|
322
327
|
|
|
328
|
+
**Custom WSDL Directory:**
|
|
329
|
+
```python
|
|
330
|
+
from onvif import ONVIFClient
|
|
331
|
+
|
|
332
|
+
# Use custom WSDL files instead of built-in ones
|
|
333
|
+
client = ONVIFClient(
|
|
334
|
+
"192.168.1.17",
|
|
335
|
+
80,
|
|
336
|
+
"admin",
|
|
337
|
+
"password",
|
|
338
|
+
wsdl_dir="/path/to/custom/wsdl" # Custom WSDL directory
|
|
339
|
+
)
|
|
340
|
+
|
|
341
|
+
# All services will automatically use custom WSDL files
|
|
342
|
+
device = client.devicemgmt()
|
|
343
|
+
media = client.media()
|
|
344
|
+
ptz = client.ptz()
|
|
345
|
+
|
|
346
|
+
# The custom WSDL directory should have a flat structure:
|
|
347
|
+
# /path/to/custom/wsdl/
|
|
348
|
+
# ├── devicemgmt.wsdl
|
|
349
|
+
# ├── media.wsdl
|
|
350
|
+
# ├── ptz.wsdl
|
|
351
|
+
# ├── imaging.wsdl
|
|
352
|
+
# └── ... (other WSDL files)
|
|
353
|
+
```
|
|
354
|
+
|
|
323
355
|
</details>
|
|
324
356
|
|
|
325
357
|
<details>
|
|
@@ -339,7 +371,8 @@ client = ONVIFClient(
|
|
|
339
371
|
use_https=True, # Secure communication
|
|
340
372
|
verify_ssl=True, # Verify certificates (default)
|
|
341
373
|
apply_patch=True, # Enhanced parsing (default)
|
|
342
|
-
capture_xml=False
|
|
374
|
+
capture_xml=False, # Disable debug mode (default)
|
|
375
|
+
wsdl_dir=None # Use built-in WSDL files (default)
|
|
343
376
|
)
|
|
344
377
|
```
|
|
345
378
|
</details>
|
|
@@ -349,12 +382,13 @@ client = ONVIFClient(
|
|
|
349
382
|
- **Authentication:** This library uses **WS-UsernameToken with Digest** authentication by default, which is the standard for ONVIF devices.
|
|
350
383
|
- **Patching:** The `apply_patch=True` (default) enables custom zeep patching that improves `xsd:any` field parsing. This is recommended for better compatibility with ONVIF responses.
|
|
351
384
|
- **XML Capture:** Only use `capture_xml=True` during development/debugging as it increases memory usage and may expose sensitive data in logs.
|
|
385
|
+
- **Custom WSDL:** Use `wsdl_dir` parameter to specify a custom directory containing WSDL files. The directory should have a flat structure with WSDL files directly in the root (e.g., `/path/to/custom/wsdl/devicemgmt.wsdl`, `/path/to/custom/wsdl/media.wsdl`, etc.).
|
|
352
386
|
- **Cache Location:** Disk cache (when using `CacheMode.DB` or `CacheMode.ALL`) is stored in `~/.onvif-python/onvif_zeep_cache.sqlite`.
|
|
353
387
|
|
|
354
388
|
## Service Discovery: Understanding Device Capabilities
|
|
355
389
|
|
|
356
390
|
> [!WARNING]
|
|
357
|
-
> Before performing any operations on an ONVIF device, it is highly recommended to discover which services are available and supported by the device. This library automatically
|
|
391
|
+
> Before performing any operations on an ONVIF device, it is highly recommended to discover which services are available and supported by the device. This library automatically performs comprehensive service discovery during initialization using a robust fallback mechanism.
|
|
358
392
|
|
|
359
393
|
**Why discover device services?**
|
|
360
394
|
|
|
@@ -365,50 +399,84 @@ client = ONVIFClient(
|
|
|
365
399
|
|
|
366
400
|
**How service discovery works in this library:**
|
|
367
401
|
|
|
368
|
-
The `ONVIFClient`
|
|
402
|
+
The `ONVIFClient` uses a **3-tier discovery approach** to maximize device compatibility:
|
|
403
|
+
|
|
404
|
+
1. **GetServices (Preferred)** - Tries `GetServices` first for detailed service information
|
|
405
|
+
2. **GetCapabilities (Fallback)** - Falls back to `GetCapabilities` if `GetServices` is not supported
|
|
406
|
+
3. **Default URLs (Final Fallback)** - Uses standard ONVIF URLs as last resort
|
|
369
407
|
|
|
370
408
|
```python
|
|
371
409
|
from onvif import ONVIFClient
|
|
372
410
|
|
|
373
411
|
client = ONVIFClient("192.168.1.17", 8000, "admin", "admin123")
|
|
374
412
|
|
|
375
|
-
#
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
413
|
+
# Check what discovery method was used
|
|
414
|
+
if client.services:
|
|
415
|
+
print("Service discovery: GetServices (preferred)")
|
|
416
|
+
print("Discovered services:", len(client.services))
|
|
417
|
+
print("Service map:", client._service_map)
|
|
418
|
+
elif client.capabilities:
|
|
419
|
+
print("Service discovery: GetCapabilities (fallback)")
|
|
420
|
+
print("Available capabilities:", client.capabilities)
|
|
421
|
+
else:
|
|
422
|
+
print("Service discovery: Using default URLs")
|
|
382
423
|
```
|
|
383
424
|
|
|
384
|
-
**
|
|
425
|
+
**Why this approach?**
|
|
385
426
|
|
|
386
|
-
|
|
427
|
+
- **GetServices** provides the most accurate and detailed service information, but it's **optional** in the ONVIF specification
|
|
428
|
+
- **GetCapabilities** is **mandatory** for all ONVIF-compliant devices, ensuring broader compatibility
|
|
429
|
+
- **Default URLs** guarantee basic connectivity even with non-compliant devices
|
|
430
|
+
|
|
431
|
+
**Get detailed service information:**
|
|
432
|
+
|
|
433
|
+
If you need comprehensive service details, you can manually call `GetServices` with capabilities:
|
|
387
434
|
|
|
388
435
|
```python
|
|
389
436
|
device = client.devicemgmt()
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
437
|
+
|
|
438
|
+
try:
|
|
439
|
+
# Try to get detailed service information
|
|
440
|
+
services = device.GetServices(IncludeCapability=True)
|
|
441
|
+
for service in services:
|
|
442
|
+
print(f"Service: {service.Namespace}")
|
|
443
|
+
print(f"XAddr: {service.XAddr}")
|
|
444
|
+
if hasattr(service, 'Capabilities'):
|
|
445
|
+
print(f"Capabilities: {service.Capabilities}")
|
|
446
|
+
except Exception:
|
|
447
|
+
# Fallback to GetCapabilities for legacy devices
|
|
448
|
+
capabilities = device.GetCapabilities()
|
|
449
|
+
print("Capabilities:", capabilities)
|
|
398
450
|
```
|
|
399
451
|
|
|
400
|
-
**
|
|
452
|
+
**Access capabilities information:**
|
|
401
453
|
|
|
402
|
-
|
|
454
|
+
When using `GetCapabilities` fallback, you can access capability information:
|
|
403
455
|
|
|
404
456
|
```python
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
457
|
+
device = client.devicemgmt()
|
|
458
|
+
|
|
459
|
+
try:
|
|
460
|
+
# Get capabilities information from device
|
|
461
|
+
capabilities = device.GetCapabilities()
|
|
462
|
+
|
|
463
|
+
# Main services (always available)
|
|
464
|
+
print("Media XAddr:", getattr(capabilities.Media, 'XAddr', 'Not available'))
|
|
465
|
+
print("PTZ XAddr:", getattr(capabilities.PTZ, 'XAddr', 'Not available'))
|
|
466
|
+
|
|
467
|
+
# Extension services (device-dependent)
|
|
468
|
+
ext = getattr(capabilities, 'Extension', None)
|
|
469
|
+
if ext:
|
|
470
|
+
print("DeviceIO XAddr:", getattr(ext.DeviceIO, 'XAddr', 'Not available'))
|
|
471
|
+
print("Recording XAddr:", getattr(ext.Recording, 'XAddr', 'Not available'))
|
|
472
|
+
print("Search XAddr:", getattr(ext.Search, 'XAddr', 'Not available'))
|
|
473
|
+
print("Replay XAddr:", getattr(ext.Replay, 'XAddr', 'Not available'))
|
|
474
|
+
except Exception as e:
|
|
475
|
+
print(f"Error getting capabilities: {e}")
|
|
408
476
|
```
|
|
409
477
|
|
|
410
478
|
> [!TIP]
|
|
411
|
-
> The library handles service discovery automatically
|
|
479
|
+
> The library handles service discovery automatically with intelligent fallback. You typically don't need to call discovery methods manually unless you need detailed capability information or want to refresh the service list after device configuration changes.
|
|
412
480
|
|
|
413
481
|
## Tested Devices
|
|
414
482
|
|
|
@@ -561,10 +629,10 @@ Some ONVIF services have multiple bindings in the same WSDL. These typically inc
|
|
|
561
629
|
|
|
562
630
|
## Future Improvements (Stay tuned and star ⭐ this repo)
|
|
563
631
|
|
|
564
|
-
- [x] Add debugging mode with raw xml on SOAP requests and responses
|
|
565
|
-
- [
|
|
566
|
-
- [ ] Add asynchronous (async/await) support for non-blocking ONVIF operations and concurrent device communication.
|
|
632
|
+
- [x] ~~Add debugging mode with raw xml on SOAP requests and responses.~~ ([c258162](https://github.com/nirsimetri/onvif-python/commit/c258162))
|
|
633
|
+
- [x] ~~Add functionality for `ONVIFClient` to accept a custom `wsdl_dir` service.~~ ([65f2570](https://github.com/nirsimetri/onvif-python/commit/65f257092e4c9daa23dd0d00825ed38a45d23b70))
|
|
567
634
|
- [ ] Add `ONVIF CLI` program to interact directly with ONVIF devices via terminal.
|
|
635
|
+
- [ ] Add asynchronous (async/await) support for non-blocking ONVIF operations and concurrent device communication.
|
|
568
636
|
- [ ] Implement structured data models for ONVIF Schemas using [xsdata](https://github.com/tefra/xsdata).
|
|
569
637
|
- [ ] Integrate [xmltodict](https://github.com/martinblech/xmltodict) for simplified XML parsing and conversion.
|
|
570
638
|
- [ ] Enhance documentation with API references and diagrams (not from [AI Wiki](https://deepwiki.com/nirsimetri/onvif-python)).
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://github.com/nirsimetri/onvif-python?tab=MIT-1-ov-file)
|
|
4
4
|
[](https://deepwiki.com/nirsimetri/onvif-python)
|
|
5
|
-
[](https://github.com/nirsimetri/onvif-python/releases)
|
|
6
6
|
<br>
|
|
7
|
-
[](https://pypi.org/project/onvif-python/)
|
|
8
8
|
[](https://clickpy.clickhouse.com/dashboard/onvif-python)
|
|
9
9
|
|
|
10
10
|
**This project provides a comprehensive and developer-friendly Python library for working with ONVIF-compliant devices.** It is designed to be reliable, easy to integrate, and flexible enough to support a wide range of ONVIF profiles and services.
|
|
@@ -55,7 +55,14 @@ Create an instance of `ONVIFClient` by providing your device's IP address, port,
|
|
|
55
55
|
```python
|
|
56
56
|
from onvif import ONVIFClient
|
|
57
57
|
|
|
58
|
+
# Basic connection
|
|
58
59
|
client = ONVIFClient("192.168.1.17", 8000, "admin", "admin123")
|
|
60
|
+
|
|
61
|
+
# With custom WSDL directory (optional)
|
|
62
|
+
client = ONVIFClient(
|
|
63
|
+
"192.168.1.17", 8000, "admin", "admin123",
|
|
64
|
+
wsdl_dir="/path/to/custom/wsdl" # Use custom WSDL files in this path
|
|
65
|
+
)
|
|
59
66
|
```
|
|
60
67
|
|
|
61
68
|
**2. Create Service Instance**
|
|
@@ -148,8 +155,9 @@ The `ONVIFClient` class provides various configuration options to customize the
|
|
|
148
155
|
|
|
149
156
|
| Parameter | Type | Required | Default | Description |
|
|
150
157
|
|-----------|------|----------|---------|-------------|
|
|
151
|
-
| `apply_patch` | `bool` | ❌ No | `True` | Enable zeep patching for better `xsd:any` field parsing and automatic flattening |
|
|
152
|
-
| `capture_xml` | `bool` | ❌ No | `False` | Enable XML capture plugin for debugging SOAP requests/responses |
|
|
158
|
+
| `apply_patch` | `bool` | ❌ No | `True` | Enable zeep patching for better `xsd:any` field parsing and automatic flattening, applied at (>= [`v0.0.4`](https://github.com/nirsimetri/onvif-python/releases/tag/v0.0.4)) |
|
|
159
|
+
| `capture_xml` | `bool` | ❌ No | `False` | Enable XML capture plugin for debugging SOAP requests/responses, applied at (>= [`v0.0.6`](https://github.com/nirsimetri/onvif-python/releases/tag/v0.0.6)) |
|
|
160
|
+
| `wsdl_dir` | `str` | ❌ No | `None` | Custom WSDL directory path for using external WSDL files instead of built-in ones (e.g., `/path/to/custom/wsdl`), applied at (>= [`v0.1.0`](https://github.com/nirsimetri/onvif-python/releases/tag/v0.1.0)) |
|
|
153
161
|
|
|
154
162
|
</details>
|
|
155
163
|
|
|
@@ -279,6 +287,33 @@ if client.xml_plugin:
|
|
|
279
287
|
> - `save_to_file(request_file, response_file)` - Save XML to files
|
|
280
288
|
> - `clear_history()` - Clear captured history
|
|
281
289
|
|
|
290
|
+
**Custom WSDL Directory:**
|
|
291
|
+
```python
|
|
292
|
+
from onvif import ONVIFClient
|
|
293
|
+
|
|
294
|
+
# Use custom WSDL files instead of built-in ones
|
|
295
|
+
client = ONVIFClient(
|
|
296
|
+
"192.168.1.17",
|
|
297
|
+
80,
|
|
298
|
+
"admin",
|
|
299
|
+
"password",
|
|
300
|
+
wsdl_dir="/path/to/custom/wsdl" # Custom WSDL directory
|
|
301
|
+
)
|
|
302
|
+
|
|
303
|
+
# All services will automatically use custom WSDL files
|
|
304
|
+
device = client.devicemgmt()
|
|
305
|
+
media = client.media()
|
|
306
|
+
ptz = client.ptz()
|
|
307
|
+
|
|
308
|
+
# The custom WSDL directory should have a flat structure:
|
|
309
|
+
# /path/to/custom/wsdl/
|
|
310
|
+
# ├── devicemgmt.wsdl
|
|
311
|
+
# ├── media.wsdl
|
|
312
|
+
# ├── ptz.wsdl
|
|
313
|
+
# ├── imaging.wsdl
|
|
314
|
+
# └── ... (other WSDL files)
|
|
315
|
+
```
|
|
316
|
+
|
|
282
317
|
</details>
|
|
283
318
|
|
|
284
319
|
<details>
|
|
@@ -298,7 +333,8 @@ client = ONVIFClient(
|
|
|
298
333
|
use_https=True, # Secure communication
|
|
299
334
|
verify_ssl=True, # Verify certificates (default)
|
|
300
335
|
apply_patch=True, # Enhanced parsing (default)
|
|
301
|
-
capture_xml=False
|
|
336
|
+
capture_xml=False, # Disable debug mode (default)
|
|
337
|
+
wsdl_dir=None # Use built-in WSDL files (default)
|
|
302
338
|
)
|
|
303
339
|
```
|
|
304
340
|
</details>
|
|
@@ -308,12 +344,13 @@ client = ONVIFClient(
|
|
|
308
344
|
- **Authentication:** This library uses **WS-UsernameToken with Digest** authentication by default, which is the standard for ONVIF devices.
|
|
309
345
|
- **Patching:** The `apply_patch=True` (default) enables custom zeep patching that improves `xsd:any` field parsing. This is recommended for better compatibility with ONVIF responses.
|
|
310
346
|
- **XML Capture:** Only use `capture_xml=True` during development/debugging as it increases memory usage and may expose sensitive data in logs.
|
|
347
|
+
- **Custom WSDL:** Use `wsdl_dir` parameter to specify a custom directory containing WSDL files. The directory should have a flat structure with WSDL files directly in the root (e.g., `/path/to/custom/wsdl/devicemgmt.wsdl`, `/path/to/custom/wsdl/media.wsdl`, etc.).
|
|
311
348
|
- **Cache Location:** Disk cache (when using `CacheMode.DB` or `CacheMode.ALL`) is stored in `~/.onvif-python/onvif_zeep_cache.sqlite`.
|
|
312
349
|
|
|
313
350
|
## Service Discovery: Understanding Device Capabilities
|
|
314
351
|
|
|
315
352
|
> [!WARNING]
|
|
316
|
-
> Before performing any operations on an ONVIF device, it is highly recommended to discover which services are available and supported by the device. This library automatically
|
|
353
|
+
> Before performing any operations on an ONVIF device, it is highly recommended to discover which services are available and supported by the device. This library automatically performs comprehensive service discovery during initialization using a robust fallback mechanism.
|
|
317
354
|
|
|
318
355
|
**Why discover device services?**
|
|
319
356
|
|
|
@@ -324,50 +361,84 @@ client = ONVIFClient(
|
|
|
324
361
|
|
|
325
362
|
**How service discovery works in this library:**
|
|
326
363
|
|
|
327
|
-
The `ONVIFClient`
|
|
364
|
+
The `ONVIFClient` uses a **3-tier discovery approach** to maximize device compatibility:
|
|
365
|
+
|
|
366
|
+
1. **GetServices (Preferred)** - Tries `GetServices` first for detailed service information
|
|
367
|
+
2. **GetCapabilities (Fallback)** - Falls back to `GetCapabilities` if `GetServices` is not supported
|
|
368
|
+
3. **Default URLs (Final Fallback)** - Uses standard ONVIF URLs as last resort
|
|
328
369
|
|
|
329
370
|
```python
|
|
330
371
|
from onvif import ONVIFClient
|
|
331
372
|
|
|
332
373
|
client = ONVIFClient("192.168.1.17", 8000, "admin", "admin123")
|
|
333
374
|
|
|
334
|
-
#
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
375
|
+
# Check what discovery method was used
|
|
376
|
+
if client.services:
|
|
377
|
+
print("Service discovery: GetServices (preferred)")
|
|
378
|
+
print("Discovered services:", len(client.services))
|
|
379
|
+
print("Service map:", client._service_map)
|
|
380
|
+
elif client.capabilities:
|
|
381
|
+
print("Service discovery: GetCapabilities (fallback)")
|
|
382
|
+
print("Available capabilities:", client.capabilities)
|
|
383
|
+
else:
|
|
384
|
+
print("Service discovery: Using default URLs")
|
|
341
385
|
```
|
|
342
386
|
|
|
343
|
-
**
|
|
387
|
+
**Why this approach?**
|
|
344
388
|
|
|
345
|
-
|
|
389
|
+
- **GetServices** provides the most accurate and detailed service information, but it's **optional** in the ONVIF specification
|
|
390
|
+
- **GetCapabilities** is **mandatory** for all ONVIF-compliant devices, ensuring broader compatibility
|
|
391
|
+
- **Default URLs** guarantee basic connectivity even with non-compliant devices
|
|
392
|
+
|
|
393
|
+
**Get detailed service information:**
|
|
394
|
+
|
|
395
|
+
If you need comprehensive service details, you can manually call `GetServices` with capabilities:
|
|
346
396
|
|
|
347
397
|
```python
|
|
348
398
|
device = client.devicemgmt()
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
399
|
+
|
|
400
|
+
try:
|
|
401
|
+
# Try to get detailed service information
|
|
402
|
+
services = device.GetServices(IncludeCapability=True)
|
|
403
|
+
for service in services:
|
|
404
|
+
print(f"Service: {service.Namespace}")
|
|
405
|
+
print(f"XAddr: {service.XAddr}")
|
|
406
|
+
if hasattr(service, 'Capabilities'):
|
|
407
|
+
print(f"Capabilities: {service.Capabilities}")
|
|
408
|
+
except Exception:
|
|
409
|
+
# Fallback to GetCapabilities for legacy devices
|
|
410
|
+
capabilities = device.GetCapabilities()
|
|
411
|
+
print("Capabilities:", capabilities)
|
|
357
412
|
```
|
|
358
413
|
|
|
359
|
-
**
|
|
414
|
+
**Access capabilities information:**
|
|
360
415
|
|
|
361
|
-
|
|
416
|
+
When using `GetCapabilities` fallback, you can access capability information:
|
|
362
417
|
|
|
363
418
|
```python
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
419
|
+
device = client.devicemgmt()
|
|
420
|
+
|
|
421
|
+
try:
|
|
422
|
+
# Get capabilities information from device
|
|
423
|
+
capabilities = device.GetCapabilities()
|
|
424
|
+
|
|
425
|
+
# Main services (always available)
|
|
426
|
+
print("Media XAddr:", getattr(capabilities.Media, 'XAddr', 'Not available'))
|
|
427
|
+
print("PTZ XAddr:", getattr(capabilities.PTZ, 'XAddr', 'Not available'))
|
|
428
|
+
|
|
429
|
+
# Extension services (device-dependent)
|
|
430
|
+
ext = getattr(capabilities, 'Extension', None)
|
|
431
|
+
if ext:
|
|
432
|
+
print("DeviceIO XAddr:", getattr(ext.DeviceIO, 'XAddr', 'Not available'))
|
|
433
|
+
print("Recording XAddr:", getattr(ext.Recording, 'XAddr', 'Not available'))
|
|
434
|
+
print("Search XAddr:", getattr(ext.Search, 'XAddr', 'Not available'))
|
|
435
|
+
print("Replay XAddr:", getattr(ext.Replay, 'XAddr', 'Not available'))
|
|
436
|
+
except Exception as e:
|
|
437
|
+
print(f"Error getting capabilities: {e}")
|
|
367
438
|
```
|
|
368
439
|
|
|
369
440
|
> [!TIP]
|
|
370
|
-
> The library handles service discovery automatically
|
|
441
|
+
> The library handles service discovery automatically with intelligent fallback. You typically don't need to call discovery methods manually unless you need detailed capability information or want to refresh the service list after device configuration changes.
|
|
371
442
|
|
|
372
443
|
## Tested Devices
|
|
373
444
|
|
|
@@ -520,10 +591,10 @@ Some ONVIF services have multiple bindings in the same WSDL. These typically inc
|
|
|
520
591
|
|
|
521
592
|
## Future Improvements (Stay tuned and star ⭐ this repo)
|
|
522
593
|
|
|
523
|
-
- [x] Add debugging mode with raw xml on SOAP requests and responses
|
|
524
|
-
- [
|
|
525
|
-
- [ ] Add asynchronous (async/await) support for non-blocking ONVIF operations and concurrent device communication.
|
|
594
|
+
- [x] ~~Add debugging mode with raw xml on SOAP requests and responses.~~ ([c258162](https://github.com/nirsimetri/onvif-python/commit/c258162))
|
|
595
|
+
- [x] ~~Add functionality for `ONVIFClient` to accept a custom `wsdl_dir` service.~~ ([65f2570](https://github.com/nirsimetri/onvif-python/commit/65f257092e4c9daa23dd0d00825ed38a45d23b70))
|
|
526
596
|
- [ ] Add `ONVIF CLI` program to interact directly with ONVIF devices via terminal.
|
|
597
|
+
- [ ] Add asynchronous (async/await) support for non-blocking ONVIF operations and concurrent device communication.
|
|
527
598
|
- [ ] Implement structured data models for ONVIF Schemas using [xsdata](https://github.com/tefra/xsdata).
|
|
528
599
|
- [ ] Integrate [xmltodict](https://github.com/martinblech/xmltodict) for simplified XML parsing and conversion.
|
|
529
600
|
- [ ] Enhance documentation with API references and diagrams (not from [AI Wiki](https://deepwiki.com/nirsimetri/onvif-python)).
|