meshcore-cli 1.2.6__tar.gz → 1.2.8__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.2.6 → meshcore_cli-1.2.8}/PKG-INFO +2 -2
- {meshcore_cli-1.2.6 → meshcore_cli-1.2.8}/pyproject.toml +2 -2
- {meshcore_cli-1.2.6 → meshcore_cli-1.2.8}/src/meshcore_cli/meshcore_cli.py +193 -23
- {meshcore_cli-1.2.6 → meshcore_cli-1.2.8}/.gitignore +0 -0
- {meshcore_cli-1.2.6 → meshcore_cli-1.2.8}/LICENSE +0 -0
- {meshcore_cli-1.2.6 → meshcore_cli-1.2.8}/README.md +0 -0
- {meshcore_cli-1.2.6 → meshcore_cli-1.2.8}/flake.lock +0 -0
- {meshcore_cli-1.2.6 → meshcore_cli-1.2.8}/flake.nix +0 -0
- {meshcore_cli-1.2.6 → meshcore_cli-1.2.8}/src/meshcore_cli/__init__.py +0 -0
- {meshcore_cli-1.2.6 → meshcore_cli-1.2.8}/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.2.
|
|
3
|
+
Version: 1.2.8
|
|
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
|
|
@@ -10,7 +10,7 @@ License-File: LICENSE
|
|
|
10
10
|
Classifier: Operating System :: OS Independent
|
|
11
11
|
Classifier: Programming Language :: Python :: 3
|
|
12
12
|
Requires-Python: >=3.10
|
|
13
|
-
Requires-Dist: meshcore>=2.1.
|
|
13
|
+
Requires-Dist: meshcore>=2.1.22
|
|
14
14
|
Requires-Dist: prompt-toolkit>=3.0.50
|
|
15
15
|
Requires-Dist: pycryptodome
|
|
16
16
|
Requires-Dist: requests>=2.28.0
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "meshcore-cli"
|
|
7
|
-
version = "1.2.
|
|
7
|
+
version = "1.2.8"
|
|
8
8
|
authors = [
|
|
9
9
|
{ name="Florent de Lamotte", email="florent@frizoncorrea.fr" },
|
|
10
10
|
]
|
|
@@ -17,7 +17,7 @@ classifiers = [
|
|
|
17
17
|
]
|
|
18
18
|
license = "MIT"
|
|
19
19
|
license-files = ["LICEN[CS]E*"]
|
|
20
|
-
dependencies = [ "meshcore >= 2.1.
|
|
20
|
+
dependencies = [ "meshcore >= 2.1.22", "prompt_toolkit >= 3.0.50", "requests >= 2.28.0", "pycryptodome" ]
|
|
21
21
|
|
|
22
22
|
[project.urls]
|
|
23
23
|
Homepage = "https://github.com/fdlamotte/meshcore-cli"
|
|
@@ -33,7 +33,7 @@ import re
|
|
|
33
33
|
from meshcore import MeshCore, EventType, logger
|
|
34
34
|
|
|
35
35
|
# Version
|
|
36
|
-
VERSION = "v1.2.
|
|
36
|
+
VERSION = "v1.2.8"
|
|
37
37
|
|
|
38
38
|
# default ble address is stored in a config file
|
|
39
39
|
MCCLI_CONFIG_DIR = str(Path.home()) + "/.config/meshcore/"
|
|
@@ -451,6 +451,7 @@ def make_completion_dict(contacts, pending={}, to=None, channels=None):
|
|
|
451
451
|
"share_contact" : contact_list,
|
|
452
452
|
"path": contact_list,
|
|
453
453
|
"disc_path" : contact_list,
|
|
454
|
+
"node_discover": {"all":None, "sens":None, "rep":None, "comp":None, "room":None, "cli":None},
|
|
454
455
|
"trace" : None,
|
|
455
456
|
"reset_path" : contact_list,
|
|
456
457
|
"change_path" : contact_list,
|
|
@@ -473,6 +474,7 @@ def make_completion_dict(contacts, pending={}, to=None, channels=None):
|
|
|
473
474
|
"remove_channel": None,
|
|
474
475
|
"apply_to": None,
|
|
475
476
|
"at": None,
|
|
477
|
+
"scope": None,
|
|
476
478
|
"set" : {
|
|
477
479
|
"name" : None,
|
|
478
480
|
"pin" : None,
|
|
@@ -579,6 +581,7 @@ def make_completion_dict(contacts, pending={}, to=None, channels=None):
|
|
|
579
581
|
"neighbors" : None,
|
|
580
582
|
"req_acl":None,
|
|
581
583
|
"setperm":contact_list,
|
|
584
|
+
"region" : {"get":None, "allowf": None, "denyf": None, "put": None, "remove": None, "save": None, "home": None},
|
|
582
585
|
"gps" : {"on":None,"off":None,"sync":None,"setloc":None,
|
|
583
586
|
"advert" : {"none": None, "share": None, "prefs": None},
|
|
584
587
|
},
|
|
@@ -707,6 +710,8 @@ Line starting with \"$\" or \".\" will issue a meshcli command.
|
|
|
707
710
|
contact = to
|
|
708
711
|
prev_contact = None
|
|
709
712
|
|
|
713
|
+
scope = await set_scope(mc, "*")
|
|
714
|
+
|
|
710
715
|
await get_contacts(mc, anim=True)
|
|
711
716
|
await get_channels(mc, anim=True)
|
|
712
717
|
await subscribe_to_msgs(mc, above=True)
|
|
@@ -745,6 +750,9 @@ Line starting with \"$\" or \".\" will issue a meshcli command.
|
|
|
745
750
|
|
|
746
751
|
last_ack = True
|
|
747
752
|
while True:
|
|
753
|
+
# reset scope (if changed)
|
|
754
|
+
scope = await set_scope(mc, scope)
|
|
755
|
+
|
|
748
756
|
color = process_event_message.color
|
|
749
757
|
classic = interactive_loop.classic or not color
|
|
750
758
|
print_name = interactive_loop.print_name
|
|
@@ -758,6 +766,9 @@ Line starting with \"$\" or \".\" will issue a meshcli command.
|
|
|
758
766
|
if print_name or contact is None :
|
|
759
767
|
prompt = prompt + f"{ANSI_BGRAY}"
|
|
760
768
|
prompt = prompt + f"{mc.self_info['name']}"
|
|
769
|
+
if contact is None: # display scope
|
|
770
|
+
if not scope is None:
|
|
771
|
+
prompt = prompt + f"|{scope}"
|
|
761
772
|
if classic :
|
|
762
773
|
prompt = prompt + " > "
|
|
763
774
|
else :
|
|
@@ -785,6 +796,17 @@ Line starting with \"$\" or \".\" will issue a meshcli command.
|
|
|
785
796
|
prompt = prompt + f"{ANSI_NORMAL}🭨{ANSI_INVERT}"
|
|
786
797
|
|
|
787
798
|
prompt = prompt + f"{contact['adv_name']}"
|
|
799
|
+
if contact["type"] == 0 or contact["out_path_len"]==-1:
|
|
800
|
+
if scope is None:
|
|
801
|
+
prompt = prompt + f"|*"
|
|
802
|
+
else:
|
|
803
|
+
prompt = prompt + f"|{scope}"
|
|
804
|
+
else: # display path to dest or 0 if 0 hop
|
|
805
|
+
if contact["out_path_len"] == 0:
|
|
806
|
+
prompt = prompt + f"|0"
|
|
807
|
+
else:
|
|
808
|
+
prompt = prompt + "|" + contact["out_path"]
|
|
809
|
+
|
|
788
810
|
if classic :
|
|
789
811
|
prompt = prompt + f"{ANSI_NORMAL} > "
|
|
790
812
|
else:
|
|
@@ -809,6 +831,8 @@ Line starting with \"$\" or \".\" will issue a meshcli command.
|
|
|
809
831
|
completer=completer,
|
|
810
832
|
key_bindings=bindings)
|
|
811
833
|
|
|
834
|
+
line = line.strip()
|
|
835
|
+
|
|
812
836
|
if line == "" : # blank line
|
|
813
837
|
pass
|
|
814
838
|
|
|
@@ -823,18 +847,41 @@ Line starting with \"$\" or \".\" will issue a meshcli command.
|
|
|
823
847
|
except ValueError:
|
|
824
848
|
logger.error("Error parsing line {line[1:]}")
|
|
825
849
|
|
|
850
|
+
elif line.startswith("/scope") or\
|
|
851
|
+
line.startswith("scope") and contact is None:
|
|
852
|
+
if not scope is None:
|
|
853
|
+
prev_scope = scope
|
|
854
|
+
try:
|
|
855
|
+
newscope = line.split(" ", 1)[1]
|
|
856
|
+
scope = await set_scope(mc, newscope)
|
|
857
|
+
except IndexError:
|
|
858
|
+
print(scope)
|
|
859
|
+
|
|
860
|
+
elif contact is None and (line.startswith("apply_to ") or line.startswith("at ")) or\
|
|
861
|
+
line.startswith("/apply_to ") or line.startswith("/at ") :
|
|
862
|
+
try:
|
|
863
|
+
await apply_command_to_contacts(mc, line.split(" ",2)[1], line.split(" ",2)[2])
|
|
864
|
+
except IndexError:
|
|
865
|
+
logger.error(f"Error with apply_to command parameters")
|
|
866
|
+
|
|
826
867
|
elif line.startswith("/") :
|
|
827
868
|
path = line.split(" ", 1)[0]
|
|
828
869
|
if path.count("/") == 1:
|
|
829
870
|
args = line[1:].split(" ")
|
|
830
|
-
|
|
871
|
+
dest = args[0]
|
|
872
|
+
dest_scope = None
|
|
873
|
+
if "%" in dest :
|
|
874
|
+
dest_scope = dest.split("%")[-1]
|
|
875
|
+
dest = dest[:-len(dest_scope)-1]
|
|
876
|
+
await set_scope (mc, dest_scope)
|
|
877
|
+
tct = mc.get_contact_by_name(dest)
|
|
831
878
|
if len(args)>1 and not tct is None: # a contact, send a message
|
|
832
879
|
if tct["type"] == 1 or tct["type"] == 3: # client or room
|
|
833
880
|
last_ack = await msg_ack(mc, tct, line.split(" ", 1)[1])
|
|
834
881
|
else:
|
|
835
882
|
print("Can only send msg to chan, client or room")
|
|
836
883
|
else :
|
|
837
|
-
ch = await get_channel_by_name(mc,
|
|
884
|
+
ch = await get_channel_by_name(mc, dest)
|
|
838
885
|
if len(args)>1 and not ch is None: # a channel, send message
|
|
839
886
|
await send_chan_msg(mc, ch["channel_idx"], line.split(" ", 1)[1])
|
|
840
887
|
else :
|
|
@@ -845,6 +892,11 @@ Line starting with \"$\" or \".\" will issue a meshcli command.
|
|
|
845
892
|
else:
|
|
846
893
|
cmdline = line[1:].split("/",1)[1]
|
|
847
894
|
contact_name = path[1:].split("/",1)[0]
|
|
895
|
+
dest_scope = None
|
|
896
|
+
if "%" in contact_name:
|
|
897
|
+
dest_scope = contact_name.split("%")[-1]
|
|
898
|
+
contact_name = contact_name[:-len(dest_scope)-1]
|
|
899
|
+
await set_scope (mc, dest_scope)
|
|
848
900
|
tct = mc.get_contact_by_name(contact_name)
|
|
849
901
|
if tct is None:
|
|
850
902
|
print(f"{contact_name} is not a contact")
|
|
@@ -860,6 +912,10 @@ Line starting with \"$\" or \".\" will issue a meshcli command.
|
|
|
860
912
|
dest = line[3:]
|
|
861
913
|
if dest.startswith("\"") or dest.startswith("\'") : # if name starts with a quote
|
|
862
914
|
dest = shlex.split(dest)[0] # use shlex.split to get contact name between quotes
|
|
915
|
+
dest_scope = None
|
|
916
|
+
if '%' in dest and scope!=None :
|
|
917
|
+
dest_scope = dest.split("%")[-1]
|
|
918
|
+
dest = dest[:-len(dest_scope)-1]
|
|
863
919
|
nc = mc.get_contact_by_name(dest)
|
|
864
920
|
if nc is None:
|
|
865
921
|
if dest == "public" :
|
|
@@ -873,6 +929,8 @@ Line starting with \"$\" or \".\" will issue a meshcli command.
|
|
|
873
929
|
nc["adv_name"] = mc.channels[dest]["channel_name"]
|
|
874
930
|
elif dest == ".." : # previous recipient
|
|
875
931
|
nc = prev_contact
|
|
932
|
+
if dest_scope is None and not scope is None:
|
|
933
|
+
dest_scope = prev_scope
|
|
876
934
|
elif dest == "~" or dest == "/" or dest == mc.self_info['name']:
|
|
877
935
|
nc = None
|
|
878
936
|
elif dest == "!" :
|
|
@@ -890,6 +948,12 @@ Line starting with \"$\" or \".\" will issue a meshcli command.
|
|
|
890
948
|
last_ack = True
|
|
891
949
|
prev_contact = contact
|
|
892
950
|
contact = nc
|
|
951
|
+
if dest_scope is None:
|
|
952
|
+
dest_scope = scope
|
|
953
|
+
if not scope is None and dest_scope != scope:
|
|
954
|
+
prev_scope = scope
|
|
955
|
+
if not dest_scope is None:
|
|
956
|
+
scope = await set_scope(mc, dest_scope)
|
|
893
957
|
|
|
894
958
|
elif line == "to" :
|
|
895
959
|
if contact is None :
|
|
@@ -918,13 +982,6 @@ Line starting with \"$\" or \".\" will issue a meshcli command.
|
|
|
918
982
|
if last_ack == False :
|
|
919
983
|
contact = ln
|
|
920
984
|
|
|
921
|
-
elif contact is None and\
|
|
922
|
-
(line.startswith("apply_to ") or line.startswith("at ")):
|
|
923
|
-
try:
|
|
924
|
-
await apply_command_to_contacts(mc, line.split(" ",2)[1], line.split(" ",2)[2])
|
|
925
|
-
except IndexError:
|
|
926
|
-
logger.error(f"Error with apply_to command parameters")
|
|
927
|
-
|
|
928
985
|
# commands are passed through if at root
|
|
929
986
|
elif contact is None or line.startswith(".") :
|
|
930
987
|
try:
|
|
@@ -976,6 +1033,12 @@ async def process_contact_chat_line(mc, contact, line):
|
|
|
976
1033
|
if contact["type"] == 0:
|
|
977
1034
|
return False
|
|
978
1035
|
|
|
1036
|
+
# if one element in line (most cases) strip the scope and apply it
|
|
1037
|
+
if not " " in line and "%" in line:
|
|
1038
|
+
dest_scope = line.split("%")[-1]
|
|
1039
|
+
line = line[:-len(dest_scope)-1]
|
|
1040
|
+
await set_scope (mc, dest_scope)
|
|
1041
|
+
|
|
979
1042
|
if line.startswith(":") : # : will send a command to current recipient
|
|
980
1043
|
args=["cmd", contact['adv_name'], line[1:]]
|
|
981
1044
|
await process_cmds(mc, args)
|
|
@@ -1090,15 +1153,21 @@ async def process_contact_chat_line(mc, contact, line):
|
|
|
1090
1153
|
return True
|
|
1091
1154
|
|
|
1092
1155
|
# same but for commands with a parameter
|
|
1093
|
-
if
|
|
1094
|
-
line.startswith("cp ") or line.startswith("change_path ") or\
|
|
1095
|
-
line.startswith("cf ") or line.startswith("change_flags ") or\
|
|
1096
|
-
line.startswith("req_binary ") or\
|
|
1097
|
-
line.startswith("login ") :
|
|
1156
|
+
if " " in line:
|
|
1098
1157
|
cmds = line.split(" ", 1)
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1158
|
+
if "%" in cmds[0]:
|
|
1159
|
+
dest_scope = cmds[0].split("%")[-1]
|
|
1160
|
+
cmds[0] = cmds[0][:-len(dest_scope)-1]
|
|
1161
|
+
await set_scope(mc, dest_scope)
|
|
1162
|
+
|
|
1163
|
+
if cmds[0] == "cmd" or cmds[0] == "msg" or\
|
|
1164
|
+
cmds[0] == "cp" or cmds[0] == "change_path" or\
|
|
1165
|
+
cmds[0] == "cf" or cmds[0] == "change_flags" or\
|
|
1166
|
+
cmds[0] == "req_binary" or\
|
|
1167
|
+
cmds[0] == "login" :
|
|
1168
|
+
args = [cmds[0], contact['adv_name'], cmds[1]]
|
|
1169
|
+
await process_cmds(mc, args)
|
|
1170
|
+
return True
|
|
1102
1171
|
|
|
1103
1172
|
if line == "login": # use stored password or prompt for it
|
|
1104
1173
|
password_file = ""
|
|
@@ -1287,7 +1356,7 @@ async def send_msg (mc, contact, msg) :
|
|
|
1287
1356
|
|
|
1288
1357
|
async def msg_ack (mc, contact, msg) :
|
|
1289
1358
|
timeout = 0 if not 'timeout' in contact else contact['timeout']
|
|
1290
|
-
res = await mc.commands.send_msg_with_retry(contact, msg,
|
|
1359
|
+
res = await mc.commands.send_msg_with_retry(contact, msg,
|
|
1291
1360
|
max_attempts=msg_ack.max_attempts,
|
|
1292
1361
|
flood_after=msg_ack.flood_after,
|
|
1293
1362
|
max_flood_attempts=msg_ack.max_flood_attempts,
|
|
@@ -1307,6 +1376,28 @@ msg_ack.max_attempts=3
|
|
|
1307
1376
|
msg_ack.flood_after=2
|
|
1308
1377
|
msg_ack.max_flood_attempts=1
|
|
1309
1378
|
|
|
1379
|
+
async def set_scope (mc, scope) :
|
|
1380
|
+
if not set_scope.has_scope:
|
|
1381
|
+
return None
|
|
1382
|
+
|
|
1383
|
+
if scope == "None" or scope == "0" or scope == "clear" or scope == "":
|
|
1384
|
+
scope = "*"
|
|
1385
|
+
|
|
1386
|
+
if set_scope.current_scope == scope:
|
|
1387
|
+
return scope
|
|
1388
|
+
|
|
1389
|
+
res = await mc.commands.set_flood_scope(scope)
|
|
1390
|
+
if res is None or res.type == EventType.ERROR:
|
|
1391
|
+
if not res is None and res.payload["error_code"] == 1: #unsupported
|
|
1392
|
+
set_scope.has_scope = False
|
|
1393
|
+
return None
|
|
1394
|
+
|
|
1395
|
+
set_scope.current_scope = scope
|
|
1396
|
+
|
|
1397
|
+
return scope
|
|
1398
|
+
set_scope.has_scope = True
|
|
1399
|
+
set_scope.current_scope = None
|
|
1400
|
+
|
|
1310
1401
|
async def get_channel (mc, chan) :
|
|
1311
1402
|
if not chan.isnumeric():
|
|
1312
1403
|
return await get_channel_by_name(mc, chan)
|
|
@@ -2110,8 +2201,8 @@ async def next_cmd(mc, cmds, json_output=False):
|
|
|
2110
2201
|
|
|
2111
2202
|
case "scope":
|
|
2112
2203
|
argnum = 1
|
|
2113
|
-
res = await mc
|
|
2114
|
-
if res is None
|
|
2204
|
+
res = await set_scope(mc, cmds[1])
|
|
2205
|
+
if res is None:
|
|
2115
2206
|
print(f"Error while setting scope")
|
|
2116
2207
|
|
|
2117
2208
|
case "remove_channel":
|
|
@@ -2180,7 +2271,7 @@ async def next_cmd(mc, cmds, json_output=False):
|
|
|
2180
2271
|
argnum = 2
|
|
2181
2272
|
dest = None
|
|
2182
2273
|
|
|
2183
|
-
if len(cmds[1]) == 12: # possibly an hex prefix
|
|
2274
|
+
if len(cmds[1]) == 12: # possibly an hex prefix
|
|
2184
2275
|
try:
|
|
2185
2276
|
dest = bytes.fromhex(cmds[1])
|
|
2186
2277
|
except ValueError:
|
|
@@ -2378,6 +2469,71 @@ async def next_cmd(mc, cmds, json_output=False):
|
|
|
2378
2469
|
inp = inp if inp != "" else "direct"
|
|
2379
2470
|
print(f"Path for {contact['adv_name']}: out {outp}, in {inp}")
|
|
2380
2471
|
|
|
2472
|
+
case "node_discover"|"nd" :
|
|
2473
|
+
argnum = 1
|
|
2474
|
+
prefix_only = True
|
|
2475
|
+
|
|
2476
|
+
if len(cmds) == 1:
|
|
2477
|
+
argnum = 0
|
|
2478
|
+
types = 0xFF
|
|
2479
|
+
else:
|
|
2480
|
+
try: # try to decode type as int
|
|
2481
|
+
types = int(cmds[1])
|
|
2482
|
+
except ValueError:
|
|
2483
|
+
if "all" in cmds[1]:
|
|
2484
|
+
types = 0xFF
|
|
2485
|
+
else :
|
|
2486
|
+
types = 0
|
|
2487
|
+
if "rep" in cmds[1] or "rpt" in cmds[1]:
|
|
2488
|
+
types = types | 4
|
|
2489
|
+
if "cli" in cmds[1] or "comp" in cmds[1]:
|
|
2490
|
+
types = types | 2
|
|
2491
|
+
if "room" in cmds[1]:
|
|
2492
|
+
types = types | 8
|
|
2493
|
+
if "sens" in cmds[1]:
|
|
2494
|
+
types = types | 16
|
|
2495
|
+
|
|
2496
|
+
if "full" in cmds[1]:
|
|
2497
|
+
prefix_only = False
|
|
2498
|
+
|
|
2499
|
+
res = await mc.commands.send_node_discover_req(types, prefix_only=prefix_only)
|
|
2500
|
+
if res is None or res.type == EventType.ERROR:
|
|
2501
|
+
print("Error sending discover request")
|
|
2502
|
+
else:
|
|
2503
|
+
exp_tag = res.payload["tag"].to_bytes(4, "little").hex()
|
|
2504
|
+
dn = []
|
|
2505
|
+
while True:
|
|
2506
|
+
r = await mc.wait_for_event(
|
|
2507
|
+
EventType.DISCOVER_RESPONSE,
|
|
2508
|
+
attribute_filters={"tag":exp_tag},
|
|
2509
|
+
timeout = 5
|
|
2510
|
+
)
|
|
2511
|
+
if r is None or r.type == EventType.ERROR:
|
|
2512
|
+
break
|
|
2513
|
+
else:
|
|
2514
|
+
dn.append(r.payload)
|
|
2515
|
+
|
|
2516
|
+
if json_output:
|
|
2517
|
+
print(json.dumps(dn))
|
|
2518
|
+
else:
|
|
2519
|
+
await mc.ensure_contacts()
|
|
2520
|
+
print(f"Discovered {len(dn)} nodes:")
|
|
2521
|
+
for n in dn:
|
|
2522
|
+
name = f"{n['pubkey'][0:2]} {mc.get_contact_by_key_prefix(n['pubkey'])['adv_name']}"
|
|
2523
|
+
if name is None:
|
|
2524
|
+
name = n["pubkey"][0:16]
|
|
2525
|
+
type = f"t:{n['node_type']}"
|
|
2526
|
+
if n['node_type'] == 1:
|
|
2527
|
+
type = "CLI"
|
|
2528
|
+
elif n['node_type'] == 2:
|
|
2529
|
+
type = "REP"
|
|
2530
|
+
elif n['node_type'] == 3:
|
|
2531
|
+
type = "ROOM"
|
|
2532
|
+
elif n['node_type'] == 4:
|
|
2533
|
+
type = "SENS"
|
|
2534
|
+
|
|
2535
|
+
print(f" {name:16} {type:>4} SNR: {n['SNR_in']:6,.2f}->{n['SNR']:6,.2f} RSSI: ->{n['RSSI']:4}")
|
|
2536
|
+
|
|
2381
2537
|
case "req_btelemetry"|"rbt" :
|
|
2382
2538
|
argnum = 1
|
|
2383
2539
|
await mc.ensure_contacts()
|
|
@@ -2931,6 +3087,7 @@ def command_help():
|
|
|
2931
3087
|
time <epoch> : sets time to given epoch
|
|
2932
3088
|
clock : get current time
|
|
2933
3089
|
clock sync : sync device clock st
|
|
3090
|
+
node_discover <filter> : discovers nodes based on their type nd
|
|
2934
3091
|
Contacts
|
|
2935
3092
|
contacts / list : gets contact list lc
|
|
2936
3093
|
reload_contacts : force reloading all contacts rc
|
|
@@ -3004,7 +3161,20 @@ def get_help_for (cmdname, context="line") :
|
|
|
3004
3161
|
at t=2,u>1d,d cn trace
|
|
3005
3162
|
# tries to do flood login to all repeaters
|
|
3006
3163
|
at t=2 rp login
|
|
3007
|
-
|
|
3164
|
+
""")
|
|
3165
|
+
|
|
3166
|
+
if cmdname == "node_discover" or cmdname == "nd" :
|
|
3167
|
+
print("""node_discover <filter> : discovers 0-hop nodes and displays signal info
|
|
3168
|
+
|
|
3169
|
+
filter can be "all" for all types or nodes or a comma separated list consisting of :
|
|
3170
|
+
- cli or comp for companions
|
|
3171
|
+
- rep for repeaters
|
|
3172
|
+
- sens for sensors
|
|
3173
|
+
- room for chat rooms
|
|
3174
|
+
|
|
3175
|
+
nd can be used with no filter parameter ... !!! BEWARE WITH CHAINING !!!
|
|
3176
|
+
""")
|
|
3177
|
+
|
|
3008
3178
|
else:
|
|
3009
3179
|
print(f"Sorry, no help yet for {cmdname}")
|
|
3010
3180
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|