@@ -806,6 +806,9 @@ def _(event):
806806 if line == "" : # blank line
807807 pass
808808
809+ elif line .startswith ("?" ) :
810+ get_help_for (line [1 :], context = "chat" )
811+
809812 # raw meshcli command as on command line
810813 elif line .startswith ("$" ) :
811814 try :
@@ -980,7 +983,7 @@ async def process_contact_chat_line(mc, contact, line):
980983 if line .startswith ("contact_name" ) or line .startswith ("cn" ):
981984 print (contact ['adv_name' ],end = "" )
982985 if " " in line :
983- print (" " , end = "" )
986+ print (" " , end = "" , flush = True )
984987 secline = line .split (" " , 1 )[1 ]
985988 await process_contact_chat_line (mc , contact , secline )
986989 else :
@@ -1159,6 +1162,8 @@ async def apply_command_to_contacts(mc, contact_filter, line):
11591162 min_hops = None
11601163 max_hops = None
11611164
1165+ await mc .ensure_contacts ()
1166+
11621167 filters = contact_filter .split ("," )
11631168 for f in filters :
11641169 if f == "all" :
@@ -1229,7 +1234,7 @@ async def apply_command_to_contacts(mc, contact_filter, line):
12291234 contact ["type" ] == 4 : # repeater, room, sensor send cmd
12301235 await process_cmds (mc , ["cmd" , contact ["adv_name" ], line ])
12311236 # wait for a reply from cmd
1232- await mc .wait_for_event (EventType .MESSAGES_WAITING )
1237+ await mc .wait_for_event (EventType .MESSAGES_WAITING , timeout = 7 )
12331238
12341239 else :
12351240 logger .error (f"Can't send { line } to { contact ['adv_name' ]} " )
@@ -1504,6 +1509,11 @@ async def next_cmd(mc, cmds, json_output=False):
15041509 """ process next command """
15051510 try :
15061511 argnum = 0
1512+
1513+ if cmds [0 ].startswith ("?" ) : # get some help
1514+ get_help_for (cmds [0 ][1 :], context = "line" )
1515+ return cmds [argnum + 1 :]
1516+
15071517 if cmds [0 ].startswith ("." ) : # override json_output
15081518 json_output = True
15091519 cmd = cmds [0 ][1 :]
@@ -1594,6 +1604,10 @@ async def next_cmd(mc, cmds, json_output=False):
15941604 else :
15951605 print ("Time set" )
15961606
1607+ case "apply_to" | "at" :
1608+ argnum = 2
1609+ await apply_command_to_contacts (mc , cmds [1 ], cmds [2 ])
1610+
15971611 case "set" :
15981612 argnum = 2
15991613 match cmds [1 ]:
@@ -2871,7 +2885,8 @@ def version():
28712885 print (f"meshcore-cli: command line interface to MeshCore companion radios { VERSION } " )
28722886
28732887def command_help ():
2874- print (""" General commands
2888+ print (""" ?<cmd> may give you some more help about cmd
2889+ General commands
28752890 chat : enter the chat (interactive) mode
28762891 chat_to <ct> : enter chat with contact to
28772892 script <filename> : execute commands in filename
@@ -2882,6 +2897,7 @@ def command_help():
28822897 reboot : reboots node
28832898 sleep <secs> : sleeps for a given amount of secs s
28842899 wait_key : wait until user presses <Enter> wk
2900+ apply_to <scope> <cmds>: sends cmds to contacts matching scope at
28852901 Messenging
28862902 msg <name> <msg> : send message to node by name m {
28872903 wait_ack : wait an ack wa }
@@ -2956,6 +2972,30 @@ def usage () :
29562972 Available Commands and shorcuts (can be chained) :""" )
29572973 command_help ()
29582974
2975+ def get_help_for (cmdname , context = "line" ) :
2976+ if cmdname == "apply_to" or cmdname == "at" :
2977+ print ("""apply_to <scope> <cmd> : applies cmd to contacts matching scope
2978+ Scope acts like a filter with comma separated fields :
2979+ - u, matches modification time < or > than a timestamp
2980+ (can also be days hours or minutes ago if followed by d,h or m)
2981+ - t, matches the type (1: client, 2: repeater, 3: room, 4: sensor)
2982+ - h, matches number of hops
2983+ - d, direct, similar to h>-1
2984+ - f, flood, similar to h<0 or h=-1
2985+
2986+ Note: Some commands like contact_name (aka cn), reset_path (aka rp), forget_password (aka fp) can be chained.
2987+
2988+ Examples:
2989+ # removes all clients that have not been updated in last 2 days
2990+ at u<2d,t=1 remove_contact
2991+ # gives traces to repeaters that have been updated in the last 24h and are direct
2992+ at t=2,u>1d,d cn trace
2993+ # tries to do flood login to all repeaters
2994+ at t=2 rp login
2995+ """ )
2996+ else :
2997+ print (f"Sorry, no help yet for { cmdname } " )
2998+
29592999async def main (argv ):
29603000 """ Do the job """
29613001 json_output = JSON
0 commit comments