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 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
- if api_key is None:
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 typing import List
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
- signal_values:list = list()
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 - Only one signal suppoerted")
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
- plt.clt() # to clear the terminal
64
- plt.cld() # to clear the data only
65
- y = list(map( lambda s: s['value'], list(x)))
66
- signal_values = signal_values + y
67
- if len(signal_values) > 1000:
68
- signal_values = signal_values[len(signal_values) - 1000:]
69
- plt.plot(signal_values)
70
- plt.sleep(0.001) # to add
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("remove", help="Stops and removes a broker from project")
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"Stopping broker {name}...", total=None)
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, help="Use this option to see only those that are beeing processed or are invalid"),
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", envvar="REMOTIVE_CLOUD_RECORDING_SESSION"),
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", envvar='REMOTIVE_CLOUD_RECORDING_SESSION'),
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
- recording_session: str = typer.Option(..., help="Recording session id that this file belongs to", envvar='REMOTIVE_CLOUD_RECORDING_SESSION'),
166
- project: str = typer.Option(..., help="Project ID", envvar='REMOTIVE_CLOUD_PROJECT')):
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(f'/api/project/{project}/files/recording/{recording_session}/recording-file/{recording_file_name}')
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 = typer.Argument(..., help="Path to valid recording to upload"),
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", envvar='REMOTIVE_CLOUD_RECORDING_SESSION'),
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 : "interfaces.json" in item, glob.iglob(directory + '**/**', recursive=True)))
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}", return_response=True)
232
- details=details_resp.json()
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 : x['name'] == broker_config_dir_name, existing_configs))
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(f'/api/project/{project}/files/recording/{recording_session}/configuration/{broker_config_dir_name}', quiet=True)
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
- { 'local_path' : item,
249
- 'remote_path' : f"/{broker_config_dir_name}{item.rsplit(broker_config_dir_name,1)[-1]}"} ,glob.iglob(directory + '**/*.*', recursive=True)))
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' : 'not_used',
256
- 'paths' : list(map(lambda x: x['remote_path'], file_infos))
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 = f'/api/project/{project}/files/recording/{recording_session}/configuration', return_response=True, body=json.dumps(json_request_upload_urls_req))
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)", total=len(file_infos))
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' : "application/x-www-form-urlencoded"
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", envvar='REMOTIVE_CLOUD_RECORDING_SESSION'),
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", envvar='REMOTIVE_CLOUD_RECORDING_SESSION'),
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
+ ![alt text](cli-plot.png "Cli plotting")
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=ib72yT0zAcmNmprm7Hw5jgjzXke-64KrWU3EgV04p1o,16696
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=BL6EBFyasI02eJtCfSBAVHd5YWu5oJaDdtNppmHlLdc,3838
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=eQxIG8qDRNmbXloFHHgqlbDT_7ixMIWQrwLeu8tfefk,3664
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=P8YOuEA4OasYnrGX-3ORhDyfnhsUpJnUaHIJ4i9gYnM,14818
21
- cli/cloud/rest_helper.py,sha256=ypmlyrL5ihaF5209uNOjCQX4HqoaBPI6gm74dHNKCQM,4246
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.1a34.dist-info/LICENSE,sha256=qDPP_yfuv1fF-u7EfexN-cN3M8aFgGVndGhGLovLKz0,608
29
- remotivelabs_cli-0.0.1a34.dist-info/METADATA,sha256=YGTF7bvio1Fuwz9H_AE-jvE5YDgeLXLXaAXQURI6vGU,861
30
- remotivelabs_cli-0.0.1a34.dist-info/WHEEL,sha256=d2fvjOD7sXsVzChCqf0Ty0JbHKBaLYwDbGQDwQTnJ50,88
31
- remotivelabs_cli-0.0.1a34.dist-info/entry_points.txt,sha256=lvDhPgagLqW_KTnLPCwKSqfYlEp-1uYVosRiPjsVj10,45
32
- remotivelabs_cli-0.0.1a34.dist-info/RECORD,,
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
-