meshcore-cli 1.2.10__py3-none-any.whl → 1.2.12__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.
- meshcore_cli/meshcore_cli.py +53 -17
- {meshcore_cli-1.2.10.dist-info → meshcore_cli-1.2.12.dist-info}/METADATA +2 -2
- meshcore_cli-1.2.12.dist-info/RECORD +8 -0
- meshcore_cli-1.2.10.dist-info/RECORD +0 -8
- {meshcore_cli-1.2.10.dist-info → meshcore_cli-1.2.12.dist-info}/WHEEL +0 -0
- {meshcore_cli-1.2.10.dist-info → meshcore_cli-1.2.12.dist-info}/entry_points.txt +0 -0
- {meshcore_cli-1.2.10.dist-info → meshcore_cli-1.2.12.dist-info}/licenses/LICENSE +0 -0
meshcore_cli/meshcore_cli.py
CHANGED
|
@@ -24,7 +24,6 @@ from prompt_toolkit.key_binding import KeyBindings
|
|
|
24
24
|
from prompt_toolkit.shortcuts import radiolist_dialog
|
|
25
25
|
from prompt_toolkit.completion.word_completer import WordCompleter
|
|
26
26
|
from prompt_toolkit.document import Document
|
|
27
|
-
from hashlib import sha256
|
|
28
27
|
from Crypto.Cipher import AES
|
|
29
28
|
from Crypto.Hash import HMAC, SHA256
|
|
30
29
|
|
|
@@ -33,7 +32,7 @@ import re
|
|
|
33
32
|
from meshcore import MeshCore, EventType, logger
|
|
34
33
|
|
|
35
34
|
# Version
|
|
36
|
-
VERSION = "v1.2.
|
|
35
|
+
VERSION = "v1.2.12"
|
|
37
36
|
|
|
38
37
|
# default ble address is stored in a config file
|
|
39
38
|
MCCLI_CONFIG_DIR = str(Path.home()) + "/.config/meshcore/"
|
|
@@ -579,6 +578,7 @@ def make_completion_dict(contacts, pending={}, to=None, channels=None):
|
|
|
579
578
|
"logout" : None,
|
|
580
579
|
"req_status" : None,
|
|
581
580
|
"req_bstatus" : None,
|
|
581
|
+
"req_neighbours": None,
|
|
582
582
|
"cmd" : None,
|
|
583
583
|
"ver" : None,
|
|
584
584
|
"advert" : None,
|
|
@@ -720,6 +720,7 @@ Line starting with \"$\" or \".\" will issue a meshcli command.
|
|
|
720
720
|
prev_contact = None
|
|
721
721
|
|
|
722
722
|
scope = await set_scope(mc, "*")
|
|
723
|
+
prev_scope = scope
|
|
723
724
|
|
|
724
725
|
await get_contacts(mc, anim=True)
|
|
725
726
|
await get_channels(mc, anim=True)
|
|
@@ -772,13 +773,14 @@ Line starting with \"$\" or \".\" will issue a meshcli command.
|
|
|
772
773
|
prompt = f"{ANSI_INVERT}"
|
|
773
774
|
|
|
774
775
|
if print_name or contact is None :
|
|
775
|
-
|
|
776
|
+
if color:
|
|
777
|
+
prompt = prompt + f"{ANSI_BGRAY}"
|
|
776
778
|
prompt = prompt + f"{mc.self_info['name']}"
|
|
777
779
|
if contact is None: # display scope
|
|
778
780
|
if not scope is None:
|
|
779
781
|
prompt = prompt + f"|{scope}"
|
|
780
782
|
if classic :
|
|
781
|
-
prompt = prompt + "
|
|
783
|
+
prompt = prompt + "> "
|
|
782
784
|
else :
|
|
783
785
|
prompt = prompt + f"{ANSI_NORMAL}{ARROW_HEAD}{ANSI_INVERT}"
|
|
784
786
|
|
|
@@ -816,7 +818,7 @@ Line starting with \"$\" or \".\" will issue a meshcli command.
|
|
|
816
818
|
prompt = prompt + "|" + contact["out_path"]
|
|
817
819
|
|
|
818
820
|
if classic :
|
|
819
|
-
prompt = prompt + f"{ANSI_NORMAL}
|
|
821
|
+
prompt = prompt + f"{ANSI_NORMAL}> "
|
|
820
822
|
else:
|
|
821
823
|
prompt = prompt + f"{ANSI_NORMAL}{ARROW_HEAD}"
|
|
822
824
|
|
|
@@ -937,7 +939,7 @@ Line starting with \"$\" or \".\" will issue a meshcli command.
|
|
|
937
939
|
nc["adv_name"] = mc.channels[dest]["channel_name"]
|
|
938
940
|
elif dest == ".." : # previous recipient
|
|
939
941
|
nc = prev_contact
|
|
940
|
-
if dest_scope is None and not
|
|
942
|
+
if dest_scope is None and not prev_scope is None:
|
|
941
943
|
dest_scope = prev_scope
|
|
942
944
|
elif dest == "~" or dest == "/" or dest == mc.self_info['name']:
|
|
943
945
|
nc = None
|
|
@@ -1082,6 +1084,7 @@ async def process_contact_chat_line(mc, contact, line):
|
|
|
1082
1084
|
line == "dp" or line == "disc_path" or\
|
|
1083
1085
|
line == "contact_info" or line == "ci" or\
|
|
1084
1086
|
line == "req_status" or line == "rs" or\
|
|
1087
|
+
line == "req_neighbours" or line == "rn" or\
|
|
1085
1088
|
line == "req_bstatus" or line == "rbs" or\
|
|
1086
1089
|
line == "req_telemetry" or line == "rt" or\
|
|
1087
1090
|
line == "req_acl" or\
|
|
@@ -1442,7 +1445,7 @@ async def set_channel (mc, chan, name, key=None):
|
|
|
1442
1445
|
return None
|
|
1443
1446
|
|
|
1444
1447
|
info = res.payload
|
|
1445
|
-
info["channel_hash"] =
|
|
1448
|
+
info["channel_hash"] = SHA256.new(info["channel_secret"]).hexdigest()[0:2]
|
|
1446
1449
|
info["channel_secret"] = info["channel_secret"].hex()
|
|
1447
1450
|
|
|
1448
1451
|
if hasattr(mc,'channels') :
|
|
@@ -1531,7 +1534,7 @@ async def get_channels (mc, anim=False) :
|
|
|
1531
1534
|
if res.type == EventType.ERROR:
|
|
1532
1535
|
break
|
|
1533
1536
|
info = res.payload
|
|
1534
|
-
info["channel_hash"] =
|
|
1537
|
+
info["channel_hash"] = SHA256.new(info["channel_secret"]).hexdigest()[0:2]
|
|
1535
1538
|
info["channel_secret"] = info["channel_secret"].hex()
|
|
1536
1539
|
mc.channels.append(info)
|
|
1537
1540
|
ch = ch + 1
|
|
@@ -2339,7 +2342,8 @@ async def next_cmd(mc, cmds, json_output=False):
|
|
|
2339
2342
|
if json_output:
|
|
2340
2343
|
print(json.dumps(ev.payload, indent=2))
|
|
2341
2344
|
else :
|
|
2342
|
-
|
|
2345
|
+
color = process_event_message.color
|
|
2346
|
+
classic = interactive_loop.classic or not color
|
|
2343
2347
|
print("]",end="")
|
|
2344
2348
|
for t in ev.payload["path"]:
|
|
2345
2349
|
if classic :
|
|
@@ -2347,18 +2351,20 @@ async def next_cmd(mc, cmds, json_output=False):
|
|
|
2347
2351
|
else:
|
|
2348
2352
|
print(f" {ANSI_INVERT}", end="")
|
|
2349
2353
|
snr = t['snr']
|
|
2350
|
-
if
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2354
|
+
if color:
|
|
2355
|
+
if snr >= 10 :
|
|
2356
|
+
print(ANSI_BGREEN, end="")
|
|
2357
|
+
elif snr <= 0:
|
|
2358
|
+
print(ANSI_BRED, end="")
|
|
2359
|
+
else :
|
|
2360
|
+
print(ANSI_BGRAY, end="")
|
|
2356
2361
|
print(f"{snr:.2f}",end="")
|
|
2357
2362
|
if classic :
|
|
2358
2363
|
print("→",end="")
|
|
2359
2364
|
else :
|
|
2360
2365
|
print(f"{ANSI_NORMAL}{ARROW_HEAD}",end="")
|
|
2361
|
-
|
|
2366
|
+
if color:
|
|
2367
|
+
print(ANSI_END, end="")
|
|
2362
2368
|
if "hash" in t:
|
|
2363
2369
|
print(f"[{t['hash']}]",end="")
|
|
2364
2370
|
else:
|
|
@@ -2630,6 +2636,31 @@ async def next_cmd(mc, cmds, json_output=False):
|
|
|
2630
2636
|
name = f"{ct['adv_name']:<20} [{e['key']}]"
|
|
2631
2637
|
print(f"{name:{' '}<35}: {e['perm']:02x}")
|
|
2632
2638
|
|
|
2639
|
+
case "req_neighbours"|"rn" :
|
|
2640
|
+
argnum = 1
|
|
2641
|
+
await mc.ensure_contacts()
|
|
2642
|
+
contact = mc.get_contact_by_name(cmds[1])
|
|
2643
|
+
timeout = 0 if not "timeout" in contact else contact["timeout"]
|
|
2644
|
+
res = await mc.commands.fetch_all_neighbours(contact, timeout=timeout)
|
|
2645
|
+
if res is None :
|
|
2646
|
+
if json_output :
|
|
2647
|
+
print(json.dumps({"error" : "Getting data"}))
|
|
2648
|
+
else:
|
|
2649
|
+
print("Error getting data")
|
|
2650
|
+
else :
|
|
2651
|
+
if json_output:
|
|
2652
|
+
print(json.dumps(res, indent=4))
|
|
2653
|
+
else:
|
|
2654
|
+
print(f"Got {res['results_count']} neighbours out of {res['neighbours_count']} from {contact['adv_name']}:")
|
|
2655
|
+
for n in res['neighbours']:
|
|
2656
|
+
ct = mc.get_contact_by_key_prefix(n["pubkey"])
|
|
2657
|
+
if ct :
|
|
2658
|
+
name = f"[{n['pubkey'][0:8]}] {ct['adv_name']}"
|
|
2659
|
+
else:
|
|
2660
|
+
name = f"[{n['pubkey']}]"
|
|
2661
|
+
|
|
2662
|
+
print(f" {name:30} last viewed {n['secs_ago']} sec ago at {n['snr']} ")
|
|
2663
|
+
|
|
2633
2664
|
case "req_binary" :
|
|
2634
2665
|
argnum = 2
|
|
2635
2666
|
await mc.ensure_contacts()
|
|
@@ -3127,6 +3158,7 @@ def command_help():
|
|
|
3127
3158
|
cmd <name> <cmd> : sends a command to a repeater (no ack) c [
|
|
3128
3159
|
wmt8 : wait for a msg (reply) with a timeout ]
|
|
3129
3160
|
req_status <name> : requests status from a node rs
|
|
3161
|
+
req_neighbours <name> : requests for neighbours in binary form rn
|
|
3130
3162
|
trace <path> : run a trace, path is comma separated""")
|
|
3131
3163
|
|
|
3132
3164
|
def usage () :
|
|
@@ -3142,6 +3174,7 @@ def usage () :
|
|
|
3142
3174
|
-D : debug
|
|
3143
3175
|
-S : scan for devices and show a selector
|
|
3144
3176
|
-l : list available ble/serial devices and exit
|
|
3177
|
+
-c <on/off> : disables most of color output if off
|
|
3145
3178
|
-T <timeout> : timeout for the ble scan (-S and -l) default 2s
|
|
3146
3179
|
-a <address> : specifies device address (can be a name)
|
|
3147
3180
|
-d <name> : filter meshcore devices with name or address
|
|
@@ -3209,9 +3242,12 @@ async def main(argv):
|
|
|
3209
3242
|
with open(MCCLI_ADDRESS, encoding="utf-8") as f :
|
|
3210
3243
|
address = f.readline().strip()
|
|
3211
3244
|
|
|
3212
|
-
opts, args = getopt.getopt(argv, "a:d:s:ht:p:b:fjDhvSlT:
|
|
3245
|
+
opts, args = getopt.getopt(argv, "a:d:s:ht:p:b:fjDhvSlT:Pc:")
|
|
3213
3246
|
for opt, arg in opts :
|
|
3214
3247
|
match opt:
|
|
3248
|
+
case "-c" :
|
|
3249
|
+
if arg == "off":
|
|
3250
|
+
process_event_message.color = False
|
|
3215
3251
|
case "-d" : # name specified on cmdline
|
|
3216
3252
|
address = arg
|
|
3217
3253
|
case "-a" : # address specified on cmdline
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: meshcore-cli
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.12
|
|
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.24
|
|
14
14
|
Requires-Dist: prompt-toolkit>=3.0.50
|
|
15
15
|
Requires-Dist: pycryptodome
|
|
16
16
|
Requires-Dist: requests>=2.28.0
|
|
@@ -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=cbZPbXrhDENJvnGlR63lrupJQ22Nzk4bxGzudBKQMxQ,143616
|
|
4
|
+
meshcore_cli-1.2.12.dist-info/METADATA,sha256=XU2LqLOUEHonAUDaa2VaiLsp_wvVa5XIwobda-mP_NE,11658
|
|
5
|
+
meshcore_cli-1.2.12.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
6
|
+
meshcore_cli-1.2.12.dist-info/entry_points.txt,sha256=77V29Pyth11GteDk7tneBN3MMk8JI7bTlS-BGSmxCmI,103
|
|
7
|
+
meshcore_cli-1.2.12.dist-info/licenses/LICENSE,sha256=F9s987VtS0AKxW7LdB2EkLMkrdeERI7ICdLJR60A9M4,1066
|
|
8
|
+
meshcore_cli-1.2.12.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=IH0LlN7z14UgiUMGRhJmzp055d9AJ1jvEKV3CrXBfCA,141831
|
|
4
|
-
meshcore_cli-1.2.10.dist-info/METADATA,sha256=p4qn8oBD1_Hlegrk4Gw4pQwd3_2_Mt5yDtX6pWt41DI,11658
|
|
5
|
-
meshcore_cli-1.2.10.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
6
|
-
meshcore_cli-1.2.10.dist-info/entry_points.txt,sha256=77V29Pyth11GteDk7tneBN3MMk8JI7bTlS-BGSmxCmI,103
|
|
7
|
-
meshcore_cli-1.2.10.dist-info/licenses/LICENSE,sha256=F9s987VtS0AKxW7LdB2EkLMkrdeERI7ICdLJR60A9M4,1066
|
|
8
|
-
meshcore_cli-1.2.10.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|