meshcore-cli 1.2.6__py3-none-any.whl → 1.2.7__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.
@@ -33,7 +33,7 @@ import re
33
33
  from meshcore import MeshCore, EventType, logger
34
34
 
35
35
  # Version
36
- VERSION = "v1.2.6"
36
+ VERSION = "v1.2.7"
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,14 @@ Line starting with \"$\" or \".\" will issue a meshcli command.
707
710
  contact = to
708
711
  prev_contact = None
709
712
 
713
+ res = await mc.commands.set_flood_scope("0")
714
+ if res is None or res.type == EventType.ERROR:
715
+ scope = None
716
+ prev_scope = None
717
+ else:
718
+ scope = "*"
719
+ prev_scope = "*"
720
+
710
721
  await get_contacts(mc, anim=True)
711
722
  await get_channels(mc, anim=True)
712
723
  await subscribe_to_msgs(mc, above=True)
@@ -758,6 +769,9 @@ Line starting with \"$\" or \".\" will issue a meshcli command.
758
769
  if print_name or contact is None :
759
770
  prompt = prompt + f"{ANSI_BGRAY}"
760
771
  prompt = prompt + f"{mc.self_info['name']}"
772
+ if contact is None: # display scope
773
+ if not scope is None:
774
+ prompt = prompt + f"|{scope}"
761
775
  if classic :
762
776
  prompt = prompt + " > "
763
777
  else :
@@ -785,6 +799,17 @@ Line starting with \"$\" or \".\" will issue a meshcli command.
785
799
  prompt = prompt + f"{ANSI_NORMAL}🭨{ANSI_INVERT}"
786
800
 
787
801
  prompt = prompt + f"{contact['adv_name']}"
802
+ if contact["type"] == 0 or contact["out_path_len"]==-1:
803
+ if scope is None:
804
+ prompt = prompt + f"|*"
805
+ else:
806
+ prompt = prompt + f"|{scope}"
807
+ else: # display path to dest or 0 if 0 hop
808
+ if contact["out_path_len"] == 0:
809
+ prompt = prompt + f"|0"
810
+ else:
811
+ prompt = prompt + "|" + contact["out_path"]
812
+
788
813
  if classic :
789
814
  prompt = prompt + f"{ANSI_NORMAL} > "
790
815
  else:
@@ -823,6 +848,12 @@ Line starting with \"$\" or \".\" will issue a meshcli command.
823
848
  except ValueError:
824
849
  logger.error("Error parsing line {line[1:]}")
825
850
 
851
+ elif line.startswith("/scope") :
852
+ if not scope is None:
853
+ prev_scope = scope
854
+ newscope = line.split(" ", 1)[1]
855
+ scope = await set_scope(mc, newscope)
856
+
826
857
  elif line.startswith("/") :
827
858
  path = line.split(" ", 1)[0]
828
859
  if path.count("/") == 1:
@@ -1307,6 +1338,14 @@ msg_ack.max_attempts=3
1307
1338
  msg_ack.flood_after=2
1308
1339
  msg_ack.max_flood_attempts=1
1309
1340
 
1341
+ async def set_scope (mc, scope) :
1342
+ if scope == "None" or scope == "0" or scope == "clear" or scope == "":
1343
+ scope = "*"
1344
+ res = await mc.commands.set_flood_scope(scope)
1345
+ if res is None or res.type == EventType.ERROR:
1346
+ return None
1347
+ return scope
1348
+
1310
1349
  async def get_channel (mc, chan) :
1311
1350
  if not chan.isnumeric():
1312
1351
  return await get_channel_by_name(mc, chan)
@@ -2110,8 +2149,8 @@ async def next_cmd(mc, cmds, json_output=False):
2110
2149
 
2111
2150
  case "scope":
2112
2151
  argnum = 1
2113
- res = await mc.commands.set_flood_scope(cmds[1])
2114
- if res is None or res.type == EventType.ERROR:
2152
+ res = await set_scope(mc, cmds[1])
2153
+ if res is None:
2115
2154
  print(f"Error while setting scope")
2116
2155
 
2117
2156
  case "remove_channel":
@@ -2180,7 +2219,7 @@ async def next_cmd(mc, cmds, json_output=False):
2180
2219
  argnum = 2
2181
2220
  dest = None
2182
2221
 
2183
- if len(cmds[1]) == 12: # possibly an hex prefix
2222
+ if len(cmds[1]) == 12: # possibly an hex prefix
2184
2223
  try:
2185
2224
  dest = bytes.fromhex(cmds[1])
2186
2225
  except ValueError:
@@ -2378,6 +2417,52 @@ async def next_cmd(mc, cmds, json_output=False):
2378
2417
  inp = inp if inp != "" else "direct"
2379
2418
  print(f"Path for {contact['adv_name']}: out {outp}, in {inp}")
2380
2419
 
2420
+ case "node_discover"|"nd" :
2421
+ argnum = 1
2422
+ try: # try to decode type as int
2423
+ types = int(cmds[1])
2424
+ except ValueError:
2425
+ if "all" in cmds[1]:
2426
+ types = 0xFF
2427
+ else :
2428
+ types = 0
2429
+ if "rep" in cmds[1]:
2430
+ types = types | 4
2431
+ if "cli" in cmds[1] or "comp" in cmds[1]:
2432
+ types = types | 2
2433
+ if "room" in cmds[1]:
2434
+ types = types | 8
2435
+ if "sens" in cmds[1]:
2436
+ types = types | 16
2437
+
2438
+ res = await mc.commands.send_node_discover_req(types)
2439
+ if res is None or res.type == EventType.ERROR:
2440
+ print("Error sending discover request")
2441
+ else:
2442
+ exp_tag = res.payload["tag"].to_bytes(4, "little").hex()
2443
+ dn = []
2444
+ while True:
2445
+ r = await mc.wait_for_event(
2446
+ EventType.DISCOVER_RESPONSE,
2447
+ attribute_filters={"tag":exp_tag},
2448
+ timeout = 5
2449
+ )
2450
+ if r is None or r.type == EventType.ERROR:
2451
+ break
2452
+ else:
2453
+ dn.append(r.payload)
2454
+
2455
+ if json_output:
2456
+ print(json.dumps(dn))
2457
+ else:
2458
+ await mc.ensure_contacts()
2459
+ print(f"Discovered {len(dn)} nodes:")
2460
+ for n in dn:
2461
+ name = mc.get_contact_by_key_prefix(n["pubkey"])['adv_name']
2462
+ if name is None:
2463
+ name = n["pubkey"][0:12]
2464
+ print(f" {name:12} type {n['node_type']} SNR: {n['SNR_in']:6,.2f}->{n['SNR']:6,.2f} RSSI: ->{n['RSSI']:4}")
2465
+
2381
2466
  case "req_btelemetry"|"rbt" :
2382
2467
  argnum = 1
2383
2468
  await mc.ensure_contacts()
@@ -2931,6 +3016,7 @@ def command_help():
2931
3016
  time <epoch> : sets time to given epoch
2932
3017
  clock : get current time
2933
3018
  clock sync : sync device clock st
3019
+ node_discover <filter> : discovers nodes based on their type nd
2934
3020
  Contacts
2935
3021
  contacts / list : gets contact list lc
2936
3022
  reload_contacts : force reloading all contacts rc
@@ -3004,7 +3090,18 @@ def get_help_for (cmdname, context="line") :
3004
3090
  at t=2,u>1d,d cn trace
3005
3091
  # tries to do flood login to all repeaters
3006
3092
  at t=2 rp login
3007
- """)
3093
+ """)
3094
+
3095
+ if cmdname == "node_discover" or cmdname == "nd" :
3096
+ print("""node_discover <filter> : discovers 0-hop nodes and displays signal info
3097
+
3098
+ filter can be "all" for all types or nodes or a comma separated list consisting of :
3099
+ - cli or comp for companions
3100
+ - rep for repeaters
3101
+ - sens for sensors
3102
+ - room for chat rooms
3103
+ """)
3104
+
3008
3105
  else:
3009
3106
  print(f"Sorry, no help yet for {cmdname}")
3010
3107
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: meshcore-cli
3
- Version: 1.2.6
3
+ Version: 1.2.7
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.20
13
+ Requires-Dist: meshcore>=2.1.21
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=E-zWpvbPyhstbU68BgINMxY6QAIM-tmU7zpPERZ_Xpk,138363
4
+ meshcore_cli-1.2.7.dist-info/METADATA,sha256=m8b_jUfFVeLgGlHOcJZTsSO91lTGdP5Jix-TF0v8W9w,11657
5
+ meshcore_cli-1.2.7.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
6
+ meshcore_cli-1.2.7.dist-info/entry_points.txt,sha256=77V29Pyth11GteDk7tneBN3MMk8JI7bTlS-BGSmxCmI,103
7
+ meshcore_cli-1.2.7.dist-info/licenses/LICENSE,sha256=F9s987VtS0AKxW7LdB2EkLMkrdeERI7ICdLJR60A9M4,1066
8
+ meshcore_cli-1.2.7.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=HrfCnKDBvC-Lni4X4rWlSuBnadmRuVK2f5Z7HK0jHNo,134323
4
- meshcore_cli-1.2.6.dist-info/METADATA,sha256=rsIFIQm9Ne8Ft-ax8PCGAnfpjymhCNjxVg5z4CRDF7s,11657
5
- meshcore_cli-1.2.6.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
6
- meshcore_cli-1.2.6.dist-info/entry_points.txt,sha256=77V29Pyth11GteDk7tneBN3MMk8JI7bTlS-BGSmxCmI,103
7
- meshcore_cli-1.2.6.dist-info/licenses/LICENSE,sha256=F9s987VtS0AKxW7LdB2EkLMkrdeERI7ICdLJR60A9M4,1066
8
- meshcore_cli-1.2.6.dist-info/RECORD,,