meshcore-cli 1.1.36__tar.gz → 1.1.38__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.
- {meshcore_cli-1.1.36 → meshcore_cli-1.1.38}/PKG-INFO +1 -1
- {meshcore_cli-1.1.36 → meshcore_cli-1.1.38}/pyproject.toml +1 -1
- {meshcore_cli-1.1.36 → meshcore_cli-1.1.38}/src/meshcore_cli/meshcore_cli.py +127 -37
- {meshcore_cli-1.1.36 → meshcore_cli-1.1.38}/.gitignore +0 -0
- {meshcore_cli-1.1.36 → meshcore_cli-1.1.38}/LICENSE +0 -0
- {meshcore_cli-1.1.36 → meshcore_cli-1.1.38}/README.md +0 -0
- {meshcore_cli-1.1.36 → meshcore_cli-1.1.38}/flake.lock +0 -0
- {meshcore_cli-1.1.36 → meshcore_cli-1.1.38}/flake.nix +0 -0
- {meshcore_cli-1.1.36 → meshcore_cli-1.1.38}/src/meshcore_cli/__init__.py +0 -0
- {meshcore_cli-1.1.36 → meshcore_cli-1.1.38}/src/meshcore_cli/__main__.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: meshcore-cli
|
|
3
|
-
Version: 1.1.
|
|
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
|
|
@@ -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.
|
|
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
|
|
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
|
-
|
|
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(
|
|
1813
|
+
print(ANSI_BGREEN, end="")
|
|
1729
1814
|
elif snr <= 0:
|
|
1730
|
-
print(
|
|
1815
|
+
print(ANSI_BRED, end="")
|
|
1816
|
+
else :
|
|
1817
|
+
print(ANSI_BGRAY, end="")
|
|
1731
1818
|
print(f"{snr:.2f}",end="")
|
|
1732
|
-
if
|
|
1733
|
-
print(
|
|
1734
|
-
|
|
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
|
|
1838
|
-
|
|
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
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
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
|
|
1936
|
+
outp = res['out_path']
|
|
1855
1937
|
outp = outp if outp != "" else "direct"
|
|
1856
|
-
inp = res
|
|
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
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
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
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
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
|
|
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 """
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|