onvif-python 0.1.4__tar.gz → 0.1.5__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.4/onvif_python.egg-info → onvif_python-0.1.5}/PKG-INFO +32 -7
- {onvif_python-0.1.4 → onvif_python-0.1.5}/README.md +31 -6
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/cli/interactive.py +105 -10
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/cli/main.py +13 -6
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/cli/utils.py +205 -51
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/client.py +4 -4
- {onvif_python-0.1.4 → onvif_python-0.1.5/onvif_python.egg-info}/PKG-INFO +32 -7
- {onvif_python-0.1.4 → onvif_python-0.1.5}/pyproject.toml +1 -1
- {onvif_python-0.1.4 → onvif_python-0.1.5}/LICENSE.md +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/MANIFEST.in +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/__init__.py +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/cli/__init__.py +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/cli/__main__.py +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/operator.py +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/services/__init__.py +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/services/accesscontrol.py +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/services/accessrules.py +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/services/actionengine.py +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/services/analytics/analytics.py +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/services/analytics/ruleengine.py +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/services/analyticsdevice.py +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/services/appmgmt.py +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/services/authenticationbehavior.py +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/services/credential.py +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/services/deviceio.py +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/services/devicemgmt.py +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/services/display.py +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/services/doorcontrol.py +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/services/events/events.py +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/services/events/notification.py +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/services/events/pullpoint.py +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/services/events/subscription.py +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/services/imaging.py +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/services/media.py +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/services/media2.py +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/services/provisioning.py +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/services/ptz.py +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/services/receiver.py +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/services/recording.py +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/services/replay.py +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/services/schedule.py +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/services/search.py +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/services/security/advancedsecurity.py +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/services/security/authorizationserver.py +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/services/security/dot1x.py +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/services/security/jwt.py +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/services/security/keystore.py +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/services/security/mediasigning.py +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/services/security/tlsserver.py +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/services/thermal.py +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/services/uplink.py +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/utils/__init__.py +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/utils/error_handlers.py +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/utils/exceptions.py +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/utils/wsdl.py +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/utils/xml_capture.py +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/utils/zeep.py +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/wsdl/ver10/accesscontrol/wsdl/index.html +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/wsdl/ver10/accessrules/wsdl/accessrules.wsdl +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/wsdl/ver10/accessrules/wsdl/index.html +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/wsdl/ver10/actionengine.wsdl +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/wsdl/ver10/advancedsecurity/wsdl/advancedsecurity.wsdl +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/wsdl/ver10/advancedsecurity/wsdl/index.html +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/wsdl/ver10/analyticsdevice.wsdl +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/wsdl/ver10/appmgmt/wsdl/appmgmt.wsdl +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/wsdl/ver10/appmgmt/wsdl/index.html +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/wsdl/ver10/authenticationbehavior/wsdl/authenticationbehavior.wsdl +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/wsdl/ver10/authenticationbehavior/wsdl/index.html +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/wsdl/ver10/credential/wsdl/credential.wsdl +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/wsdl/ver10/credential/wsdl/index.html +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/wsdl/ver10/device/wsdl/devicemgmt.wsdl +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/wsdl/ver10/deviceio.wsdl +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/wsdl/ver10/display/display.wsdl +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/wsdl/ver10/display/wsdl/index.htm +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/wsdl/ver10/display.wsdl +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/wsdl/ver10/doorcontrol/wsdl/index.html +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/wsdl/ver10/events/wsdl/bw-2-vs-mod.wsdl +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/wsdl/ver10/events/wsdl/event-vs.wsdl +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/wsdl/ver10/events/wsdl/event.wsdl +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/wsdl/ver10/events/wsdl/index.html +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/wsdl/ver10/federatedsearch.wsdl +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/wsdl/ver10/media/wsdl/media.wsdl +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/wsdl/ver10/pacs/accesscontrol.wsdl +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/wsdl/ver10/pacs/doorcontrol.wsdl +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/wsdl/ver10/pacs/types.xsd +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/wsdl/ver10/provisioning/wsdl/provisioning.wsdl +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/wsdl/ver10/receiver.wsdl +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/wsdl/ver10/recording.wsdl +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/wsdl/ver10/replay.wsdl +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/wsdl/ver10/schedule/wsdl/index.html +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/wsdl/ver10/schedule/wsdl/schedule.wsdl +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/wsdl/ver10/schema/common.xsd +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/wsdl/ver10/schema/metadatastream.xsd +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/wsdl/ver10/schema/onvif.xsd +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/wsdl/ver10/search.wsdl +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/wsdl/ver10/thermal/wsdl/index.html +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/wsdl/ver10/thermal/wsdl/thermal.wsdl +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/wsdl/ver10/topics/topicns.xml +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/wsdl/ver10/uplink/wsdl/index.html +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/wsdl/ver10/uplink/wsdl/uplink.wsdl +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/wsdl/ver20/analytics/humanbody.xsd +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/wsdl/ver20/analytics/humanface.xsd +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/wsdl/ver20/analytics/index.html +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/wsdl/ver20/analytics/radiometry.xsd +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/wsdl/ver20/analytics/rules.xsd +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/wsdl/ver20/analytics/wsdl/analytics.wsdl +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/wsdl/ver20/analytics/wsdl/index.html +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/wsdl/ver20/imaging/wsdl/imaging.wsdl +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/wsdl/ver20/media/wsdl/index.html +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/wsdl/ver20/media/wsdl/media.wsdl +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/wsdl/ver20/ptz/wsdl/ptz.wsdl +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/wsdl/ver20/util/federated_search_documentation.html +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/wsdl/ver20/util/fedsearch-docu-viewer.xsl +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/wsdl/ver20/util/onvif-wsdl-viewer.xsl +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif/wsdl/ver20/util/operationIndex.html +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif_python.egg-info/SOURCES.txt +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif_python.egg-info/dependency_links.txt +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif_python.egg-info/entry_points.txt +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif_python.egg-info/requires.txt +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/onvif_python.egg-info/top_level.txt +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/setup.cfg +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/setup.py +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/tests/test_client.py +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/tests/test_core.py +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/tests/test_error_handlers.py +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/tests/test_exceptions.py +0 -0
- {onvif_python-0.1.4 → onvif_python-0.1.5}/tests/test_wsdl_map.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: onvif-python
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.5
|
|
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
|
|
@@ -38,9 +38,9 @@ Dynamic: license-file
|
|
|
38
38
|
|
|
39
39
|
# ONVIF Python
|
|
40
40
|
|
|
41
|
-
[](https://app.codacy.com/gh/nirsimetri/onvif-python/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade)
|
|
42
42
|
[](https://deepwiki.com/nirsimetri/onvif-python)
|
|
43
|
-
[](https://pypi.org/project/onvif-python/)
|
|
44
44
|
[](https://clickpy.clickhouse.com/dashboard/onvif-python)
|
|
45
45
|
<br>
|
|
46
46
|
[](https://github.com/nirsimetri/onvif-python/actions/workflows/python-app.yml)
|
|
@@ -212,10 +212,10 @@ This library includes a powerful command-line interface (CLI) for interacting wi
|
|
|
212
212
|
|
|
213
213
|
```bash
|
|
214
214
|
usage: onvif [-h] [--host HOST] [--port PORT] [--username USERNAME] [--password PASSWORD] [--discover] [--timeout TIMEOUT] [--https] [--no-verify]
|
|
215
|
-
[--no-patch] [--interactive] [--debug] [--wsdl WSDL] [--cache {all,db,mem,none}] [--version]
|
|
215
|
+
[--no-patch] [--interactive] [--debug] [--wsdl WSDL] [--cache {all,db,mem,none}] [--health-check-interval HEALTH_CHECK_INTERVAL] [--version]
|
|
216
216
|
[service] [method] [params ...]
|
|
217
217
|
|
|
218
|
-
ONVIF Terminal Client — v0.1.
|
|
218
|
+
ONVIF Terminal Client — v0.1.5
|
|
219
219
|
https://github.com/nirsimetri/onvif-python
|
|
220
220
|
|
|
221
221
|
positional arguments:
|
|
@@ -241,6 +241,8 @@ options:
|
|
|
241
241
|
--wsdl WSDL Custom WSDL directory path
|
|
242
242
|
--cache {all,db,mem,none}
|
|
243
243
|
Caching mode for ONVIFClient (default: all). 'all': memory+disk, 'db': disk-only, 'mem': memory-only, 'none': disabled.
|
|
244
|
+
--health-check-interval HEALTH_CHECK_INTERVAL, -hci HEALTH_CHECK_INTERVAL
|
|
245
|
+
Health check interval in seconds for interactive mode (default: 10)
|
|
244
246
|
--version, -v Show ONVIF CLI version and exit
|
|
245
247
|
|
|
246
248
|
Examples:
|
|
@@ -270,7 +272,7 @@ Examples:
|
|
|
270
272
|
<summary><b>2. Interactive Shell</b></summary>
|
|
271
273
|
|
|
272
274
|
```bash
|
|
273
|
-
ONVIF Interactive Shell Commands - v0.1.
|
|
275
|
+
ONVIF Interactive Shell Commands - v0.1.5
|
|
274
276
|
https://github.com/nirsimetri/onvif-python
|
|
275
277
|
|
|
276
278
|
Basic Commands:
|
|
@@ -282,6 +284,7 @@ Basic Commands:
|
|
|
282
284
|
|
|
283
285
|
Navigation Commands:
|
|
284
286
|
<service> - Enter service mode (e.g., devicemgmt, media)
|
|
287
|
+
<service> <argument> - Enter service mode with argument (e.g. pullpoint SubscriptionRef=<value>)
|
|
285
288
|
cd <service> - Enter service mode (alias)
|
|
286
289
|
ls - List commands/services/methods in grid format
|
|
287
290
|
up - Exit current service mode (go up one level)
|
|
@@ -301,6 +304,7 @@ Method Execution:
|
|
|
301
304
|
Data Management:
|
|
302
305
|
store <name> - Store last result with a name
|
|
303
306
|
show <name> - Show stored data
|
|
307
|
+
show <name>[0] - Show element at index (for lists)
|
|
304
308
|
show <name>.attribute - Show specific attribute
|
|
305
309
|
show - List all stored data
|
|
306
310
|
rm <name> - Remove stored data by name
|
|
@@ -368,6 +372,27 @@ If you omit the username or password, you will be prompted to enter them securel
|
|
|
368
372
|
> [!IMPORTANT]
|
|
369
373
|
> You can see all the other commands available in the interactive shell by trying it out directly. The interactive shell runs periodic background health checks to detect connection loss. It uses silent TCP pings to avoid interrupting your work and will automatically exit if the device is unreachable, similar to an SSH session.
|
|
370
374
|
|
|
375
|
+
**Command Chaining with `&&`:**
|
|
376
|
+
|
|
377
|
+
The CLI supports chaining multiple commands in a single line using the `&&` operator, allowing you to execute sequential operations efficiently:
|
|
378
|
+
|
|
379
|
+
```bash
|
|
380
|
+
# Enter service and execute method in one line
|
|
381
|
+
192.168.1.17:8000 > media && GetProfiles && store profiles
|
|
382
|
+
|
|
383
|
+
# Chain multiple method calls
|
|
384
|
+
192.168.1.17:8000 > devicemgmt && GetDeviceInformation && store device_info
|
|
385
|
+
|
|
386
|
+
# Complex workflow
|
|
387
|
+
192.168.1.17:8000 > media && GetProfiles && store profiles && up && imaging && GetImagingSettings VideoSourceToken=$profiles[0].VideoSourceConfiguration.SourceToken
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
This feature is particularly useful for:
|
|
391
|
+
- Quick operations without entering service mode
|
|
392
|
+
- Scripting repetitive tasks
|
|
393
|
+
- Testing workflows
|
|
394
|
+
- Automating multi-step procedures
|
|
395
|
+
|
|
371
396
|
**2. Device Discovery (WS-Discovery)**
|
|
372
397
|
|
|
373
398
|
The CLI includes automatic ONVIF device discovery using the WS-Discovery protocol. This feature allows you to find all ONVIF-compliant devices on your local network without knowing their IP addresses beforehand.
|
|
@@ -491,7 +516,7 @@ The `ONVIFClient` class provides various configuration options to customize the
|
|
|
491
516
|
|
|
492
517
|
| Parameter | Type | Required | Default | Description |
|
|
493
518
|
|-----------|------|----------|---------|-------------|
|
|
494
|
-
| `cache` | `CacheMode` | ❌ No | `CacheMode.ALL` | WSDL caching strategy (see
|
|
519
|
+
| `cache` | `CacheMode` | ❌ No | `CacheMode.ALL` | WSDL caching strategy (see **Cache Modes** below) |
|
|
495
520
|
|
|
496
521
|
</details>
|
|
497
522
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# ONVIF Python
|
|
2
2
|
|
|
3
|
-
[](https://app.codacy.com/gh/nirsimetri/onvif-python/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade)
|
|
4
4
|
[](https://deepwiki.com/nirsimetri/onvif-python)
|
|
5
|
-
[](https://pypi.org/project/onvif-python/)
|
|
6
6
|
[](https://clickpy.clickhouse.com/dashboard/onvif-python)
|
|
7
7
|
<br>
|
|
8
8
|
[](https://github.com/nirsimetri/onvif-python/actions/workflows/python-app.yml)
|
|
@@ -174,10 +174,10 @@ This library includes a powerful command-line interface (CLI) for interacting wi
|
|
|
174
174
|
|
|
175
175
|
```bash
|
|
176
176
|
usage: onvif [-h] [--host HOST] [--port PORT] [--username USERNAME] [--password PASSWORD] [--discover] [--timeout TIMEOUT] [--https] [--no-verify]
|
|
177
|
-
[--no-patch] [--interactive] [--debug] [--wsdl WSDL] [--cache {all,db,mem,none}] [--version]
|
|
177
|
+
[--no-patch] [--interactive] [--debug] [--wsdl WSDL] [--cache {all,db,mem,none}] [--health-check-interval HEALTH_CHECK_INTERVAL] [--version]
|
|
178
178
|
[service] [method] [params ...]
|
|
179
179
|
|
|
180
|
-
ONVIF Terminal Client — v0.1.
|
|
180
|
+
ONVIF Terminal Client — v0.1.5
|
|
181
181
|
https://github.com/nirsimetri/onvif-python
|
|
182
182
|
|
|
183
183
|
positional arguments:
|
|
@@ -203,6 +203,8 @@ options:
|
|
|
203
203
|
--wsdl WSDL Custom WSDL directory path
|
|
204
204
|
--cache {all,db,mem,none}
|
|
205
205
|
Caching mode for ONVIFClient (default: all). 'all': memory+disk, 'db': disk-only, 'mem': memory-only, 'none': disabled.
|
|
206
|
+
--health-check-interval HEALTH_CHECK_INTERVAL, -hci HEALTH_CHECK_INTERVAL
|
|
207
|
+
Health check interval in seconds for interactive mode (default: 10)
|
|
206
208
|
--version, -v Show ONVIF CLI version and exit
|
|
207
209
|
|
|
208
210
|
Examples:
|
|
@@ -232,7 +234,7 @@ Examples:
|
|
|
232
234
|
<summary><b>2. Interactive Shell</b></summary>
|
|
233
235
|
|
|
234
236
|
```bash
|
|
235
|
-
ONVIF Interactive Shell Commands - v0.1.
|
|
237
|
+
ONVIF Interactive Shell Commands - v0.1.5
|
|
236
238
|
https://github.com/nirsimetri/onvif-python
|
|
237
239
|
|
|
238
240
|
Basic Commands:
|
|
@@ -244,6 +246,7 @@ Basic Commands:
|
|
|
244
246
|
|
|
245
247
|
Navigation Commands:
|
|
246
248
|
<service> - Enter service mode (e.g., devicemgmt, media)
|
|
249
|
+
<service> <argument> - Enter service mode with argument (e.g. pullpoint SubscriptionRef=<value>)
|
|
247
250
|
cd <service> - Enter service mode (alias)
|
|
248
251
|
ls - List commands/services/methods in grid format
|
|
249
252
|
up - Exit current service mode (go up one level)
|
|
@@ -263,6 +266,7 @@ Method Execution:
|
|
|
263
266
|
Data Management:
|
|
264
267
|
store <name> - Store last result with a name
|
|
265
268
|
show <name> - Show stored data
|
|
269
|
+
show <name>[0] - Show element at index (for lists)
|
|
266
270
|
show <name>.attribute - Show specific attribute
|
|
267
271
|
show - List all stored data
|
|
268
272
|
rm <name> - Remove stored data by name
|
|
@@ -330,6 +334,27 @@ If you omit the username or password, you will be prompted to enter them securel
|
|
|
330
334
|
> [!IMPORTANT]
|
|
331
335
|
> You can see all the other commands available in the interactive shell by trying it out directly. The interactive shell runs periodic background health checks to detect connection loss. It uses silent TCP pings to avoid interrupting your work and will automatically exit if the device is unreachable, similar to an SSH session.
|
|
332
336
|
|
|
337
|
+
**Command Chaining with `&&`:**
|
|
338
|
+
|
|
339
|
+
The CLI supports chaining multiple commands in a single line using the `&&` operator, allowing you to execute sequential operations efficiently:
|
|
340
|
+
|
|
341
|
+
```bash
|
|
342
|
+
# Enter service and execute method in one line
|
|
343
|
+
192.168.1.17:8000 > media && GetProfiles && store profiles
|
|
344
|
+
|
|
345
|
+
# Chain multiple method calls
|
|
346
|
+
192.168.1.17:8000 > devicemgmt && GetDeviceInformation && store device_info
|
|
347
|
+
|
|
348
|
+
# Complex workflow
|
|
349
|
+
192.168.1.17:8000 > media && GetProfiles && store profiles && up && imaging && GetImagingSettings VideoSourceToken=$profiles[0].VideoSourceConfiguration.SourceToken
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
This feature is particularly useful for:
|
|
353
|
+
- Quick operations without entering service mode
|
|
354
|
+
- Scripting repetitive tasks
|
|
355
|
+
- Testing workflows
|
|
356
|
+
- Automating multi-step procedures
|
|
357
|
+
|
|
333
358
|
**2. Device Discovery (WS-Discovery)**
|
|
334
359
|
|
|
335
360
|
The CLI includes automatic ONVIF device discovery using the WS-Discovery protocol. This feature allows you to find all ONVIF-compliant devices on your local network without knowing their IP addresses beforehand.
|
|
@@ -453,7 +478,7 @@ The `ONVIFClient` class provides various configuration options to customize the
|
|
|
453
478
|
|
|
454
479
|
| Parameter | Type | Required | Default | Description |
|
|
455
480
|
|-----------|------|----------|---------|-------------|
|
|
456
|
-
| `cache` | `CacheMode` | ❌ No | `CacheMode.ALL` | WSDL caching strategy (see
|
|
481
|
+
| `cache` | `CacheMode` | ❌ No | `CacheMode.ALL` | WSDL caching strategy (see **Cache Modes** below) |
|
|
457
482
|
|
|
458
483
|
</details>
|
|
459
484
|
|
|
@@ -18,6 +18,7 @@ from ..utils.exceptions import ONVIFOperationException
|
|
|
18
18
|
from .utils import (
|
|
19
19
|
parse_json_params,
|
|
20
20
|
get_service_methods,
|
|
21
|
+
get_service_required_args,
|
|
21
22
|
get_device_available_services,
|
|
22
23
|
colorize,
|
|
23
24
|
format_capabilities_as_services,
|
|
@@ -172,6 +173,13 @@ class InteractiveShell(cmd.Cmd):
|
|
|
172
173
|
if hasattr(args, "no_patch") and args.no_patch:
|
|
173
174
|
options_info.append(f" ZeepPatcher : {colorize('Disabled', 'red')}")
|
|
174
175
|
|
|
176
|
+
if (
|
|
177
|
+
hasattr(args, "health_check_interval") and args.health_check_interval != 10
|
|
178
|
+
): # 10 is default
|
|
179
|
+
options_info.append(
|
|
180
|
+
f" Health Check : every {colorize(f'{args.health_check_interval}s', 'yellow')}"
|
|
181
|
+
)
|
|
182
|
+
|
|
175
183
|
# Format options info
|
|
176
184
|
options_display = ""
|
|
177
185
|
if options_info:
|
|
@@ -183,7 +191,7 @@ class InteractiveShell(cmd.Cmd):
|
|
|
183
191
|
" / __ \\/ | / / | / / _/ ____/",
|
|
184
192
|
" / / / / |/ /| | / // // /_ ",
|
|
185
193
|
"/ /_/ / /| / | |/ // // __/ ",
|
|
186
|
-
"\\____/_/ |_/ |___/___/_/ v0.1.
|
|
194
|
+
"\\____/_/ |_/ |___/___/_/ v0.1.5",
|
|
187
195
|
" ",
|
|
188
196
|
]
|
|
189
197
|
|
|
@@ -223,8 +231,11 @@ class InteractiveShell(cmd.Cmd):
|
|
|
223
231
|
|
|
224
232
|
def _periodic_health_check(self):
|
|
225
233
|
"""Periodically checks device connection using TCP or TLS depending on mode."""
|
|
234
|
+
# Get health check interval from args, default to 10 seconds
|
|
235
|
+
health_check_interval = getattr(self.args, "health_check_interval", 10)
|
|
236
|
+
|
|
226
237
|
# Wait before first check to allow intro to finish
|
|
227
|
-
self._stop_health_check.wait(
|
|
238
|
+
self._stop_health_check.wait(health_check_interval)
|
|
228
239
|
|
|
229
240
|
while not self._stop_health_check.is_set():
|
|
230
241
|
sock = None
|
|
@@ -236,6 +247,7 @@ class InteractiveShell(cmd.Cmd):
|
|
|
236
247
|
# If HTTPS, perform a short TLS handshake check
|
|
237
248
|
if getattr(self.args, "https", False):
|
|
238
249
|
context = ssl.create_default_context()
|
|
250
|
+
context.minimum_version = ssl.TLSVersion.TLSv1_2
|
|
239
251
|
context.check_hostname = False
|
|
240
252
|
context.verify_mode = ssl.CERT_NONE
|
|
241
253
|
|
|
@@ -279,7 +291,7 @@ class InteractiveShell(cmd.Cmd):
|
|
|
279
291
|
sock.close()
|
|
280
292
|
|
|
281
293
|
# Wait before next check or stop signal
|
|
282
|
-
self._stop_health_check.wait(
|
|
294
|
+
self._stop_health_check.wait(health_check_interval)
|
|
283
295
|
|
|
284
296
|
def _handle_connection_error(self, e):
|
|
285
297
|
"""Handle connection errors by notifying the user and exiting."""
|
|
@@ -549,8 +561,17 @@ class InteractiveShell(cmd.Cmd):
|
|
|
549
561
|
|
|
550
562
|
def default(self, line):
|
|
551
563
|
"""Handle unknown commands"""
|
|
552
|
-
|
|
553
|
-
|
|
564
|
+
available_services = get_device_available_services(self.client)
|
|
565
|
+
|
|
566
|
+
# Check if it's a service call (with or without arguments)
|
|
567
|
+
# Extract first word to check if it's a service name
|
|
568
|
+
first_word = line.split()[0] if line.split() else line
|
|
569
|
+
|
|
570
|
+
if first_word in available_services:
|
|
571
|
+
return self.do_enter_service(line)
|
|
572
|
+
|
|
573
|
+
# Check if the whole line (without arguments) is a service
|
|
574
|
+
if line in available_services:
|
|
554
575
|
return self.do_enter_service(line)
|
|
555
576
|
|
|
556
577
|
# Check if it's a method call in service context
|
|
@@ -721,8 +742,13 @@ class InteractiveShell(cmd.Cmd):
|
|
|
721
742
|
else:
|
|
722
743
|
print(f"{colorize('Error:', 'red')} {e}")
|
|
723
744
|
|
|
724
|
-
def do_enter_service(self,
|
|
725
|
-
"""Enter service mode"""
|
|
745
|
+
def do_enter_service(self, line):
|
|
746
|
+
"""Enter service mode with optional arguments for services that require them"""
|
|
747
|
+
# Parse service name and arguments
|
|
748
|
+
parts = line.split(None, 1)
|
|
749
|
+
service_name = parts[0] if parts else ""
|
|
750
|
+
args_str = parts[1] if len(parts) > 1 else ""
|
|
751
|
+
|
|
726
752
|
available_services = get_device_available_services(self.client)
|
|
727
753
|
if service_name not in available_services:
|
|
728
754
|
print(f"{colorize('Error:', 'red')} Unknown service '{service_name}'")
|
|
@@ -731,7 +757,63 @@ class InteractiveShell(cmd.Cmd):
|
|
|
731
757
|
return
|
|
732
758
|
|
|
733
759
|
try:
|
|
734
|
-
service
|
|
760
|
+
# Check if this service requires arguments
|
|
761
|
+
required_args = get_service_required_args(service_name)
|
|
762
|
+
|
|
763
|
+
if required_args:
|
|
764
|
+
# Service requires arguments
|
|
765
|
+
if not args_str:
|
|
766
|
+
# No arguments provided, show help
|
|
767
|
+
print(
|
|
768
|
+
f"{colorize('Error:', 'red')} Service '{service_name}' requires arguments"
|
|
769
|
+
)
|
|
770
|
+
print(
|
|
771
|
+
f"{colorize('Usage:', 'yellow')} {service_name} {' '.join([f'{arg}=<value>' for arg in required_args])}"
|
|
772
|
+
)
|
|
773
|
+
print(
|
|
774
|
+
f"{colorize('Example:', 'yellow')} {service_name} {required_args[0]}=$subscription"
|
|
775
|
+
)
|
|
776
|
+
return
|
|
777
|
+
|
|
778
|
+
# Parse arguments
|
|
779
|
+
try:
|
|
780
|
+
parsed_args = parse_json_params(args_str)
|
|
781
|
+
except Exception as e:
|
|
782
|
+
print(f"{colorize('Error parsing arguments:', 'red')} {e}")
|
|
783
|
+
return
|
|
784
|
+
|
|
785
|
+
# Check if all required arguments are provided
|
|
786
|
+
missing_args = [arg for arg in required_args if arg not in parsed_args]
|
|
787
|
+
if missing_args:
|
|
788
|
+
print(
|
|
789
|
+
f"{colorize('Error:', 'red')} Missing required arguments: {', '.join(missing_args)}"
|
|
790
|
+
)
|
|
791
|
+
print(
|
|
792
|
+
f"{colorize('Usage:', 'yellow')} {service_name} {' '.join([f'{arg}=<value>' for arg in required_args])}"
|
|
793
|
+
)
|
|
794
|
+
return
|
|
795
|
+
|
|
796
|
+
# Resolve stored references in arguments
|
|
797
|
+
for arg_name in required_args:
|
|
798
|
+
arg_value = parsed_args[arg_name]
|
|
799
|
+
if isinstance(arg_value, str) and arg_value.startswith("$"):
|
|
800
|
+
# Resolve stored reference
|
|
801
|
+
reference = arg_value[1:] # Remove $ prefix
|
|
802
|
+
resolved_value = self._resolve_stored_reference(reference)
|
|
803
|
+
if resolved_value is None:
|
|
804
|
+
print(
|
|
805
|
+
f"{colorize('Error:', 'red')} Could not resolve reference '{arg_value}'"
|
|
806
|
+
)
|
|
807
|
+
return
|
|
808
|
+
parsed_args[arg_name] = resolved_value
|
|
809
|
+
|
|
810
|
+
# Call service method with arguments
|
|
811
|
+
service_method = getattr(self.client, service_name)
|
|
812
|
+
service = service_method(**parsed_args)
|
|
813
|
+
else:
|
|
814
|
+
# Service doesn't require arguments
|
|
815
|
+
service = getattr(self.client, service_name)()
|
|
816
|
+
|
|
735
817
|
self.current_service = service
|
|
736
818
|
self.current_service_name = service_name
|
|
737
819
|
self.update_prompt()
|
|
@@ -756,6 +838,10 @@ class InteractiveShell(cmd.Cmd):
|
|
|
756
838
|
|
|
757
839
|
except Exception as e:
|
|
758
840
|
print(f"{colorize('Error entering service:', 'red')} {e}")
|
|
841
|
+
if self.args.debug:
|
|
842
|
+
import traceback
|
|
843
|
+
|
|
844
|
+
traceback.print_exc()
|
|
759
845
|
|
|
760
846
|
def do_ls(self, line):
|
|
761
847
|
"""List available commands/services like TAB completion"""
|
|
@@ -843,7 +929,7 @@ class InteractiveShell(cmd.Cmd):
|
|
|
843
929
|
print(
|
|
844
930
|
f"{colorize('Error:', 'red')} You must be in a service mode to use 'type'."
|
|
845
931
|
)
|
|
846
|
-
print(f"Enter a service first (e.g., {colorize('
|
|
932
|
+
print(f"Enter a service first (e.g., {colorize('devicemgmt', 'yellow')})")
|
|
847
933
|
return
|
|
848
934
|
|
|
849
935
|
if not operation_name:
|
|
@@ -1191,6 +1277,14 @@ class InteractiveShell(cmd.Cmd):
|
|
|
1191
1277
|
if hasattr(self.args, "no_patch") and self.args.no_patch:
|
|
1192
1278
|
options_info.append(f" ZeepPatcher : {colorize('Disabled', 'red')}")
|
|
1193
1279
|
|
|
1280
|
+
if (
|
|
1281
|
+
hasattr(self.args, "health_check_interval")
|
|
1282
|
+
and self.args.health_check_interval != 10
|
|
1283
|
+
): # 10 is default
|
|
1284
|
+
options_info.append(
|
|
1285
|
+
f" Health Check : every {colorize(f'{self.args.health_check_interval}s', 'yellow')}"
|
|
1286
|
+
)
|
|
1287
|
+
|
|
1194
1288
|
# Format options info
|
|
1195
1289
|
options_display = ""
|
|
1196
1290
|
if options_info:
|
|
@@ -1300,7 +1394,7 @@ class InteractiveShell(cmd.Cmd):
|
|
|
1300
1394
|
super().do_help(line)
|
|
1301
1395
|
else:
|
|
1302
1396
|
help_text = f"""
|
|
1303
|
-
{colorize('ONVIF Interactive Shell Commands - v0.1.
|
|
1397
|
+
{colorize('ONVIF Interactive Shell Commands - v0.1.5', 'cyan')}\n{colorize('https://github.com/nirsimetri/onvif-python', 'white')}
|
|
1304
1398
|
|
|
1305
1399
|
{colorize('Basic Commands:', 'yellow')}
|
|
1306
1400
|
capabilities, caps - Show device capabilities
|
|
@@ -1311,6 +1405,7 @@ class InteractiveShell(cmd.Cmd):
|
|
|
1311
1405
|
|
|
1312
1406
|
{colorize('Navigation Commands:', 'yellow')}
|
|
1313
1407
|
<service> - Enter service mode (e.g., devicemgmt, media)
|
|
1408
|
+
<service> <argument> - Enter service mode with argument (e.g. pullpoint SubscriptionRef=<value>)
|
|
1314
1409
|
cd <service> - Enter service mode (alias)
|
|
1315
1410
|
ls - List commands/services/methods in grid format
|
|
1316
1411
|
up - Exit current service mode (go up one level)
|
|
@@ -16,7 +16,7 @@ def create_parser():
|
|
|
16
16
|
"""Create argument parser for ONVIF CLI"""
|
|
17
17
|
parser = argparse.ArgumentParser(
|
|
18
18
|
prog="onvif",
|
|
19
|
-
description=f"{colorize('ONVIF Terminal Client', 'yellow')} — v0.1.
|
|
19
|
+
description=f"{colorize('ONVIF Terminal Client', 'yellow')} — v0.1.5\nhttps://github.com/nirsimetri/onvif-python",
|
|
20
20
|
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
21
21
|
epilog=f"""
|
|
22
22
|
Examples:
|
|
@@ -93,6 +93,13 @@ Examples:
|
|
|
93
93
|
help="Caching mode for ONVIFClient (default: all). "
|
|
94
94
|
"'all': memory+disk, 'db': disk-only, 'mem': memory-only, 'none': disabled.",
|
|
95
95
|
)
|
|
96
|
+
parser.add_argument(
|
|
97
|
+
"--health-check-interval",
|
|
98
|
+
"-hci",
|
|
99
|
+
type=int,
|
|
100
|
+
default=10,
|
|
101
|
+
help="Health check interval in seconds for interactive mode (default: 10)",
|
|
102
|
+
)
|
|
96
103
|
|
|
97
104
|
# Service and method (for direct command execution)
|
|
98
105
|
parser.add_argument(
|
|
@@ -131,7 +138,7 @@ def main():
|
|
|
131
138
|
|
|
132
139
|
# Show ONVIF CLI version
|
|
133
140
|
if args.version:
|
|
134
|
-
print(colorize("0.1.
|
|
141
|
+
print(colorize("0.1.5", "yellow"))
|
|
135
142
|
sys.exit(0)
|
|
136
143
|
|
|
137
144
|
# Validate arguments early (before discovery)
|
|
@@ -151,14 +158,14 @@ def main():
|
|
|
151
158
|
devices = discover_devices(timeout=4, prefer_https=args.https)
|
|
152
159
|
|
|
153
160
|
if not devices:
|
|
154
|
-
print(
|
|
161
|
+
print(colorize("No ONVIF devices discovered. Exiting.", "red"))
|
|
155
162
|
sys.exit(1)
|
|
156
163
|
|
|
157
164
|
# Let user select a device
|
|
158
165
|
selected = select_device_interactive(devices)
|
|
159
166
|
|
|
160
167
|
if selected is None:
|
|
161
|
-
print(
|
|
168
|
+
print(colorize("Device selection cancelled.", "cyan"))
|
|
162
169
|
sys.exit(0)
|
|
163
170
|
|
|
164
171
|
# Set host, port, and HTTPS from selected device
|
|
@@ -523,10 +530,10 @@ def select_device_interactive(devices: list) -> Optional[Tuple[str, int, bool]]:
|
|
|
523
530
|
selected.get("use_https", False),
|
|
524
531
|
)
|
|
525
532
|
else:
|
|
526
|
-
print(
|
|
533
|
+
print(colorize("Invalid selection. Please try again.", "red"))
|
|
527
534
|
|
|
528
535
|
except ValueError:
|
|
529
|
-
print(
|
|
536
|
+
print(colorize("Invalid input. Please enter a number.", "red"))
|
|
530
537
|
except (EOFError, KeyboardInterrupt):
|
|
531
538
|
return None
|
|
532
539
|
|