onvif-python 0.1.7__tar.gz → 0.1.8__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.1.7/onvif_python.egg-info → onvif_python-0.1.8}/PKG-INFO +21 -9
- {onvif_python-0.1.7 → onvif_python-0.1.8}/README.md +14 -6
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/cli/interactive.py +2 -2
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/cli/main.py +2 -2
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/cli/utils.py +4 -2
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/client.py +101 -21
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/operator.py +50 -0
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/services/accesscontrol.py +2 -2
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/services/accessrules.py +2 -2
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/services/actionengine.py +2 -2
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/services/analytics/analytics.py +2 -2
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/services/analytics/ruleengine.py +2 -2
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/services/analyticsdevice.py +2 -2
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/services/appmgmt.py +2 -2
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/services/authenticationbehavior.py +2 -2
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/services/credential.py +2 -2
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/services/deviceio.py +4 -4
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/services/devicemgmt.py +4 -4
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/services/display.py +2 -2
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/services/doorcontrol.py +2 -2
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/services/events/events.py +2 -2
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/services/events/notification.py +2 -2
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/services/events/pullpoint.py +2 -2
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/services/events/subscription.py +2 -2
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/services/imaging.py +2 -2
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/services/media.py +2 -2
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/services/media2.py +2 -2
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/services/provisioning.py +2 -2
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/services/ptz.py +2 -2
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/services/receiver.py +2 -2
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/services/recording.py +2 -2
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/services/replay.py +2 -2
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/services/schedule.py +2 -2
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/services/search.py +2 -2
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/services/security/advancedsecurity.py +2 -2
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/services/security/authorizationserver.py +2 -2
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/services/security/dot1x.py +2 -2
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/services/security/jwt.py +2 -2
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/services/security/keystore.py +2 -2
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/services/security/mediasigning.py +2 -2
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/services/security/tlsserver.py +2 -2
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/services/thermal.py +2 -2
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/services/uplink.py +2 -2
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/utils/__init__.py +2 -0
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/utils/discovery.py +25 -6
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/utils/error_handlers.py +31 -4
- onvif_python-0.1.8/onvif/utils/exceptions.py +163 -0
- onvif_python-0.1.8/onvif/utils/service.py +108 -0
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/utils/wsdl.py +144 -16
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/utils/xml_capture.py +63 -15
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/utils/zeep.py +144 -20
- {onvif_python-0.1.7 → onvif_python-0.1.8/onvif_python.egg-info}/PKG-INFO +21 -9
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif_python.egg-info/SOURCES.txt +1 -0
- {onvif_python-0.1.7 → onvif_python-0.1.8}/pyproject.toml +7 -3
- {onvif_python-0.1.7 → onvif_python-0.1.8}/tests/test_client.py +3 -1
- onvif_python-0.1.7/onvif/utils/exceptions.py +0 -91
- {onvif_python-0.1.7 → onvif_python-0.1.8}/LICENSE.md +0 -0
- {onvif_python-0.1.7 → onvif_python-0.1.8}/MANIFEST.in +0 -0
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/__init__.py +0 -0
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/cli/__init__.py +0 -0
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/cli/__main__.py +0 -0
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/services/__init__.py +0 -0
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/wsdl/ver10/accesscontrol/wsdl/index.html +0 -0
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/wsdl/ver10/accessrules/wsdl/accessrules.wsdl +0 -0
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/wsdl/ver10/accessrules/wsdl/index.html +0 -0
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/wsdl/ver10/actionengine.wsdl +0 -0
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/wsdl/ver10/advancedsecurity/wsdl/advancedsecurity.wsdl +0 -0
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/wsdl/ver10/advancedsecurity/wsdl/index.html +0 -0
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/wsdl/ver10/analyticsdevice.wsdl +0 -0
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/wsdl/ver10/appmgmt/wsdl/appmgmt.wsdl +0 -0
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/wsdl/ver10/appmgmt/wsdl/index.html +0 -0
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/wsdl/ver10/authenticationbehavior/wsdl/authenticationbehavior.wsdl +0 -0
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/wsdl/ver10/authenticationbehavior/wsdl/index.html +0 -0
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/wsdl/ver10/credential/wsdl/credential.wsdl +0 -0
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/wsdl/ver10/credential/wsdl/index.html +0 -0
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/wsdl/ver10/device/wsdl/devicemgmt.wsdl +0 -0
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/wsdl/ver10/deviceio.wsdl +0 -0
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/wsdl/ver10/display/display.wsdl +0 -0
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/wsdl/ver10/display/wsdl/index.htm +0 -0
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/wsdl/ver10/display.wsdl +0 -0
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/wsdl/ver10/doorcontrol/wsdl/index.html +0 -0
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/wsdl/ver10/events/wsdl/bw-2-vs-mod.wsdl +0 -0
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/wsdl/ver10/events/wsdl/event-vs.wsdl +0 -0
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/wsdl/ver10/events/wsdl/event.wsdl +0 -0
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/wsdl/ver10/events/wsdl/index.html +0 -0
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/wsdl/ver10/federatedsearch.wsdl +0 -0
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/wsdl/ver10/media/wsdl/media.wsdl +0 -0
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/wsdl/ver10/pacs/accesscontrol.wsdl +0 -0
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/wsdl/ver10/pacs/doorcontrol.wsdl +0 -0
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/wsdl/ver10/pacs/types.xsd +0 -0
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/wsdl/ver10/provisioning/wsdl/provisioning.wsdl +0 -0
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/wsdl/ver10/receiver.wsdl +0 -0
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/wsdl/ver10/recording.wsdl +0 -0
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/wsdl/ver10/replay.wsdl +0 -0
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/wsdl/ver10/schedule/wsdl/index.html +0 -0
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/wsdl/ver10/schedule/wsdl/schedule.wsdl +0 -0
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/wsdl/ver10/schema/common.xsd +0 -0
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/wsdl/ver10/schema/metadatastream.xsd +0 -0
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/wsdl/ver10/schema/onvif.xsd +0 -0
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/wsdl/ver10/search.wsdl +0 -0
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/wsdl/ver10/thermal/wsdl/index.html +0 -0
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/wsdl/ver10/thermal/wsdl/thermal.wsdl +0 -0
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/wsdl/ver10/topics/topicns.xml +0 -0
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/wsdl/ver10/uplink/wsdl/index.html +0 -0
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/wsdl/ver10/uplink/wsdl/uplink.wsdl +0 -0
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/wsdl/ver20/analytics/humanbody.xsd +0 -0
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/wsdl/ver20/analytics/humanface.xsd +0 -0
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/wsdl/ver20/analytics/index.html +0 -0
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/wsdl/ver20/analytics/radiometry.xsd +0 -0
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/wsdl/ver20/analytics/rules.xsd +0 -0
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/wsdl/ver20/analytics/wsdl/analytics.wsdl +0 -0
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/wsdl/ver20/analytics/wsdl/index.html +0 -0
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/wsdl/ver20/imaging/wsdl/imaging.wsdl +0 -0
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/wsdl/ver20/media/wsdl/index.html +0 -0
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/wsdl/ver20/media/wsdl/media.wsdl +0 -0
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/wsdl/ver20/ptz/wsdl/ptz.wsdl +0 -0
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/wsdl/ver20/util/federated_search_documentation.html +0 -0
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/wsdl/ver20/util/fedsearch-docu-viewer.xsl +0 -0
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/wsdl/ver20/util/onvif-wsdl-viewer.xsl +0 -0
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif/wsdl/ver20/util/operationIndex.html +0 -0
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif_python.egg-info/dependency_links.txt +0 -0
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif_python.egg-info/entry_points.txt +0 -0
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif_python.egg-info/requires.txt +0 -0
- {onvif_python-0.1.7 → onvif_python-0.1.8}/onvif_python.egg-info/top_level.txt +0 -0
- {onvif_python-0.1.7 → onvif_python-0.1.8}/setup.cfg +0 -0
- {onvif_python-0.1.7 → onvif_python-0.1.8}/setup.py +0 -0
- {onvif_python-0.1.7 → onvif_python-0.1.8}/tests/test_core.py +0 -0
- {onvif_python-0.1.7 → onvif_python-0.1.8}/tests/test_error_handlers.py +0 -0
- {onvif_python-0.1.7 → onvif_python-0.1.8}/tests/test_exceptions.py +0 -0
- {onvif_python-0.1.7 → onvif_python-0.1.8}/tests/test_wsdl_map.py +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: onvif-python
|
|
3
|
-
Version: 0.1.
|
|
4
|
-
Summary: A
|
|
3
|
+
Version: 0.1.8
|
|
4
|
+
Summary: A modern Python library for ONVIF-compliant devices
|
|
5
5
|
Author-email: Nirsimetri Technologies® <open@nirsimetri.com>
|
|
6
6
|
Maintainer: Kaburagi
|
|
7
7
|
License-Expression: MIT
|
|
@@ -11,8 +11,12 @@ Project-URL: Changelog, https://github.com/nirsimetri/onvif-python/releases
|
|
|
11
11
|
Keywords: onvif,Camera,onvif-python,ip-camera,cctv,soap,surveillance,cctv cameras,soap-client,onvif-client,onvif-library,onvif-specifications
|
|
12
12
|
Classifier: Development Status :: 5 - Production/Stable
|
|
13
13
|
Classifier: Environment :: Console
|
|
14
|
-
Classifier: Programming Language :: Python :: 3
|
|
15
14
|
Classifier: Programming Language :: Python :: 3.9
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
16
20
|
Classifier: Operating System :: OS Independent
|
|
17
21
|
Classifier: Intended Audience :: Developers
|
|
18
22
|
Classifier: Intended Audience :: Information Technology
|
|
@@ -37,15 +41,23 @@ Requires-Dist: black; extra == "dev"
|
|
|
37
41
|
Requires-Dist: flake8; extra == "dev"
|
|
38
42
|
Dynamic: license-file
|
|
39
43
|
|
|
40
|
-
|
|
44
|
+
<h1 align="center">ONVIF Python</h1>
|
|
41
45
|
|
|
42
|
-
|
|
46
|
+
<div align="center">
|
|
47
|
+
|
|
48
|
+
[](https://app.codacy.com/gh/nirsimetri/onvif-python/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade)
|
|
43
49
|
[](https://deepwiki.com/nirsimetri/onvif-python)
|
|
44
|
-
[](https://pypi.org/project/onvif-python/)
|
|
45
51
|
[](https://clickpy.clickhouse.com/dashboard/onvif-python)
|
|
46
52
|
<br>
|
|
47
53
|
[](https://github.com/nirsimetri/onvif-python/actions/workflows/python-app.yml)
|
|
48
54
|
[](https://github.com/nirsimetri/onvif-python/actions/workflows/python-publish.yml)
|
|
55
|
+
</div>
|
|
56
|
+
|
|
57
|
+
<h1 align="center">
|
|
58
|
+
<img src="https://raw.githubusercontent.com/nirsimetri/onvif-python/refs/heads/main/assets/carbon_onvif.png" alt="onvif" width="700px">
|
|
59
|
+
<br>
|
|
60
|
+
</h1>
|
|
49
61
|
|
|
50
62
|
**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.
|
|
51
63
|
|
|
@@ -187,7 +199,7 @@ Explore more advanced usage and service-specific operations in the [`examples/`]
|
|
|
187
199
|
## ONVIF CLI
|
|
188
200
|
|
|
189
201
|
> [!NOTE]
|
|
190
|
-
> The CLI is automatically installed when you install the `onvif-python` see [Installation](#installation). This feature has been available since `onvif-python` version [
|
|
202
|
+
> The CLI is automatically installed when you install the `onvif-python` see [Installation](#installation). This feature has been available since `onvif-python` version [`>=0.1.1`](https://github.com/nirsimetri/onvif-python/releases/tag/v0.1.1).
|
|
191
203
|
|
|
192
204
|

|
|
193
205
|

|
|
@@ -242,7 +254,7 @@ usage: onvif [-h] [--host HOST] [--port PORT] [--username USERNAME] [--password
|
|
|
242
254
|
[--health-check-interval HEALTH_CHECK_INTERVAL] [--version]
|
|
243
255
|
[service] [method] [params ...]
|
|
244
256
|
|
|
245
|
-
ONVIF Terminal Client — v0.1.
|
|
257
|
+
ONVIF Terminal Client — v0.1.8
|
|
246
258
|
https://github.com/nirsimetri/onvif-python
|
|
247
259
|
|
|
248
260
|
positional arguments:
|
|
@@ -306,7 +318,7 @@ Examples:
|
|
|
306
318
|
<summary><b>2. Interactive Shell</b></summary>
|
|
307
319
|
|
|
308
320
|
```bash
|
|
309
|
-
ONVIF Interactive Shell — v0.1.
|
|
321
|
+
ONVIF Interactive Shell — v0.1.8
|
|
310
322
|
https://github.com/nirsimetri/onvif-python
|
|
311
323
|
|
|
312
324
|
Basic Commands:
|
|
@@ -1,12 +1,20 @@
|
|
|
1
|
-
|
|
1
|
+
<h1 align="center">ONVIF Python</h1>
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
<div align="center">
|
|
4
|
+
|
|
5
|
+
[](https://app.codacy.com/gh/nirsimetri/onvif-python/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade)
|
|
4
6
|
[](https://deepwiki.com/nirsimetri/onvif-python)
|
|
5
|
-
[](https://pypi.org/project/onvif-python/)
|
|
6
8
|
[](https://clickpy.clickhouse.com/dashboard/onvif-python)
|
|
7
9
|
<br>
|
|
8
10
|
[](https://github.com/nirsimetri/onvif-python/actions/workflows/python-app.yml)
|
|
9
11
|
[](https://github.com/nirsimetri/onvif-python/actions/workflows/python-publish.yml)
|
|
12
|
+
</div>
|
|
13
|
+
|
|
14
|
+
<h1 align="center">
|
|
15
|
+
<img src="https://raw.githubusercontent.com/nirsimetri/onvif-python/refs/heads/main/assets/carbon_onvif.png" alt="onvif" width="700px">
|
|
16
|
+
<br>
|
|
17
|
+
</h1>
|
|
10
18
|
|
|
11
19
|
**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.
|
|
12
20
|
|
|
@@ -148,7 +156,7 @@ Explore more advanced usage and service-specific operations in the [`examples/`]
|
|
|
148
156
|
## ONVIF CLI
|
|
149
157
|
|
|
150
158
|
> [!NOTE]
|
|
151
|
-
> The CLI is automatically installed when you install the `onvif-python` see [Installation](#installation). This feature has been available since `onvif-python` version [
|
|
159
|
+
> The CLI is automatically installed when you install the `onvif-python` see [Installation](#installation). This feature has been available since `onvif-python` version [`>=0.1.1`](https://github.com/nirsimetri/onvif-python/releases/tag/v0.1.1).
|
|
152
160
|
|
|
153
161
|

|
|
154
162
|

|
|
@@ -203,7 +211,7 @@ usage: onvif [-h] [--host HOST] [--port PORT] [--username USERNAME] [--password
|
|
|
203
211
|
[--health-check-interval HEALTH_CHECK_INTERVAL] [--version]
|
|
204
212
|
[service] [method] [params ...]
|
|
205
213
|
|
|
206
|
-
ONVIF Terminal Client — v0.1.
|
|
214
|
+
ONVIF Terminal Client — v0.1.8
|
|
207
215
|
https://github.com/nirsimetri/onvif-python
|
|
208
216
|
|
|
209
217
|
positional arguments:
|
|
@@ -267,7 +275,7 @@ Examples:
|
|
|
267
275
|
<summary><b>2. Interactive Shell</b></summary>
|
|
268
276
|
|
|
269
277
|
```bash
|
|
270
|
-
ONVIF Interactive Shell — v0.1.
|
|
278
|
+
ONVIF Interactive Shell — v0.1.8
|
|
271
279
|
https://github.com/nirsimetri/onvif-python
|
|
272
280
|
|
|
273
281
|
Basic Commands:
|
|
@@ -191,7 +191,7 @@ class InteractiveShell(cmd.Cmd):
|
|
|
191
191
|
" / __ \\/ | / / | / / _/ ____/",
|
|
192
192
|
" / / / / |/ /| | / // // /_ ",
|
|
193
193
|
"/ /_/ / /| / | |/ // // __/ ",
|
|
194
|
-
"\\____/_/ |_/ |___/___/_/ v0.1.
|
|
194
|
+
"\\____/_/ |_/ |___/___/_/ v0.1.8",
|
|
195
195
|
" ",
|
|
196
196
|
]
|
|
197
197
|
|
|
@@ -1385,7 +1385,7 @@ class InteractiveShell(cmd.Cmd):
|
|
|
1385
1385
|
super().do_help(line)
|
|
1386
1386
|
else:
|
|
1387
1387
|
help_text = f"""
|
|
1388
|
-
{colorize('ONVIF Interactive Shell — v0.1.
|
|
1388
|
+
{colorize('ONVIF Interactive Shell — v0.1.8', 'cyan')}\n{colorize('https://github.com/nirsimetri/onvif-python', 'white')}
|
|
1389
1389
|
|
|
1390
1390
|
{colorize('Basic Commands:', 'yellow')}
|
|
1391
1391
|
capabilities, caps - Show device capabilities
|
|
@@ -17,7 +17,7 @@ def create_parser():
|
|
|
17
17
|
"""Create argument parser for ONVIF CLI"""
|
|
18
18
|
parser = argparse.ArgumentParser(
|
|
19
19
|
prog="onvif",
|
|
20
|
-
description=f"{colorize('ONVIF Terminal Client', 'yellow')} — v0.1.
|
|
20
|
+
description=f"{colorize('ONVIF Terminal Client', 'yellow')} — v0.1.8\nhttps://github.com/nirsimetri/onvif-python",
|
|
21
21
|
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
22
22
|
epilog=f"""
|
|
23
23
|
Examples:
|
|
@@ -149,7 +149,7 @@ def main():
|
|
|
149
149
|
|
|
150
150
|
# Show ONVIF CLI version
|
|
151
151
|
if args.version:
|
|
152
|
-
print(colorize("0.1.
|
|
152
|
+
print(colorize("0.1.8", "yellow"))
|
|
153
153
|
sys.exit(0)
|
|
154
154
|
|
|
155
155
|
# Validate arguments early (before discovery)
|
|
@@ -317,7 +317,8 @@ def get_method_documentation(service_obj, method_name: str) -> Optional[Dict[str
|
|
|
317
317
|
doc_text = colorize("No description available.", "reset")
|
|
318
318
|
|
|
319
319
|
# 2. Get parameters from Python method signature using inspect
|
|
320
|
-
|
|
320
|
+
# Use object.__getattribute__ to bypass ONVIFService wrapper and get original method
|
|
321
|
+
method = object.__getattribute__(service_obj, method_name)
|
|
321
322
|
sig = inspect.signature(method)
|
|
322
323
|
for param in sig.parameters.values():
|
|
323
324
|
if param.name != "self":
|
|
@@ -331,7 +332,8 @@ def get_method_documentation(service_obj, method_name: str) -> Optional[Dict[str
|
|
|
331
332
|
except (etree.ParseError, FileNotFoundError, AttributeError, ValueError):
|
|
332
333
|
# Fallback in case of any error, still try to get params
|
|
333
334
|
try:
|
|
334
|
-
|
|
335
|
+
# Use object.__getattribute__ to bypass ONVIFService wrapper and get original method
|
|
336
|
+
method = object.__getattribute__(service_obj, method_name)
|
|
335
337
|
sig = inspect.signature(method)
|
|
336
338
|
for param in sig.parameters.values():
|
|
337
339
|
if param.name != "self":
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# onvif/client.py
|
|
2
2
|
|
|
3
3
|
from urllib.parse import urlparse, urlunparse
|
|
4
|
+
from functools import wraps
|
|
4
5
|
|
|
5
6
|
from .services import (
|
|
6
7
|
Device,
|
|
@@ -41,10 +42,56 @@ from .services import (
|
|
|
41
42
|
MediaSigning,
|
|
42
43
|
)
|
|
43
44
|
from .operator import CacheMode
|
|
44
|
-
from .utils import ONVIFWSDL, ZeepPatcher, XMLCapturePlugin
|
|
45
|
+
from .utils import ONVIFWSDL, ZeepPatcher, XMLCapturePlugin, ONVIFOperationException
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def service(func):
|
|
49
|
+
"""Decorator to wrap service accessor methods with ONVIFOperationException handling.
|
|
50
|
+
|
|
51
|
+
This decorator catches any exception raised during service initialization and
|
|
52
|
+
wraps it in ONVIFOperationException for consistent error handling across all
|
|
53
|
+
ONVIF client service accessors.
|
|
54
|
+
|
|
55
|
+
Args:
|
|
56
|
+
func: Service accessor method to wrap
|
|
57
|
+
|
|
58
|
+
Returns:
|
|
59
|
+
Wrapped function that handles exceptions
|
|
60
|
+
|
|
61
|
+
Raises:
|
|
62
|
+
ONVIFOperationException: If service initialization fails
|
|
63
|
+
"""
|
|
64
|
+
|
|
65
|
+
@wraps(func)
|
|
66
|
+
def wrapper(self, *args, **kwargs):
|
|
67
|
+
try:
|
|
68
|
+
return func(self, *args, **kwargs)
|
|
69
|
+
except ONVIFOperationException:
|
|
70
|
+
# Re-raise ONVIFOperationException as-is to avoid double-wrapping
|
|
71
|
+
raise
|
|
72
|
+
except Exception as e:
|
|
73
|
+
# Wrap any other exception in ONVIFOperationException
|
|
74
|
+
raise ONVIFOperationException(func.__name__, e)
|
|
75
|
+
|
|
76
|
+
return wrapper
|
|
45
77
|
|
|
46
78
|
|
|
47
79
|
class ONVIFClient:
|
|
80
|
+
"""ONVIF Client for communicating with ONVIF-compliant devices.
|
|
81
|
+
|
|
82
|
+
This is the main class for interacting with ONVIF devices. It provides access to
|
|
83
|
+
all ONVIF services including Device Management, Media, PTZ, Events, Analytics, and more.
|
|
84
|
+
|
|
85
|
+
The client automatically discovers available services on the device using GetServices
|
|
86
|
+
or GetCapabilities, and provides lazy initialization for service endpoints.
|
|
87
|
+
|
|
88
|
+
Attributes:
|
|
89
|
+
services: List of available services from GetServices response
|
|
90
|
+
capabilities: Device capabilities from GetCapabilities response (fallback)
|
|
91
|
+
xml_plugin: XML capture plugin for debugging (if capture_xml=True)
|
|
92
|
+
wsdl_dir: Custom WSDL directory path (if provided)
|
|
93
|
+
"""
|
|
94
|
+
|
|
48
95
|
def __init__(
|
|
49
96
|
self,
|
|
50
97
|
host: str,
|
|
@@ -90,7 +137,8 @@ class ONVIFClient:
|
|
|
90
137
|
}
|
|
91
138
|
|
|
92
139
|
# Device Management (Core) service is always available
|
|
93
|
-
self._devicemgmt =
|
|
140
|
+
self._devicemgmt = None
|
|
141
|
+
self._devicemgmt = self.devicemgmt()
|
|
94
142
|
|
|
95
143
|
# Try to retrieve device services and create namespace -> XAddr mapping
|
|
96
144
|
self.services = None
|
|
@@ -280,11 +328,15 @@ class ONVIFClient:
|
|
|
280
328
|
|
|
281
329
|
# Core (Device Management)
|
|
282
330
|
|
|
331
|
+
@service
|
|
283
332
|
def devicemgmt(self):
|
|
333
|
+
if self._devicemgmt is None:
|
|
334
|
+
self._devicemgmt = Device(**self.common_args)
|
|
284
335
|
return self._devicemgmt
|
|
285
336
|
|
|
286
337
|
# Core (Events)
|
|
287
338
|
|
|
339
|
+
@service
|
|
288
340
|
def events(self):
|
|
289
341
|
if self._events is None:
|
|
290
342
|
self._events = Events(
|
|
@@ -292,18 +344,16 @@ class ONVIFClient:
|
|
|
292
344
|
)
|
|
293
345
|
return self._events
|
|
294
346
|
|
|
347
|
+
@service
|
|
295
348
|
def pullpoint(self, SubscriptionRef):
|
|
296
349
|
xaddr = None
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
xaddr = addr_obj._value_1
|
|
350
|
+
addr_obj = SubscriptionRef["SubscriptionReference"]["Address"]
|
|
351
|
+
if isinstance(addr_obj, dict) and "_value_1" in addr_obj:
|
|
352
|
+
xaddr = addr_obj["_value_1"]
|
|
353
|
+
elif hasattr(addr_obj, "_value_1"):
|
|
354
|
+
xaddr = addr_obj._value_1
|
|
303
355
|
|
|
304
|
-
|
|
305
|
-
except Exception:
|
|
306
|
-
pass
|
|
356
|
+
xaddr = self._rewrite_xaddr_if_needed(xaddr)
|
|
307
357
|
|
|
308
358
|
if not xaddr:
|
|
309
359
|
raise RuntimeError(
|
|
@@ -315,6 +365,7 @@ class ONVIFClient:
|
|
|
315
365
|
|
|
316
366
|
return self._pullpoints[xaddr]
|
|
317
367
|
|
|
368
|
+
@service
|
|
318
369
|
def notification(self):
|
|
319
370
|
if self._notification is None:
|
|
320
371
|
self._notification = Notification(
|
|
@@ -322,18 +373,16 @@ class ONVIFClient:
|
|
|
322
373
|
)
|
|
323
374
|
return self._notification
|
|
324
375
|
|
|
376
|
+
@service
|
|
325
377
|
def subscription(self, SubscriptionRef):
|
|
326
378
|
xaddr = None
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
xaddr = addr_obj._value_1
|
|
379
|
+
addr_obj = SubscriptionRef["SubscriptionReference"]["Address"]
|
|
380
|
+
if isinstance(addr_obj, dict) and "_value_1" in addr_obj:
|
|
381
|
+
xaddr = addr_obj["_value_1"]
|
|
382
|
+
elif hasattr(addr_obj, "_value_1"):
|
|
383
|
+
xaddr = addr_obj._value_1
|
|
333
384
|
|
|
334
|
-
|
|
335
|
-
except Exception:
|
|
336
|
-
pass
|
|
385
|
+
xaddr = self._rewrite_xaddr_if_needed(xaddr)
|
|
337
386
|
|
|
338
387
|
if not xaddr:
|
|
339
388
|
raise RuntimeError(
|
|
@@ -347,6 +396,7 @@ class ONVIFClient:
|
|
|
347
396
|
|
|
348
397
|
# Imaging
|
|
349
398
|
|
|
399
|
+
@service
|
|
350
400
|
def imaging(self):
|
|
351
401
|
if self._imaging is None:
|
|
352
402
|
self._imaging = Imaging(
|
|
@@ -356,6 +406,7 @@ class ONVIFClient:
|
|
|
356
406
|
|
|
357
407
|
# Media
|
|
358
408
|
|
|
409
|
+
@service
|
|
359
410
|
def media(self):
|
|
360
411
|
if self._media is None:
|
|
361
412
|
self._media = Media(
|
|
@@ -363,6 +414,7 @@ class ONVIFClient:
|
|
|
363
414
|
)
|
|
364
415
|
return self._media
|
|
365
416
|
|
|
417
|
+
@service
|
|
366
418
|
def media2(self):
|
|
367
419
|
if self._media2 is None:
|
|
368
420
|
self._media2 = Media2(
|
|
@@ -372,6 +424,7 @@ class ONVIFClient:
|
|
|
372
424
|
|
|
373
425
|
# PTZ
|
|
374
426
|
|
|
427
|
+
@service
|
|
375
428
|
def ptz(self):
|
|
376
429
|
if self._ptz is None:
|
|
377
430
|
self._ptz = PTZ(xaddr=self._get_xaddr("ptz", "PTZ"), **self.common_args)
|
|
@@ -379,6 +432,7 @@ class ONVIFClient:
|
|
|
379
432
|
|
|
380
433
|
# DeviceIO
|
|
381
434
|
|
|
435
|
+
@service
|
|
382
436
|
def deviceio(self):
|
|
383
437
|
if self._deviceio is None:
|
|
384
438
|
self._deviceio = DeviceIO(
|
|
@@ -388,6 +442,7 @@ class ONVIFClient:
|
|
|
388
442
|
|
|
389
443
|
# Display
|
|
390
444
|
|
|
445
|
+
@service
|
|
391
446
|
def display(self):
|
|
392
447
|
if self._display is None:
|
|
393
448
|
self._display = Display(
|
|
@@ -397,6 +452,7 @@ class ONVIFClient:
|
|
|
397
452
|
|
|
398
453
|
# Analytics
|
|
399
454
|
|
|
455
|
+
@service
|
|
400
456
|
def analytics(self):
|
|
401
457
|
if self._analytics is None:
|
|
402
458
|
self._analytics = Analytics(
|
|
@@ -404,6 +460,7 @@ class ONVIFClient:
|
|
|
404
460
|
)
|
|
405
461
|
return self._analytics
|
|
406
462
|
|
|
463
|
+
@service
|
|
407
464
|
def ruleengine(self):
|
|
408
465
|
if self._ruleengine is None:
|
|
409
466
|
self._ruleengine = RuleEngine(
|
|
@@ -411,6 +468,7 @@ class ONVIFClient:
|
|
|
411
468
|
)
|
|
412
469
|
return self._ruleengine
|
|
413
470
|
|
|
471
|
+
@service
|
|
414
472
|
def analyticsdevice(self):
|
|
415
473
|
if self._analyticsdevice is None:
|
|
416
474
|
self._analyticsdevice = AnalyticsDevice(
|
|
@@ -421,6 +479,7 @@ class ONVIFClient:
|
|
|
421
479
|
|
|
422
480
|
# PACS
|
|
423
481
|
|
|
482
|
+
@service
|
|
424
483
|
def accesscontrol(self):
|
|
425
484
|
if self._accesscontrol is None:
|
|
426
485
|
self._accesscontrol = AccessControl(
|
|
@@ -429,6 +488,7 @@ class ONVIFClient:
|
|
|
429
488
|
)
|
|
430
489
|
return self._accesscontrol
|
|
431
490
|
|
|
491
|
+
@service
|
|
432
492
|
def doorcontrol(self):
|
|
433
493
|
if self._doorcontrol is None:
|
|
434
494
|
self._doorcontrol = DoorControl(
|
|
@@ -438,6 +498,7 @@ class ONVIFClient:
|
|
|
438
498
|
|
|
439
499
|
# AccessRules
|
|
440
500
|
|
|
501
|
+
@service
|
|
441
502
|
def accessrules(self):
|
|
442
503
|
if self._accessrules is None:
|
|
443
504
|
self._accessrules = AccessRules(
|
|
@@ -447,6 +508,7 @@ class ONVIFClient:
|
|
|
447
508
|
|
|
448
509
|
# ActionEngine
|
|
449
510
|
|
|
511
|
+
@service
|
|
450
512
|
def actionengine(self):
|
|
451
513
|
if self._actionengine is None:
|
|
452
514
|
self._actionengine = ActionEngine(
|
|
@@ -457,6 +519,7 @@ class ONVIFClient:
|
|
|
457
519
|
|
|
458
520
|
# AppManagement
|
|
459
521
|
|
|
522
|
+
@service
|
|
460
523
|
def appmanagement(self):
|
|
461
524
|
if self._appmanagement is None:
|
|
462
525
|
self._appmanagement = AppManagement(
|
|
@@ -467,6 +530,7 @@ class ONVIFClient:
|
|
|
467
530
|
|
|
468
531
|
# AuthenticationBehavior
|
|
469
532
|
|
|
533
|
+
@service
|
|
470
534
|
def authenticationbehavior(self):
|
|
471
535
|
if self._authenticationbehavior is None:
|
|
472
536
|
self._authenticationbehavior = AuthenticationBehavior(
|
|
@@ -479,6 +543,7 @@ class ONVIFClient:
|
|
|
479
543
|
|
|
480
544
|
# Credential
|
|
481
545
|
|
|
546
|
+
@service
|
|
482
547
|
def credential(self):
|
|
483
548
|
if self._credential is None:
|
|
484
549
|
self._credential = Credential(
|
|
@@ -489,6 +554,7 @@ class ONVIFClient:
|
|
|
489
554
|
|
|
490
555
|
# Recording
|
|
491
556
|
|
|
557
|
+
@service
|
|
492
558
|
def recording(self):
|
|
493
559
|
if self._recording is None:
|
|
494
560
|
self._recording = Recording(
|
|
@@ -499,6 +565,7 @@ class ONVIFClient:
|
|
|
499
565
|
|
|
500
566
|
# Replay
|
|
501
567
|
|
|
568
|
+
@service
|
|
502
569
|
def replay(self):
|
|
503
570
|
if self._replay is None:
|
|
504
571
|
self._replay = Replay(
|
|
@@ -509,6 +576,7 @@ class ONVIFClient:
|
|
|
509
576
|
|
|
510
577
|
# Provisioning
|
|
511
578
|
|
|
579
|
+
@service
|
|
512
580
|
def provisioning(self):
|
|
513
581
|
if self._provisioning is None:
|
|
514
582
|
self._provisioning = Provisioning(
|
|
@@ -519,6 +587,7 @@ class ONVIFClient:
|
|
|
519
587
|
|
|
520
588
|
# Receiver
|
|
521
589
|
|
|
590
|
+
@service
|
|
522
591
|
def receiver(self):
|
|
523
592
|
if self._receiver is None:
|
|
524
593
|
self._receiver = Receiver(
|
|
@@ -529,6 +598,7 @@ class ONVIFClient:
|
|
|
529
598
|
|
|
530
599
|
# Schedule
|
|
531
600
|
|
|
601
|
+
@service
|
|
532
602
|
def schedule(self):
|
|
533
603
|
if self._schedule is None:
|
|
534
604
|
self._schedule = Schedule(
|
|
@@ -537,8 +607,9 @@ class ONVIFClient:
|
|
|
537
607
|
)
|
|
538
608
|
return self._schedule
|
|
539
609
|
|
|
540
|
-
# Search
|
|
610
|
+
# Search Recording
|
|
541
611
|
|
|
612
|
+
@service
|
|
542
613
|
def search(self):
|
|
543
614
|
if self._search is None:
|
|
544
615
|
self._search = Search(
|
|
@@ -549,6 +620,7 @@ class ONVIFClient:
|
|
|
549
620
|
|
|
550
621
|
# Thermal
|
|
551
622
|
|
|
623
|
+
@service
|
|
552
624
|
def thermal(self):
|
|
553
625
|
if self._thermal is None:
|
|
554
626
|
self._thermal = Thermal(
|
|
@@ -559,6 +631,7 @@ class ONVIFClient:
|
|
|
559
631
|
|
|
560
632
|
# Uplink
|
|
561
633
|
|
|
634
|
+
@service
|
|
562
635
|
def uplink(self):
|
|
563
636
|
if self._uplink is None:
|
|
564
637
|
self._uplink = Uplink(
|
|
@@ -569,6 +642,7 @@ class ONVIFClient:
|
|
|
569
642
|
|
|
570
643
|
# Security - AdvancedSecurity
|
|
571
644
|
|
|
645
|
+
@service
|
|
572
646
|
def security(self):
|
|
573
647
|
if self._security is None:
|
|
574
648
|
self._security = AdvancedSecurity(
|
|
@@ -577,30 +651,35 @@ class ONVIFClient:
|
|
|
577
651
|
)
|
|
578
652
|
return self._security
|
|
579
653
|
|
|
654
|
+
@service
|
|
580
655
|
def jwt(self, xaddr):
|
|
581
656
|
if self._jwt is None:
|
|
582
657
|
xaddr = self._rewrite_xaddr_if_needed(xaddr)
|
|
583
658
|
self._jwt = JWT(xaddr=xaddr, **self.common_args)
|
|
584
659
|
return self._jwt
|
|
585
660
|
|
|
661
|
+
@service
|
|
586
662
|
def keystore(self, xaddr):
|
|
587
663
|
if self._keystore is None:
|
|
588
664
|
xaddr = self._rewrite_xaddr_if_needed(xaddr)
|
|
589
665
|
self._keystore = Keystore(xaddr=xaddr, **self.common_args)
|
|
590
666
|
return self._keystore
|
|
591
667
|
|
|
668
|
+
@service
|
|
592
669
|
def tlsserver(self, xaddr):
|
|
593
670
|
if self._tlsserver is None:
|
|
594
671
|
xaddr = self._rewrite_xaddr_if_needed(xaddr)
|
|
595
672
|
self._tlsserver = TLSServer(xaddr=xaddr, **self.common_args)
|
|
596
673
|
return self._tlsserver
|
|
597
674
|
|
|
675
|
+
@service
|
|
598
676
|
def dot1x(self, xaddr):
|
|
599
677
|
if self._dot1x is None:
|
|
600
678
|
xaddr = self._rewrite_xaddr_if_needed(xaddr)
|
|
601
679
|
self._dot1x = Dot1X(xaddr=xaddr, **self.common_args)
|
|
602
680
|
return self._dot1x
|
|
603
681
|
|
|
682
|
+
@service
|
|
604
683
|
def authorizationserver(self, xaddr):
|
|
605
684
|
if self._authorizationserver is None:
|
|
606
685
|
xaddr = self._rewrite_xaddr_if_needed(xaddr)
|
|
@@ -609,6 +688,7 @@ class ONVIFClient:
|
|
|
609
688
|
)
|
|
610
689
|
return self._authorizationserver
|
|
611
690
|
|
|
691
|
+
@service
|
|
612
692
|
def mediasigning(self, xaddr):
|
|
613
693
|
if self._mediasigning is None:
|
|
614
694
|
xaddr = self._rewrite_xaddr_if_needed(xaddr)
|
|
@@ -15,6 +15,18 @@ from .utils import ONVIFOperationException, ZeepPatcher
|
|
|
15
15
|
|
|
16
16
|
|
|
17
17
|
class CacheMode(Enum):
|
|
18
|
+
"""WSDL caching strategies for ONVIF client performance optimization.
|
|
19
|
+
|
|
20
|
+
Different caching modes provide trade-offs between performance, memory usage,
|
|
21
|
+
and disk storage. Choose based on your application's requirements.
|
|
22
|
+
|
|
23
|
+
Attributes:
|
|
24
|
+
ALL: Maximum performance with both memory and disk caching
|
|
25
|
+
DB: Disk-only caching for persistent storage
|
|
26
|
+
MEM: Memory-only caching for temporary sessions
|
|
27
|
+
NONE: No caching, always fetch fresh WSDLs
|
|
28
|
+
"""
|
|
29
|
+
|
|
18
30
|
ALL = "all" # CachingClient + SqliteCache →
|
|
19
31
|
# (+) Fast startup (WSDL/schema cached in memory + disk), great for multi-device and long-running apps
|
|
20
32
|
# (-) More complex, extra overhead on both disk and memory
|
|
@@ -37,6 +49,27 @@ class CacheMode(Enum):
|
|
|
37
49
|
|
|
38
50
|
|
|
39
51
|
class ONVIFOperator:
|
|
52
|
+
"""Low-level ONVIF service operator using Zeep SOAP client.
|
|
53
|
+
|
|
54
|
+
This class handles the actual SOAP communication with ONVIF devices. It manages
|
|
55
|
+
WSDL loading, service binding, authentication, caching, and error handling.
|
|
56
|
+
|
|
57
|
+
ONVIFOperator is typically used internally by service classes (Device, Media, PTZ, etc.)
|
|
58
|
+
and is not meant to be instantiated directly by end users. Use ONVIFClient instead.
|
|
59
|
+
|
|
60
|
+
Attributes:
|
|
61
|
+
wsdl_path (str): Path to the WSDL file
|
|
62
|
+
host (str): Device hostname or IP address
|
|
63
|
+
port (int): Device port number
|
|
64
|
+
username (str): ONVIF username
|
|
65
|
+
password (str): ONVIF password
|
|
66
|
+
timeout (int): Request timeout in seconds
|
|
67
|
+
apply_patch (bool): Whether to apply xsd:any flattening patch
|
|
68
|
+
address (str): Service endpoint URL (XAddr)
|
|
69
|
+
client: Zeep SOAP client instance
|
|
70
|
+
service: Zeep service proxy for making SOAP calls
|
|
71
|
+
"""
|
|
72
|
+
|
|
40
73
|
def __init__(
|
|
41
74
|
self,
|
|
42
75
|
wsdl_path: str,
|
|
@@ -124,6 +157,23 @@ class ONVIFOperator:
|
|
|
124
157
|
# logging.debug(f"ONVIFOperator initialized {binding} at {self.address}")
|
|
125
158
|
|
|
126
159
|
def call(self, method: str, *args, **kwargs):
|
|
160
|
+
"""Call an ONVIF service operation.
|
|
161
|
+
|
|
162
|
+
This method invokes a SOAP operation on the ONVIF device service and handles
|
|
163
|
+
errors gracefully. It automatically flattens xsd:any fields in the response
|
|
164
|
+
when apply_patch is enabled.
|
|
165
|
+
|
|
166
|
+
Args:
|
|
167
|
+
method: Name of the ONVIF operation to call (e.g., "GetDeviceInformation")
|
|
168
|
+
*args: Positional arguments to pass to the operation
|
|
169
|
+
**kwargs: Keyword arguments to pass to the operation
|
|
170
|
+
|
|
171
|
+
Returns:
|
|
172
|
+
The operation result, with xsd:any fields flattened if apply_patch=True
|
|
173
|
+
|
|
174
|
+
Raises:
|
|
175
|
+
ONVIFOperationException: If the operation fails (wraps original exception)
|
|
176
|
+
"""
|
|
127
177
|
try:
|
|
128
178
|
func = getattr(self.service, method)
|
|
129
179
|
except AttributeError as e:
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# onvif/services/accesscontrol.py
|
|
2
2
|
|
|
3
3
|
from ..operator import ONVIFOperator
|
|
4
|
-
from ..utils import ONVIFWSDL
|
|
4
|
+
from ..utils import ONVIFWSDL, ONVIFService
|
|
5
5
|
|
|
6
6
|
|
|
7
|
-
class AccessControl:
|
|
7
|
+
class AccessControl(ONVIFService):
|
|
8
8
|
def __init__(self, xaddr=None, **kwargs):
|
|
9
9
|
# References:
|
|
10
10
|
# - ONVIF Release 2.3 (May 2013) Release Notes
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# onvif/services/accessrules.py
|
|
2
2
|
|
|
3
3
|
from ..operator import ONVIFOperator
|
|
4
|
-
from ..utils import ONVIFWSDL
|
|
4
|
+
from ..utils import ONVIFWSDL, ONVIFService
|
|
5
5
|
|
|
6
6
|
|
|
7
|
-
class AccessRules:
|
|
7
|
+
class AccessRules(ONVIFService):
|
|
8
8
|
def __init__(self, xaddr=None, **kwargs):
|
|
9
9
|
# References:
|
|
10
10
|
# - ONVIF Release 2.6 (June 2015) Release Notes
|