diff --git a/README.md b/README.md index 4072695..ad39073 100644 --- a/README.md +++ b/README.md @@ -46,6 +46,7 @@ Any messages that are over 160 characters are chunked into 160 message bytes to - `messages` Replay the last messages heard, like Store and Forward - `motd` or to set the message `motd $New Message Of the day` - `lheard` returns the last 5 heard nodes with SNR, can also use `sitrep` + - `history` returns the last commands ran by user(s) - `cmd` returns the list of commands (the help message) - Games - `lemonstand` plays the classic Lemonade Stand Finance game via DM @@ -121,6 +122,13 @@ enabled = False DadJokes = False StoreForward = False ``` +History command is like a linix terminal, shows the last commands the user ran and the `lheard` reflects last users on the bot. +``` +# history command +enableCmdHistory = True +# command history ignore list ex: 2813308004,4258675309 +lheardCmdIgnoreNodes = +``` Sentry Bot detects anyone coming close to the bot-node ``` # detect anyone close to the bot @@ -258,5 +266,5 @@ Games Ported from.. - https://github.com/devtronvarma/Video-Poker-Terminal-Game GitHub user Nestpebble, for new ideas and enhancments, mrpatrick1991 For Docker configs, PiDiBi looking at test functions and other suggestions like wxc, CPU use, and alerting ideas -Discord and Mesh user Cisien, and github Hailo1999, for testing and ideas! Lots of individuals on the Meshtastic discord who have tossed out ideas and tested code! +Discord and Mesh user Cisien, bitflip, and github Hailo1999, for testing and ideas! Lots of individuals on the Meshtastic discord who have tossed out ideas and tested code! diff --git a/config.template b/config.template index c799780..0aa9384 100644 --- a/config.template +++ b/config.template @@ -45,6 +45,10 @@ ollama = False # StoreForward Enabled and Limits StoreForward = True StoreLimit = 3 +# history command +enableCmdHistory = True +# command history ignore list ex: 2813308004,4258675309 +lheardCmdIgnoreNodes = # 24 hour clock zuluTime = False # wait time for URL requests diff --git a/mesh_bot.py b/mesh_bot.py index a650870..8d91d2b 100755 --- a/mesh_bot.py +++ b/mesh_bot.py @@ -10,7 +10,11 @@ from modules.system import * DEBUGpacket = False # Debug print the packet rx +# Global Variables +cmdHistory = [] # list to hold the last commands + def auto_response(message, snr, rssi, hop, pkiStatus, message_from_id, channel_number, deviceID): + global cmdHistory #Auto response to messages message_lower = message.lower() bot_response = "I'm sorry, I'm afraid I can't do that." @@ -41,11 +45,12 @@ def auto_response(message, snr, rssi, hop, pkiStatus, message_from_id, channel_n "messages": lambda: handle_messages(deviceID, channel_number, msg_history, publicChannel), "cmd": lambda: help_message, "cmd?": lambda: help_message, + "history": lambda: handle_history(message_from_id, deviceID), "sun": lambda: handle_sun(message_from_id, deviceID, channel_number), "hfcond": hf_band_conditions, "solar": lambda: drap_xray_conditions() + "\n" + solar_conditions(), - "lheard": lambda: handle_lheard(), - "sitrep": lambda: handle_lheard(), + "lheard": lambda: handle_lheard(message_from_id, deviceID), + "sitrep": lambda: handle_lheard(message_from_id, deviceID), "whereami": lambda: handle_whereami(message_from_id, deviceID, channel_number), "tide": lambda: handle_tide(message_from_id, deviceID, channel_number), "moon": lambda: handle_moon(message_from_id, deviceID, channel_number), @@ -57,6 +62,7 @@ def auto_response(message, snr, rssi, hop, pkiStatus, message_from_id, channel_n cmds = [] # list to hold the commands found in the message for key in command_handler: if key in message_lower.split(' '): + # append all the commands found in the message to the cmds list cmds.append({'cmd': key, 'index': message_lower.index(key)}) if len(cmds) > 0: @@ -65,6 +71,8 @@ def auto_response(message, snr, rssi, hop, pkiStatus, message_from_id, channel_n logger.debug(f"System: Bot detected Commands:{cmds}") # run the first command after sorting bot_response = command_handler[cmds[0]['cmd']]() + # append the command to the cmdHistory list for lheard and history + cmdHistory.append({'nodeID': message_from_id, 'cmd': cmds[0]['cmd'], 'time': time.time()}) # wait a responseDelay to avoid message collision from lora-ack time.sleep(responseDelay) @@ -453,7 +461,7 @@ def handle_sun(message_from_id, deviceID, channel_number): location = get_node_location(message_from_id, deviceID, channel_number) return get_sun(str(location[0]), str(location[1])) -def handle_lheard(): +def handle_lheard(nodeid, deviceID): bot_response = "Last heard:\n" + str(get_node_list(1)) chutil1 = interface1.nodes.get(decimal_to_hex(myNodeNum1), {}).get("deviceMetrics", {}).get("channelUtilization", 0) chutil1 = "{:.2f}".format(chutil1) @@ -464,8 +472,52 @@ def handle_lheard(): bot_response += "Ch Use: " + str(chutil1) + "%" if interface2_enabled: bot_response += " P2:" + str(chutil2) + "%" + + # show last users of the bot with the cmdHistory list + history = handle_history(nodeid, deviceID, lheard=True) + if history: + bot_response += f'\n{history}' return bot_response +def handle_history(nodeid, deviceID, lheard=False): + global cmdHistory, lheardCmdIgnoreNode + msg = "" + # show the last commands from the user to the bot + if not lheard: + for i in range(len(cmdHistory)): + prettyTime = round((time.time() - cmdHistory[i]['time']) / 600) * 10 + if prettyTime < 60: + prettyTime = str(prettyTime) + "m" + else: + prettyTime = str(prettyTime/60) + "h" + # history display output + if nodeid in bbs_admin_list and not cmdHistory[i]['nodeID'] in lheardCmdIgnoreNode: + msg += f"{get_name_from_number(nodeid,'short',deviceID)}:cmd:{cmdHistory[i]['cmd']}@{prettyTime} ago. " + elif cmdHistory[i]['nodeID'] == nodeid and not cmdHistory[i]['nodeID'] in lheardCmdIgnoreNode: + msg += f"{get_name_from_number(nodeid,'short',deviceID)}:cmd:{cmdHistory[i]['cmd']}@ {prettyTime} ago. " + if i > 2: break # only show the last 3 commands + else: + # sort the cmdHistory list by time, return the username and time into a new list which used for display + cmdHistorySorted = sorted(cmdHistory, key=lambda k: k['time'], reverse=True) + buffer = [] + for i in range(len(cmdHistorySorted)): + prettyTime = round((time.time() - cmdHistorySorted[i]['time']) / 600) * 10 + if prettyTime < 60: + prettyTime = str(prettyTime) + "m" + else: + prettyTime = str(prettyTime/60) + "h" + + if not cmdHistorySorted[i]['nodeID'] in lheardCmdIgnoreNode: + # add line to a new list for display + if get_name_from_number(nodeid, 'short', deviceID) not in buffer: + buffer.append([get_name_from_number(nodeid, 'short', deviceID), prettyTime]) + if i > 2: break + # format the buffer list into a string for return + for line in buffer: + msg += f"{line[0]}@{line[1]} ago. " + + return msg + def handle_whereami(message_from_id, deviceID, channel_number): location = get_node_location(message_from_id, deviceID, channel_number) return where_am_i(str(location[0]), str(location[1])) diff --git a/modules/settings.py b/modules/settings.py index 83f3063..79c019c 100644 --- a/modules/settings.py +++ b/modules/settings.py @@ -104,6 +104,8 @@ try: welcome_message = (f"{welcome_message}").replace('\\n', '\n') # allow for newlines in the welcome message motd_enabled = config['general'].getboolean('motdEnabled', True) MOTD = config['general'].get('motd', MOTD) + enableCmdHistory = config['general'].getboolean('enableCmdHistory', True) + lheardCmdIgnoreNode = config['general'].get('lheardCmdIgnoreNode', '').split(',') whoami_enabled = config['general'].getboolean('whoami', True) dad_jokes_enabled = config['general'].getboolean('DadJokes', False) solar_conditions_enabled = config['general'].getboolean('spaceWeather', True) diff --git a/modules/system.py b/modules/system.py index 9603b39..53bfb8d 100644 --- a/modules/system.py +++ b/modules/system.py @@ -46,6 +46,11 @@ if solar_conditions_enabled: trap_list = trap_list + trap_list_solarconditions # items hfcond, solar, sun, moon help_message = help_message + ", sun, hfcond, solar, moon" +# Command History Configuration +if enableCmdHistory: + trap_list = trap_list + ("history",) + #help_message = help_message + ", history" + # Location Configuration if location_enabled: from modules.locationdata import * # from the spudgunman/meshing-around repo