remotivelabs-cli 0.0.14__py3-none-any.whl → 0.0.16__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/export.py CHANGED
@@ -9,7 +9,7 @@ import typer
9
9
 
10
10
  from cli.errors import ErrorPrinter
11
11
 
12
- from .lib.broker import Broker
12
+ from .lib.broker import Broker, SubscribableSignal
13
13
 
14
14
  app = typer.Typer(
15
15
  rich_markup_mode="rich",
@@ -24,8 +24,8 @@ but more formats will come soon
24
24
  def influxdb(
25
25
  url: str = typer.Option(..., help="Broker URL", envvar="REMOTIVE_BROKER_URL"),
26
26
  api_key: str = typer.Option(None, help="Cloud Broker API-KEY", envvar="REMOTIVE_BROKER_API_KEY"),
27
- signal: List[str] = typer.Option(..., help="List of signal names to subscribe to"),
28
- namespace: str = typer.Option(..., help="Cloud Broker API-KEY or access token", envvar="REMOTIVE_BROKER_API_KEY"),
27
+ signal: List[str] = typer.Option(..., help="List of signal names to subscribe to in format namespace:signal_name"),
28
+ # namespace: str = typer.Option(..., help="Cloud Broker API-KEY or access token", envvar="REMOTIVE_BROKER_API_KEY"),
29
29
  on_change_only: bool = typer.Option(default=False, help="Only get signal if value is changed"),
30
30
  output: str = typer.Option(None, help="Write results to file, defaults to stdout"),
31
31
  ):
@@ -37,12 +37,12 @@ def influxdb(
37
37
 
38
38
  Export:
39
39
  remotive broker export influxdb --url [URL] --output signals.influx --namespace VehicleBus \\
40
- --signal Control.SteeringWheel_Position --signal Control.Accelerator_PedalPosition \\
41
- --signal GpsPosition.GPS_Longitude --signal GpsPosition.GPS_Latitude
40
+ --signal vehiclebus:Control.SteeringWheel_Position --signal Control.Accelerator_PedalPosition \\
41
+ --signal vehiclebus:GpsPosition.GPS_Longitude --signal vehiclebus:GpsPosition.GPS_Latitude
42
42
 
43
43
  Output:
44
- Control, SteeringWheel_Position=1.0,Accelerator_PedalPosition=0,Speed=0 1664787032944374000
45
- GpsPosition, GPS_Longitude=12.982076,GPS_Latitude=55.618748 1664787032948256000
44
+ Control, namespace:vehiclebus SteeringWheel_Position=1.0,Accelerator_PedalPosition=0,Speed=0 1664787032944374000
45
+ GpsPosition, namespace:vehiclebus GPS_Longitude=12.982076,GPS_Latitude=55.618748 1664787032948256000
46
46
 
47
47
  Import:
48
48
  influx write --org myorg -b my-bucket -p ns --format=lp -f signals.influx
@@ -62,10 +62,12 @@ def influxdb(
62
62
  signals = list(x)
63
63
  if len(signals) == 0:
64
64
  return
65
-
66
- frame_name = signals[0]["name"].split(".")[0]
67
- signals_str = ",".join(list(map(lambda s: f'{s["name"].split(".")[1]}={s["value"]}', signals)))
68
- influx_lp = f"{frame_name},namespace={namespace} {signals_str} {round(signals[0]['timestamp_us'] * 1000)}"
65
+ sig: str = signals[0]["name"].rpartition(".")[-1]
66
+ frame = signals[0]["name"].rsplit(".", 1)[0]
67
+ # frame_name = signals[0]["name"].split(".")[1]
68
+ namespace = signals[0]["namespace"]
69
+ signals_str = ",".join(list(map(lambda s: f'{sig}={s["value"]}', signals)))
70
+ influx_lp = f"{frame},namespace={namespace} {signals_str} {round(signals[0]['timestamp_us'] * 1000)}"
69
71
  if output is not None:
70
72
  f.write(f"{influx_lp}\n")
71
73
  else:
@@ -104,7 +106,17 @@ def influxdb(
104
106
  # print(namespace)
105
107
  # signals2 = list(map( lambda s: s['signal'], broker.list_signal_names2(namespace)))
106
108
  try:
109
+
110
+ def to_subscribable_signal(sig: str):
111
+ arr = sig.split(":")
112
+ if len(arr) != 2:
113
+ ErrorPrinter.print_hint(f"--signal must have format namespace:signal ({sig})")
114
+ exit(1)
115
+
116
+ return SubscribableSignal(namespace=arr[0], name=arr[1])
117
+
118
+ signals_to_subscribe_to = list(map(to_subscribable_signal, signal))
107
119
  broker = Broker(url, api_key)
108
- broker.subscribe(signal, namespace, per_frame_influx_line_protocol, on_change_only)
120
+ broker.long_name_subscribe(signals_to_subscribe_to, per_frame_influx_line_protocol, on_change_only)
109
121
  except grpc.RpcError as rpc_error:
110
122
  ErrorPrinter.print_grpc_error(rpc_error)
cli/broker/lib/broker.py CHANGED
@@ -1,7 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import binascii
4
- import datetime
5
4
  import ntpath
6
5
  import os
7
6
  import posixpath
@@ -183,7 +182,9 @@ class Broker:
183
182
  self.__check_playbackmode_result(status)
184
183
  return status
185
184
 
186
- def listen_on_playback(self, callback: Callable[[str], None]):
185
+ def listen_on_playback(self, repeat: bool, recording_and_namespace: List, callback: Callable[[int, int, str], None]):
186
+ # include recording_and_namespace if we want to loop the recording
187
+ # This can probably be improved
187
188
  def get_mode(mode: int):
188
189
  if mode == 0:
189
190
  return "playing"
@@ -195,14 +196,19 @@ class Broker:
195
196
  sub = self.traffic_stub.PlayTrafficStatus(br.common_pb2.Empty())
196
197
  for playback_state in sub:
197
198
  p = typing.cast(br.traffic_api_pb2.PlaybackInfos, playback_state)
198
- offset_time = int(p.playbackInfo[0].playbackMode.offsetTime / 1000000)
199
+ offset_length = int(p.playbackInfo[0].playbackMode.offsetTime / 1000000)
199
200
  start_time = p.playbackInfo[0].playbackMode.startTime
200
201
  end_time = p.playbackInfo[0].playbackMode.endTime
201
202
  mode = p.playbackInfo[0].playbackMode.mode
202
203
 
203
- length = int((end_time - start_time) / 1000000)
204
+ total_length = int((end_time - start_time) / 1000000)
204
205
 
205
- callback(f"{(datetime.timedelta(seconds=offset_time))} / {(datetime.timedelta(seconds=length))} ({get_mode(mode)})")
206
+ if mode == 2 and repeat:
207
+ # If we get a stop and is fairly (this is mostly not 100%) close to the end
208
+ # we repeat the recording when files are included
209
+ if abs(total_length - offset_length) < 5:
210
+ self.play(recording_and_namespace)
211
+ callback(offset_length, total_length, get_mode(mode))
206
212
 
207
213
  def pause(self, namespace: str, path: str, silent: bool = False):
208
214
  playback_list = [
@@ -478,7 +484,12 @@ class Broker:
478
484
  return subscription
479
485
 
480
486
  def __each_signal(self, signals, callback):
481
- callback(map(lambda s: {"timestamp_us": s.timestamp, "name": s.id.name, "value": self.__get_value(s)}, signals))
487
+ callback(
488
+ map(
489
+ lambda s: {"timestamp_us": s.timestamp, "namespace": s.id.namespace.name, "name": s.id.name, "value": self.__get_value(s)},
490
+ signals,
491
+ )
492
+ )
482
493
 
483
494
  @staticmethod
484
495
  def __get_value(signal):
@@ -1,9 +1,12 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import datetime
3
4
  import json
4
5
  import tempfile
6
+ from typing import List
5
7
 
6
8
  import grpc
9
+ import rich
7
10
  import typer
8
11
  from rich.progress import Progress, SpinnerColumn, TextColumn
9
12
 
@@ -25,13 +28,15 @@ def play(
25
28
  broker: str = typer.Option(None, help="Broker to use"),
26
29
  project: str = typer.Option(..., help="Project ID", envvar="REMOTIVE_CLOUD_PROJECT"),
27
30
  show_progress: bool = typer.Option(False, help="Show progress after started playing"),
31
+ repeat: bool = typer.Option(False, help="Repeat recording - must keep command running in terminal"),
28
32
  ):
29
33
  """
30
- Start playing a recording
34
+ Start playing a recording.
35
+ There is no problem invoking play multiple times since if it is already playing the command will be ignored.
36
+ Use --repeat to have the recording replayed when it reaches the end.
31
37
  """
32
- _do_change_playback_mode("play", recording_session, broker, project)
33
- if progress:
34
- _do_change_playback_mode("status", recording_session, broker, project)
38
+
39
+ _do_change_playback_mode("play", recording_session, broker, project, progress_on_play=show_progress, repeat=repeat)
35
40
 
36
41
 
37
42
  @app.command()
@@ -53,7 +58,8 @@ def progress(
53
58
  project: str = typer.Option(..., help="Project ID", envvar="REMOTIVE_CLOUD_PROJECT"),
54
59
  ):
55
60
  """
56
- Shows progress of the recording playing
61
+ Shows progress of the recording playing.
62
+ Use --repeat to have the recording replayed when it reaches the end.
57
63
  """
58
64
  _do_change_playback_mode("status", recording_session, broker, project)
59
65
 
@@ -83,7 +89,15 @@ def stop(
83
89
  _do_change_playback_mode("stop", recording_session, broker, project)
84
90
 
85
91
 
86
- def _do_change_playback_mode(mode: str, recording_session: str, broker: str, project: str, seconds: int | None = None): # noqa: C901
92
+ def _do_change_playback_mode(
93
+ mode: str,
94
+ recording_session: str,
95
+ broker: str,
96
+ project: str,
97
+ seconds: int | None = None,
98
+ progress_on_play: bool = False,
99
+ repeat: bool = False,
100
+ ): # noqa: C901
87
101
  response = rest.handle_get(f"/api/project/{project}/files/recording/{recording_session}", return_response=True)
88
102
  r = json.loads(response.text)
89
103
  recordings: list = r["recordings"]
@@ -103,6 +117,42 @@ def _do_change_playback_mode(mode: str, recording_session: str, broker: str, pro
103
117
 
104
118
  broker_info = json.loads(response.text)
105
119
  broker = Broker(broker_info["url"], None)
120
+
121
+ _verify_recording_on_broker(broker, recording_session, mode, project)
122
+
123
+ if mode == "pause":
124
+ broker.pause_play(files, True)
125
+ elif mode == "play":
126
+ broker.play(files, True)
127
+ if progress_on_play or repeat:
128
+ _track_progress(broker, repeat, files)
129
+ elif mode == "seek":
130
+ broker.seek(files, int(seconds * 1000000), True)
131
+ elif mode == "stop":
132
+ broker.seek(files, 0, True)
133
+ elif mode == "status":
134
+ _track_progress(broker, repeat, files)
135
+ else:
136
+ raise Exception(f"Illegal command {mode}")
137
+
138
+
139
+ def _track_progress(broker: Broker, repeat: bool, files: List):
140
+ p = Progress(SpinnerColumn(), TextColumn("[progress.description]{task.description}"), transient=True)
141
+ t = p.add_task("label", total=1)
142
+ if repeat:
143
+ rich.print(":point_right: Keep this command running in terminal to keep the recording play with repeat")
144
+ with p:
145
+
146
+ def print_progress(offset: int, total: int, current_mode: str):
147
+ p.update(
148
+ t,
149
+ description=f"{(datetime.timedelta(seconds=offset))} " f"/ {(datetime.timedelta(seconds=total))} ({current_mode})",
150
+ )
151
+
152
+ broker.listen_on_playback(repeat, files, print_progress)
153
+
154
+
155
+ def _verify_recording_on_broker(broker: Broker, recording_session: str, mode: str, project: str):
106
156
  try:
107
157
  # Here we try to verify that we are operating on a recording that is mounted on the
108
158
  # broker so we can verify this before we try playback and can also present some good
@@ -126,19 +176,3 @@ def _do_change_playback_mode(mode: str, recording_session: str, broker: str, pro
126
176
  else:
127
177
  ErrorPrinter.print_grpc_error(rpc_error)
128
178
  exit(1)
129
- if mode == "pause":
130
- broker.pause_play(files, True)
131
- elif mode == "play":
132
- r = broker.play(files, True)
133
- elif mode == "seek":
134
- broker.seek(files, int(seconds * 1000000), True)
135
- elif mode == "stop":
136
- broker.seek(files, 0, True)
137
- elif mode == "status":
138
- p = Progress(SpinnerColumn(), TextColumn("[progress.description]{task.description}"), transient=True)
139
- t = p.add_task("label", total=1)
140
-
141
- with p:
142
- broker.listen_on_playback(lambda c: p.update(t, description=str(c)))
143
- else:
144
- raise Exception(f"Illegal command {mode}")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: remotivelabs-cli
3
- Version: 0.0.14
3
+ Version: 0.0.16
4
4
  Summary: CLI for operating RemotiveCloud and RemotiveBroker
5
5
  Author: Johan Rask
6
6
  Author-email: johan.rask@remotivelabs.com
@@ -1,10 +1,10 @@
1
1
  cli/__about__.py,sha256=qXVkxWb3aPCF-4MjQhB0wqL2GEblEH4Qwk70o29UkJk,122
2
2
  cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
3
  cli/broker/brokers.py,sha256=sSX--mm5ln5RUFR60VFHQR6NWu4Qz7Jqi2Ws-4TJsDI,3052
4
- cli/broker/export.py,sha256=GxwE9ufWRwfxVh3eTLkwuOqwUOtsvS9Wb7b-BooULC8,3734
4
+ cli/broker/export.py,sha256=kPB8xRe-I-fte5d95E0Uy2wLvQp943e4yFARGPKySoY,4386
5
5
  cli/broker/files.py,sha256=_8elBjbmJ5MEEeFGJ7QYkXzyuLDCDpO6UvEVXHbRy7U,4133
6
6
  cli/broker/lib/__about__.py,sha256=xnZ5V6ZcHW9dhWLWdMzVjYJbEnMKpeXm0_S_mbNzypE,141
7
- cli/broker/lib/broker.py,sha256=fmGsdxmdC3llrIvr0o3E2cpkGHU6mxrbZ7_ac2ZqVvU,20664
7
+ cli/broker/lib/broker.py,sha256=kpcSaHcjZlcsgNgxwDBEa13RYRtx0Uz-fbBg2pKAHI0,21174
8
8
  cli/broker/playback.py,sha256=oOfC8Jn4Ib-nc9T6ob_uNXZSeCWfft7MrMQPafH4U2I,4846
9
9
  cli/broker/record.py,sha256=gEvo3myHbIl6UyXzhJE741NiwRrFf7doBg6HXzzp5z0,1382
10
10
  cli/broker/scripting.py,sha256=sLDtuktWsVk0fJ3RW4kYyh-_YAVJP3VM0xFIQR499Oo,3392
@@ -17,7 +17,7 @@ cli/cloud/cloud_cli.py,sha256=nRRXFF_IgUMayerxS-h7oqsNe6tt34Q5VeThq8gatEg,1443
17
17
  cli/cloud/configs.py,sha256=2p1mCHf5BwYNtwbY0Cbed5t6-79WHGKWU4Fv6LuJ21o,4069
18
18
  cli/cloud/projects.py,sha256=-uqltAOficwprOKaPd2R0Itm4sqTz3VJNs9Sc8jtO5k,1369
19
19
  cli/cloud/recordings.py,sha256=0xQw8iv-NjUUqxQjq5O4WqNYsew2lNlQ9Z0Qevl2f9E,20844
20
- cli/cloud/recordings_playback.py,sha256=QNQ_icUxffUVKNM48WRo74EhBxjhpy2mrPjq4uZC3JI,5930
20
+ cli/cloud/recordings_playback.py,sha256=ygJRBbJ_BYmrEZ7k0j2b11N3xrrgmOdL3jZckJ-f-uU,7120
21
21
  cli/cloud/rest_helper.py,sha256=g7lmGosAS0IDlo9Aso0bH0tdlLTCz0IYx3R71DXKtkc,6491
22
22
  cli/cloud/sample_recordings.py,sha256=g1X6JTxvzWInSP9R1BJsDmL4WqvpEKqjdJR_xT4bo1U,639
23
23
  cli/cloud/service_account_tokens.py,sha256=7vjoMd6Xq7orWCUP7TVUVa86JA0OiX8O10NZcHUE6rM,2294
@@ -33,8 +33,8 @@ cli/tools/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
33
33
  cli/tools/can/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
34
34
  cli/tools/can/can.py,sha256=kSd1c-nxxXyeKkm19oDILiDBZsKOcpjsUT0T3xox5Qs,2172
35
35
  cli/tools/tools.py,sha256=LwQdWMcJ19pCyKUsVfSB2B3R6ui61NxxFWP0Nrnd5Jk,198
36
- remotivelabs_cli-0.0.14.dist-info/LICENSE,sha256=qDPP_yfuv1fF-u7EfexN-cN3M8aFgGVndGhGLovLKz0,608
37
- remotivelabs_cli-0.0.14.dist-info/METADATA,sha256=rhN0Ppf8WBcns42rzb8vF4thU7MHOi2M4oxXY_hTMD8,1224
38
- remotivelabs_cli-0.0.14.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
39
- remotivelabs_cli-0.0.14.dist-info/entry_points.txt,sha256=lvDhPgagLqW_KTnLPCwKSqfYlEp-1uYVosRiPjsVj10,45
40
- remotivelabs_cli-0.0.14.dist-info/RECORD,,
36
+ remotivelabs_cli-0.0.16.dist-info/LICENSE,sha256=qDPP_yfuv1fF-u7EfexN-cN3M8aFgGVndGhGLovLKz0,608
37
+ remotivelabs_cli-0.0.16.dist-info/METADATA,sha256=A5ZA5VGXfw287Q187R5Pt4cPH5xOVmDWzeRq8offtPk,1224
38
+ remotivelabs_cli-0.0.16.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
39
+ remotivelabs_cli-0.0.16.dist-info/entry_points.txt,sha256=lvDhPgagLqW_KTnLPCwKSqfYlEp-1uYVosRiPjsVj10,45
40
+ remotivelabs_cli-0.0.16.dist-info/RECORD,,