esp-rainmaker-cli 1.12.0__tar.gz → 1.13.1__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.
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/PKG-INFO +25 -2
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/esp_rainmaker_cli.egg-info/PKG-INFO +25 -2
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/esp_rainmaker_cli.egg-info/SOURCES.txt +4 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/esp_rainmaker_cli.egg-info/requires.txt +6 -1
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rainmaker/rainmaker.py +121 -1
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rainmaker/version.py +1 -1
- esp_rainmaker_cli-1.13.1/rmaker_cmd/automation.py +217 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_cmd/node.py +10 -2
- esp_rainmaker_cli-1.13.1/rmaker_cmd/stream.py +203 -0
- esp_rainmaker_cli-1.13.1/rmaker_lib/aws_credentials.py +220 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_lib/configmanager.py +1 -1
- esp_rainmaker_cli-1.13.1/rmaker_lib/kvs_streaming.py +2014 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_lib/session.py +79 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/setup.py +2 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/LICENSE +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/README.md +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/esp_rainmaker_cli.egg-info/dependency_links.txt +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/esp_rainmaker_cli.egg-info/entry_points.txt +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/esp_rainmaker_cli.egg-info/top_level.txt +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rainmaker/__init__.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_cmd/__init__.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_cmd/browserlogin.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_cmd/cache.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_cmd/cmd_response.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_cmd/group.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_cmd/html/welcome.html +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_cmd/provision.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_cmd/test.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_cmd/user.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_lib/__init__.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_lib/cmd_response.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_lib/constants.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_lib/device.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_lib/envval.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_lib/exceptions.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_lib/local_control.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_lib/logger.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_lib/node.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_lib/node_cache.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_lib/profile_manager.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_lib/profile_utils.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_lib/schedule_utils.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_lib/serverconfig.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_lib/service.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_lib/session_store.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_lib/simple_local_control.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_lib/user.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_tools/__init__.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_tools/common/__init__.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_tools/common/discovery/__init__.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_tools/common/discovery/mdns_discovery.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_tools/common/prov/__init__.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_tools/common/prov/wifi_ctrl.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_tools/common/prov/wifi_prov.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_tools/common/prov/wifi_scan.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_tools/common/security/__init__.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_tools/common/security/security.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_tools/common/security/security0.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_tools/common/security/security1.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_tools/common/security/security2.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_tools/common/security/srp6a.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_tools/common/transport/__init__.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_tools/common/transport/ble_cli.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_tools/common/transport/transport.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_tools/common/transport/transport_ble.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_tools/common/transport/transport_console.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_tools/common/transport/transport_http.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_tools/common/utils/__init__.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_tools/common/utils/convenience.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_tools/rmaker_claim/__init__.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_tools/rmaker_claim/claim.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_tools/rmaker_claim/claim_config.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_tools/rmaker_local_ctrl/__init__.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_tools/rmaker_local_ctrl/constants_pb2.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_tools/rmaker_local_ctrl/esp_local_ctrl.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_tools/rmaker_local_ctrl/esp_local_ctrl_pb2.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_tools/rmaker_local_ctrl/esp_prov.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_tools/rmaker_local_ctrl/esp_rainmaker_ctrl.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_tools/rmaker_local_ctrl/esp_rmaker_prov_local_ctrl_pb2.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_tools/rmaker_local_ctrl/integration.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_tools/rmaker_local_ctrl/proto/__init__.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_tools/rmaker_local_ctrl/proto/proto_lc.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_tools/rmaker_local_ctrl/prov/__init__.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_tools/rmaker_local_ctrl/prov/custom_prov.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_tools/rmaker_local_ctrl/prov/wifi_ctrl.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_tools/rmaker_local_ctrl/raw_config.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_tools/rmaker_local_ctrl/raw_params.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_tools/rmaker_local_ctrl/sec0_pb2.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_tools/rmaker_local_ctrl/sec1_pb2.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_tools/rmaker_local_ctrl/sec2_pb2.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_tools/rmaker_local_ctrl/security/__init__.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_tools/rmaker_local_ctrl/session_pb2.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_tools/rmaker_local_ctrl/transport/__init__.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_tools/rmaker_local_ctrl/utils/__init__.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_tools/rmaker_prov/__init__.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_tools/rmaker_prov/challenge_response.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_tools/rmaker_prov/config/__init__.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_tools/rmaker_prov/config/custom_cloud_config_pb2.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_tools/rmaker_prov/config/esp_rmaker_chal_resp_pb2.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_tools/rmaker_prov/config/esp_rmaker_claim_pb2.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_tools/rmaker_prov/config/esp_rmaker_user_mapping_pb2.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_tools/rmaker_prov/esp_rainmaker_prov.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_tools/rmaker_prov/on_network_chal_resp.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_tools/rmaker_prov/proto/__init__.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_tools/rmaker_prov/protocomm/__init__.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_tools/rmaker_prov/protocomm/python/__init__.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_tools/rmaker_prov/protocomm/python/constants_pb2.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_tools/rmaker_prov/protocomm/python/sec0_pb2.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_tools/rmaker_prov/protocomm/python/sec1_pb2.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_tools/rmaker_prov/protocomm/python/sec2_pb2.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_tools/rmaker_prov/protocomm/python/session_pb2.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_tools/rmaker_prov/prov/__init__.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_tools/rmaker_prov/prov/prov_util.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_tools/rmaker_prov/prov/user_mapping.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_tools/rmaker_prov/security/__init__.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_tools/rmaker_prov/transport/__init__.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_tools/rmaker_prov/utils/__init__.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_tools/rmaker_prov/wifi_provisioning/__init__.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_tools/rmaker_prov/wifi_provisioning/python/__init__.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_tools/rmaker_prov/wifi_provisioning/python/wifi_config_pb2.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_tools/rmaker_prov/wifi_provisioning/python/wifi_constants_pb2.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_tools/rmaker_prov/wifi_provisioning/python/wifi_ctrl_pb2.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/rmaker_tools/rmaker_prov/wifi_provisioning/python/wifi_scan_pb2.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/server_cert/__init__.py +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/server_cert/server_cert.pem +0 -0
- {esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: esp-rainmaker-cli
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.13.1
|
|
4
4
|
Summary: A python utility to perform host based claiming
|
|
5
5
|
Home-page: https://github.com/espressif/esp-rainmaker-cli
|
|
6
6
|
Author: Espressif Systems
|
|
@@ -18,6 +18,8 @@ Classifier: Topic :: Software Development :: Embedded Systems
|
|
|
18
18
|
Classifier: Programming Language :: Python :: 3.9
|
|
19
19
|
Classifier: Programming Language :: Python :: 3.10
|
|
20
20
|
Classifier: Programming Language :: Python :: 3.11
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
23
|
Requires-Python: >=3.9
|
|
22
24
|
Description-Content-Type: text/markdown
|
|
23
25
|
License-File: LICENSE
|
|
@@ -32,11 +34,16 @@ Requires-Dist: future>=0.15.2
|
|
|
32
34
|
Requires-Dist: pyparsing>=2.4.0
|
|
33
35
|
Requires-Dist: pyelftools>=0.22
|
|
34
36
|
Requires-Dist: esptool>=4.4
|
|
35
|
-
Requires-Dist: esp-secure-cert-tool
|
|
37
|
+
Requires-Dist: esp-secure-cert-tool>=2.3.6
|
|
36
38
|
Requires-Dist: setuptools
|
|
37
39
|
Requires-Dist: esp_idf_nvs_partition_gen>=0.1.6
|
|
38
40
|
Requires-Dist: bleak>=0.20.0
|
|
39
41
|
Requires-Dist: zeroconf>=0.131.0
|
|
42
|
+
Requires-Dist: aiortc>=1.6.0
|
|
43
|
+
Requires-Dist: boto3>=1.28.0
|
|
44
|
+
Requires-Dist: websockets>=11.0
|
|
45
|
+
Requires-Dist: opencv-python>=4.8.0
|
|
46
|
+
Requires-Dist: numpy>=1.24.0
|
|
40
47
|
Dynamic: author
|
|
41
48
|
Dynamic: classifier
|
|
42
49
|
Dynamic: description
|
|
@@ -115,6 +122,22 @@ Changelog
|
|
|
115
122
|
|
|
116
123
|
All major changes to ESP RainMaker CLI will be documented in this file.
|
|
117
124
|
|
|
125
|
+
## [1.13.1] - 23-Apr-2026
|
|
126
|
+
### Added
|
|
127
|
+
- Node sharing enhancements:
|
|
128
|
+
- Support for sharing as "primary"
|
|
129
|
+
- Transferring nodes
|
|
130
|
+
- Adding sub-roles
|
|
131
|
+
|
|
132
|
+
## [1.13.0] - 08-Apr-2026
|
|
133
|
+
### Added
|
|
134
|
+
- New `stream` command for WebRTC video streaming from ESP RainMaker camera devices via Amazon Kinesis Video Streams (KVS) signaling:
|
|
135
|
+
- Live video display with optional recording to file (`--output` / `-o`)
|
|
136
|
+
- Duration-limited streaming (`--duration`)
|
|
137
|
+
- Parallel ICE server fetch and WebSocket connection for faster stream setup
|
|
138
|
+
- Graceful handling of device disconnects, reboots, and frame timeouts
|
|
139
|
+
- Suppression of macOS FFmpeg duplicate library warnings during import
|
|
140
|
+
|
|
118
141
|
## [1.12.0] - 19-Feb-2026
|
|
119
142
|
### Added
|
|
120
143
|
- Local node cache layer for faster `--local` control operations:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: esp-rainmaker-cli
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.13.1
|
|
4
4
|
Summary: A python utility to perform host based claiming
|
|
5
5
|
Home-page: https://github.com/espressif/esp-rainmaker-cli
|
|
6
6
|
Author: Espressif Systems
|
|
@@ -18,6 +18,8 @@ Classifier: Topic :: Software Development :: Embedded Systems
|
|
|
18
18
|
Classifier: Programming Language :: Python :: 3.9
|
|
19
19
|
Classifier: Programming Language :: Python :: 3.10
|
|
20
20
|
Classifier: Programming Language :: Python :: 3.11
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
23
|
Requires-Python: >=3.9
|
|
22
24
|
Description-Content-Type: text/markdown
|
|
23
25
|
License-File: LICENSE
|
|
@@ -32,11 +34,16 @@ Requires-Dist: future>=0.15.2
|
|
|
32
34
|
Requires-Dist: pyparsing>=2.4.0
|
|
33
35
|
Requires-Dist: pyelftools>=0.22
|
|
34
36
|
Requires-Dist: esptool>=4.4
|
|
35
|
-
Requires-Dist: esp-secure-cert-tool
|
|
37
|
+
Requires-Dist: esp-secure-cert-tool>=2.3.6
|
|
36
38
|
Requires-Dist: setuptools
|
|
37
39
|
Requires-Dist: esp_idf_nvs_partition_gen>=0.1.6
|
|
38
40
|
Requires-Dist: bleak>=0.20.0
|
|
39
41
|
Requires-Dist: zeroconf>=0.131.0
|
|
42
|
+
Requires-Dist: aiortc>=1.6.0
|
|
43
|
+
Requires-Dist: boto3>=1.28.0
|
|
44
|
+
Requires-Dist: websockets>=11.0
|
|
45
|
+
Requires-Dist: opencv-python>=4.8.0
|
|
46
|
+
Requires-Dist: numpy>=1.24.0
|
|
40
47
|
Dynamic: author
|
|
41
48
|
Dynamic: classifier
|
|
42
49
|
Dynamic: description
|
|
@@ -115,6 +122,22 @@ Changelog
|
|
|
115
122
|
|
|
116
123
|
All major changes to ESP RainMaker CLI will be documented in this file.
|
|
117
124
|
|
|
125
|
+
## [1.13.1] - 23-Apr-2026
|
|
126
|
+
### Added
|
|
127
|
+
- Node sharing enhancements:
|
|
128
|
+
- Support for sharing as "primary"
|
|
129
|
+
- Transferring nodes
|
|
130
|
+
- Adding sub-roles
|
|
131
|
+
|
|
132
|
+
## [1.13.0] - 08-Apr-2026
|
|
133
|
+
### Added
|
|
134
|
+
- New `stream` command for WebRTC video streaming from ESP RainMaker camera devices via Amazon Kinesis Video Streams (KVS) signaling:
|
|
135
|
+
- Live video display with optional recording to file (`--output` / `-o`)
|
|
136
|
+
- Duration-limited streaming (`--duration`)
|
|
137
|
+
- Parallel ICE server fetch and WebSocket connection for faster stream setup
|
|
138
|
+
- Graceful handling of device disconnects, reboots, and frame timeouts
|
|
139
|
+
- Suppression of macOS FFmpeg duplicate library warnings during import
|
|
140
|
+
|
|
118
141
|
## [1.12.0] - 19-Feb-2026
|
|
119
142
|
### Added
|
|
120
143
|
- Local node cache layer for faster `--local` control operations:
|
{esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/esp_rainmaker_cli.egg-info/SOURCES.txt
RENAMED
|
@@ -11,22 +11,26 @@ rainmaker/__init__.py
|
|
|
11
11
|
rainmaker/rainmaker.py
|
|
12
12
|
rainmaker/version.py
|
|
13
13
|
rmaker_cmd/__init__.py
|
|
14
|
+
rmaker_cmd/automation.py
|
|
14
15
|
rmaker_cmd/browserlogin.py
|
|
15
16
|
rmaker_cmd/cache.py
|
|
16
17
|
rmaker_cmd/cmd_response.py
|
|
17
18
|
rmaker_cmd/group.py
|
|
18
19
|
rmaker_cmd/node.py
|
|
19
20
|
rmaker_cmd/provision.py
|
|
21
|
+
rmaker_cmd/stream.py
|
|
20
22
|
rmaker_cmd/test.py
|
|
21
23
|
rmaker_cmd/user.py
|
|
22
24
|
rmaker_cmd/html/welcome.html
|
|
23
25
|
rmaker_lib/__init__.py
|
|
26
|
+
rmaker_lib/aws_credentials.py
|
|
24
27
|
rmaker_lib/cmd_response.py
|
|
25
28
|
rmaker_lib/configmanager.py
|
|
26
29
|
rmaker_lib/constants.py
|
|
27
30
|
rmaker_lib/device.py
|
|
28
31
|
rmaker_lib/envval.py
|
|
29
32
|
rmaker_lib/exceptions.py
|
|
33
|
+
rmaker_lib/kvs_streaming.py
|
|
30
34
|
rmaker_lib/local_control.py
|
|
31
35
|
rmaker_lib/logger.py
|
|
32
36
|
rmaker_lib/node.py
|
{esp_rainmaker_cli-1.12.0 → esp_rainmaker_cli-1.13.1}/esp_rainmaker_cli.egg-info/requires.txt
RENAMED
|
@@ -9,8 +9,13 @@ future>=0.15.2
|
|
|
9
9
|
pyparsing>=2.4.0
|
|
10
10
|
pyelftools>=0.22
|
|
11
11
|
esptool>=4.4
|
|
12
|
-
esp-secure-cert-tool
|
|
12
|
+
esp-secure-cert-tool>=2.3.6
|
|
13
13
|
setuptools
|
|
14
14
|
esp_idf_nvs_partition_gen>=0.1.6
|
|
15
15
|
bleak>=0.20.0
|
|
16
16
|
zeroconf>=0.131.0
|
|
17
|
+
aiortc>=1.6.0
|
|
18
|
+
boto3>=1.28.0
|
|
19
|
+
websockets>=11.0
|
|
20
|
+
opencv-python>=4.8.0
|
|
21
|
+
numpy>=1.24.0
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
2
|
#
|
|
3
|
-
# SPDX-FileCopyrightText: 2020-
|
|
3
|
+
# SPDX-FileCopyrightText: 2020-2026 Espressif Systems (Shanghai) CO LTD
|
|
4
4
|
#
|
|
5
5
|
# SPDX-License-Identifier: Apache-2.0
|
|
6
6
|
|
|
@@ -16,7 +16,9 @@ from rmaker_cmd.provision import provision
|
|
|
16
16
|
from rmaker_cmd.test import test
|
|
17
17
|
from rmaker_lib.logger import log
|
|
18
18
|
from rmaker_cmd.group import group_add, group_remove, group_edit, group_list, group_show, group_add_nodes, group_remove_nodes, group_list_nodes
|
|
19
|
+
from rmaker_cmd.automation import automation_add, automation_edit, automation_remove, automation_get
|
|
19
20
|
from rmaker_cmd.cache import cache_manage
|
|
21
|
+
from rmaker_cmd.stream import stream_video
|
|
20
22
|
|
|
21
23
|
# Import the version
|
|
22
24
|
from rainmaker.version import VERSION
|
|
@@ -666,6 +668,29 @@ def main():
|
|
|
666
668
|
"format: <nodeid1>,<nodeid2>,...",
|
|
667
669
|
required=True)
|
|
668
670
|
|
|
671
|
+
add_op_parser.add_argument('--sub_role',
|
|
672
|
+
type=int,
|
|
673
|
+
metavar='<sub_role>',
|
|
674
|
+
choices=range(1, 5),
|
|
675
|
+
help='Sub-role for the secondary user (1-4)',
|
|
676
|
+
default=None)
|
|
677
|
+
|
|
678
|
+
add_op_parser.add_argument('--primary',
|
|
679
|
+
action='store_true',
|
|
680
|
+
help='Set "primary":true in the sharing request')
|
|
681
|
+
|
|
682
|
+
add_op_parser.add_argument('--transfer',
|
|
683
|
+
action='store_true',
|
|
684
|
+
help='Transfer node ownership to the specified user')
|
|
685
|
+
|
|
686
|
+
add_op_parser.add_argument('--new_role',
|
|
687
|
+
type=str,
|
|
688
|
+
metavar='<new_role>',
|
|
689
|
+
choices=['primary', 'secondary'],
|
|
690
|
+
help='New role for the current user after transfer (primary/secondary).\n'
|
|
691
|
+
'Only used with --transfer',
|
|
692
|
+
default=None)
|
|
693
|
+
|
|
669
694
|
add_profile_argument(add_op_parser)
|
|
670
695
|
add_op_parser.set_defaults(func=node_sharing_ops, parser=add_op_parser)
|
|
671
696
|
|
|
@@ -909,6 +934,76 @@ def main():
|
|
|
909
934
|
add_profile_argument(group_list_nodes_parser)
|
|
910
935
|
group_list_nodes_parser.set_defaults(func=group_list_nodes)
|
|
911
936
|
|
|
937
|
+
# Automation Management
|
|
938
|
+
automation_parser = subparsers.add_parser('automations',
|
|
939
|
+
help='Manage automation triggers')
|
|
940
|
+
automation_parser.set_defaults(func=lambda vars=None: automation_parser.print_help())
|
|
941
|
+
automation_subparsers = automation_parser.add_subparsers(dest='automation_command',
|
|
942
|
+
help='Automation operations')
|
|
943
|
+
|
|
944
|
+
# automations add
|
|
945
|
+
auto_add_parser = automation_subparsers.add_parser('add', help='Create a new automation trigger')
|
|
946
|
+
auto_add_parser.add_argument('--name', type=str, required=True, help='Name of the automation')
|
|
947
|
+
auto_add_parser.add_argument('--event-type', type=str, required=True,
|
|
948
|
+
choices=['params', 'weather', 'daylight'],
|
|
949
|
+
help='Event type (params, weather, daylight)')
|
|
950
|
+
auto_add_parser.add_argument('--event', type=str, required=True, action='append',
|
|
951
|
+
help='Event JSON object (repeatable). '
|
|
952
|
+
'E.g., \'{"params": {"Light": {"Brightness": 100}}, "check": "=="}\'')
|
|
953
|
+
auto_add_parser.add_argument('--action', type=str, required=True,
|
|
954
|
+
help='Action JSON (object or array of objects). '
|
|
955
|
+
'E.g., \'{"node_id": "xxx", "params": {"Light": {"Output": true}}}\'')
|
|
956
|
+
auto_add_parser.add_argument('--node-id', type=str,
|
|
957
|
+
help='Node ID (required for event-type params)')
|
|
958
|
+
auto_add_parser.add_argument('--location', type=str,
|
|
959
|
+
help='Location as lat,long (required for event-type weather/daylight). '
|
|
960
|
+
'E.g., 18.521428,73.8544541')
|
|
961
|
+
auto_add_parser.add_argument('--event-operator', type=str, choices=['AND', 'OR'],
|
|
962
|
+
help='Logical operator for multiple events (AND/OR)')
|
|
963
|
+
auto_add_parser.add_argument('--retrigger', action='store_true', default=False,
|
|
964
|
+
help='Allow retriggering for the same event')
|
|
965
|
+
auto_add_parser.add_argument('--metadata', type=str, help='Metadata as JSON string')
|
|
966
|
+
add_profile_argument(auto_add_parser)
|
|
967
|
+
auto_add_parser.set_defaults(func=automation_add)
|
|
968
|
+
|
|
969
|
+
# automations edit
|
|
970
|
+
auto_edit_parser = automation_subparsers.add_parser('edit', help='Edit an existing automation trigger')
|
|
971
|
+
auto_edit_parser.add_argument('--id', type=str, required=True, help='Automation ID')
|
|
972
|
+
auto_edit_parser.add_argument('--name', type=str, help='New name for the automation')
|
|
973
|
+
auto_edit_parser.add_argument('--event', type=str, action='append',
|
|
974
|
+
help='Event JSON object (repeatable)')
|
|
975
|
+
auto_edit_parser.add_argument('--action', type=str,
|
|
976
|
+
help='Action JSON (object or array of objects)')
|
|
977
|
+
auto_edit_parser.add_argument('--node-id', type=str, help='Node ID')
|
|
978
|
+
auto_edit_parser.add_argument('--location', type=str,
|
|
979
|
+
help='Location as lat,long')
|
|
980
|
+
auto_edit_parser.add_argument('--event-operator', type=str, choices=['AND', 'OR'],
|
|
981
|
+
help='Logical operator for multiple events (AND/OR)')
|
|
982
|
+
auto_edit_parser.add_argument('--retrigger', action='store_true', default=False,
|
|
983
|
+
help='Enable retriggering')
|
|
984
|
+
auto_edit_parser.add_argument('--no-retrigger', action='store_true', default=False,
|
|
985
|
+
help='Disable retriggering')
|
|
986
|
+
auto_edit_parser.add_argument('--enabled', action='store_true', default=False,
|
|
987
|
+
help='Enable the automation')
|
|
988
|
+
auto_edit_parser.add_argument('--disabled', action='store_true', default=False,
|
|
989
|
+
help='Disable the automation')
|
|
990
|
+
auto_edit_parser.add_argument('--metadata', type=str, help='Metadata as JSON string')
|
|
991
|
+
add_profile_argument(auto_edit_parser)
|
|
992
|
+
auto_edit_parser.set_defaults(func=automation_edit)
|
|
993
|
+
|
|
994
|
+
# automations remove
|
|
995
|
+
auto_remove_parser = automation_subparsers.add_parser('remove', help='Remove an automation trigger')
|
|
996
|
+
auto_remove_parser.add_argument('--id', type=str, required=True, help='Automation ID to remove')
|
|
997
|
+
add_profile_argument(auto_remove_parser)
|
|
998
|
+
auto_remove_parser.set_defaults(func=automation_remove)
|
|
999
|
+
|
|
1000
|
+
# automations get
|
|
1001
|
+
auto_get_parser = automation_subparsers.add_parser('get', help='Get automation triggers')
|
|
1002
|
+
auto_get_parser.add_argument('--id', type=str, help='Automation ID (omit to list all)')
|
|
1003
|
+
auto_get_parser.add_argument('--node-id', type=str, help='Filter by node ID')
|
|
1004
|
+
add_profile_argument(auto_get_parser)
|
|
1005
|
+
auto_get_parser.set_defaults(func=automation_get)
|
|
1006
|
+
|
|
912
1007
|
# Node Management (tags, metadata)
|
|
913
1008
|
node_parser = subparsers.add_parser('node',
|
|
914
1009
|
help='Manage node properties (tags, metadata)')
|
|
@@ -1018,6 +1113,31 @@ def main():
|
|
|
1018
1113
|
add_profile_argument(raw_api_parser)
|
|
1019
1114
|
raw_api_parser.set_defaults(func=raw_api_call)
|
|
1020
1115
|
|
|
1116
|
+
# Video Streaming
|
|
1117
|
+
stream_parser = subparsers.add_parser('stream',
|
|
1118
|
+
help='Stream video from a camera device')
|
|
1119
|
+
stream_parser.add_argument('nodeid',
|
|
1120
|
+
type=str,
|
|
1121
|
+
metavar='<nodeid>',
|
|
1122
|
+
help='Node ID for the camera device')
|
|
1123
|
+
stream_parser.add_argument('--output', '-o',
|
|
1124
|
+
type=str,
|
|
1125
|
+
metavar='<path>',
|
|
1126
|
+
help='Save video to file (MP4)')
|
|
1127
|
+
stream_parser.add_argument('--region',
|
|
1128
|
+
type=str,
|
|
1129
|
+
metavar='<region>',
|
|
1130
|
+
help='AWS region override')
|
|
1131
|
+
stream_parser.add_argument('--duration',
|
|
1132
|
+
type=int,
|
|
1133
|
+
metavar='<seconds>',
|
|
1134
|
+
help='Stream duration in seconds')
|
|
1135
|
+
stream_parser.add_argument('--stats-only',
|
|
1136
|
+
action='store_true',
|
|
1137
|
+
help='Show statistics only, no video display')
|
|
1138
|
+
add_profile_argument(stream_parser)
|
|
1139
|
+
stream_parser.set_defaults(func=stream_video)
|
|
1140
|
+
|
|
1021
1141
|
args = parser.parse_args()
|
|
1022
1142
|
|
|
1023
1143
|
if args.func is not None:
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: 2020-2025 Espressif Systems (Shanghai) CO LTD
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
5
|
+
from rmaker_lib.profile_utils import get_session_with_profile
|
|
6
|
+
import json
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def _handle_error(e, operation):
|
|
10
|
+
"""Helper function to handle errors and extract descriptions from API responses"""
|
|
11
|
+
error_msg = str(e)
|
|
12
|
+
try:
|
|
13
|
+
if hasattr(e, 'response') and e.response is not None:
|
|
14
|
+
resp = e.response.json()
|
|
15
|
+
if 'description' in resp:
|
|
16
|
+
error_msg = resp['description']
|
|
17
|
+
except Exception:
|
|
18
|
+
pass
|
|
19
|
+
print(f"Failed to {operation}: {error_msg}")
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def _parse_json(value, field_name):
|
|
23
|
+
"""Parse a JSON string, returning the parsed object or None on error."""
|
|
24
|
+
try:
|
|
25
|
+
return json.loads(value)
|
|
26
|
+
except Exception as e:
|
|
27
|
+
print(f"Invalid JSON for {field_name}: {e}")
|
|
28
|
+
return None
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _parse_location(location_str):
|
|
32
|
+
"""Parse 'lat,long' string into location dict."""
|
|
33
|
+
parts = location_str.split(',')
|
|
34
|
+
if len(parts) != 2:
|
|
35
|
+
print("Invalid location format. Use: lat,long (e.g., 18.521428,73.8544541)")
|
|
36
|
+
return None
|
|
37
|
+
return {"latitude": parts[0].strip(), "longitude": parts[1].strip()}
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def automation_add(vars=None):
|
|
41
|
+
try:
|
|
42
|
+
s = get_session_with_profile(vars or {})
|
|
43
|
+
name = vars['name']
|
|
44
|
+
event_type = vars['event_type']
|
|
45
|
+
event_jsons = vars['event']
|
|
46
|
+
action_json = vars['action']
|
|
47
|
+
node_id = vars.get('node_id')
|
|
48
|
+
location = vars.get('location')
|
|
49
|
+
event_operator = vars.get('event_operator')
|
|
50
|
+
retrigger = vars.get('retrigger', False)
|
|
51
|
+
metadata_arg = vars.get('metadata')
|
|
52
|
+
|
|
53
|
+
# Map 'params' to 'node_params' for the API
|
|
54
|
+
api_event_type = 'node_params' if event_type == 'params' else event_type
|
|
55
|
+
|
|
56
|
+
# Validate event_type-specific requirements
|
|
57
|
+
if event_type == 'params' and not node_id:
|
|
58
|
+
print("Error: --node-id is required when --event-type is 'params'")
|
|
59
|
+
return
|
|
60
|
+
if event_type in ('weather', 'daylight') and not location:
|
|
61
|
+
print(f"Error: --location is required when --event-type is '{event_type}'")
|
|
62
|
+
return
|
|
63
|
+
|
|
64
|
+
# Parse events
|
|
65
|
+
events = []
|
|
66
|
+
for ev in event_jsons:
|
|
67
|
+
parsed = _parse_json(ev, 'event')
|
|
68
|
+
if parsed is None:
|
|
69
|
+
return
|
|
70
|
+
events.append(parsed)
|
|
71
|
+
|
|
72
|
+
# Validate event_operator if multiple events
|
|
73
|
+
if len(events) > 1 and not event_operator:
|
|
74
|
+
print("Error: --event-operator (AND/OR) is required when multiple events are specified")
|
|
75
|
+
return
|
|
76
|
+
|
|
77
|
+
# Parse action
|
|
78
|
+
action = _parse_json(action_json, 'action')
|
|
79
|
+
if action is None:
|
|
80
|
+
return
|
|
81
|
+
if isinstance(action, dict):
|
|
82
|
+
actions = [action]
|
|
83
|
+
elif isinstance(action, list):
|
|
84
|
+
actions = action
|
|
85
|
+
else:
|
|
86
|
+
print("Error: --action must be a JSON object or array of objects")
|
|
87
|
+
return
|
|
88
|
+
|
|
89
|
+
# Build payload
|
|
90
|
+
payload = {
|
|
91
|
+
'name': name,
|
|
92
|
+
'event_type': api_event_type,
|
|
93
|
+
'events': events,
|
|
94
|
+
'actions': actions,
|
|
95
|
+
'retrigger': retrigger,
|
|
96
|
+
}
|
|
97
|
+
if node_id:
|
|
98
|
+
payload['node_id'] = node_id
|
|
99
|
+
if location:
|
|
100
|
+
loc = _parse_location(location)
|
|
101
|
+
if loc is None:
|
|
102
|
+
return
|
|
103
|
+
payload['location'] = loc
|
|
104
|
+
if event_operator:
|
|
105
|
+
payload['event_operator'] = event_operator.lower()
|
|
106
|
+
if metadata_arg:
|
|
107
|
+
metadata = _parse_json(metadata_arg, 'metadata')
|
|
108
|
+
if metadata is None:
|
|
109
|
+
return
|
|
110
|
+
payload['metadata'] = metadata
|
|
111
|
+
|
|
112
|
+
resp = s.create_automation(payload)
|
|
113
|
+
print("Automation created successfully:")
|
|
114
|
+
print(json.dumps(resp, indent=2))
|
|
115
|
+
except Exception as e:
|
|
116
|
+
_handle_error(e, "create automation")
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def automation_edit(vars=None):
|
|
120
|
+
try:
|
|
121
|
+
s = get_session_with_profile(vars or {})
|
|
122
|
+
automation_id = vars['id']
|
|
123
|
+
|
|
124
|
+
payload = {}
|
|
125
|
+
if vars.get('name'):
|
|
126
|
+
payload['name'] = vars['name']
|
|
127
|
+
if vars.get('node_id'):
|
|
128
|
+
payload['node_id'] = vars['node_id']
|
|
129
|
+
if vars.get('event'):
|
|
130
|
+
events = []
|
|
131
|
+
for ev in vars['event']:
|
|
132
|
+
parsed = _parse_json(ev, 'event')
|
|
133
|
+
if parsed is None:
|
|
134
|
+
return
|
|
135
|
+
events.append(parsed)
|
|
136
|
+
payload['events'] = events
|
|
137
|
+
if vars.get('action'):
|
|
138
|
+
action = _parse_json(vars['action'], 'action')
|
|
139
|
+
if action is None:
|
|
140
|
+
return
|
|
141
|
+
if isinstance(action, dict):
|
|
142
|
+
payload['actions'] = [action]
|
|
143
|
+
elif isinstance(action, list):
|
|
144
|
+
payload['actions'] = action
|
|
145
|
+
else:
|
|
146
|
+
print("Error: --action must be a JSON object or array of objects")
|
|
147
|
+
return
|
|
148
|
+
if vars.get('event_operator'):
|
|
149
|
+
payload['event_operator'] = vars['event_operator'].lower()
|
|
150
|
+
if vars.get('location'):
|
|
151
|
+
loc = _parse_location(vars['location'])
|
|
152
|
+
if loc is None:
|
|
153
|
+
return
|
|
154
|
+
payload['location'] = loc
|
|
155
|
+
if vars.get('metadata'):
|
|
156
|
+
metadata = _parse_json(vars['metadata'], 'metadata')
|
|
157
|
+
if metadata is None:
|
|
158
|
+
return
|
|
159
|
+
payload['metadata'] = metadata
|
|
160
|
+
|
|
161
|
+
# Handle retrigger/no-retrigger
|
|
162
|
+
if vars.get('retrigger'):
|
|
163
|
+
payload['retrigger'] = True
|
|
164
|
+
elif vars.get('no_retrigger'):
|
|
165
|
+
payload['retrigger'] = False
|
|
166
|
+
|
|
167
|
+
# Handle enabled/disabled
|
|
168
|
+
if vars.get('enabled'):
|
|
169
|
+
payload['enabled'] = True
|
|
170
|
+
elif vars.get('disabled'):
|
|
171
|
+
payload['enabled'] = False
|
|
172
|
+
|
|
173
|
+
if not payload:
|
|
174
|
+
print("No fields to update. Provide at least one option to edit.")
|
|
175
|
+
return
|
|
176
|
+
|
|
177
|
+
resp = s.update_automation(automation_id, payload)
|
|
178
|
+
print("Automation updated successfully:")
|
|
179
|
+
print(json.dumps(resp, indent=2))
|
|
180
|
+
except Exception as e:
|
|
181
|
+
_handle_error(e, "update automation")
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
def automation_remove(vars=None):
|
|
185
|
+
try:
|
|
186
|
+
s = get_session_with_profile(vars or {})
|
|
187
|
+
automation_id = vars['id']
|
|
188
|
+
resp = s.remove_automation(automation_id)
|
|
189
|
+
print("Automation removed successfully:")
|
|
190
|
+
print(json.dumps(resp, indent=2))
|
|
191
|
+
except Exception as e:
|
|
192
|
+
_handle_error(e, "remove automation")
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
def automation_get(vars=None):
|
|
196
|
+
try:
|
|
197
|
+
s = get_session_with_profile(vars or {})
|
|
198
|
+
automation_id = vars.get('id')
|
|
199
|
+
node_id = vars.get('node_id')
|
|
200
|
+
resp = s.get_automations(automation_id=automation_id, node_id=node_id)
|
|
201
|
+
|
|
202
|
+
if not resp:
|
|
203
|
+
print("No automations found.")
|
|
204
|
+
return
|
|
205
|
+
|
|
206
|
+
automations = resp.get('automation_trigger_actions', [])
|
|
207
|
+
if not automations:
|
|
208
|
+
print("No automations found.")
|
|
209
|
+
return
|
|
210
|
+
|
|
211
|
+
if automation_id:
|
|
212
|
+
print("Automation details:")
|
|
213
|
+
else:
|
|
214
|
+
print(f"Automations ({len(automations)}):")
|
|
215
|
+
print(json.dumps(automations, indent=2))
|
|
216
|
+
except Exception as e:
|
|
217
|
+
_handle_error(e, "get automations")
|
|
@@ -897,7 +897,7 @@ def list_sharing_details(node_id=None, primary_user=False, request_id=None, list
|
|
|
897
897
|
|
|
898
898
|
return node_json_resp
|
|
899
899
|
|
|
900
|
-
def add_user_to_share_nodes(nodes=None, user=None, profile_override=None):
|
|
900
|
+
def add_user_to_share_nodes(nodes=None, user=None, sub_role=None, primary=False, transfer=False, new_role=None, profile_override=None):
|
|
901
901
|
"""
|
|
902
902
|
Add user to share nodes
|
|
903
903
|
|
|
@@ -932,6 +932,14 @@ def add_user_to_share_nodes(nodes=None, user=None, profile_override=None):
|
|
|
932
932
|
api_input = {}
|
|
933
933
|
api_input['nodes'] = node_id_list
|
|
934
934
|
api_input['user_name'] = user
|
|
935
|
+
if sub_role is not None:
|
|
936
|
+
api_input['sub_role'] = sub_role
|
|
937
|
+
if primary:
|
|
938
|
+
api_input['primary'] = True
|
|
939
|
+
if transfer:
|
|
940
|
+
api_input['transfer'] = True
|
|
941
|
+
if new_role is not None:
|
|
942
|
+
api_input['new_role'] = new_role
|
|
935
943
|
log.debug("API data set: {}".format(api_input))
|
|
936
944
|
|
|
937
945
|
# API with profile-aware session
|
|
@@ -1116,7 +1124,7 @@ def node_sharing_ops(vars=None):
|
|
|
1116
1124
|
if action == 'add_user':
|
|
1117
1125
|
# Share nodes with user
|
|
1118
1126
|
print("Adding user to share node(s)")
|
|
1119
|
-
node_json_resp = add_user_to_share_nodes(nodes=vars['nodes'], user=vars['user'], profile_override=profile_override)
|
|
1127
|
+
node_json_resp = add_user_to_share_nodes(nodes=vars['nodes'], user=vars['user'], sub_role=vars.get('sub_role'), primary=vars.get('primary', False), transfer=vars.get('transfer', False), new_role=vars.get('new_role'), profile_override=profile_override)
|
|
1120
1128
|
|
|
1121
1129
|
# Print success response
|
|
1122
1130
|
if 'status' in node_json_resp and node_json_resp['status'].lower() == 'success':
|