onvif-python 0.4.0__py3-none-any.whl → 0.4.2__py3-none-any.whl
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/__init__.py +29 -29
- onvif/cli/__init__.py +5 -5
- onvif/cli/__main__.py +7 -7
- onvif/cli/helpers/__init__.py +21 -21
- onvif/cli/helpers/discovery.py +181 -156
- onvif/cli/helpers/execution.py +57 -57
- onvif/cli/helpers/files.py +191 -191
- onvif/cli/helpers/messages.py +220 -220
- onvif/cli/helpers/products.py +336 -294
- onvif/cli/helpers/wsdl_parser.py +973 -973
- onvif/cli/interactive.py +1335 -1319
- onvif/cli/main.py +352 -342
- onvif/cli/utils.py +510 -510
- onvif/client.py +969 -969
- onvif/meta.py +6 -6
- onvif/operator.py +450 -450
- onvif/services/__init__.py +79 -79
- onvif/services/accesscontrol.py +292 -292
- onvif/services/accessrules.py +128 -128
- onvif/services/actionengine.py +109 -109
- onvif/services/analytics/__init__.py +1 -1
- onvif/services/analytics/analytics.py +124 -124
- onvif/services/analytics/ruleengine.py +78 -78
- onvif/services/analyticsdevice.py +159 -159
- onvif/services/appmgmt.py +74 -74
- onvif/services/authenticationbehavior.py +219 -219
- onvif/services/credential.py +321 -321
- onvif/services/deviceio.py +328 -328
- onvif/services/devicemgmt.py +970 -970
- onvif/services/display.py +132 -132
- onvif/services/doorcontrol.py +267 -267
- onvif/services/events/__init__.py +1 -1
- onvif/services/events/events.py +87 -87
- onvif/services/events/notification.py +57 -57
- onvif/services/events/pausable_subscription.py +76 -76
- onvif/services/events/pullpoint.py +80 -80
- onvif/services/events/subscription.py +53 -53
- onvif/services/imaging.py +145 -145
- onvif/services/media.py +886 -886
- onvif/services/media2.py +667 -667
- onvif/services/provisioning.py +70 -70
- onvif/services/ptz.py +380 -380
- onvif/services/receiver.py +94 -94
- onvif/services/recording.py +289 -289
- onvif/services/replay.py +60 -60
- onvif/services/schedule.py +182 -182
- onvif/services/search.py +410 -410
- onvif/services/security/__init__.py +1 -1
- onvif/services/security/advancedsecurity.py +35 -35
- onvif/services/security/authorizationserver.py +53 -53
- onvif/services/security/dot1x.py +161 -161
- onvif/services/security/jwt.py +37 -37
- onvif/services/security/keystore.py +612 -612
- onvif/services/security/mediasigning.py +78 -78
- onvif/services/security/tlsserver.py +262 -262
- onvif/services/thermal.py +88 -88
- onvif/services/uplink.py +56 -56
- onvif/utils/__init__.py +26 -26
- onvif/utils/discovery.py +526 -521
- onvif/utils/error_handlers.py +241 -237
- onvif/utils/exceptions.py +184 -184
- onvif/utils/plugins.py +500 -500
- onvif/utils/service.py +363 -363
- onvif/utils/wsdl.py +788 -785
- onvif/utils/zeep.py +685 -683
- onvif/wsdl/LICENSE.md +231 -231
- onvif/wsdl/schema/common/b-2.xsd +579 -579
- onvif/wsdl/schema/common/bf-2.xsd +84 -84
- onvif/wsdl/schema/common/bw-2.wsdl +447 -447
- onvif/wsdl/schema/common/include +13 -13
- onvif/wsdl/schema/common/mpqf.xsd +1109 -1109
- onvif/wsdl/schema/common/r-2.xsd +50 -50
- onvif/wsdl/schema/common/rw-2.wsdl +54 -54
- onvif/wsdl/schema/common/soap-envelope +165 -165
- onvif/wsdl/schema/common/t-1.xsd +184 -184
- onvif/wsdl/schema/common/ws-addr.xsd +144 -144
- onvif/wsdl/schema/common/xml.xsd +287 -287
- onvif/wsdl/schema/common/xmlmime +48 -48
- onvif/wsdl/ver10/accesscontrol/wsdl/index.html +6 -6
- onvif/wsdl/ver10/accessrules/wsdl/accessrules.wsdl +702 -702
- onvif/wsdl/ver10/accessrules/wsdl/index.html +6 -6
- onvif/wsdl/ver10/actionengine.wsdl +1265 -1265
- onvif/wsdl/ver10/advancedsecurity/wsdl/advancedsecurity.wsdl +4205 -4205
- onvif/wsdl/ver10/advancedsecurity/wsdl/index.html +6 -6
- onvif/wsdl/ver10/analyticsdevice.wsdl +709 -709
- onvif/wsdl/ver10/appmgmt/wsdl/appmgmt.wsdl +502 -502
- onvif/wsdl/ver10/appmgmt/wsdl/index.html +6 -6
- onvif/wsdl/ver10/authenticationbehavior/wsdl/authenticationbehavior.wsdl +1382 -1382
- onvif/wsdl/ver10/authenticationbehavior/wsdl/index.html +6 -6
- onvif/wsdl/ver10/credential/wsdl/credential.wsdl +2018 -2018
- onvif/wsdl/ver10/credential/wsdl/index.html +6 -6
- onvif/wsdl/ver10/device/wsdl/devicemgmt.wsdl +4786 -4786
- onvif/wsdl/ver10/deviceio.wsdl +1414 -1414
- onvif/wsdl/ver10/display/display.wsdl +383 -383
- onvif/wsdl/ver10/display/wsdl/index.htm +383 -383
- onvif/wsdl/ver10/display.wsdl +521 -521
- onvif/wsdl/ver10/doorcontrol/wsdl/index.html +6 -6
- onvif/wsdl/ver10/events/wsdl/bw-2-vs-mod.wsdl +448 -448
- onvif/wsdl/ver10/events/wsdl/event-vs.wsdl +947 -947
- onvif/wsdl/ver10/events/wsdl/event.wsdl +947 -947
- onvif/wsdl/ver10/events/wsdl/index.html +6 -6
- onvif/wsdl/ver10/federatedsearch.wsdl +344 -344
- onvif/wsdl/ver10/media/wsdl/media.wsdl +3684 -3684
- onvif/wsdl/ver10/pacs/accesscontrol.wsdl +1942 -1942
- onvif/wsdl/ver10/pacs/doorcontrol.wsdl +1792 -1792
- onvif/wsdl/ver10/pacs/types.xsd +181 -181
- onvif/wsdl/ver10/provisioning/wsdl/provisioning.wsdl +588 -588
- onvif/wsdl/ver10/receiver.wsdl +398 -398
- onvif/wsdl/ver10/recording.wsdl +1442 -1442
- onvif/wsdl/ver10/replay.wsdl +221 -221
- onvif/wsdl/ver10/schedule/wsdl/index.html +6 -6
- onvif/wsdl/ver10/schedule/wsdl/schedule.wsdl +1383 -1383
- onvif/wsdl/ver10/schema/common.xsd +431 -431
- onvif/wsdl/ver10/schema/metadatastream.xsd +534 -534
- onvif/wsdl/ver10/schema/onvif.xsd +9743 -9743
- onvif/wsdl/ver10/search.wsdl +1114 -1114
- onvif/wsdl/ver10/thermal/wsdl/index.html +6 -6
- onvif/wsdl/ver10/thermal/wsdl/thermal.wsdl +777 -777
- onvif/wsdl/ver10/topics/topicns.xml +13 -13
- onvif/wsdl/ver10/uplink/wsdl/index.html +6 -6
- onvif/wsdl/ver10/uplink/wsdl/uplink.wsdl +256 -256
- onvif/wsdl/ver20/analytics/humanbody.xsd +490 -490
- onvif/wsdl/ver20/analytics/humanface.xsd +501 -501
- onvif/wsdl/ver20/analytics/index.html +6 -6
- onvif/wsdl/ver20/analytics/radiometry.xsd +388 -388
- onvif/wsdl/ver20/analytics/rules.xsd +126 -126
- onvif/wsdl/ver20/analytics/wsdl/analytics.wsdl +757 -757
- onvif/wsdl/ver20/analytics/wsdl/index.html +6 -6
- onvif/wsdl/ver20/imaging/wsdl/imaging.wsdl +603 -603
- onvif/wsdl/ver20/media/wsdl/index.html +6 -6
- onvif/wsdl/ver20/media/wsdl/media.wsdl +3126 -3126
- onvif/wsdl/ver20/ptz/wsdl/ptz.wsdl +1450 -1450
- onvif/wsdl/ver20/util/federated_search_documentation.html +1647 -1647
- onvif/wsdl/ver20/util/fedsearch-docu-viewer.xsl +8 -8
- onvif/wsdl/ver20/util/onvif-wsdl-viewer.xsl +2579 -2579
- onvif/wsdl/ver20/util/operationIndex.html +97 -97
- {onvif_python-0.4.0.dist-info → onvif_python-0.4.2.dist-info}/METADATA +115 -113
- onvif_python-0.4.2.dist-info/RECORD +144 -0
- {onvif_python-0.4.0.dist-info → onvif_python-0.4.2.dist-info}/licenses/LICENSE.md +20 -20
- onvif_python-0.4.0.dist-info/RECORD +0 -144
- {onvif_python-0.4.0.dist-info → onvif_python-0.4.2.dist-info}/WHEEL +0 -0
- {onvif_python-0.4.0.dist-info → onvif_python-0.4.2.dist-info}/entry_points.txt +0 -0
- {onvif_python-0.4.0.dist-info → onvif_python-0.4.2.dist-info}/top_level.txt +0 -0
onvif/__init__.py
CHANGED
|
@@ -1,29 +1,29 @@
|
|
|
1
|
-
"""ONVIF Python."""
|
|
2
|
-
|
|
3
|
-
from onvif.cli import main as ONVIFCLI
|
|
4
|
-
from onvif.client import ONVIFClient
|
|
5
|
-
from onvif.operator import CacheMode
|
|
6
|
-
from onvif.utils import (
|
|
7
|
-
ONVIFWSDL,
|
|
8
|
-
ONVIFDiscovery,
|
|
9
|
-
ONVIFOperationException,
|
|
10
|
-
ONVIFParser,
|
|
11
|
-
ZeepPatcher,
|
|
12
|
-
ignore_unsupported,
|
|
13
|
-
is_action_not_supported,
|
|
14
|
-
safe_call,
|
|
15
|
-
)
|
|
16
|
-
|
|
17
|
-
__all__ = [
|
|
18
|
-
"ONVIFClient",
|
|
19
|
-
"CacheMode",
|
|
20
|
-
"ONVIFWSDL",
|
|
21
|
-
"ONVIFOperationException",
|
|
22
|
-
"ZeepPatcher",
|
|
23
|
-
"ONVIFCLI",
|
|
24
|
-
"ONVIFDiscovery",
|
|
25
|
-
"ONVIFParser",
|
|
26
|
-
"ignore_unsupported",
|
|
27
|
-
"is_action_not_supported",
|
|
28
|
-
"safe_call",
|
|
29
|
-
]
|
|
1
|
+
"""ONVIF Python."""
|
|
2
|
+
|
|
3
|
+
from onvif.cli import main as ONVIFCLI
|
|
4
|
+
from onvif.client import ONVIFClient
|
|
5
|
+
from onvif.operator import CacheMode
|
|
6
|
+
from onvif.utils import (
|
|
7
|
+
ONVIFWSDL,
|
|
8
|
+
ONVIFDiscovery,
|
|
9
|
+
ONVIFOperationException,
|
|
10
|
+
ONVIFParser,
|
|
11
|
+
ZeepPatcher,
|
|
12
|
+
ignore_unsupported,
|
|
13
|
+
is_action_not_supported,
|
|
14
|
+
safe_call,
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
__all__ = [
|
|
18
|
+
"ONVIFClient",
|
|
19
|
+
"CacheMode",
|
|
20
|
+
"ONVIFWSDL",
|
|
21
|
+
"ONVIFOperationException",
|
|
22
|
+
"ZeepPatcher",
|
|
23
|
+
"ONVIFCLI",
|
|
24
|
+
"ONVIFDiscovery",
|
|
25
|
+
"ONVIFParser",
|
|
26
|
+
"ignore_unsupported",
|
|
27
|
+
"is_action_not_supported",
|
|
28
|
+
"safe_call",
|
|
29
|
+
]
|
onvif/cli/__init__.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
"""ONVIF CLI."""
|
|
2
|
-
|
|
3
|
-
from onvif.cli.main import main
|
|
4
|
-
|
|
5
|
-
__all__ = ["main"]
|
|
1
|
+
"""ONVIF CLI."""
|
|
2
|
+
|
|
3
|
+
from onvif.cli.main import main
|
|
4
|
+
|
|
5
|
+
__all__ = ["main"]
|
onvif/cli/__main__.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
"""ONVIF CLI entry point for python -m onvif.cli."""
|
|
3
|
-
|
|
4
|
-
from onvif.cli.main import main
|
|
5
|
-
|
|
6
|
-
if __name__ == "__main__":
|
|
7
|
-
main()
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""ONVIF CLI entry point for python -m onvif.cli."""
|
|
3
|
+
|
|
4
|
+
from onvif.cli.main import main
|
|
5
|
+
|
|
6
|
+
if __name__ == "__main__":
|
|
7
|
+
main()
|
onvif/cli/helpers/__init__.py
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
"""ONVIF CLI helpers."""
|
|
2
|
-
|
|
3
|
-
from onvif.cli.helpers.discovery import discover_devices, select_device_interactive
|
|
4
|
-
from onvif.cli.helpers.execution import execute_command, setup_warning_format
|
|
5
|
-
from onvif.cli.helpers.files import save_output_to_file
|
|
6
|
-
from onvif.cli.helpers.products import search_products
|
|
7
|
-
from onvif.cli.helpers.wsdl_parser import (
|
|
8
|
-
get_method_documentation,
|
|
9
|
-
get_operation_type_info,
|
|
10
|
-
)
|
|
11
|
-
|
|
12
|
-
__all__ = [
|
|
13
|
-
"search_products",
|
|
14
|
-
"save_output_to_file",
|
|
15
|
-
"discover_devices",
|
|
16
|
-
"select_device_interactive",
|
|
17
|
-
"execute_command",
|
|
18
|
-
"setup_warning_format",
|
|
19
|
-
"get_method_documentation",
|
|
20
|
-
"get_operation_type_info",
|
|
21
|
-
]
|
|
1
|
+
"""ONVIF CLI helpers."""
|
|
2
|
+
|
|
3
|
+
from onvif.cli.helpers.discovery import discover_devices, select_device_interactive
|
|
4
|
+
from onvif.cli.helpers.execution import execute_command, setup_warning_format
|
|
5
|
+
from onvif.cli.helpers.files import save_output_to_file
|
|
6
|
+
from onvif.cli.helpers.products import search_products
|
|
7
|
+
from onvif.cli.helpers.wsdl_parser import (
|
|
8
|
+
get_method_documentation,
|
|
9
|
+
get_operation_type_info,
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
__all__ = [
|
|
13
|
+
"search_products",
|
|
14
|
+
"save_output_to_file",
|
|
15
|
+
"discover_devices",
|
|
16
|
+
"select_device_interactive",
|
|
17
|
+
"execute_command",
|
|
18
|
+
"setup_warning_format",
|
|
19
|
+
"get_method_documentation",
|
|
20
|
+
"get_operation_type_info",
|
|
21
|
+
]
|
onvif/cli/helpers/discovery.py
CHANGED
|
@@ -1,156 +1,181 @@
|
|
|
1
|
-
"""ONVIF discovery helpers."""
|
|
2
|
-
|
|
3
|
-
from datetime import datetime
|
|
4
|
-
|
|
5
|
-
from onvif.cli.utils import colorize
|
|
6
|
-
from onvif.utils import ONVIFDiscovery
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
def discover_devices(
|
|
10
|
-
timeout: int = 4,
|
|
11
|
-
interface: str | None = None,
|
|
12
|
-
prefer_https: bool = False,
|
|
13
|
-
filter_term: str | None = None,
|
|
14
|
-
) -> list:
|
|
15
|
-
"""Discover ONVIF devices on the network using WS-Discovery.
|
|
16
|
-
|
|
17
|
-
Args:
|
|
18
|
-
timeout (int): Discovery timeout in seconds
|
|
19
|
-
interface (str | None): Network interface to use for discovery
|
|
20
|
-
prefer_https (bool): If True, prioritize HTTPS XAddrs when available
|
|
21
|
-
filter_term (str | None): Optional search term to filter devices by
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
print(f"
|
|
31
|
-
print(f"
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
def select_device_interactive(devices: list) -> tuple[str, int, bool] | None:
|
|
43
|
-
"""Display devices and allow user to select one interactively.
|
|
44
|
-
|
|
45
|
-
Args:
|
|
46
|
-
devices (list): Discovered devices
|
|
47
|
-
|
|
48
|
-
Returns:
|
|
49
|
-
Tuple of (host, port, use_https) or None if cancelled
|
|
50
|
-
"""
|
|
51
|
-
if not devices:
|
|
52
|
-
print(f"\n{colorize('No ONVIF devices found.', 'red')}")
|
|
53
|
-
return None
|
|
54
|
-
|
|
55
|
-
print(f"{colorize(f'Found {len(devices)} ONVIF device(s):', 'green')}")
|
|
56
|
-
|
|
57
|
-
for idx, device in enumerate(devices, 1):
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
f
|
|
101
|
-
f'{" [
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
1
|
+
"""ONVIF discovery helpers."""
|
|
2
|
+
|
|
3
|
+
from datetime import datetime
|
|
4
|
+
|
|
5
|
+
from onvif.cli.utils import colorize
|
|
6
|
+
from onvif.utils import ONVIFDiscovery
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def discover_devices(
|
|
10
|
+
timeout: int = 4,
|
|
11
|
+
interface: str | None = None,
|
|
12
|
+
prefer_https: bool = False,
|
|
13
|
+
filter_term: str | None = None,
|
|
14
|
+
) -> list:
|
|
15
|
+
"""Discover ONVIF devices on the network using WS-Discovery.
|
|
16
|
+
|
|
17
|
+
Args:
|
|
18
|
+
timeout (int): Discovery timeout in seconds
|
|
19
|
+
interface (str | None): Network interface to use for discovery
|
|
20
|
+
prefer_https (bool): If True, prioritize HTTPS XAddrs when available
|
|
21
|
+
filter_term (str | None): Optional search term to filter devices by
|
|
22
|
+
types or scopes (case-insensitive)
|
|
23
|
+
|
|
24
|
+
Returns:
|
|
25
|
+
List of discovered devices with connection info
|
|
26
|
+
"""
|
|
27
|
+
# Use ONVIFDiscovery class
|
|
28
|
+
discovery = ONVIFDiscovery(timeout=timeout, interface=interface)
|
|
29
|
+
|
|
30
|
+
print(f"\n{colorize('Discovering ONVIF devices on network...', 'yellow')}")
|
|
31
|
+
print(f"Network interface: {colorize(discovery.get_local_ip(), 'white')}")
|
|
32
|
+
print(f"Timeout: {timeout}s")
|
|
33
|
+
if filter_term:
|
|
34
|
+
print(f"Filter: {colorize(filter_term, 'yellow')}")
|
|
35
|
+
print()
|
|
36
|
+
|
|
37
|
+
devices = discovery.discover(prefer_https=prefer_https, search=filter_term)
|
|
38
|
+
|
|
39
|
+
return devices
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def select_device_interactive(devices: list) -> tuple[str, int, bool] | None:
|
|
43
|
+
"""Display devices and allow user to select one interactively.
|
|
44
|
+
|
|
45
|
+
Args:
|
|
46
|
+
devices (list): Discovered devices
|
|
47
|
+
|
|
48
|
+
Returns:
|
|
49
|
+
Tuple of (host, port, use_https) or None if cancelled
|
|
50
|
+
"""
|
|
51
|
+
if not devices:
|
|
52
|
+
print(f"\n{colorize('No ONVIF devices found.', 'red')}")
|
|
53
|
+
return None
|
|
54
|
+
|
|
55
|
+
print(f"{colorize(f'Found {len(devices)} ONVIF device(s):', 'green')}")
|
|
56
|
+
|
|
57
|
+
for idx, device in enumerate(devices, 1):
|
|
58
|
+
protocol = "https" if device.get("use_https", False) else "http"
|
|
59
|
+
host_port = f"{device['host']}:{device['port']}"
|
|
60
|
+
protocol_indicator = (
|
|
61
|
+
colorize("🔒 HTTPS", "green")
|
|
62
|
+
if device.get("use_https", False)
|
|
63
|
+
else colorize("HTTP", "white")
|
|
64
|
+
)
|
|
65
|
+
print(
|
|
66
|
+
f"\n{colorize(f'[{idx}]', 'yellow')} {colorize(host_port, 'yellow')} ({protocol_indicator})"
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
# Remove uuid: or urn:uuid: prefix from EPR
|
|
70
|
+
epr_display = device["epr"]
|
|
71
|
+
if epr_display.startswith("urn:uuid:"):
|
|
72
|
+
epr_display = epr_display.replace("urn:uuid:", "")
|
|
73
|
+
elif epr_display.startswith("uuid:"):
|
|
74
|
+
epr_display = epr_display.replace("uuid:", "")
|
|
75
|
+
print(f" [uuid] {epr_display}")
|
|
76
|
+
|
|
77
|
+
_print_optional_field("hostname", device.get("hostname"))
|
|
78
|
+
|
|
79
|
+
_print_optional_field(
|
|
80
|
+
"xaddrs",
|
|
81
|
+
" ".join(f"[{xaddr}]" for xaddr in device.get("xaddrs", [])),
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
if device.get("date_time"):
|
|
85
|
+
utc = (
|
|
86
|
+
datetime.fromisoformat(device["date_time"].get("utc")).strftime(
|
|
87
|
+
"%H:%M:%S %d-%m-%Y"
|
|
88
|
+
)
|
|
89
|
+
if device["date_time"].get("utc")
|
|
90
|
+
else ""
|
|
91
|
+
)
|
|
92
|
+
local = (
|
|
93
|
+
datetime.fromisoformat(device["date_time"].get("local")).strftime(
|
|
94
|
+
"%H:%M:%S %d-%m-%Y"
|
|
95
|
+
)
|
|
96
|
+
if device["date_time"].get("local")
|
|
97
|
+
else ""
|
|
98
|
+
)
|
|
99
|
+
print(
|
|
100
|
+
f" [date_time]"
|
|
101
|
+
f'{" [UTC: " + utc + "]" if utc else ""}'
|
|
102
|
+
f'{" [Local: " + local + "]" if local else ""}'
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
_print_optional_field(
|
|
106
|
+
"types",
|
|
107
|
+
" ".join(f"[{device_type}]" for device_type in device.get("types", [])),
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
_print_optional_field(
|
|
111
|
+
"services",
|
|
112
|
+
" ".join(f"[{service}]" for service in device.get("services", [])),
|
|
113
|
+
"cyan",
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
if device.get("scopes"):
|
|
117
|
+
scope_parts = []
|
|
118
|
+
for scope in device["scopes"]:
|
|
119
|
+
# Remove the prefix "onvif://www.onvif.org/" if present
|
|
120
|
+
if scope.startswith("onvif://www.onvif.org/"):
|
|
121
|
+
simplified = scope.replace("onvif://www.onvif.org/", "")
|
|
122
|
+
scope_parts.append(f"[{simplified}]")
|
|
123
|
+
else:
|
|
124
|
+
# Keep other scopes as-is (e.g., http:123)
|
|
125
|
+
scope_parts.append(f"[{scope}]")
|
|
126
|
+
|
|
127
|
+
if scope_parts:
|
|
128
|
+
print(f" [scopes] {' '.join(scope_parts)}")
|
|
129
|
+
|
|
130
|
+
return _process_device_selection(protocol, devices)
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def _print_optional_field(
|
|
134
|
+
label: str,
|
|
135
|
+
value: object,
|
|
136
|
+
color: str | None = None,
|
|
137
|
+
) -> None:
|
|
138
|
+
"""Print an optional device field when it has a value."""
|
|
139
|
+
if not value:
|
|
140
|
+
return
|
|
141
|
+
|
|
142
|
+
if color:
|
|
143
|
+
value = colorize(str(value), color)
|
|
144
|
+
|
|
145
|
+
print(f" [{label}] {value}")
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def _process_device_selection(protocol, devices):
|
|
149
|
+
"""Simple selection (without arrow keys for cross-platform compatibility)"""
|
|
150
|
+
while True:
|
|
151
|
+
try:
|
|
152
|
+
selection = input(
|
|
153
|
+
f"\nSelect device number {colorize(f'1-{len(devices)}', 'white')} "
|
|
154
|
+
f"or {colorize('q', 'white')} to quit: "
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
if selection.lower() == "q":
|
|
158
|
+
return None
|
|
159
|
+
|
|
160
|
+
idx = int(selection)
|
|
161
|
+
if 1 <= idx <= len(devices):
|
|
162
|
+
selected = devices[idx - 1]
|
|
163
|
+
protocol = "https" if selected.get("use_https", False) else "http"
|
|
164
|
+
host_port = f"{selected['host']}:{selected['port']}"
|
|
165
|
+
print(
|
|
166
|
+
f"\n{colorize('Selected:', 'green')} {colorize(protocol, 'cyan')}:"
|
|
167
|
+
f"//{colorize(host_port, 'yellow')}"
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
return (
|
|
171
|
+
selected["host"],
|
|
172
|
+
selected["port"],
|
|
173
|
+
selected.get("use_https", False),
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
print(colorize("Invalid selection. Please try again.", "red"))
|
|
177
|
+
|
|
178
|
+
except ValueError:
|
|
179
|
+
print(colorize("Invalid input. Please enter a number.", "red"))
|
|
180
|
+
except (EOFError, KeyboardInterrupt):
|
|
181
|
+
return None
|
onvif/cli/helpers/execution.py
CHANGED
|
@@ -1,57 +1,57 @@
|
|
|
1
|
-
"""ONVIF command execution helpers."""
|
|
2
|
-
|
|
3
|
-
import warnings
|
|
4
|
-
from typing import Any
|
|
5
|
-
|
|
6
|
-
from onvif.cli.utils import colorize, parse_json_params
|
|
7
|
-
from onvif.client import ONVIFClient
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
def execute_command(
|
|
11
|
-
client: ONVIFClient,
|
|
12
|
-
service_name: str,
|
|
13
|
-
method_name: str,
|
|
14
|
-
params_str: str | None = None,
|
|
15
|
-
) -> Any:
|
|
16
|
-
"""Execute a single ONVIF command.
|
|
17
|
-
|
|
18
|
-
Args:
|
|
19
|
-
client (ONVIFClient): ONVIFClient instance
|
|
20
|
-
service_name (str): Selected service for command execution
|
|
21
|
-
method_name (str): Method to execute by service
|
|
22
|
-
params_str (str | None): Provided params for method execution
|
|
23
|
-
|
|
24
|
-
Returns:
|
|
25
|
-
The operation response printed in terminal
|
|
26
|
-
"""
|
|
27
|
-
# Get service instance
|
|
28
|
-
try:
|
|
29
|
-
service = getattr(client, service_name.lower())()
|
|
30
|
-
except AttributeError as e:
|
|
31
|
-
raise ValueError(f"{colorize('Unknown service:', 'red')} {service_name}") from e
|
|
32
|
-
|
|
33
|
-
# Get method
|
|
34
|
-
try:
|
|
35
|
-
method = getattr(service, method_name)
|
|
36
|
-
except AttributeError as e:
|
|
37
|
-
raise ValueError(
|
|
38
|
-
f"{colorize('Unknown method', 'red')} '{method_name}' for service '{service_name}'"
|
|
39
|
-
) from e
|
|
40
|
-
|
|
41
|
-
# Parse parameters
|
|
42
|
-
params = parse_json_params(params_str) if params_str else {}
|
|
43
|
-
|
|
44
|
-
# Execute method
|
|
45
|
-
return method(**params)
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
def setup_warning_format() -> None:
|
|
49
|
-
"""Setup custom warning format to show clean, concise warnings."""
|
|
50
|
-
|
|
51
|
-
def custom_warning_format(
|
|
52
|
-
message, category, filename, lineno, line=None
|
|
53
|
-
): # pylint: disable=unused-argument
|
|
54
|
-
# Show only the warning message without file path and line number
|
|
55
|
-
return f"{category.__name__}: {message}\n"
|
|
56
|
-
|
|
57
|
-
warnings.formatwarning = custom_warning_format
|
|
1
|
+
"""ONVIF command execution helpers."""
|
|
2
|
+
|
|
3
|
+
import warnings
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
from onvif.cli.utils import colorize, parse_json_params
|
|
7
|
+
from onvif.client import ONVIFClient
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def execute_command(
|
|
11
|
+
client: ONVIFClient,
|
|
12
|
+
service_name: str,
|
|
13
|
+
method_name: str,
|
|
14
|
+
params_str: str | None = None,
|
|
15
|
+
) -> Any:
|
|
16
|
+
"""Execute a single ONVIF command.
|
|
17
|
+
|
|
18
|
+
Args:
|
|
19
|
+
client (ONVIFClient): ONVIFClient instance
|
|
20
|
+
service_name (str): Selected service for command execution
|
|
21
|
+
method_name (str): Method to execute by service
|
|
22
|
+
params_str (str | None): Provided params for method execution
|
|
23
|
+
|
|
24
|
+
Returns:
|
|
25
|
+
The operation response printed in terminal
|
|
26
|
+
"""
|
|
27
|
+
# Get service instance
|
|
28
|
+
try:
|
|
29
|
+
service = getattr(client, service_name.lower())()
|
|
30
|
+
except AttributeError as e:
|
|
31
|
+
raise ValueError(f"{colorize('Unknown service:', 'red')} {service_name}") from e
|
|
32
|
+
|
|
33
|
+
# Get method
|
|
34
|
+
try:
|
|
35
|
+
method = getattr(service, method_name)
|
|
36
|
+
except AttributeError as e:
|
|
37
|
+
raise ValueError(
|
|
38
|
+
f"{colorize('Unknown method', 'red')} '{method_name}' for service '{service_name}'"
|
|
39
|
+
) from e
|
|
40
|
+
|
|
41
|
+
# Parse parameters
|
|
42
|
+
params = parse_json_params(params_str) if params_str else {}
|
|
43
|
+
|
|
44
|
+
# Execute method
|
|
45
|
+
return method(**params)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def setup_warning_format() -> None:
|
|
49
|
+
"""Setup custom warning format to show clean, concise warnings."""
|
|
50
|
+
|
|
51
|
+
def custom_warning_format(
|
|
52
|
+
message, category, filename, lineno, line=None
|
|
53
|
+
): # pylint: disable=unused-argument
|
|
54
|
+
# Show only the warning message without file path and line number
|
|
55
|
+
return f"{category.__name__}: {message}\n"
|
|
56
|
+
|
|
57
|
+
warnings.formatwarning = custom_warning_format
|