meshcore-cli 1.1.36__py3-none-any.whl → 1.1.38__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.
@@ -23,7 +23,7 @@ from prompt_toolkit.shortcuts import radiolist_dialog
23
23
  from meshcore import MeshCore, EventType, logger
24
24
 
25
25
  # Version
26
- VERSION = "v1.1.36"
26
+ VERSION = "v1.1.38"
27
27
 
28
28
  # default ble address is stored in a config file
29
29
  MCCLI_CONFIG_DIR = str(Path.home()) + "/.config/meshcore/"
@@ -69,7 +69,7 @@ def escape_ansi(line):
69
69
  ansi_escape = re.compile(r'(?:\x1B[@-_]|[\x80-\x9F])[0-?]*[ -/]*[@-~]')
70
70
  return ansi_escape.sub('', line)
71
71
 
72
- def print_above(str):
72
+ def print_one_line_above(str):
73
73
  """ prints a string above current line """
74
74
  width = os.get_terminal_size().columns
75
75
  stringlen = len(escape_ansi(str))-1
@@ -85,6 +85,11 @@ def print_above(str):
85
85
  print(str, end="") # Print output status msg
86
86
  print("\u001B[u", end="", flush=True) # Jump back to saved cursor position
87
87
 
88
+ def print_above(str):
89
+ lines = str.split('\n')
90
+ for l in lines:
91
+ print_one_line_above(l)
92
+
88
93
  async def process_event_message(mc, ev, json_output, end="\n", above=False):
89
94
  """ display incoming message """
90
95
  if ev is None :
@@ -350,6 +355,7 @@ def make_completion_dict(contacts, pending={}, to=None, channels=None):
350
355
  "share_contact" : contact_list,
351
356
  "path": contact_list,
352
357
  "disc_path" : contact_list,
358
+ "trace" : None,
353
359
  "reset_path" : contact_list,
354
360
  "change_path" : contact_list,
355
361
  "change_flags" : contact_list,
@@ -439,6 +445,8 @@ def make_completion_dict(contacts, pending={}, to=None, channels=None):
439
445
  "upload_contact" : None,
440
446
  "path": None,
441
447
  "disc_path": None,
448
+ "trace": None,
449
+ "dtrace": None,
442
450
  "reset_path" : None,
443
451
  "change_path" : None,
444
452
  "change_flags" : None,
@@ -804,6 +812,15 @@ Line starting with \"$\" or \".\" will issue a meshcli command.
804
812
  await process_cmds(mc, ["cmd", contact["adv_name"], newline])
805
813
  except IndexError:
806
814
  print("Wrong number of parameters")
815
+
816
+ # trace called on a contact
817
+ elif contact["type"] > 0 and (
818
+ line == "trace" or line == "tr") :
819
+ await print_trace_to(mc, contact)
820
+
821
+ elif contact["type"] > 0 and (
822
+ line == "dtrace" or line == "dt") :
823
+ await print_disc_trace_to(mc, contact)
807
824
 
808
825
  # same but for commands with a parameter
809
826
  elif contact["type"] > 0 and (line.startswith("cmd ") or\
@@ -1058,6 +1075,70 @@ async def get_channels (mc, anim=False) :
1058
1075
  print (" Done")
1059
1076
  return mc.channels
1060
1077
 
1078
+ async def print_trace_to (mc, contact):
1079
+ path = contact["out_path"]
1080
+ path_len = contact["out_path_len"]
1081
+ trace = ""
1082
+
1083
+ if path_len == -1:
1084
+ print ("No path to destination")
1085
+ return
1086
+
1087
+ if contact["type"] == 2 or contact["type"] == 3:
1088
+ # repeater or room, can trace to the contact itself
1089
+ trace = contact["public_key"][0:2]
1090
+
1091
+ for i in range(0, path_len):
1092
+ elem = path[2*(path_len-i-1):2*(path_len-i)]
1093
+ trace = elem if trace=="" else f"{elem},{trace},{elem}"
1094
+
1095
+ await next_cmd(mc, ["trace", trace])
1096
+
1097
+ async def discover_path(mc, contact):
1098
+ await mc.ensure_contacts()
1099
+ res = await mc.commands.send_path_discovery(contact)
1100
+ if res.type == EventType.ERROR:
1101
+ return None
1102
+ else:
1103
+ timeout = res.payload["suggested_timeout"]/600 if not "timeout" in contact or contact['timeout']==0 else contact["timeout"]
1104
+ res = await mc.wait_for_event(EventType.PATH_RESPONSE, timeout=timeout)
1105
+ if res is None:
1106
+ return {"error": "timeout"}
1107
+ else :
1108
+ return res.payload
1109
+
1110
+ async def print_disc_trace_to (mc, contact):
1111
+ p = await discover_path(mc, contact)
1112
+ if p is None:
1113
+ print("Error discovering path")
1114
+ return
1115
+
1116
+ if "error" in p:
1117
+ print("Timeout discovering path")
1118
+ return
1119
+
1120
+ inp = p["in_path"]
1121
+ outp = p["out_path"]
1122
+ inp_l = int(len(inp)/2)
1123
+ outp_l = int(len(outp)/2)
1124
+
1125
+ trace = ""
1126
+
1127
+ for i in range(0, outp_l):
1128
+ elem = outp[2*i:2*(i+1)]
1129
+ trace = elem if trace == "" else f"{trace},{elem}"
1130
+
1131
+ if contact["type"] == 2 or contact["type"] == 3:
1132
+ # repeater or room, can trace to the contact itself
1133
+ elem = contact["public_key"][0:2]
1134
+ trace = elem if trace == "" else f"{trace},{elem}"
1135
+
1136
+ for i in range(0, inp_l):
1137
+ elem = inp[2*i:2*(i+1)]
1138
+ trace = elem if trace == "" else f"{trace},{elem}"
1139
+
1140
+ await next_cmd(mc, ["trace", trace])
1141
+
1061
1142
  async def next_cmd(mc, cmds, json_output=False):
1062
1143
  """ process next command """
1063
1144
  try :
@@ -1697,7 +1778,7 @@ async def next_cmd(mc, cmds, json_output=False):
1697
1778
  print(res.payload)
1698
1779
  print(json.dumps(res.payload, indent=4))
1699
1780
 
1700
- case "trace" :
1781
+ case "trace" | "tr":
1701
1782
  argnum = 1
1702
1783
  res = await mc.commands.send_trace(path=cmds[1])
1703
1784
  if res and res.type != EventType.ERROR:
@@ -1710,7 +1791,7 @@ async def next_cmd(mc, cmds, json_output=False):
1710
1791
  if json_output:
1711
1792
  print(json.dumps({"error" : "timeout waiting trace"}))
1712
1793
  else :
1713
- print("Timeout waiting trace")
1794
+ print(f"Timeout waiting trace for path {cmds[1]}")
1714
1795
  elif ev.type == EventType.ERROR:
1715
1796
  if json_output:
1716
1797
  print(json.dumps(ev.payload))
@@ -1720,18 +1801,26 @@ async def next_cmd(mc, cmds, json_output=False):
1720
1801
  if json_output:
1721
1802
  print(json.dumps(ev.payload, indent=2))
1722
1803
  else :
1804
+ classic = interactive_loop.classic or not process_event_message.color
1723
1805
  print("]",end="")
1724
1806
  for t in ev.payload["path"]:
1725
- print("→",end="")
1807
+ if classic :
1808
+ print("→",end="")
1809
+ else:
1810
+ print(f" {ANSI_INVERT}", end="")
1726
1811
  snr = t['snr']
1727
1812
  if snr >= 10 :
1728
- print(ANSI_GREEN, end="")
1813
+ print(ANSI_BGREEN, end="")
1729
1814
  elif snr <= 0:
1730
- print(ANSI_RED, end="")
1815
+ print(ANSI_BRED, end="")
1816
+ else :
1817
+ print(ANSI_BGRAY, end="")
1731
1818
  print(f"{snr:.2f}",end="")
1732
- if snr >= 10 or snr <= 0:
1733
- print(ANSI_END, end="")
1734
- print("→",end="")
1819
+ if classic :
1820
+ print("→",end="")
1821
+ else :
1822
+ print(f"{ANSI_NORMAL}🭬",end="")
1823
+ print(ANSI_END, end="")
1735
1824
  if "hash" in t:
1736
1825
  print(f"[{t['hash']}]",end="")
1737
1826
  else:
@@ -1834,26 +1923,19 @@ async def next_cmd(mc, cmds, json_output=False):
1834
1923
  argnum = 1
1835
1924
  await mc.ensure_contacts()
1836
1925
  contact = mc.get_contact_by_name(cmds[1])
1837
- res = await mc.commands.send_path_discovery(contact)
1838
- logger.debug(res)
1839
- if res.type == EventType.ERROR:
1926
+ res = await discover_path(mc, contact)
1927
+ if res is None:
1840
1928
  print(f"Error while discovering path")
1841
1929
  else:
1842
- timeout = res.payload["suggested_timeout"]/800 if not "timeout" in contact or contact['timeout']==0 else contact["timeout"]
1843
- res = await mc.wait_for_event(EventType.PATH_RESPONSE, timeout=timeout)
1844
- logger.debug(res)
1845
- if res is None:
1846
- if json_output :
1847
- print(json.dumps({"error" : "Timeout discovering path"}))
1848
- else:
1849
- print("Timeout discovering path")
1850
- else :
1851
- if json_output :
1852
- print(json.dumps(res.payload, indent=4))
1930
+ if json_output :
1931
+ print(json.dumps(res, indent=4))
1932
+ else:
1933
+ if "error" in res :
1934
+ print("Timeout while discovering path")
1853
1935
  else:
1854
- outp = res.payload['out_path']
1936
+ outp = res['out_path']
1855
1937
  outp = outp if outp != "" else "direct"
1856
- inp = res.payload['in_path']
1938
+ inp = res['in_path']
1857
1939
  inp = inp if inp != "" else "direct"
1858
1940
  print(f"Path for {contact['adv_name']}: out {outp}, in {inp}")
1859
1941
 
@@ -2048,12 +2130,16 @@ async def next_cmd(mc, cmds, json_output=False):
2048
2130
  else:
2049
2131
  print(f"Unknown contact {cmds[1]}")
2050
2132
  else:
2051
- res = await mc.commands.change_contact_path(contact, cmds[2])
2052
- logger.debug(res)
2053
- if res.type == EventType.ERROR:
2054
- print(f"Error setting path: {res}")
2055
- elif json_output :
2056
- print(json.dumps(res.payload, indent=4))
2133
+ path = cmds[2].replace(",","") # we'll accept path with ,
2134
+ try:
2135
+ res = await mc.commands.change_contact_path(contact, path)
2136
+ logger.debug(res)
2137
+ if res.type == EventType.ERROR:
2138
+ print(f"Error setting path: {res}")
2139
+ elif json_output :
2140
+ print(json.dumps(res.payload, indent=4))
2141
+ except ValueError:
2142
+ print(f"Bad path format {cmds[2]}")
2057
2143
 
2058
2144
  case "change_flags" | "cf":
2059
2145
  argnum = 2
@@ -2349,9 +2435,11 @@ async def process_script(mc, file, json_output=False):
2349
2435
  lines=f.readlines()
2350
2436
 
2351
2437
  for line in lines:
2352
- logger.debug(f"processing {line}")
2353
- cmds = shlex.split(line[:-1])
2354
- await process_cmds(mc, cmds, json_output)
2438
+ line = line.strip()
2439
+ if not (line == "" or line[0] == "#"):
2440
+ logger.debug(f"processing {line}")
2441
+ cmds = shlex.split(line)
2442
+ await process_cmds(mc, cmds, json_output)
2355
2443
 
2356
2444
  def version():
2357
2445
  print (f"meshcore-cli: command line interface to MeshCore companion radios {VERSION}")
@@ -2399,6 +2487,7 @@ def command_help():
2399
2487
  import_contact <URI> : import a contact from its URI ic
2400
2488
  remove_contact <ct> : removes a contact from this node
2401
2489
  path <ct> : diplays path for a contact
2490
+ disc_path <ct> : discover new path and display dp
2402
2491
  reset_path <ct> : resets path to a contact to flood rp
2403
2492
  change_path <ct> <pth> : change the path to a contact cp
2404
2493
  change_flags <ct> <f> : change contact flags (tel_l|tel_a|star)cf
@@ -2407,13 +2496,14 @@ def command_help():
2407
2496
  req_acl <ct> : requests access control list for sensor
2408
2497
  pending_contacts : show pending contacts
2409
2498
  add_pending <key> : manually add pending contact from key
2410
- flush_pending : flush pending contact clist
2499
+ flush_pending : flush pending contact list
2411
2500
  Repeaters
2412
2501
  login <name> <pwd> : log into a node (rep) with given pwd l
2413
2502
  logout <name> : log out of a repeater
2414
2503
  cmd <name> <cmd> : sends a command to a repeater (no ack) c [
2415
2504
  wmt8 : wait for a msg (reply) with a timeout ]
2416
- req_status <name> : requests status from a node rs""")
2505
+ req_status <name> : requests status from a node rs
2506
+ trace <path> : run a trace, path is comma separated""")
2417
2507
 
2418
2508
  def usage () :
2419
2509
  """ Prints some help """
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: meshcore-cli
3
- Version: 1.1.36
3
+ Version: 1.1.38
4
4
  Summary: Command line interface to meshcore companion radios
5
5
  Project-URL: Homepage, https://github.com/fdlamotte/meshcore-cli
6
6
  Project-URL: Issues, https://github.com/fdlamotte/meshcore-cli/issues
@@ -0,0 +1,8 @@
1
+ meshcore_cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ meshcore_cli/__main__.py,sha256=PfYgibmu2LEtC-OV7L1UgmvV3swJ5rQ4bbXHlwUFlgE,83
3
+ meshcore_cli/meshcore_cli.py,sha256=GlPpqekJDG7eEHAb2KjwP16uI0H4vantFGS26ksxqks,115362
4
+ meshcore_cli-1.1.38.dist-info/METADATA,sha256=nBLa9D9f8TuAE1uTox-nxjLzPpq9o_h41WYf5TKrNPE,11630
5
+ meshcore_cli-1.1.38.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
6
+ meshcore_cli-1.1.38.dist-info/entry_points.txt,sha256=77V29Pyth11GteDk7tneBN3MMk8JI7bTlS-BGSmxCmI,103
7
+ meshcore_cli-1.1.38.dist-info/licenses/LICENSE,sha256=F9s987VtS0AKxW7LdB2EkLMkrdeERI7ICdLJR60A9M4,1066
8
+ meshcore_cli-1.1.38.dist-info/RECORD,,
@@ -1,8 +0,0 @@
1
- meshcore_cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- meshcore_cli/__main__.py,sha256=PfYgibmu2LEtC-OV7L1UgmvV3swJ5rQ4bbXHlwUFlgE,83
3
- meshcore_cli/meshcore_cli.py,sha256=ptCcnezjVouTz1Irp7ptnNABB3DrsAA1fiqRx_-O1hU,112472
4
- meshcore_cli-1.1.36.dist-info/METADATA,sha256=ZqOmWqxcXTHj-KsLPn0b2yyDJsJVfi_1_CzMw_AEFBE,11630
5
- meshcore_cli-1.1.36.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
6
- meshcore_cli-1.1.36.dist-info/entry_points.txt,sha256=77V29Pyth11GteDk7tneBN3MMk8JI7bTlS-BGSmxCmI,103
7
- meshcore_cli-1.1.36.dist-info/licenses/LICENSE,sha256=F9s987VtS0AKxW7LdB2EkLMkrdeERI7ICdLJR60A9M4,1066
8
- meshcore_cli-1.1.36.dist-info/RECORD,,