meshcore-cli 1.3.12__py3-none-any.whl → 1.3.15__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 +449 -171
- {meshcore_cli-1.3.12.dist-info → meshcore_cli-1.3.15.dist-info}/METADATA +1 -1
- meshcore_cli-1.3.15.dist-info/RECORD +8 -0
- meshcore_cli-1.3.12.dist-info/RECORD +0 -8
- {meshcore_cli-1.3.12.dist-info → meshcore_cli-1.3.15.dist-info}/WHEEL +0 -0
- {meshcore_cli-1.3.12.dist-info → meshcore_cli-1.3.15.dist-info}/entry_points.txt +0 -0
- {meshcore_cli-1.3.12.dist-info → meshcore_cli-1.3.15.dist-info}/licenses/LICENSE +0 -0
meshcore_cli/meshcore_cli.py
CHANGED
|
@@ -32,7 +32,7 @@ import re
|
|
|
32
32
|
from meshcore import MeshCore, EventType, logger
|
|
33
33
|
|
|
34
34
|
# Version
|
|
35
|
-
VERSION = "v1.3.
|
|
35
|
+
VERSION = "v1.3.15"
|
|
36
36
|
|
|
37
37
|
# default ble address is stored in a config file
|
|
38
38
|
MCCLI_CONFIG_DIR = str(Path.home()) + "/.config/meshcore/"
|
|
@@ -1028,7 +1028,7 @@ Some cmds have an help accessible with ?<cmd>. Do ?[Tab] to get a list.
|
|
|
1028
1028
|
if '%' in dest and scope!=None :
|
|
1029
1029
|
dest_scope = dest.split("%")[-1]
|
|
1030
1030
|
dest = dest[:-len(dest_scope)-1]
|
|
1031
|
-
nc = mc
|
|
1031
|
+
nc = await get_contact_from_arg(mc, dest)
|
|
1032
1032
|
if nc is None:
|
|
1033
1033
|
if dest == "public" :
|
|
1034
1034
|
nc = {"adv_name" : "public", "type" : 0, "chan_nb" : 0}
|
|
@@ -1083,7 +1083,7 @@ Some cmds have an help accessible with ?<cmd>. Do ?[Tab] to get a list.
|
|
|
1083
1083
|
dest_scope = dest.split("%")[-1]
|
|
1084
1084
|
dest = dest[:-len(dest_scope)-1]
|
|
1085
1085
|
await set_scope (mc, dest_scope)
|
|
1086
|
-
tct = mc
|
|
1086
|
+
tct = await get_contact_from_arg(mc, dest)
|
|
1087
1087
|
if len(args)>1 and not tct is None: # a contact, send a message
|
|
1088
1088
|
if tct["type"] == 1 or tct["type"] == 3: # client or room
|
|
1089
1089
|
last_ack = await msg_ack(mc, tct, line.split(" ", 1)[1])
|
|
@@ -1106,7 +1106,7 @@ Some cmds have an help accessible with ?<cmd>. Do ?[Tab] to get a list.
|
|
|
1106
1106
|
dest_scope = contact_name.split("%")[-1]
|
|
1107
1107
|
contact_name = contact_name[:-len(dest_scope)-1]
|
|
1108
1108
|
await set_scope (mc, dest_scope)
|
|
1109
|
-
tct = mc.
|
|
1109
|
+
tct = mc.get_contact_from_arg(mc, contact_name)
|
|
1110
1110
|
if tct is None:
|
|
1111
1111
|
print(f"{contact_name} is not a contact")
|
|
1112
1112
|
else:
|
|
@@ -1346,9 +1346,7 @@ async def process_contact_chat_line(mc, contact, line):
|
|
|
1346
1346
|
perm = int(perm_string[1:])
|
|
1347
1347
|
else:
|
|
1348
1348
|
perm = int(perm_string,16)
|
|
1349
|
-
ct=mc
|
|
1350
|
-
if ct is None:
|
|
1351
|
-
ct=mc.get_contact_by_key_prefix(name)
|
|
1349
|
+
ct= await get_contact_from_arg(mc, name)
|
|
1352
1350
|
if ct is None:
|
|
1353
1351
|
if name == "self" or mc.self_info["public_key"].startswith(name):
|
|
1354
1352
|
key = mc.self_info["public_key"]
|
|
@@ -1847,6 +1845,22 @@ async def print_disc_trace_to (mc, contact):
|
|
|
1847
1845
|
|
|
1848
1846
|
await next_cmd(mc, ["trace", trace])
|
|
1849
1847
|
|
|
1848
|
+
|
|
1849
|
+
async def get_contact_from_arg(mc, arg):
|
|
1850
|
+
contact = None
|
|
1851
|
+
await mc.ensure_contacts()
|
|
1852
|
+
|
|
1853
|
+
# first try with key prefix
|
|
1854
|
+
try: # try only if its a valid hex
|
|
1855
|
+
int(arg ,16)
|
|
1856
|
+
contact = mc.get_contact_by_key_prefix(arg)
|
|
1857
|
+
except ValueError:
|
|
1858
|
+
pass
|
|
1859
|
+
if contact is None: # try by name
|
|
1860
|
+
contact = mc.get_contact_by_name(arg)
|
|
1861
|
+
|
|
1862
|
+
return contact
|
|
1863
|
+
|
|
1850
1864
|
async def next_cmd(mc, cmds, json_output=False):
|
|
1851
1865
|
""" process next command """
|
|
1852
1866
|
global ARROW_HEAD, SLASH_START, SLASH_END, INVERT_SLASH
|
|
@@ -2497,8 +2511,7 @@ async def next_cmd(mc, cmds, json_output=False):
|
|
|
2497
2511
|
dest = None
|
|
2498
2512
|
|
|
2499
2513
|
if dest is None:
|
|
2500
|
-
await mc
|
|
2501
|
-
dest = mc.get_contact_by_name(cmds[1])
|
|
2514
|
+
dest = await get_contact_from_arg(mc, cmds[1])
|
|
2502
2515
|
|
|
2503
2516
|
if dest is None:
|
|
2504
2517
|
if json_output :
|
|
@@ -2549,8 +2562,7 @@ async def next_cmd(mc, cmds, json_output=False):
|
|
|
2549
2562
|
dest = None
|
|
2550
2563
|
|
|
2551
2564
|
if dest is None:
|
|
2552
|
-
await mc
|
|
2553
|
-
dest = mc.get_contact_by_name(cmds[1])
|
|
2565
|
+
dest = await get_contact_from_arg(mc, cmds[1])
|
|
2554
2566
|
|
|
2555
2567
|
if dest is None:
|
|
2556
2568
|
if json_output :
|
|
@@ -2627,9 +2639,9 @@ async def next_cmd(mc, cmds, json_output=False):
|
|
|
2627
2639
|
|
|
2628
2640
|
case "login" | "l" :
|
|
2629
2641
|
argnum = 2
|
|
2630
|
-
await mc
|
|
2631
|
-
|
|
2632
|
-
if contact is None:
|
|
2642
|
+
contact = await get_contact_from_arg(mc, cmds[1])
|
|
2643
|
+
|
|
2644
|
+
if contact is None: # still none ? contact not found
|
|
2633
2645
|
if json_output :
|
|
2634
2646
|
print(json.dumps({"error" : "contact unknown", "name" : cmds[1]}))
|
|
2635
2647
|
else:
|
|
@@ -2666,42 +2678,57 @@ async def next_cmd(mc, cmds, json_output=False):
|
|
|
2666
2678
|
|
|
2667
2679
|
case "logout" :
|
|
2668
2680
|
argnum = 1
|
|
2669
|
-
await mc
|
|
2670
|
-
contact
|
|
2671
|
-
|
|
2672
|
-
|
|
2673
|
-
|
|
2674
|
-
|
|
2675
|
-
elif json_output :
|
|
2676
|
-
print(json.dumps(res.payload))
|
|
2681
|
+
contact = await get_contact_from_arg(mc, cmds[1])
|
|
2682
|
+
if contact is None:
|
|
2683
|
+
if json_output :
|
|
2684
|
+
print(json.dumps({"error" : "unknown contact"}))
|
|
2685
|
+
else:
|
|
2686
|
+
print(f"Unknown contact {cmds[1]}")
|
|
2677
2687
|
else:
|
|
2678
|
-
|
|
2679
|
-
|
|
2688
|
+
res = await mc.commands.send_logout(contact)
|
|
2689
|
+
logger.debug(res)
|
|
2690
|
+
if res.type == EventType.ERROR:
|
|
2691
|
+
print(f"Error while logout: {res}")
|
|
2692
|
+
elif json_output :
|
|
2693
|
+
print(json.dumps(res.payload))
|
|
2694
|
+
else:
|
|
2695
|
+
print("Logout ok")
|
|
2696
|
+
|
|
2680
2697
|
case "contact_timeout" :
|
|
2681
2698
|
argnum = 2
|
|
2682
|
-
await mc
|
|
2683
|
-
contact
|
|
2684
|
-
|
|
2699
|
+
contact = await get_contact_from_args(mc, cmds[1])
|
|
2700
|
+
if contact is None:
|
|
2701
|
+
if json_output :
|
|
2702
|
+
print(json.dumps({"error" : "unknown contact"}))
|
|
2703
|
+
else:
|
|
2704
|
+
print(f"Unknown contact {cmds[1]}")
|
|
2705
|
+
else:
|
|
2706
|
+
contact["timeout"] = float(cmds[2])
|
|
2685
2707
|
|
|
2686
2708
|
case "disc_path" | "dp" :
|
|
2687
2709
|
argnum = 1
|
|
2688
|
-
await mc
|
|
2689
|
-
contact
|
|
2690
|
-
res = await discover_path(mc, contact)
|
|
2691
|
-
if res is None:
|
|
2692
|
-
print(f"Error while discovering path")
|
|
2693
|
-
else:
|
|
2710
|
+
contact = await get_contact_from_arg(mc, cmds[1])
|
|
2711
|
+
if contact is None:
|
|
2694
2712
|
if json_output :
|
|
2695
|
-
print(json.dumps(
|
|
2713
|
+
print(json.dumps({"error" : "unknown contact"}))
|
|
2696
2714
|
else:
|
|
2697
|
-
|
|
2698
|
-
|
|
2715
|
+
print(f"Unknown contact {cmds[1]}")
|
|
2716
|
+
else:
|
|
2717
|
+
res = await discover_path(mc, contact)
|
|
2718
|
+
if res is None:
|
|
2719
|
+
print(f"Error while discovering path")
|
|
2720
|
+
else:
|
|
2721
|
+
if json_output :
|
|
2722
|
+
print(json.dumps(res, indent=4))
|
|
2699
2723
|
else:
|
|
2700
|
-
|
|
2701
|
-
|
|
2702
|
-
|
|
2703
|
-
|
|
2704
|
-
|
|
2724
|
+
if "error" in res :
|
|
2725
|
+
print("Timeout while discovering path")
|
|
2726
|
+
else:
|
|
2727
|
+
outp = res['out_path']
|
|
2728
|
+
outp = outp if outp != "" else "direct"
|
|
2729
|
+
inp = res['in_path']
|
|
2730
|
+
inp = inp if inp != "" else "direct"
|
|
2731
|
+
print(f"Path for {contact['adv_name']}: out {outp}, in {inp}")
|
|
2705
2732
|
|
|
2706
2733
|
case "node_discover"|"nd" :
|
|
2707
2734
|
argnum = 1
|
|
@@ -2767,143 +2794,174 @@ async def next_cmd(mc, cmds, json_output=False):
|
|
|
2767
2794
|
case "req_telemetry"|"rt" :
|
|
2768
2795
|
argnum = 1
|
|
2769
2796
|
await mc.ensure_contacts()
|
|
2770
|
-
contact = mc
|
|
2771
|
-
|
|
2772
|
-
res = await mc.commands.req_telemetry_sync(contact, timeout)
|
|
2773
|
-
if res is None :
|
|
2797
|
+
contact = await get_contact_from_arg(mc, cmds[1])
|
|
2798
|
+
if contact is None:
|
|
2774
2799
|
if json_output :
|
|
2775
|
-
print(json.dumps({"error" : "
|
|
2800
|
+
print(json.dumps({"error" : "unknown contact"}))
|
|
2776
2801
|
else:
|
|
2777
|
-
print("
|
|
2778
|
-
else
|
|
2779
|
-
|
|
2780
|
-
|
|
2781
|
-
|
|
2782
|
-
|
|
2783
|
-
|
|
2802
|
+
print(f"Unknown contact {cmds[1]}")
|
|
2803
|
+
else:
|
|
2804
|
+
timeout = 0 if not "timeout" in contact else contact["timeout"]
|
|
2805
|
+
res = await mc.commands.req_telemetry_sync(contact, timeout)
|
|
2806
|
+
if res is None :
|
|
2807
|
+
if json_output :
|
|
2808
|
+
print(json.dumps({"error" : "Getting data"}))
|
|
2809
|
+
else:
|
|
2810
|
+
print("Error getting data")
|
|
2811
|
+
else :
|
|
2812
|
+
print(json.dumps({
|
|
2813
|
+
"name": contact["adv_name"],
|
|
2814
|
+
"pubkey_pre": contact["public_key"][0:16],
|
|
2815
|
+
"lpp": res,
|
|
2816
|
+
}, indent = 4))
|
|
2784
2817
|
|
|
2785
2818
|
case "req_status"|"rs" :
|
|
2786
2819
|
argnum = 1
|
|
2787
|
-
await mc
|
|
2788
|
-
contact
|
|
2789
|
-
timeout = 0 if not "timeout" in contact else contact["timeout"]
|
|
2790
|
-
res = await mc.commands.req_status_sync(contact, timeout)
|
|
2791
|
-
if res is None :
|
|
2820
|
+
contact = await get_contact_from_arg(mc, cmds[1])
|
|
2821
|
+
if contact is None:
|
|
2792
2822
|
if json_output :
|
|
2793
|
-
print(json.dumps({"error" : "
|
|
2823
|
+
print(json.dumps({"error" : "unknown contact"}))
|
|
2794
2824
|
else:
|
|
2795
|
-
print("
|
|
2796
|
-
else
|
|
2797
|
-
|
|
2825
|
+
print(f"Unknown contact {cmds[1]}")
|
|
2826
|
+
else:
|
|
2827
|
+
timeout = 0 if not "timeout" in contact else contact["timeout"]
|
|
2828
|
+
res = await mc.commands.req_status_sync(contact, timeout)
|
|
2829
|
+
if res is None :
|
|
2830
|
+
if json_output :
|
|
2831
|
+
print(json.dumps({"error" : "Getting data"}))
|
|
2832
|
+
else:
|
|
2833
|
+
print("Error getting data")
|
|
2834
|
+
else :
|
|
2835
|
+
print(json.dumps(res, indent=4))
|
|
2798
2836
|
|
|
2799
2837
|
case "req_mma" | "rm":
|
|
2800
2838
|
argnum = 3
|
|
2801
2839
|
await mc.ensure_contacts()
|
|
2802
|
-
contact = mc
|
|
2803
|
-
if
|
|
2804
|
-
from_secs = int(cmds[2][0:-1])
|
|
2805
|
-
elif cmds[2][-1] == "m":
|
|
2806
|
-
from_secs = int(cmds[2][0:-1]) * 60
|
|
2807
|
-
elif cmds[2][-1] == "h":
|
|
2808
|
-
from_secs = int(cmds[2][0:-1]) * 3600
|
|
2809
|
-
else :
|
|
2810
|
-
from_secs = int(cmds[2]) * 60 # same as tdeck
|
|
2811
|
-
if cmds[3][-1] == "s":
|
|
2812
|
-
to_secs = int(cmds[3][0:-1])
|
|
2813
|
-
elif cmds[3][-1] == "m":
|
|
2814
|
-
to_secs = int(cmds[3][0:-1]) * 60
|
|
2815
|
-
elif cmds[3][-1] == "h":
|
|
2816
|
-
to_secs = int(cmds[3][0:-1]) * 3600
|
|
2817
|
-
else :
|
|
2818
|
-
to_secs = int(cmds[3]) * 60
|
|
2819
|
-
timeout = 0 if not "timeout" in contact else contact["timeout"]
|
|
2820
|
-
res = await mc.commands.req_mma_sync(contact, from_secs, to_secs, timeout)
|
|
2821
|
-
if res is None :
|
|
2840
|
+
contact = await get_contact_from_arg(mc, cmds[1])
|
|
2841
|
+
if contact is None:
|
|
2822
2842
|
if json_output :
|
|
2823
|
-
print(json.dumps({"error" : "
|
|
2843
|
+
print(json.dumps({"error" : "unknown contact"}))
|
|
2824
2844
|
else:
|
|
2825
|
-
print("
|
|
2826
|
-
else
|
|
2827
|
-
|
|
2845
|
+
print(f"Unknown contact {cmds[1]}")
|
|
2846
|
+
else:
|
|
2847
|
+
if cmds[2][-1] == "s":
|
|
2848
|
+
from_secs = int(cmds[2][0:-1])
|
|
2849
|
+
elif cmds[2][-1] == "m":
|
|
2850
|
+
from_secs = int(cmds[2][0:-1]) * 60
|
|
2851
|
+
elif cmds[2][-1] == "h":
|
|
2852
|
+
from_secs = int(cmds[2][0:-1]) * 3600
|
|
2853
|
+
else :
|
|
2854
|
+
from_secs = int(cmds[2]) * 60 # same as tdeck
|
|
2855
|
+
if cmds[3][-1] == "s":
|
|
2856
|
+
to_secs = int(cmds[3][0:-1])
|
|
2857
|
+
elif cmds[3][-1] == "m":
|
|
2858
|
+
to_secs = int(cmds[3][0:-1]) * 60
|
|
2859
|
+
elif cmds[3][-1] == "h":
|
|
2860
|
+
to_secs = int(cmds[3][0:-1]) * 3600
|
|
2861
|
+
else :
|
|
2862
|
+
to_secs = int(cmds[3]) * 60
|
|
2863
|
+
timeout = 0 if not "timeout" in contact else contact["timeout"]
|
|
2864
|
+
res = await mc.commands.req_mma_sync(contact, from_secs, to_secs, timeout)
|
|
2865
|
+
if res is None :
|
|
2866
|
+
if json_output :
|
|
2867
|
+
print(json.dumps({"error" : "Getting data"}))
|
|
2868
|
+
else:
|
|
2869
|
+
print("Error getting data")
|
|
2870
|
+
else :
|
|
2871
|
+
print(json.dumps(res, indent=4))
|
|
2828
2872
|
|
|
2829
2873
|
case "req_acl" :
|
|
2830
2874
|
argnum = 1
|
|
2831
|
-
await mc
|
|
2832
|
-
contact
|
|
2833
|
-
timeout = 0 if not "timeout" in contact else contact["timeout"]
|
|
2834
|
-
res = await mc.commands.req_acl_sync(contact, timeout)
|
|
2835
|
-
if res is None :
|
|
2875
|
+
contact = await get_contact_from_arg(mc, cmds[1])
|
|
2876
|
+
if contact is None:
|
|
2836
2877
|
if json_output :
|
|
2837
|
-
print(json.dumps({"error" : "
|
|
2878
|
+
print(json.dumps({"error" : "unknown contact"}))
|
|
2838
2879
|
else:
|
|
2839
|
-
print("
|
|
2840
|
-
else
|
|
2841
|
-
if
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
|
|
2845
|
-
|
|
2846
|
-
|
|
2847
|
-
|
|
2848
|
-
|
|
2849
|
-
|
|
2850
|
-
|
|
2851
|
-
|
|
2852
|
-
|
|
2880
|
+
print(f"Unknown contact {cmds[1]}")
|
|
2881
|
+
else:
|
|
2882
|
+
timeout = 0 if not "timeout" in contact else contact["timeout"]
|
|
2883
|
+
res = await mc.commands.req_acl_sync(contact, timeout)
|
|
2884
|
+
if res is None :
|
|
2885
|
+
if json_output :
|
|
2886
|
+
print(json.dumps({"error" : "Getting data"}))
|
|
2887
|
+
else:
|
|
2888
|
+
print("Error getting data")
|
|
2889
|
+
else :
|
|
2890
|
+
if json_output:
|
|
2891
|
+
print(json.dumps(res, indent=4))
|
|
2892
|
+
else:
|
|
2893
|
+
for e in res:
|
|
2894
|
+
name = e['key']
|
|
2895
|
+
ct = mc.get_contact_by_key_prefix(e['key'])
|
|
2896
|
+
if ct is None:
|
|
2897
|
+
if mc.self_info["public_key"].startswith(e['key']):
|
|
2898
|
+
name = f"{'self':<20} [{e['key']}]"
|
|
2899
|
+
else:
|
|
2900
|
+
name = f"{ct['adv_name']:<20} [{e['key']}]"
|
|
2901
|
+
print(f"{name:{' '}<35}: {e['perm']:02x}")
|
|
2853
2902
|
|
|
2854
2903
|
case "req_neighbours"|"rn" :
|
|
2855
2904
|
argnum = 1
|
|
2856
|
-
await mc
|
|
2857
|
-
contact
|
|
2858
|
-
timeout = 0 if not "timeout" in contact else contact["timeout"]
|
|
2859
|
-
res = await mc.commands.fetch_all_neighbours(contact, timeout=timeout)
|
|
2860
|
-
if res is None :
|
|
2905
|
+
contact = await get_contact_from_arg(mc, cmds[1])
|
|
2906
|
+
if contact is None:
|
|
2861
2907
|
if json_output :
|
|
2862
|
-
print(json.dumps({"error" : "
|
|
2863
|
-
else:
|
|
2864
|
-
print("Error getting data")
|
|
2865
|
-
else :
|
|
2866
|
-
if json_output:
|
|
2867
|
-
print(json.dumps(res, indent=4))
|
|
2908
|
+
print(json.dumps({"error" : "unknown contact"}))
|
|
2868
2909
|
else:
|
|
2869
|
-
|
|
2870
|
-
|
|
2871
|
-
|
|
2872
|
-
|
|
2873
|
-
|
|
2874
|
-
|
|
2875
|
-
|
|
2876
|
-
|
|
2877
|
-
|
|
2878
|
-
|
|
2879
|
-
|
|
2880
|
-
|
|
2881
|
-
|
|
2882
|
-
|
|
2883
|
-
|
|
2884
|
-
|
|
2885
|
-
|
|
2886
|
-
|
|
2887
|
-
|
|
2888
|
-
|
|
2889
|
-
|
|
2890
|
-
|
|
2891
|
-
|
|
2892
|
-
|
|
2910
|
+
print(f"Unknown contact {cmds[1]}")
|
|
2911
|
+
else:
|
|
2912
|
+
timeout = 0 if not "timeout" in contact else contact["timeout"]
|
|
2913
|
+
res = await mc.commands.fetch_all_neighbours(contact, timeout=timeout)
|
|
2914
|
+
if res is None :
|
|
2915
|
+
if json_output :
|
|
2916
|
+
print(json.dumps({"error" : "Getting data"}))
|
|
2917
|
+
else:
|
|
2918
|
+
print("Error getting data")
|
|
2919
|
+
else :
|
|
2920
|
+
if json_output:
|
|
2921
|
+
print(json.dumps(res, indent=4))
|
|
2922
|
+
else:
|
|
2923
|
+
width = os.get_terminal_size().columns
|
|
2924
|
+
print(f"Got {res['results_count']} neighbours out of {res['neighbours_count']} from {contact['adv_name']}:")
|
|
2925
|
+
for n in res['neighbours']:
|
|
2926
|
+
ct = mc.get_contact_by_key_prefix(n["pubkey"])
|
|
2927
|
+
if ct and width > 60 :
|
|
2928
|
+
name = f"[{n['pubkey'][0:8]}] {ct['adv_name']}"
|
|
2929
|
+
name = f"{name:30}"
|
|
2930
|
+
elif ct :
|
|
2931
|
+
name = f"{ct['adv_name']}"
|
|
2932
|
+
name = f"{name:20}"
|
|
2933
|
+
else:
|
|
2934
|
+
name = f"[{n['pubkey']}]"
|
|
2935
|
+
|
|
2936
|
+
t_s = n['secs_ago']
|
|
2937
|
+
time_ago = f"{t_s}s"
|
|
2938
|
+
if t_s / 86400 >= 1 : # result in days
|
|
2939
|
+
time_ago = f"{int(t_s/86400)}d ago{f' ({time_ago})' if width > 62 else ''}"
|
|
2940
|
+
elif t_s / 3600 >= 1 : # result in days
|
|
2941
|
+
time_ago = f"{int(t_s/3600)}h ago{f' ({time_ago})' if width > 62 else ''}"
|
|
2942
|
+
elif t_s / 60 >= 1 : # result in min
|
|
2943
|
+
time_ago = f"{int(t_s/60)}m ago{f' ({time_ago})' if width > 62 else ''}"
|
|
2944
|
+
|
|
2945
|
+
print(f" {name} {time_ago}, {n['snr']}dB{' SNR' if width > 66 else ''}")
|
|
2893
2946
|
|
|
2894
2947
|
case "req_binary" :
|
|
2895
2948
|
argnum = 2
|
|
2896
|
-
await mc
|
|
2897
|
-
contact
|
|
2898
|
-
timeout = 0 if not "timeout" in contact else contact["timeout"]
|
|
2899
|
-
res = await mc.commands.req_binary(contact, bytes.fromhex(cmds[2]), timeout)
|
|
2900
|
-
if res is None :
|
|
2949
|
+
contact = await get_contact_from_arg(mc, cmds[1])
|
|
2950
|
+
if contact is None:
|
|
2901
2951
|
if json_output :
|
|
2902
|
-
print(json.dumps({"error" : "
|
|
2952
|
+
print(json.dumps({"error" : "unknown contact"}))
|
|
2903
2953
|
else:
|
|
2904
|
-
print("
|
|
2905
|
-
else
|
|
2906
|
-
|
|
2954
|
+
print(f"Unknown contact {cmds[1]}")
|
|
2955
|
+
else:
|
|
2956
|
+
timeout = 0 if not "timeout" in contact else contact["timeout"]
|
|
2957
|
+
res = await mc.commands.req_binary(contact, bytes.fromhex(cmds[2]), timeout)
|
|
2958
|
+
if res is None :
|
|
2959
|
+
if json_output :
|
|
2960
|
+
print(json.dumps({"error" : "Getting binary data"}))
|
|
2961
|
+
else:
|
|
2962
|
+
print("Error getting binary data")
|
|
2963
|
+
else :
|
|
2964
|
+
print(json.dumps(res))
|
|
2907
2965
|
|
|
2908
2966
|
case "contacts" | "list" | "lc":
|
|
2909
2967
|
await mc.ensure_contacts(follow=True)
|
|
@@ -2968,8 +3026,7 @@ async def next_cmd(mc, cmds, json_output=False):
|
|
|
2968
3026
|
|
|
2969
3027
|
case "path":
|
|
2970
3028
|
argnum = 1
|
|
2971
|
-
|
|
2972
|
-
contact = mc.get_contact_by_name(cmds[1])
|
|
3029
|
+
contact = await get_contact_from_arg(mc, cmds[1])
|
|
2973
3030
|
if contact is None:
|
|
2974
3031
|
if json_output :
|
|
2975
3032
|
print(json.dumps({"error" : "contact unknown", "name" : cmds[1]}))
|
|
@@ -2993,7 +3050,7 @@ async def next_cmd(mc, cmds, json_output=False):
|
|
|
2993
3050
|
case "contact_info" | "ci":
|
|
2994
3051
|
argnum = 1
|
|
2995
3052
|
res = await mc.ensure_contacts(follow=True)
|
|
2996
|
-
contact = mc
|
|
3053
|
+
contact = await get_contact_from_arg(mc, cmds[1])
|
|
2997
3054
|
if contact is None:
|
|
2998
3055
|
if json_output :
|
|
2999
3056
|
print(json.dumps({"error" : "contact unknown", "name" : cmds[1]}))
|
|
@@ -3004,8 +3061,7 @@ async def next_cmd(mc, cmds, json_output=False):
|
|
|
3004
3061
|
|
|
3005
3062
|
case "change_path" | "cp":
|
|
3006
3063
|
argnum = 2
|
|
3007
|
-
await mc
|
|
3008
|
-
contact = mc.get_contact_by_name(cmds[1])
|
|
3064
|
+
contact = await get_contact_from_arg(mc, cmds[1])
|
|
3009
3065
|
if contact is None:
|
|
3010
3066
|
if json_output :
|
|
3011
3067
|
print(json.dumps({"error" : "contact unknown", "name" : cmds[1]}))
|
|
@@ -3027,8 +3083,7 @@ async def next_cmd(mc, cmds, json_output=False):
|
|
|
3027
3083
|
|
|
3028
3084
|
case "change_flags" | "cf":
|
|
3029
3085
|
argnum = 2
|
|
3030
|
-
await mc
|
|
3031
|
-
contact = mc.get_contact_by_name(cmds[1])
|
|
3086
|
+
contact = await get_contact_from_arg(mc, cmds[1])
|
|
3032
3087
|
if contact is None:
|
|
3033
3088
|
if json_output :
|
|
3034
3089
|
print(json.dumps({"error" : "contact unknown", "name" : cmds[1]}))
|
|
@@ -3044,8 +3099,7 @@ async def next_cmd(mc, cmds, json_output=False):
|
|
|
3044
3099
|
|
|
3045
3100
|
case "reset_path" | "rp" :
|
|
3046
3101
|
argnum = 1
|
|
3047
|
-
await mc
|
|
3048
|
-
contact = mc.get_contact_by_name(cmds[1])
|
|
3102
|
+
contact = await get_contact_from_arg(mc, cmds[1])
|
|
3049
3103
|
if contact is None:
|
|
3050
3104
|
if json_output :
|
|
3051
3105
|
print(json.dumps({"error" : "contact unknown", "name" : cmds[1]}))
|
|
@@ -3064,8 +3118,7 @@ async def next_cmd(mc, cmds, json_output=False):
|
|
|
3064
3118
|
|
|
3065
3119
|
case "share_contact" | "sc":
|
|
3066
3120
|
argnum = 1
|
|
3067
|
-
await mc
|
|
3068
|
-
contact = mc.get_contact_by_name(cmds[1])
|
|
3121
|
+
contact = await get_contact_from_arg(mc, cmds[1])
|
|
3069
3122
|
if contact is None:
|
|
3070
3123
|
if json_output :
|
|
3071
3124
|
print(json.dumps({"error" : "contact unknown", "name" : cmds[1]}))
|
|
@@ -3081,8 +3134,7 @@ async def next_cmd(mc, cmds, json_output=False):
|
|
|
3081
3134
|
|
|
3082
3135
|
case "export_contact"|"ec":
|
|
3083
3136
|
argnum = 1
|
|
3084
|
-
await mc
|
|
3085
|
-
contact = mc.get_contact_by_name(cmds[1])
|
|
3137
|
+
contact = await get_contact_from_arg(mc, cmds[1])
|
|
3086
3138
|
if contact is None:
|
|
3087
3139
|
if json_output :
|
|
3088
3140
|
print(json.dumps({"error" : "contact unknown", "name" : cmds[1]}))
|
|
@@ -3112,8 +3164,7 @@ async def next_cmd(mc, cmds, json_output=False):
|
|
|
3112
3164
|
|
|
3113
3165
|
case "upload_contact" | "uc" :
|
|
3114
3166
|
argnum = 1
|
|
3115
|
-
await mc
|
|
3116
|
-
contact = mc.get_contact_by_name(cmds[1])
|
|
3167
|
+
contact = await get_contact_from_arg(mc, cmds[1])
|
|
3117
3168
|
if contact is None:
|
|
3118
3169
|
if json_output :
|
|
3119
3170
|
print(json.dumps({"error" : "contact unknown", "name" : cmds[1]}))
|
|
@@ -3157,7 +3208,6 @@ async def next_cmd(mc, cmds, json_output=False):
|
|
|
3157
3208
|
|
|
3158
3209
|
case "remove_contact" :
|
|
3159
3210
|
argnum = 1
|
|
3160
|
-
await mc.ensure_contacts()
|
|
3161
3211
|
contact = mc.get_contact_by_name(cmds[1])
|
|
3162
3212
|
if contact is None:
|
|
3163
3213
|
if json_output :
|
|
@@ -3279,8 +3329,7 @@ async def next_cmd(mc, cmds, json_output=False):
|
|
|
3279
3329
|
|
|
3280
3330
|
case "chat_to" | "imto" | "to" :
|
|
3281
3331
|
argnum = 1
|
|
3282
|
-
await mc
|
|
3283
|
-
contact = mc.get_contact_by_name(cmds[1])
|
|
3332
|
+
contact = await get_contact_from_arg(mc, cmds[1])
|
|
3284
3333
|
await interactive_loop(mc, to=contact)
|
|
3285
3334
|
|
|
3286
3335
|
case "script" :
|
|
@@ -3288,8 +3337,7 @@ async def next_cmd(mc, cmds, json_output=False):
|
|
|
3288
3337
|
await process_script(mc, cmds[1], json_output=json_output)
|
|
3289
3338
|
|
|
3290
3339
|
case _ :
|
|
3291
|
-
await mc
|
|
3292
|
-
contact = mc.get_contact_by_name(cmds[0])
|
|
3340
|
+
contact = await get_contact_from_arg(mc, cmds[0])
|
|
3293
3341
|
if contact is None:
|
|
3294
3342
|
logger.error(f"Unknown command : {cmd}, {cmds} not executed ...")
|
|
3295
3343
|
return None
|
|
@@ -3429,6 +3477,7 @@ def command_usage() :
|
|
|
3429
3477
|
-b <baudrate> : specify baudrate
|
|
3430
3478
|
-C : toggles classic mode for prompt
|
|
3431
3479
|
-c <on/off> : disables most of color output if off
|
|
3480
|
+
-r : repeater mode (raw text CLI, use with -s)
|
|
3432
3481
|
""")
|
|
3433
3482
|
|
|
3434
3483
|
def get_help_for (cmdname, context="line") :
|
|
@@ -3588,6 +3637,223 @@ To remove a channel, use remove_channel, either with channel name or number.
|
|
|
3588
3637
|
else:
|
|
3589
3638
|
print(f"Sorry, no help yet for {cmdname}")
|
|
3590
3639
|
|
|
3640
|
+
# Repeater mode history file
|
|
3641
|
+
MCCLI_REPEATER_HISTORY_FILE = MCCLI_CONFIG_DIR + "repeater_history"
|
|
3642
|
+
|
|
3643
|
+
# Repeater command completion dictionary
|
|
3644
|
+
REPEATER_COMMANDS = {
|
|
3645
|
+
"ver": None,
|
|
3646
|
+
"board": None,
|
|
3647
|
+
"reboot": None,
|
|
3648
|
+
"advert": None,
|
|
3649
|
+
"clock": {"sync": None},
|
|
3650
|
+
"time": None,
|
|
3651
|
+
"neighbors": None,
|
|
3652
|
+
"stats-core": None,
|
|
3653
|
+
"stats-radio": None,
|
|
3654
|
+
"stats-packets": None,
|
|
3655
|
+
"clear": {"stats": None},
|
|
3656
|
+
"log": {"start": None, "stop": None, "erase": None},
|
|
3657
|
+
"get": {
|
|
3658
|
+
"name": None, "radio": None, "tx": None, "freq": None,
|
|
3659
|
+
"public.key": None, "prv.key": None, "repeat": None, "role": None,
|
|
3660
|
+
"lat": None, "lon": None, "af": None,
|
|
3661
|
+
"rxdelay": None, "txdelay": None, "direct.txdelay": None,
|
|
3662
|
+
"flood.max": None, "flood.advert.interval": None,
|
|
3663
|
+
"advert.interval": None, "guest.password": None,
|
|
3664
|
+
"allow.read.only": None, "multi.acks": None,
|
|
3665
|
+
"int.thresh": None, "agc.reset.interval": None,
|
|
3666
|
+
"bridge.enabled": None, "bridge.delay": None,
|
|
3667
|
+
"bridge.source": None, "bridge.baud": None,
|
|
3668
|
+
"bridge.channel": None, "bridge.secret": None, "bridge.type": None,
|
|
3669
|
+
"adc.multiplier": None, "acl": None,
|
|
3670
|
+
},
|
|
3671
|
+
"set": {
|
|
3672
|
+
"name": None, "radio": None, "tx": None, "freq": None,
|
|
3673
|
+
"prv.key": None, "repeat": {"on": None, "off": None},
|
|
3674
|
+
"lat": None, "lon": None, "af": None,
|
|
3675
|
+
"rxdelay": None, "txdelay": None, "direct.txdelay": None,
|
|
3676
|
+
"flood.max": None, "flood.advert.interval": None,
|
|
3677
|
+
"advert.interval": None, "guest.password": None,
|
|
3678
|
+
"allow.read.only": {"on": None, "off": None},
|
|
3679
|
+
"multi.acks": None, "int.thresh": None, "agc.reset.interval": None,
|
|
3680
|
+
"bridge.enabled": {"on": None, "off": None},
|
|
3681
|
+
"bridge.delay": None, "bridge.source": None,
|
|
3682
|
+
"bridge.baud": None, "bridge.channel": None, "bridge.secret": None,
|
|
3683
|
+
"adc.multiplier": None,
|
|
3684
|
+
},
|
|
3685
|
+
"password": None,
|
|
3686
|
+
"erase": None,
|
|
3687
|
+
"gps": {"on": None, "off": None, "sync": None, "setloc": None, "advert": {"none": None, "share": None, "prefs": None}},
|
|
3688
|
+
"sensor": {"list": None, "get": None, "set": None},
|
|
3689
|
+
"region": {"get": None, "put": None, "remove": None, "save": None, "load": None, "home": None, "allowf": None, "denyf": None},
|
|
3690
|
+
"setperm": None,
|
|
3691
|
+
"tempradio": None,
|
|
3692
|
+
"neighbor.remove": None,
|
|
3693
|
+
"quit": None,
|
|
3694
|
+
"q": None,
|
|
3695
|
+
"help": None,
|
|
3696
|
+
}
|
|
3697
|
+
|
|
3698
|
+
REPEATER_HELP = f"""
|
|
3699
|
+
{ANSI_BCYAN}Repeater CLI Commands:{ANSI_END}
|
|
3700
|
+
|
|
3701
|
+
{ANSI_BGREEN}Info:{ANSI_END}
|
|
3702
|
+
ver - Firmware version
|
|
3703
|
+
board - Board name
|
|
3704
|
+
clock - Show current time
|
|
3705
|
+
|
|
3706
|
+
{ANSI_BGREEN}Stats:{ANSI_END}
|
|
3707
|
+
stats-core - Core stats (uptime, battery, queue)
|
|
3708
|
+
stats-radio - Radio stats (RSSI, SNR, noise floor)
|
|
3709
|
+
stats-packets - Packet statistics (sent/recv counts)
|
|
3710
|
+
clear stats - Reset all statistics
|
|
3711
|
+
|
|
3712
|
+
{ANSI_BGREEN}Network:{ANSI_END}
|
|
3713
|
+
neighbors - Show neighboring repeaters (zero-hop)
|
|
3714
|
+
advert - Send advertisement now
|
|
3715
|
+
|
|
3716
|
+
{ANSI_BGREEN}Logging:{ANSI_END}
|
|
3717
|
+
log start - Enable packet logging
|
|
3718
|
+
log stop - Disable packet logging
|
|
3719
|
+
log - Dump log file to console
|
|
3720
|
+
log erase - Erase log file
|
|
3721
|
+
|
|
3722
|
+
{ANSI_BGREEN}Configuration (get/set):{ANSI_END}
|
|
3723
|
+
get name - Node name
|
|
3724
|
+
get radio - Radio params (freq,bw,sf,cr)
|
|
3725
|
+
get tx - TX power (dBm)
|
|
3726
|
+
get repeat - Repeat mode on/off
|
|
3727
|
+
get public.key - Node public key
|
|
3728
|
+
get advert.interval - Advertisement interval (minutes)
|
|
3729
|
+
|
|
3730
|
+
set name <name> - Set node name
|
|
3731
|
+
set tx <power> - Set TX power (dBm)
|
|
3732
|
+
set repeat on|off - Enable/disable repeating
|
|
3733
|
+
set radio f,bw,sf,cr - Set radio params (reboot to apply)
|
|
3734
|
+
set advert.interval <min> - Set advert interval (60-240 min)
|
|
3735
|
+
|
|
3736
|
+
{ANSI_BGREEN}System:{ANSI_END}
|
|
3737
|
+
reboot - Reboot device
|
|
3738
|
+
erase - Erase filesystem (serial only)
|
|
3739
|
+
|
|
3740
|
+
{ANSI_BYELLOW}Type 'quit' or 'q' to exit, Ctrl+C to abort{ANSI_END}
|
|
3741
|
+
"""
|
|
3742
|
+
|
|
3743
|
+
async def repeater_loop(port, baudrate):
|
|
3744
|
+
"""Interactive loop for repeater text CLI (raw serial commands)"""
|
|
3745
|
+
import serial as pyserial
|
|
3746
|
+
|
|
3747
|
+
print(f"{ANSI_BCYAN}Connecting to repeater at {port} ({baudrate} baud)...{ANSI_END}")
|
|
3748
|
+
try:
|
|
3749
|
+
ser = pyserial.Serial(port, baudrate, timeout=1)
|
|
3750
|
+
except PermissionError:
|
|
3751
|
+
print(f"{ANSI_BRED}Error: Permission denied. Try running with sudo or add user to dialout group.{ANSI_END}")
|
|
3752
|
+
return
|
|
3753
|
+
except Exception as e:
|
|
3754
|
+
print(f"{ANSI_BRED}Error opening serial port: {e}{ANSI_END}")
|
|
3755
|
+
return
|
|
3756
|
+
|
|
3757
|
+
await asyncio.sleep(0.5) # Wait for connection to stabilize
|
|
3758
|
+
ser.reset_input_buffer()
|
|
3759
|
+
|
|
3760
|
+
# Send initial CR to wake up CLI
|
|
3761
|
+
ser.write(b"\r")
|
|
3762
|
+
await asyncio.sleep(0.2)
|
|
3763
|
+
ser.reset_input_buffer()
|
|
3764
|
+
|
|
3765
|
+
# Try to get device info
|
|
3766
|
+
ser.write(b"ver\r")
|
|
3767
|
+
await asyncio.sleep(0.3)
|
|
3768
|
+
ver_response = ser.read(ser.in_waiting or 256).decode(errors='ignore').strip()
|
|
3769
|
+
device_name = "Repeater"
|
|
3770
|
+
for line in ver_response.split('\n'):
|
|
3771
|
+
line = line.strip()
|
|
3772
|
+
if line and not line.startswith("ver") and ">" not in line[:3]:
|
|
3773
|
+
device_name = line.split('(')[0].strip() if '(' in line else line
|
|
3774
|
+
break
|
|
3775
|
+
|
|
3776
|
+
print(f"{ANSI_BGREEN}Connected!{ANSI_END} Device: {ANSI_BMAGENTA}{device_name}{ANSI_END}")
|
|
3777
|
+
print(f"Type {ANSI_BCYAN}help{ANSI_END} for commands, {ANSI_BCYAN}quit{ANSI_END} to exit, {ANSI_BCYAN}Tab{ANSI_END} for completion")
|
|
3778
|
+
print("-" * 50)
|
|
3779
|
+
|
|
3780
|
+
# Setup history and session
|
|
3781
|
+
try:
|
|
3782
|
+
if os.path.isdir(MCCLI_CONFIG_DIR):
|
|
3783
|
+
our_history = FileHistory(MCCLI_REPEATER_HISTORY_FILE)
|
|
3784
|
+
else:
|
|
3785
|
+
our_history = None
|
|
3786
|
+
except Exception:
|
|
3787
|
+
our_history = None
|
|
3788
|
+
|
|
3789
|
+
session = PromptSession(
|
|
3790
|
+
history=our_history,
|
|
3791
|
+
wrap_lines=False,
|
|
3792
|
+
mouse_support=False,
|
|
3793
|
+
complete_style=CompleteStyle.MULTI_COLUMN
|
|
3794
|
+
)
|
|
3795
|
+
|
|
3796
|
+
# Setup key bindings
|
|
3797
|
+
bindings = KeyBindings()
|
|
3798
|
+
|
|
3799
|
+
@bindings.add("escape")
|
|
3800
|
+
def _(event):
|
|
3801
|
+
event.app.current_buffer.cancel_completion()
|
|
3802
|
+
|
|
3803
|
+
# Build prompt
|
|
3804
|
+
prompt_base = f"{ANSI_BGRAY}{device_name}{ANSI_MAGENTA}>{ANSI_END} "
|
|
3805
|
+
|
|
3806
|
+
# Setup completer
|
|
3807
|
+
completer = NestedCompleter.from_nested_dict(REPEATER_COMMANDS)
|
|
3808
|
+
|
|
3809
|
+
while True:
|
|
3810
|
+
try:
|
|
3811
|
+
cmd = await session.prompt_async(
|
|
3812
|
+
ANSI(prompt_base),
|
|
3813
|
+
completer=completer,
|
|
3814
|
+
complete_while_typing=False,
|
|
3815
|
+
key_bindings=bindings
|
|
3816
|
+
)
|
|
3817
|
+
except (KeyboardInterrupt, EOFError):
|
|
3818
|
+
break
|
|
3819
|
+
|
|
3820
|
+
cmd = cmd.strip()
|
|
3821
|
+
|
|
3822
|
+
if not cmd:
|
|
3823
|
+
continue
|
|
3824
|
+
|
|
3825
|
+
if cmd.lower() in ("quit", "exit", "q"):
|
|
3826
|
+
break
|
|
3827
|
+
|
|
3828
|
+
if cmd.lower() == "help":
|
|
3829
|
+
print(REPEATER_HELP)
|
|
3830
|
+
continue
|
|
3831
|
+
|
|
3832
|
+
# Send command with CR terminator
|
|
3833
|
+
ser.write(f"{cmd}\r".encode())
|
|
3834
|
+
await asyncio.sleep(0.3)
|
|
3835
|
+
|
|
3836
|
+
# Read response
|
|
3837
|
+
response = ser.read(ser.in_waiting or 4096).decode(errors='ignore')
|
|
3838
|
+
if response:
|
|
3839
|
+
# Clean up echo and format response
|
|
3840
|
+
lines = response.strip().split('\n')
|
|
3841
|
+
for line in lines:
|
|
3842
|
+
line = line.strip()
|
|
3843
|
+
if line and line != cmd: # Skip echo of command
|
|
3844
|
+
# Color code certain responses
|
|
3845
|
+
if line.startswith("OK") or line.startswith("ok"):
|
|
3846
|
+
print(f"{ANSI_GREEN}{line}{ANSI_END}")
|
|
3847
|
+
elif line.startswith("Error") or line.startswith("ERR"):
|
|
3848
|
+
print(f"{ANSI_RED}{line}{ANSI_END}")
|
|
3849
|
+
elif line.startswith("->"):
|
|
3850
|
+
print(f"{ANSI_CYAN}{line}{ANSI_END}")
|
|
3851
|
+
else:
|
|
3852
|
+
print(line)
|
|
3853
|
+
|
|
3854
|
+
ser.close()
|
|
3855
|
+
print(f"\n{ANSI_BGRAY}Disconnected from repeater.{ANSI_END}")
|
|
3856
|
+
|
|
3591
3857
|
async def main(argv):
|
|
3592
3858
|
""" Do the job """
|
|
3593
3859
|
json_output = JSON
|
|
@@ -3598,6 +3864,7 @@ async def main(argv):
|
|
|
3598
3864
|
hostname = None
|
|
3599
3865
|
serial_port = None
|
|
3600
3866
|
baudrate = 115200
|
|
3867
|
+
repeater_mode = False
|
|
3601
3868
|
timeout = 2
|
|
3602
3869
|
pin = None
|
|
3603
3870
|
first_device = False
|
|
@@ -3608,7 +3875,7 @@ async def main(argv):
|
|
|
3608
3875
|
address = f.readline().strip()
|
|
3609
3876
|
|
|
3610
3877
|
try:
|
|
3611
|
-
opts, args = getopt.getopt(argv, "a:d:s:ht:p:b:fjDhvSlT:Pc:
|
|
3878
|
+
opts, args = getopt.getopt(argv, "a:d:s:ht:p:b:fjDhvSlT:Pc:Cr")
|
|
3612
3879
|
except getopt.GetoptError:
|
|
3613
3880
|
print("Unrecognized option, use -h to get more help")
|
|
3614
3881
|
command_usage()
|
|
@@ -3620,6 +3887,8 @@ async def main(argv):
|
|
|
3620
3887
|
process_event_message.color = False
|
|
3621
3888
|
case "-C":
|
|
3622
3889
|
interactive_loop.classic = not interactive_loop.classic
|
|
3890
|
+
case "-r": # repeater mode (raw text CLI)
|
|
3891
|
+
repeater_mode = True
|
|
3623
3892
|
case "-d" : # name specified on cmdline
|
|
3624
3893
|
address = arg
|
|
3625
3894
|
case "-a" : # address specified on cmdline
|
|
@@ -3707,6 +3976,15 @@ async def main(argv):
|
|
|
3707
3976
|
elif (json_output) :
|
|
3708
3977
|
logger.setLevel(logging.ERROR)
|
|
3709
3978
|
|
|
3979
|
+
# Repeater mode - raw text CLI over serial
|
|
3980
|
+
if repeater_mode:
|
|
3981
|
+
if serial_port is None:
|
|
3982
|
+
print("Error: Repeater mode (-r) requires serial port (-s)")
|
|
3983
|
+
command_usage()
|
|
3984
|
+
return
|
|
3985
|
+
await repeater_loop(serial_port, baudrate)
|
|
3986
|
+
return
|
|
3987
|
+
|
|
3710
3988
|
mc = None
|
|
3711
3989
|
if not hostname is None : # connect via tcp
|
|
3712
3990
|
mc = await MeshCore.create_tcp(host=hostname, port=port, debug=debug, only_error=json_output)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: meshcore-cli
|
|
3
|
-
Version: 1.3.
|
|
3
|
+
Version: 1.3.15
|
|
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=VgOnJFXkFt8Pt3Inx7mfcqWXM5YvRBlTQialBc_RSBY,171639
|
|
4
|
+
meshcore_cli-1.3.15.dist-info/METADATA,sha256=Pvi791fQQ54tLnATv4LfluErw5y6ximHcH71cKZzeqE,18194
|
|
5
|
+
meshcore_cli-1.3.15.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
6
|
+
meshcore_cli-1.3.15.dist-info/entry_points.txt,sha256=77V29Pyth11GteDk7tneBN3MMk8JI7bTlS-BGSmxCmI,103
|
|
7
|
+
meshcore_cli-1.3.15.dist-info/licenses/LICENSE,sha256=F9s987VtS0AKxW7LdB2EkLMkrdeERI7ICdLJR60A9M4,1066
|
|
8
|
+
meshcore_cli-1.3.15.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=rDkT80QQIAcymcU6Ht26IUgVclL1ezr9vtz-n_J2Z-s,160907
|
|
4
|
-
meshcore_cli-1.3.12.dist-info/METADATA,sha256=sim9NxysAUn_A_P2c_omTeI52--lYtWk8nTQPtF14SI,18194
|
|
5
|
-
meshcore_cli-1.3.12.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
6
|
-
meshcore_cli-1.3.12.dist-info/entry_points.txt,sha256=77V29Pyth11GteDk7tneBN3MMk8JI7bTlS-BGSmxCmI,103
|
|
7
|
-
meshcore_cli-1.3.12.dist-info/licenses/LICENSE,sha256=F9s987VtS0AKxW7LdB2EkLMkrdeERI7ICdLJR60A9M4,1066
|
|
8
|
-
meshcore_cli-1.3.12.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|