remotivelabs-cli 0.0.1a34__py3-none-any.whl → 0.0.1a36__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.
- cli/broker/lib/broker.py +2 -1
- cli/broker/signals.py +55 -14
- cli/cloud/brokers.py +2 -2
- cli/cloud/recordings.py +55 -38
- cli/cloud/rest_helper.py +8 -3
- remotivelabs_cli-0.0.1a36.dist-info/METADATA +124 -0
- {remotivelabs_cli-0.0.1a34.dist-info → remotivelabs_cli-0.0.1a36.dist-info}/RECORD +10 -10
- remotivelabs_cli-0.0.1a34.dist-info/METADATA +0 -26
- {remotivelabs_cli-0.0.1a34.dist-info → remotivelabs_cli-0.0.1a36.dist-info}/LICENSE +0 -0
- {remotivelabs_cli-0.0.1a34.dist-info → remotivelabs_cli-0.0.1a36.dist-info}/WHEEL +0 -0
- {remotivelabs_cli-0.0.1a34.dist-info → remotivelabs_cli-0.0.1a36.dist-info}/entry_points.txt +0 -0
cli/broker/lib/broker.py
CHANGED
@@ -31,7 +31,8 @@ class Broker:
|
|
31
31
|
self.q = queue.Queue()
|
32
32
|
"""Main function, checking arguments passed to script, setting up stubs, configuration and starting Threads."""
|
33
33
|
# Setting up stubs and configuration
|
34
|
-
|
34
|
+
|
35
|
+
if api_key is None or api_key == "":
|
35
36
|
if url.startswith("https"):
|
36
37
|
self.intercept_channel = br.create_channel(url, None, settings.read_token())
|
37
38
|
# TODO - Temporary solution to print proper error message, remove ENV once api-key is gone
|
cli/broker/signals.py
CHANGED
@@ -1,19 +1,30 @@
|
|
1
1
|
import json
|
2
2
|
import os
|
3
3
|
import signal as os_signal
|
4
|
-
from
|
4
|
+
from datetime import time
|
5
|
+
from typing import List, TypedDict
|
5
6
|
import grpc
|
6
7
|
import plotext as plt
|
7
8
|
import typer
|
8
9
|
from rich import print as rich_rprint
|
10
|
+
import numbers
|
9
11
|
|
10
12
|
from .lib.broker import Broker
|
11
13
|
from .lib.errors import ErrorPrinter as err_printer
|
12
14
|
|
13
|
-
|
14
15
|
app = typer.Typer(help=help)
|
15
16
|
|
16
|
-
|
17
|
+
|
18
|
+
# signal_values:list = list()
|
19
|
+
|
20
|
+
|
21
|
+
class Signals(TypedDict):
|
22
|
+
name: str
|
23
|
+
signals: List
|
24
|
+
|
25
|
+
|
26
|
+
signal_values = {}
|
27
|
+
|
17
28
|
|
18
29
|
@app.command(help="List signals names on broker")
|
19
30
|
def signal_names(
|
@@ -38,6 +49,7 @@ def read_scripted_code_file(file_path: str) -> str:
|
|
38
49
|
print("File not found. Please check your file path.")
|
39
50
|
exit(1)
|
40
51
|
|
52
|
+
|
41
53
|
@app.command(help="Subscribe to signals")
|
42
54
|
def subscribe(
|
43
55
|
url: str = typer.Option(..., help="Broker URL", envvar='REMOTIVE_BROKER_URL'),
|
@@ -48,7 +60,8 @@ def subscribe(
|
|
48
60
|
envvar='REMOTIVE_BROKER_API_KEY'),
|
49
61
|
on_change_only: bool = typer.Option(default=False, help="Only get signal if value is changed"),
|
50
62
|
script: str = typer.Option(None, help="Supply a path to Lua script that to use for signal transformation"),
|
51
|
-
x_plot: bool = typer.Option(default=False, help="Experimental: Plot the signal in terminal
|
63
|
+
x_plot: bool = typer.Option(default=False, help="Experimental: Plot the signal in terminal. Note graphs are not aligned by time"),
|
64
|
+
x_plot_size:int = typer.Option(default=100, help="Experimental: how many points show for each plot")
|
52
65
|
# samples: int = typer.Option(default=0, he)
|
53
66
|
|
54
67
|
):
|
@@ -60,14 +73,43 @@ def subscribe(
|
|
60
73
|
|
61
74
|
def on_frame_plot(x):
|
62
75
|
global signal_values
|
63
|
-
|
64
|
-
plt.
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
plt.
|
70
|
-
|
76
|
+
|
77
|
+
plt.clt() # to clear the terminal
|
78
|
+
plt.cld() # to clear the data only
|
79
|
+
frames = list(x)
|
80
|
+
plt.clf()
|
81
|
+
plt.subplots(len(list(filter(lambda n: n.startswith("ts_"), signal_values.keys()))))
|
82
|
+
plt.theme("pro")
|
83
|
+
|
84
|
+
for frame in frames:
|
85
|
+
name = frame['name']
|
86
|
+
|
87
|
+
if not isinstance(frame['value'], numbers.Number):
|
88
|
+
# Skip non numberic values
|
89
|
+
# TODO - would exit and print info message if I knew how to
|
90
|
+
continue
|
91
|
+
|
92
|
+
y = [frame['value']]
|
93
|
+
t = [frame['timestamp_us']]
|
94
|
+
|
95
|
+
if name not in signal_values:
|
96
|
+
signal_values[name] = [None] * x_plot_size
|
97
|
+
signal_values[f"ts_{name}"] = [None] * x_plot_size
|
98
|
+
signal_values[name] = signal_values[name] + y
|
99
|
+
signal_values[f"ts_{name}"] = signal_values[f"ts_{name}"] + t
|
100
|
+
|
101
|
+
if len(signal_values[name]) > x_plot_size:
|
102
|
+
signal_values[name] = signal_values[name][len(signal_values[name]) - x_plot_size:]
|
103
|
+
|
104
|
+
if len(signal_values[f"ts_{name}"]) > x_plot_size:
|
105
|
+
signal_values[f"ts_{name}"] = signal_values[f"ts_{name}"][len(signal_values[f"ts_{name}"]) - x_plot_size:]
|
106
|
+
|
107
|
+
cnt = 1
|
108
|
+
for key in signal_values:
|
109
|
+
if not key.startswith("ts_"):
|
110
|
+
plt.subplot(cnt, 1).plot(signal_values[f"ts_{key}"], signal_values[key], label=key, color=cnt)
|
111
|
+
cnt = cnt + 1
|
112
|
+
plt.sleep(0.001) # to add
|
71
113
|
plt.show()
|
72
114
|
|
73
115
|
def on_frame_print(x):
|
@@ -97,10 +139,9 @@ def namespaces(
|
|
97
139
|
api_key: str = typer.Option(None, help="Cloud Broker API-KEY or access token",
|
98
140
|
envvar='REMOTIVE_BROKER_API_KEY')
|
99
141
|
):
|
100
|
-
|
101
142
|
try:
|
102
143
|
broker = Broker(url, api_key)
|
103
144
|
namespaces_json = broker.list_namespaces()
|
104
145
|
print(json.dumps(namespaces_json))
|
105
146
|
except grpc.RpcError as rpc_error:
|
106
|
-
err_printer.print_grpc_error(rpc_error)
|
147
|
+
err_printer.print_grpc_error(rpc_error)
|
cli/cloud/brokers.py
CHANGED
@@ -22,14 +22,14 @@ def describe(name: str, project: str = typer.Option(..., help="Project ID", envv
|
|
22
22
|
rest.handle_get(f"/api/project/{project}/brokers/{name}")
|
23
23
|
|
24
24
|
|
25
|
-
@app.command("
|
25
|
+
@app.command("delete", help="Stops and deletes a broker from project")
|
26
26
|
def stop(name: str, project: str = typer.Option(..., help="Project ID", envvar='REMOTIVE_CLOUD_PROJECT')):
|
27
27
|
with Progress(
|
28
28
|
SpinnerColumn(),
|
29
29
|
TextColumn("[progress.description]{task.description}"),
|
30
30
|
transient=True,
|
31
31
|
) as progress:
|
32
|
-
progress.add_task(description=f"
|
32
|
+
progress.add_task(description=f"Deleting broker {name}...", total=None)
|
33
33
|
rest.handle_delete(f"/api/project/{project}/brokers/{name}")
|
34
34
|
|
35
35
|
|
cli/cloud/recordings.py
CHANGED
@@ -18,8 +18,9 @@ def uid(p):
|
|
18
18
|
print(p)
|
19
19
|
return p['uid']
|
20
20
|
|
21
|
+
|
21
22
|
# to be used in options
|
22
|
-
#autocompletion=project_names)
|
23
|
+
# autocompletion=project_names)
|
23
24
|
def project_names():
|
24
25
|
r = requests.get(f'{rest.base_url}/api/bu/{rest.org}/project', headers=rest.headers)
|
25
26
|
# sys.stderr.write(r.text)
|
@@ -40,7 +41,8 @@ def project_names():
|
|
40
41
|
|
41
42
|
|
42
43
|
@app.command("list")
|
43
|
-
def listRecordings(is_processing: bool = typer.Option(default=False,
|
44
|
+
def listRecordings(is_processing: bool = typer.Option(default=False,
|
45
|
+
help="Use this option to see only those that are beeing processed or are invalid"),
|
44
46
|
project: str = typer.Option(..., help="Project ID", envvar='REMOTIVE_CLOUD_PROJECT')):
|
45
47
|
"""
|
46
48
|
List all recording sessions in a project. You can choose to see all valid recordings (default) or use
|
@@ -54,7 +56,6 @@ def listRecordings(is_processing: bool = typer.Option(default=False, help="Use t
|
|
54
56
|
rest.handle_get(f"/api/project/{project}/files/recording")
|
55
57
|
|
56
58
|
|
57
|
-
|
58
59
|
@app.command(help="Shows details about a specific recording in project")
|
59
60
|
def describe(recording_session: str = typer.Argument(..., help="Recording session id"),
|
60
61
|
|
@@ -72,10 +73,11 @@ def doStart(name: str, project: str, api_key: str, return_response: bool = False
|
|
72
73
|
|
73
74
|
|
74
75
|
@app.command(help="Plays all recording files or a single recording")
|
75
|
-
def play(recording_session: str = typer.Argument(..., help="Recording session id",
|
76
|
+
def play(recording_session: str = typer.Argument(..., help="Recording session id",
|
77
|
+
envvar="REMOTIVE_CLOUD_RECORDING_SESSION"),
|
76
78
|
broker: str = typer.Option(..., help="Broker name to play on"),
|
77
79
|
ensure_broker_started: bool = typer.Option(default=False, help="Ensure broker exists, start otherwise"),
|
78
|
-
broker_config_name: str = typer.Option("default", help="Specify a custom broker configuration to use"
|
80
|
+
broker_config_name: str = typer.Option("default", help="Specify a custom broker configuration to use"),
|
79
81
|
project: str = typer.Option(..., help="Project ID", envvar='REMOTIVE_CLOUD_PROJECT')):
|
80
82
|
with Progress(
|
81
83
|
SpinnerColumn(),
|
@@ -84,8 +86,10 @@ def play(recording_session: str = typer.Argument(..., help="Recording session id
|
|
84
86
|
) as progress:
|
85
87
|
rest.ensure_auth_token()
|
86
88
|
v = progress.add_task(description=f"Verifying broker {broker} exists...", total=100)
|
89
|
+
r = rest.handle_get(url=f'/api/project/{project}/brokers/{broker}',
|
90
|
+
return_response=True,
|
91
|
+
allow_status_codes=[404])
|
87
92
|
|
88
|
-
r = requests.get(f'{rest.base_url}/api/project/{project}/brokers/{broker}', headers=rest.headers, )
|
89
93
|
progress.update(v, advance=100.0)
|
90
94
|
if r.status_code == 404:
|
91
95
|
if ensure_broker_started:
|
@@ -108,7 +112,7 @@ def play(recording_session: str = typer.Argument(..., help="Recording session id
|
|
108
112
|
# rest.handle_get(f"/api/project/{project}/files/recording/{recording_session}/upload",
|
109
113
|
# params={'brokerName': broker})
|
110
114
|
# else:
|
111
|
-
broker_config_query=""
|
115
|
+
broker_config_query = ""
|
112
116
|
if (broker_config_name != "default"):
|
113
117
|
broker_config_query = f"?brokerConfigName={broker_config_name}"
|
114
118
|
|
@@ -119,7 +123,8 @@ def play(recording_session: str = typer.Argument(..., help="Recording session id
|
|
119
123
|
@app.command(help="Downloads the specified recording file to disk")
|
120
124
|
def download_recording_file(
|
121
125
|
recording_file_name: str = typer.Argument(..., help="Recording file to download"),
|
122
|
-
recording_session: str = typer.Option(..., help="Recording session id that this file belongs to",
|
126
|
+
recording_session: str = typer.Option(..., help="Recording session id that this file belongs to",
|
127
|
+
envvar='REMOTIVE_CLOUD_RECORDING_SESSION'),
|
123
128
|
project: str = typer.Option(..., help="Project ID", envvar='REMOTIVE_CLOUD_PROJECT')):
|
124
129
|
with Progress(
|
125
130
|
SpinnerColumn(),
|
@@ -162,16 +167,20 @@ def delete(recording_session: str = typer.Argument(..., help="Recording session
|
|
162
167
|
|
163
168
|
@app.command(name="delete-recording-file")
|
164
169
|
def delete_recording_file(recording_file_name: str = typer.Argument(..., help="Recording file to download"),
|
165
|
-
|
166
|
-
|
170
|
+
recording_session: str = typer.Option(...,
|
171
|
+
help="Recording session id that this file belongs to",
|
172
|
+
envvar='REMOTIVE_CLOUD_RECORDING_SESSION'),
|
173
|
+
project: str = typer.Option(..., help="Project ID", envvar='REMOTIVE_CLOUD_PROJECT')):
|
167
174
|
"""
|
168
175
|
Deletes the specified recording file
|
169
176
|
|
170
177
|
"""
|
171
|
-
rest.handle_delete(
|
178
|
+
rest.handle_delete(
|
179
|
+
f'/api/project/{project}/files/recording/{recording_session}/recording-file/{recording_file_name}')
|
180
|
+
|
172
181
|
|
173
182
|
@app.command()
|
174
|
-
def upload(path: str
|
183
|
+
def upload(path: str = typer.Argument(..., help="Path to valid recording to upload"),
|
175
184
|
project: str = typer.Option(..., help="Project ID", envvar='REMOTIVE_CLOUD_PROJECT')):
|
176
185
|
with Progress(
|
177
186
|
SpinnerColumn(),
|
@@ -193,10 +202,12 @@ def upload(path: str = typer.Argument(..., help="Path to valid recording to upl
|
|
193
202
|
else:
|
194
203
|
print(r.text)
|
195
204
|
|
205
|
+
|
196
206
|
@app.command()
|
197
207
|
def upload_broker_configuration(
|
198
|
-
directory:str = typer.Argument(..., help="Configuration directory"),
|
199
|
-
recording_session: str = typer.Option(..., help="Recording session id",
|
208
|
+
directory: str = typer.Argument(..., help="Configuration directory"),
|
209
|
+
recording_session: str = typer.Option(..., help="Recording session id",
|
210
|
+
envvar='REMOTIVE_CLOUD_RECORDING_SESSION'),
|
200
211
|
project: str = typer.Option(..., help="Project ID", envvar='REMOTIVE_CLOUD_PROJECT'),
|
201
212
|
overwrite: bool = typer.Option(False, help="Overwrite existing configuration if it exists")
|
202
213
|
):
|
@@ -214,7 +225,7 @@ def upload_broker_configuration(
|
|
214
225
|
# List files in specified directory. Look for interfaces.json and use that directory where this is located
|
215
226
|
# as configuration home directory
|
216
227
|
#
|
217
|
-
files = list(filter(lambda item
|
228
|
+
files = list(filter(lambda item: "interfaces.json" in item, glob.iglob(directory + '**/**', recursive=True)))
|
218
229
|
if len(files) == 0:
|
219
230
|
sys.stderr.write("No interfaces.json found in directory, this file is required")
|
220
231
|
raise typer.Exit(1)
|
@@ -227,15 +238,18 @@ def upload_broker_configuration(
|
|
227
238
|
# Get the current details about broker configurations to see if a config with this
|
228
239
|
# name already exists
|
229
240
|
#
|
230
|
-
task=progress.add_task(description=f"Preparing upload of {broker_config_dir_name}", total=1)
|
231
|
-
details_resp=rest.handle_get(f"/api/project/{project}/files/recording/{recording_session}",
|
232
|
-
|
241
|
+
task = progress.add_task(description=f"Preparing upload of {broker_config_dir_name}", total=1)
|
242
|
+
details_resp = rest.handle_get(f"/api/project/{project}/files/recording/{recording_session}",
|
243
|
+
return_response=True)
|
244
|
+
details = details_resp.json()
|
233
245
|
existing_configs = details['brokerConfigurations']
|
234
246
|
if (len(existing_configs) > 0):
|
235
|
-
data=list(filter(lambda x
|
247
|
+
data = list(filter(lambda x: x['name'] == broker_config_dir_name, existing_configs))
|
236
248
|
if len(data) > 0:
|
237
249
|
if (overwrite):
|
238
|
-
rest.handle_delete(
|
250
|
+
rest.handle_delete(
|
251
|
+
f'/api/project/{project}/files/recording/{recording_session}/configuration/{broker_config_dir_name}',
|
252
|
+
quiet=True)
|
239
253
|
else:
|
240
254
|
sys.stderr.write("Broker configuration already exists, use --overwrite to replace\n")
|
241
255
|
raise typer.Exit(1)
|
@@ -244,26 +258,29 @@ def upload_broker_configuration(
|
|
244
258
|
# From the list of files, create a tuple of local_path to the actual file
|
245
259
|
# and a remote path as it should be stored in cloud
|
246
260
|
#
|
247
|
-
file_infos = list(map(lambda item
|
248
|
-
|
249
|
-
|
261
|
+
file_infos = list(map(lambda item:
|
262
|
+
{'local_path': item,
|
263
|
+
'remote_path': f"/{broker_config_dir_name}{item.rsplit(broker_config_dir_name, 1)[-1]}"},
|
264
|
+
glob.iglob(directory + '**/*.*', recursive=True)))
|
250
265
|
|
251
266
|
#
|
252
267
|
# convert this remote paths and ask cloud to prepare upload urls for those
|
253
268
|
#
|
254
269
|
json_request_upload_urls_req = {
|
255
|
-
'name'
|
256
|
-
'paths'
|
270
|
+
'name': 'not_used',
|
271
|
+
'paths': list(map(lambda x: x['remote_path'], file_infos))
|
257
272
|
}
|
258
273
|
|
259
|
-
response = rest.handle_put(url
|
274
|
+
response = rest.handle_put(url=f'/api/project/{project}/files/recording/{recording_session}/configuration',
|
275
|
+
return_response=True, body=json.dumps(json_request_upload_urls_req))
|
260
276
|
if (response.status_code != 200):
|
261
277
|
print(f'Failed to prepare configuration upload')
|
262
278
|
print(f'{response.text} - {response.status_code}')
|
263
279
|
raise typer.Exit(1)
|
264
280
|
progress.update(task, advance=1)
|
265
281
|
|
266
|
-
task=progress.add_task(description=f"Uploading {broker_config_dir_name} ({len(file_infos)} files)",
|
282
|
+
task = progress.add_task(description=f"Uploading {broker_config_dir_name} ({len(file_infos)} files)",
|
283
|
+
total=len(file_infos))
|
267
284
|
|
268
285
|
#
|
269
286
|
# Upload urls is a remote_path : upload_url dict
|
@@ -273,12 +290,12 @@ def upload_broker_configuration(
|
|
273
290
|
|
274
291
|
# For each file - upload
|
275
292
|
for file in file_infos:
|
276
|
-
key=file['remote_path']
|
277
|
-
path=file['local_path']
|
278
|
-
url=upload_urls[key]
|
279
|
-
upload_task=progress.add_task(description=f"Uploading {key}", total=1)
|
280
|
-
headers={
|
281
|
-
'Content-Type'
|
293
|
+
key = file['remote_path']
|
294
|
+
path = file['local_path']
|
295
|
+
url = upload_urls[key]
|
296
|
+
upload_task = progress.add_task(description=f"Uploading {key}", total=1)
|
297
|
+
headers = {
|
298
|
+
'Content-Type': "application/x-www-form-urlencoded"
|
282
299
|
}
|
283
300
|
r = requests.put(url, open(path, 'rb'), headers=headers)
|
284
301
|
progress.update(task, advance=1)
|
@@ -292,11 +309,11 @@ def upload_broker_configuration(
|
|
292
309
|
print(f"Successfully uploaded broker configuration {broker_config_dir_name}")
|
293
310
|
|
294
311
|
|
295
|
-
|
296
312
|
@app.command(help="Downloads the specified broker configuration directory as zip file")
|
297
313
|
def download_configuration(
|
298
314
|
broker_config_name: str = typer.Argument(..., help="Broker config name"),
|
299
|
-
recording_session: str = typer.Option(..., help="Recording session id",
|
315
|
+
recording_session: str = typer.Option(..., help="Recording session id",
|
316
|
+
envvar='REMOTIVE_CLOUD_RECORDING_SESSION'),
|
300
317
|
project: str = typer.Option(..., help="Project ID", envvar='REMOTIVE_CLOUD_PROJECT')
|
301
318
|
):
|
302
319
|
rest.ensure_auth_token()
|
@@ -311,18 +328,18 @@ def download_configuration(
|
|
311
328
|
open(filename, 'wb').write(r.content)
|
312
329
|
print(f'Downloaded file {filename}')
|
313
330
|
|
331
|
+
|
314
332
|
@app.command(help="Downloads the specified broker configuration directory as zip file")
|
315
333
|
def delete_configuration(
|
316
334
|
broker_config_name: str = typer.Argument(..., help="Broker config name"),
|
317
|
-
recording_session: str = typer.Option(..., help="Recording session id",
|
335
|
+
recording_session: str = typer.Option(..., help="Recording session id",
|
336
|
+
envvar='REMOTIVE_CLOUD_RECORDING_SESSION'),
|
318
337
|
project: str = typer.Option(..., help="Project ID", envvar='REMOTIVE_CLOUD_PROJECT')
|
319
338
|
):
|
320
|
-
|
321
339
|
rest.handle_delete(
|
322
340
|
url=f"/api/project/{project}/files/recording/{recording_session}/configuration/{broker_config_name}")
|
323
341
|
|
324
342
|
|
325
|
-
|
326
343
|
def get_filename_from_cd(cd):
|
327
344
|
"""
|
328
345
|
Get filename from content-disposition
|
cli/cloud/rest_helper.py
CHANGED
@@ -4,6 +4,7 @@ import requests
|
|
4
4
|
import os
|
5
5
|
import json
|
6
6
|
import logging
|
7
|
+
from typing import List
|
7
8
|
from pathlib import Path
|
8
9
|
from os.path import exists
|
9
10
|
import typer
|
@@ -64,14 +65,14 @@ def ensure_auth_token():
|
|
64
65
|
}
|
65
66
|
|
66
67
|
|
67
|
-
def handle_get(url, params=None, return_response: bool = False):
|
68
|
+
def handle_get(url, params=None, return_response: bool = False, allow_status_codes=None):
|
68
69
|
if params is None:
|
69
70
|
params = {}
|
70
71
|
ensure_auth_token()
|
71
72
|
r = requests.get(f'{base_url}{url}', headers=headers, params=params)
|
72
73
|
|
73
74
|
if return_response:
|
74
|
-
check_api_result(r)
|
75
|
+
check_api_result(r, allow_status_codes)
|
75
76
|
return r
|
76
77
|
print_api_result(r)
|
77
78
|
|
@@ -85,8 +86,12 @@ def has_access(url, params={}):
|
|
85
86
|
return True
|
86
87
|
|
87
88
|
|
88
|
-
def check_api_result(response):
|
89
|
+
def check_api_result(response, allow_status_codes: List[int] = None):
|
90
|
+
|
89
91
|
if response.status_code > 299:
|
92
|
+
|
93
|
+
if allow_status_codes is not None and response.status_code in allow_status_codes:
|
94
|
+
return
|
90
95
|
err_console.print(f':boom: [bold red]Got status code[/bold red]: {response.status_code}')
|
91
96
|
if response.status_code == 401:
|
92
97
|
err_console.print("Your token has expired, please login again")
|
@@ -0,0 +1,124 @@
|
|
1
|
+
Metadata-Version: 2.1
|
2
|
+
Name: remotivelabs-cli
|
3
|
+
Version: 0.0.1a36
|
4
|
+
Summary:
|
5
|
+
Author: Johan Rask
|
6
|
+
Author-email: johan.rask@remotivelabs.com
|
7
|
+
Requires-Python: >=3.9,<4.0
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
9
|
+
Classifier: Programming Language :: Python :: 3.9
|
10
|
+
Classifier: Programming Language :: Python :: 3.10
|
11
|
+
Classifier: Programming Language :: Python :: 3.11
|
12
|
+
Requires-Dist: plotext (>=5.2,<6.0)
|
13
|
+
Requires-Dist: pyjwt (>=2.6,<3.0)
|
14
|
+
Requires-Dist: remotivelabs-broker (>=0.1.12)
|
15
|
+
Requires-Dist: rich (>=13.6.0,<13.7.0)
|
16
|
+
Requires-Dist: typer (>=0.9.0,<0.10.0)
|
17
|
+
Requires-Dist: websocket-client (>=1.6,<2.0)
|
18
|
+
Requires-Dist: zeroconf (>=0.119.0,<0.120.0)
|
19
|
+
Description-Content-Type: text/markdown
|
20
|
+
|
21
|
+
# RemotiveLabs - CLI
|
22
|
+
|
23
|
+
Use this CLI with our cloud and broker as a compliment to code and web tools.
|
24
|
+
|
25
|
+
Read more at https://docs.remotivelabs.com/docs/cloud-cli/Installation
|
26
|
+
|
27
|
+
## Cloud and broker API
|
28
|
+
|
29
|
+
You can use our CLI against both cloud and broker.
|
30
|
+
|
31
|
+
## Cloud
|
32
|
+
|
33
|
+
Here summary of what you can do with the cli, for a complete list of cloud features
|
34
|
+
visit https://docs.remotivelabs.com/docs/category/remotivecloud/
|
35
|
+
|
36
|
+
The CLI does not currently support everything but we are working on having them in pair.
|
37
|
+
|
38
|
+
* remotive cloud auth
|
39
|
+
* Login / Logout
|
40
|
+
* Manage personal and service account tokens
|
41
|
+
|
42
|
+
* remotive cloud brokers
|
43
|
+
* Create broker
|
44
|
+
* Delete broker
|
45
|
+
* List brokers
|
46
|
+
* View broker logs
|
47
|
+
|
48
|
+
* remotive cloud licenses
|
49
|
+
* View physical broker licenses for your organisation
|
50
|
+
|
51
|
+
* remotive cloud recordings
|
52
|
+
* Upload recording
|
53
|
+
* Play recording
|
54
|
+
* List recordings
|
55
|
+
* Download recordings
|
56
|
+
* Upload custom configuration (i.e signal transformation)
|
57
|
+
* Download custom configurations
|
58
|
+
* Delete recordings and configurations
|
59
|
+
|
60
|
+
* remotive cloud signal-databases
|
61
|
+
* Upload
|
62
|
+
* Download
|
63
|
+
* Delete
|
64
|
+
|
65
|
+
* remotive cloud projects
|
66
|
+
* Create
|
67
|
+
* Delete
|
68
|
+
* List
|
69
|
+
|
70
|
+
* remotve cloud service-accounts
|
71
|
+
* Create
|
72
|
+
* Delete
|
73
|
+
* List
|
74
|
+
|
75
|
+
|
76
|
+
### Broker
|
77
|
+
|
78
|
+
remotive cloud auth
|
79
|
+
|
80
|
+
## Subscribe to signals
|
81
|
+
|
82
|
+
Output from running subscribe against our demo. You can visit https://demoo.remotivelabs.com
|
83
|
+
to start a broker and subscribe to - from the demo you can copy/paste the exact command to run.
|
84
|
+
|
85
|
+
```
|
86
|
+
remotive broker signals subscribe \
|
87
|
+
--namespace VehicleBus \
|
88
|
+
--signal ID257DIspeed.DI_vehicleSpeed \
|
89
|
+
--signal ID129SteeringAngle.SteeringAngle129 \
|
90
|
+
--url https://some_url --api-key some-api-key
|
91
|
+
```
|
92
|
+
|
93
|
+
```json
|
94
|
+
[{"timestamp_us": 1663574225650092, "name": "ID129SteeringAngle.SteeringAngle129", "value": -363.0}, {"timestamp_us": 1663574225650092,
|
95
|
+
"name": "ID129SteeringAngle", "value": "0xcb2cd251fe1fff3f"}]
|
96
|
+
[{"timestamp_us": 1663574225658703, "name": "ID257DIspeed.DI_vehicleSpeed", "value": 7.200000000000003}, {"timestamp_us": 1663574225658703,
|
97
|
+
"name": "ID257DIspeed", "value": "0xf3e9240802701201"}]
|
98
|
+
[{"timestamp_us": 1663574225658708, "name": "ID129SteeringAngle.SteeringAngle129", "value": -363.0}, {"timestamp_us": 1663574225658708,
|
99
|
+
"name": "ID129SteeringAngle", "value": "0xd92dd251fe1fff3f"}]
|
100
|
+
[{"timestamp_us": 1663574225664791, "name": "ID129SteeringAngle.SteeringAngle129", "value": -363.0}, {"timestamp_us": 1663574225664791,
|
101
|
+
"name": "ID129SteeringAngle", "value": "0x062ed251fe1fff3f"}]
|
102
|
+
[{"timestamp_us": 1663574225674805, "name": "ID129SteeringAngle.SteeringAngle129", "value": -363.0}, {"timestamp_us": 1663574225674805,
|
103
|
+
"name": "ID129SteeringAngle", "value": "0xf72fd251fe1fff3f"}]
|
104
|
+
[{"timestamp_us": 1663574225678242, "name": "ID257DIspeed.DI_vehicleSpeed", "value": 7.200000000000003}, {"timestamp_us": 1663574225678242,
|
105
|
+
"name": "ID257DIspeed", "value": "0xf4ea240802701201"}]
|
106
|
+
[{"timestamp_us": 1663574225684858, "name": "ID129SteeringAngle.SteeringAngle129", "value": -363.0}, {"timestamp_us": 1663574225684858,
|
107
|
+
"name": "ID129SteeringAngle", "value": "0xbf20d251ff1fff3f"}]
|
108
|
+
```
|
109
|
+
|
110
|
+
## Subscribe with terminal plotting
|
111
|
+
|
112
|
+
To just make sure that your signals make sense you can plot them in terminal.
|
113
|
+
|
114
|
+
```
|
115
|
+
remotive broker signals subscribe \
|
116
|
+
--namespace VehicleBus \
|
117
|
+
--signal ID257DIspeed.DI_vehicleSpeed \
|
118
|
+
--signal ID129SteeringAngle.SteeringAngle129 \
|
119
|
+
--url https://some_url --api-key some-api-key \
|
120
|
+
--x-plot --x-plot-size 1000
|
121
|
+
```
|
122
|
+
|
123
|
+

|
124
|
+
|
@@ -4,29 +4,29 @@ cli/broker/brokers.py,sha256=6O4AMJpio3Zunzq8ySKyFpU_nPZnsPQ02aLFyQbwhgY,5377
|
|
4
4
|
cli/broker/export.py,sha256=LSxDojpOgy4hRbXM5H2l_NtQ7DVtOGrvrhfwZfKhFOs,3930
|
5
5
|
cli/broker/files.py,sha256=K8P6eOdKwBYLXV3CO-1eHUD41fniEWGd6oYtKWVfEbg,4331
|
6
6
|
cli/broker/lib/__about__.py,sha256=GLOW8iEx5xn9rbJvxUH3elZiLi47SAWamMjdJTd52k0,141
|
7
|
-
cli/broker/lib/broker.py,sha256=
|
7
|
+
cli/broker/lib/broker.py,sha256=aDfkZLNAkUzkaa4GKBppbXAwl2wSi3jUVTQKxyT1m6I,16714
|
8
8
|
cli/broker/lib/errors.py,sha256=lmQjciWmc_xZVrDYQk07MaoLrwnY0PcyIwNmODYGAtg,1318
|
9
9
|
cli/broker/playback.py,sha256=sn6ctTw01wvFM6fSr2CXynzFm2ZxGAYUY8784gT4wGg,5124
|
10
10
|
cli/broker/record.py,sha256=LkemnrHEaWEqSKgxa0X2wAfg1gS5OTcqfo77Jv8K-Jc,1459
|
11
11
|
cli/broker/scripting.py,sha256=ZPzxiKqoo2n7cq6S5UpXSk-K2aW4L-9dDGP7wNocrzA,2584
|
12
|
-
cli/broker/signals.py,sha256=
|
12
|
+
cli/broker/signals.py,sha256=IK1M1FkArkkOOJYnZPYJXnOiV1gwJ4zYmjww-6TrjKw,5244
|
13
13
|
cli/cloud/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
14
14
|
cli/cloud/auth.py,sha256=MKYDjYxAUBXivulJG8_RwMJUnMYNfxsKFRJaQmqSQBs,3487
|
15
15
|
cli/cloud/auth_tokens.py,sha256=HRC7N6O9FfS1wwIrQFYciIS0jKzhEIXhYeScZC4c1vo,3508
|
16
|
-
cli/cloud/brokers.py,sha256=
|
16
|
+
cli/cloud/brokers.py,sha256=EPjMnJWd7c-XEZYM6PbQJJTqm7IvcApU2LkggEL7tcc,3664
|
17
17
|
cli/cloud/cloud_cli.py,sha256=un7h49FbIf-IrW_51cTx2CyBK7pUg4A2zs768p9sxN8,1348
|
18
18
|
cli/cloud/configs.py,sha256=2qPP4XxVO4deVT0srdP4FN6IRj4Ig4i9229thtfO710,3507
|
19
19
|
cli/cloud/projects.py,sha256=w5Oqie80e59XrMNiIxIUIrlt3frYOyOpCbalkqZR7RQ,1366
|
20
|
-
cli/cloud/recordings.py,sha256=
|
21
|
-
cli/cloud/rest_helper.py,sha256=
|
20
|
+
cli/cloud/recordings.py,sha256=mGwKp-c-E5gGGbqaD4lkB-dp1B_C0gmTDMjvZchpEA0,15561
|
21
|
+
cli/cloud/rest_helper.py,sha256=QWU_7-0f7Ca9pU26N8BJ9W8-1zI8QgFEUCra_FXrSzQ,4465
|
22
22
|
cli/cloud/service_account_tokens.py,sha256=24GebX1JE3ATHfUGSDTZzcH3qmeJ9x34VSpJYGNX_hM,2322
|
23
23
|
cli/cloud/service_accounts.py,sha256=jpiSuteew_9hz0-dtLbLfavM9Bg6Zs2wTbS2a-4FVwM,1630
|
24
24
|
cli/remotive.py,sha256=y1xtdspjpunFL0MBsrV3uetUkN19VGEJF_KqFuTey34,1164
|
25
25
|
cli/requirements.txt,sha256=Tjpv2HSAPemgKC-eJbwDw-gvAdklfJ18LixRcwzvQIU,78
|
26
26
|
cli/settings.py,sha256=mDdfIeZNepsFGga2rI49DP63pqMNicRQFFurYIOtOSo,783
|
27
27
|
cli/test/test_simple.py,sha256=c60_dg5EmhNVmBC6rDcDP-tvKJCBqjIA2Z5Ym9ums4M,63
|
28
|
-
remotivelabs_cli-0.0.
|
29
|
-
remotivelabs_cli-0.0.
|
30
|
-
remotivelabs_cli-0.0.
|
31
|
-
remotivelabs_cli-0.0.
|
32
|
-
remotivelabs_cli-0.0.
|
28
|
+
remotivelabs_cli-0.0.1a36.dist-info/LICENSE,sha256=qDPP_yfuv1fF-u7EfexN-cN3M8aFgGVndGhGLovLKz0,608
|
29
|
+
remotivelabs_cli-0.0.1a36.dist-info/METADATA,sha256=a9y3E4SSZWh0GxEKZJdIA-W7CAdQ7WF_EFsqAeEiL2g,4191
|
30
|
+
remotivelabs_cli-0.0.1a36.dist-info/WHEEL,sha256=d2fvjOD7sXsVzChCqf0Ty0JbHKBaLYwDbGQDwQTnJ50,88
|
31
|
+
remotivelabs_cli-0.0.1a36.dist-info/entry_points.txt,sha256=lvDhPgagLqW_KTnLPCwKSqfYlEp-1uYVosRiPjsVj10,45
|
32
|
+
remotivelabs_cli-0.0.1a36.dist-info/RECORD,,
|
@@ -1,26 +0,0 @@
|
|
1
|
-
Metadata-Version: 2.1
|
2
|
-
Name: remotivelabs-cli
|
3
|
-
Version: 0.0.1a34
|
4
|
-
Summary:
|
5
|
-
Author: Johan Rask
|
6
|
-
Author-email: johan.rask@remotivelabs.com
|
7
|
-
Requires-Python: >=3.9,<4.0
|
8
|
-
Classifier: Programming Language :: Python :: 3
|
9
|
-
Classifier: Programming Language :: Python :: 3.9
|
10
|
-
Classifier: Programming Language :: Python :: 3.10
|
11
|
-
Classifier: Programming Language :: Python :: 3.11
|
12
|
-
Requires-Dist: plotext (>=5.2.8)
|
13
|
-
Requires-Dist: pyjwt (>=2.6.0,<3.0.0)
|
14
|
-
Requires-Dist: remotivelabs-broker (>=0.1.8)
|
15
|
-
Requires-Dist: rich (>=12.6.0,<13.0.0)
|
16
|
-
Requires-Dist: typer (>=0.6.1,<0.7.0)
|
17
|
-
Requires-Dist: websocket-client (>=1.6.1,<2.0.0)
|
18
|
-
Requires-Dist: zeroconf (>=0.64.1,<0.65.0)
|
19
|
-
Description-Content-Type: text/markdown
|
20
|
-
|
21
|
-
# RemotiveLabs - CLI
|
22
|
-
|
23
|
-
Use this CLI with our cloud and broker as a compliment to code and web tools.
|
24
|
-
|
25
|
-
Read more at https://docs.remotivelabs.com/docs/cloud-cli/Installation
|
26
|
-
|
File without changes
|
File without changes
|
{remotivelabs_cli-0.0.1a34.dist-info → remotivelabs_cli-0.0.1a36.dist-info}/entry_points.txt
RENAMED
File without changes
|