diff --git a/README.md b/README.md index 20b629b..4c9bdbb 100644 --- a/README.md +++ b/README.md @@ -440,6 +440,8 @@ I used ideas and snippets from other responder bots and want to call them out! - **[https://github.com/A-c0rN](A-c0rN)**: Assistance with iPAWS and EAS - **Mike O'Connell/skrrt**: For [eas_alert_parser](etc/eas_alert_parser.py) enhanced by **sheer.cold** - **PiDiBi**: For looking at test functions and other suggestions like wxc, CPU use, and alerting ideas. +- **WH6GXZ nurse dude**: For bashing on installer +- **Josh**: For more bashing on installer! - **Cisien, bitflip, **Woof**, **propstg**, **Josh** and Hailo1999**: For testing and feature ideas on Discord and GitHub. - **Meshtastic Discord Community**: For tossing out ideas and testing code. diff --git a/config.template b/config.template index 1a890c8..86dc89a 100644 --- a/config.template +++ b/config.template @@ -8,8 +8,7 @@ type = serial port = /dev/ttyACM0 # port = /dev/ttyUSB0 -# port = COM1 -# hostname = localhost +# hostname = meshtastic.local # mac = 00:11:22:33:44:55 # Additional interface for multi radio support @@ -17,9 +16,9 @@ port = /dev/ttyACM0 enabled = False type = serial port = /dev/ttyUSB0 -#port = /dev/ttyACM1 +# port = /dev/ttyACM1 # port = COM1 -# hostname = meshtastic.local +# hostname = localhost # mac = 00:11:22:33:44:55 # example, the third interface would be [interface3] up to 9 @@ -76,6 +75,8 @@ urlTimeout = 10 LogMessagesToFile = False # Logging of system messages to file SyslogToFile = True +# logging level for the bot (DEBUG, INFO, WARNING, ERROR, CRITICAL) +sysloglevel = DEBUG # Number of log files to keep in days, 0 to keep all log_backup_count = 32 @@ -190,6 +191,7 @@ enable_read_news = False news_file_path = news.txt # only return a single random line from the news file news_random_line = False +# enable the use of exernal shell commands enable_runShellCmd = False [smtp] @@ -238,7 +240,7 @@ splitDelay = 0.0 MESSAGE_CHUNK_SIZE = 160 # Request Acknowledgement of message OTA wantAck = False -# Max lilmit Buffer for radio testing +# Max limit buffer for radio testing. 233 is hard limit 2.5+ firmware maxBuffer = 220 diff --git a/install.sh b/install.sh index dac96c5..36aeb97 100755 --- a/install.sh +++ b/install.sh @@ -7,27 +7,42 @@ program_path=$(pwd) printf "\n########################" printf "\nMeshing Around Installer\n" printf "########################\n" -printf "\nThis script will try and install the Meshing Around Bot and its dependencies." -printf "Installer works best in raspian/debian/ubuntu, if there is a problem, try running the installer again.\n" +printf "\nThis script will try and install the Meshing Around Bot and its dependencies.\n" +printf "Installer works best in raspian/debian/ubuntu or foxbuntu embedded systems.\n" +printf "If there is a problem, try running the installer again.\n" printf "\nChecking for dependencies...\n" -# check if running on embedded -printf "\nAre You installing into an embedded system? (y/n)" -read embedded - -if [ $embedded == "y" ]; then - printf "\nDetected embedded skipping dependency installation\n" - if [ $program_path != "/opt/meshing-around" ]; then - printf "\nIt is suggested to project path to /opt/meshing-around\n" - printf "Do you want to move the project to /opt/meshing-around? (y/n)" - read move - if [ $move == "y" ]; then - sudo mv $program_path /opt/meshing-around - cd /opt/meshing-around - printf "\nProject moved to /opt/meshing-around. re-run the installer\n" - exit 0 - fi +# check if we are in /opt/meshing-around +if [ $program_path != "/opt/meshing-around" ]; then + printf "\nIt is suggested to project path to /opt/meshing-around\n" + printf "Do you want to move the project to /opt/meshing-around? (y/n)" + read move + if [[ $(echo "$move" | grep -i "^y") ]]; then + sudo mv $program_path /opt/meshing-around + cd /opt/meshing-around + printf "\nProject moved to /opt/meshing-around. re-run the installer\n" + exit 0 fi +fi + +# check write access to program path +if [[ ! -w ${program_path} ]]; then + printf "\nInstall path not writable, try running the installer with sudo\n" + exit 1 +fi + +# if hostname = femtofox, then we are on embedded +if [[ $(hostname) == "femtofox" ]]; then + printf "\nDetected femtofox embedded system\n" + embedded="y" +else + # check if running on embedded + printf "\nAre You installing into an embedded system like a luckfox or -native? most should say no here (y/n)" + read embedded +fi + +if [[ $(echo "${embedded}" | grep -i "^y") ]]; then + printf "\nDetected embedded skipping dependency installation\n" else # Check and install dependencies if ! command -v python3 &> /dev/null @@ -67,7 +82,7 @@ cp etc/mesh_bot.tmp etc/mesh_bot.service cp etc/mesh_bot_reporting.tmp etc/mesh_bot_reporting.service # generate config file, check if it exists -if [ -f config.ini ]; then +if [[ -f config.ini ]]; then printf "\nConfig file already exists, moving to backup config.old\n" mv config.ini config.old fi @@ -75,14 +90,21 @@ fi cp config.template config.ini printf "\nConfig files generated!\n" +# update lat,long in config.ini +latlong=$(curl --silent --max-time 20 https://ipinfo.io/loc || echo "48.50,-123.0") +IFS=',' read -r lat lon <<< "$latlong" +sed -i "s|lat = 48.50|lat = $lat|g" config.ini +sed -i "s|lon = -123.0|lon = $lon|g" config.ini +echo "lat,long updated in config.ini to $latlong" + # check if running on embedded -if [ $embedded == "y" ]; then +if [[ $(echo "${embedded}" | grep -i "^y") ]]; then printf "\nDetected embedded skipping venv\n" else - printf "\nDo you want to install the bot in a python virtual environment? (y/n)" + printf "\nRecomended install is in a python virtual environment, do you want to use venv? (y/n)" read venv - if [ $venv == "y" ]; then + if [[ $(echo "${venv}" | grep -i "^y") ]]; then # set virtual environment if ! python3 -m venv --help &> /dev/null; then printf "Python3/venv error, please install python3-venv with your OS\n" @@ -91,7 +113,7 @@ else echo "The Following could be messy, or take some time on slower devices." echo "Creating virtual environment..." #check if python3 has venv module - if [ -f venv/bin/activate ]; then + if [[ -f venv/bin/activate ]]; then printf "\nFound virtual environment for python\n" python3 -m venv venv source venv/bin/activate @@ -103,7 +125,7 @@ else python3 -m venv venv # double check for python3-venv - if [ -f venv/bin/activate ]; then + if [[ -f venv/bin/activate ]]; then printf "\nFound virtual environment for python\n" source venv/bin/activate else @@ -119,15 +141,15 @@ else replace="s|python3 pong_bot.py|/usr/bin/bash launch.sh pong|g" sed -i "$replace" etc/pong_bot.service - # install dependencies + # install dependencies to venv pip install -U -r requirements.txt fi else printf "\nSkipping virtual environment...\n" - # install dependencies + # install dependencies to system printf "Are you on Raspberry Pi(debian/ubuntu)?\nshould we add --break-system-packages to the pip install command? (y/n)" read rpi - if [ $rpi == "y" ]; then + if [[ $(echo "${rpi}" | grep -i "^y") ]]; then pip install -U -r requirements.txt --break-system-packages else pip install -U -r requirements.txt @@ -135,9 +157,17 @@ else fi fi -printf "\n\n" -echo "Which bot do you want to install as a service? Pong Mesh or None? (pong/mesh/n)" -read bot +# if $1 is passed +if [[ $1 == "mesh" ]]; then + bot="mesh" +elif [[ $1 == "pong" ]]; then + bot="pong" +else + printf "\n\n" + echo "Which bot do you want to install as a service? Pong Mesh or None? (pong/mesh/n)" + echo "Pong bot is a simple bot for network testing, Mesh bot is a more complex bot more suited for meshing around" + read bot +fi # set the correct path in the service file replace="s|/dir/|$program_path/|g" @@ -145,7 +175,32 @@ sed -i $replace etc/pong_bot.service sed -i $replace etc/mesh_bot.service sed -i $replace etc/mesh_bot_reporting.service # set the correct user in the service file? -whoami=$(whoami) + +#ask if we should add a user for the bot +if [[ $(echo "${embedded}" | grep -i "^n") ]]; then + printf "\nDo you want to add a local user (meshbot) no login, for the bot? (y/n)" + read meshbotservice +fi + +if [[ $(echo "${meshbotservice}" | grep -i "^y") ]] || [[ $(echo "${embedded}" | grep -i "^y") ]]; then + sudo useradd -M meshbot + sudo usermod -L meshbot + sudo groupadd meshbot + sudo usermod -a -G meshbot meshbot + whoami="meshbot" + echo "Added user meshbot with no home directory" + sudo usermod -a -G dialout $whoami + sudo usermod -a -G tty $whoami + sudo usermod -a -G bluetooth $whoami + echo "Added meshbot to dialout, tty, and bluetooth groups" + + sudo chown -R $whoami:$whoami $program_path/logs + sudo chown -R $whoami:$whoami $program_path/data + echo "Permissions set for meshbot on logs and data directories" +else + whoami=$(whoami) +fi +# set the correct user in the service file replace="s|User=pi|User=$whoami|g" sed -i $replace etc/pong_bot.service sed -i $replace etc/mesh_bot.service @@ -154,64 +209,78 @@ replace="s|Group=pi|Group=$whoami|g" sed -i $replace etc/pong_bot.service sed -i $replace etc/mesh_bot.service sed -i $replace etc/mesh_bot_reporting.service -sudo systemctl daemon-reload printf "\n service files updated\n" -if [ $bot == "pong" ]; then - echo "useradd -M meshbot" - echo "usermod -L meshbot" - echo "Added user meshbot with no home directory" +if [[ $(echo "${bot}" | grep -i "^p") ]]; then # install service for pong bot sudo cp etc/pong_bot.service /etc/systemd/system/ sudo systemctl enable pong_bot.service + sudo systemctl daemon-reload + echo "to start pong bot service: systemctl start pong_bot" + service="pong_bot" fi -if [ $bot == "mesh" ]; then - echo "useradd -M meshbot" - echo "usermod -L meshbot" - echo "Added user meshbot with no home directory" +if [[ $(echo "${bot}" | grep -i "^m") ]]; then # install service for mesh bot sudo cp etc/mesh_bot.service /etc/systemd/system/ sudo systemctl enable mesh_bot.service + sudo systemctl daemon-reload + echo "to start mesh bot service: systemctl start mesh_bot" + service="mesh_bot" fi -# check if running on embedded -if [ $embedded == "n" ]; then +# check if running on embedded for final steps +if [[ $(echo "${embedded}" | grep -i "^n") ]]; then # ask if emoji font should be installed for linux printf "\nDo you want to install the emoji font for debian/ubuntu linux? (y/n)" read emoji - if [ $emoji == "y" ]; then + if [[ $(echo "${emoji}" | grep -i "^y") ]]; then sudo apt-get install -y fonts-noto-color-emoji echo "Emoji font installed!, reboot to load the font" fi - printf "\nOptionally if you want to install the multi gig LLM Ollama compnents we will execute the following commands\n" printf "\ncurl -fsSL https://ollama.com/install.sh | sh\n" - + printf "ollama pull gemma2:2b\n" + printf "Total download is multi GB, recomend pi5/8GB or better for this\n" # ask if the user wants to install the LLM Ollama components printf "\nDo you want to install the LLM Ollama components? (y/n)" read ollama - if [ $ollama == "y" ]; then + if [[ $(echo "${ollama}" | grep -i "^y") ]]; then curl -fsSL https://ollama.com/install.sh | sh # ask if want to install gemma2:2b - printf "\n Ollama install done now we can install the Gemma2:2b components, multi GB download\n" + printf "\n Ollama install done now we can install the Gemma2:2b components\n" echo "Do you want to install the Gemma2:2b components? (y/n)" read gemma - if [ $gemma == "y" ]; then + if [[ $(echo "${gemma}" | grep -i "^y") ]]; then ollama pull gemma2:2b fi fi - - if [ $venv == "y" ]; then - printf "\nFor running in virtual, launch bot with './launch.sh mesh' in path $program_path\n" + if [[ $(echo "${embedded}" | grep -i "^n") ]]; then + # document the service install + printf "To install the %s service and keep notes, reference following commands:\n\n" "$service" > install_notes.txt + printf "sudo cp %s/etc/%s.service /etc/systemd/system/etc/%s.service\n" "$program_path" "$service" "$service" >> install_notes.txt + printf "sudo systemctl daemon-reload\n" >> install_notes.txt + printf "sudo systemctl enable %s.service\n" "$service" >> install_notes.txt + printf "sudo systemctl start %s.service\n" "$service" >> install_notes.txt + printf "sudo systemctl status %s.service\n\n" "$service" >> install_notes.txt + printf "To see logs and stop the service:\n" >> install_notes.txt + printf "sudo journalctl -u %s.service\n" "$service" >> install_notes.txt + printf "sudo systemctl stop %s.service\n" "$service" >> install_notes.txt + printf "sudo systemctl disable %s.service\n" "$service" >> install_notes.txt fi + + if [[ $(echo "${venv}" | grep -i "^y") ]]; then + printf "\nFor running on venv, virtual launch bot with './launch.sh mesh' in path $program_path\n" >> install_notes.txt + fi + + read -p "Press enter to complete the installation, these commands saved to install_notes.txt" printf "\nGood time to reboot? (y/n)" read reboot - if [ $reboot == "y" ]; then + if [[ $(echo "${reboot}" | grep -i "^y") ]]; then sudo reboot fi else @@ -219,17 +288,26 @@ else # replace "type = serial" with "type = tcp" in config.ini replace="s|type = serial|type = tcp|g" sed -i "$replace" config.ini - # replace "# hostname = 192.168.0.1" with "hostname = localhost" in config.ini - replace="s|# hostname = 192.168.0.1|hostname = localhost|g" + # replace "# hostname = meshtastic.local" with "hostname = localhost" in config.ini + replace="s|# hostname = meshtastic.local|hostname = localhost|g" sed -i "$replace" config.ini printf "\nConfig file updated for embedded\n" # Set up the meshing around service - #sudo cp /opt/meshing-around/meshing-around.service /etc/systemd/system/meshing-around.service - #sudo systemctl enable meshing-around.service + sudo cp /opt/meshing-around/etc/$service.service /etc/systemd/system/$service.service + sudo systemctl daemon-reload + sudo systemctl enable $service.service + sudo systemctl start $service.service + printf "Reference following commands:\n\n" "$service" > install_notes.txt + printf "sudo systemctl status %s.service\n\n" "$service" >> install_notes.txt + printf "To see logs and stop the service:\n" >> install_notes.txt + printf "sudo journalctl -u %s.service\n" "$service" >> install_notes.txt + printf "sudo systemctl stop %s.service\n" "$service" >> install_notes.txt + printf "sudo systemctl disable %s.service\n" "$service" >> install_notes.txt fi printf "\nInstallation complete!\n" + exit 0 # after install shenannigans # add 'bee = True' to config.ini General section. You will likley want to clean the txt up a bit diff --git a/logs/README.md b/logs/README.md index 1413dc4..f54d005 100644 --- a/logs/README.md +++ b/logs/README.md @@ -14,6 +14,8 @@ Logging messages to disk or 'Syslog' to disk uses the python native logging func LogMessagesToFile = False # Logging of system messages to file, needed for reporting engine SyslogToFile = True +# logging level for the bot (DEBUG, INFO, WARNING, ERROR, CRITICAL) +sysloglevel = DEBUG # Number of log files to keep in days, 0 to keep all log_backup_count = 32 ``` diff --git a/mesh_bot.py b/mesh_bot.py index a7de28f..b0e29fe 100755 --- a/mesh_bot.py +++ b/mesh_bot.py @@ -2,10 +2,15 @@ # Meshtastic Autoresponder MESH Bot # K7MHI Kelly Keeton 2024 +try: + from pubsub import pub +except ImportError: + print(f"Important dependencies are not met, try install.sh\n\n Did you mean to './launch.sh mesh' using a virtual environment.") + exit(1) + import asyncio import time # for sleep, get some when you can :) import random -from pubsub import pub # pip install pubsub from modules.log import * from modules.system import * @@ -767,7 +772,7 @@ def sysinfo(message, message_from_id, deviceID): return "sysinfo command returns system information." else: if enable_runShellCmd and file_monitor_enabled: - shellData = call_external_script(message) + shellData = call_external_script(None, "sysEnv.sh").rstrip() return get_sysinfo(message_from_id, deviceID) + "\n" + shellData else: return get_sysinfo(message_from_id, deviceID) diff --git a/modules/filemon.py b/modules/filemon.py index 4bec6fd..d309b96 100644 --- a/modules/filemon.py +++ b/modules/filemon.py @@ -70,8 +70,12 @@ def call_external_script(message, script="runShell.sh"): script_path = os.path.join(current_working_directory, script) if not os.path.exists(script_path): - logger.warning(f"FileMon: Script not found: {script_path}") - return "sorry I can't do that" + # try the raw script name + script_path = script + if not os.path.exists(script_path): + logger.warning(f"FileMon: Script not found: {script_path}") + return "sorry I can't do that" + output = os.popen(f"bash {script_path} {message}").read() return output except Exception as e: diff --git a/modules/locationdata_eu.py b/modules/globalalert.py similarity index 100% rename from modules/locationdata_eu.py rename to modules/globalalert.py diff --git a/modules/locationdata.py b/modules/locationdata.py index 78cd6d6..e57fa44 100644 --- a/modules/locationdata.py +++ b/modules/locationdata.py @@ -357,6 +357,7 @@ def getWeatherAlertsNOAA(lat=0, lon=0, useDefaultLatLon=False): alerts = "" alertxml = xml.dom.minidom.parseString(alert_data.text) + for i in alertxml.getElementsByTagName("entry"): title = i.getElementsByTagName("title")[0].childNodes[0].nodeValue area_desc = i.getElementsByTagName("cap:areaDesc")[0].childNodes[0].nodeValue diff --git a/modules/log.py b/modules/log.py index f8174ec..9191907 100644 --- a/modules/log.py +++ b/modules/log.py @@ -3,6 +3,11 @@ from logging.handlers import TimedRotatingFileHandler import re from datetime import datetime from modules.settings import * +# if LOGGING_LEVEL is not set in settings.py, default to DEBUG +if not LOGGING_LEVEL: + LOGGING_LEVEL = "DEBUG" + +LOGGING_LEVEL = getattr(logging, LOGGING_LEVEL) class CustomFormatter(logging.Formatter): grey = '\x1b[38;21m' @@ -41,7 +46,7 @@ class plainFormatter(logging.Formatter): # Create logger logger = logging.getLogger("MeshBot System Logger") -logger.setLevel(logging.DEBUG) +logger.setLevel(LOGGING_LEVEL) logger.propagate = False msgLogger = logging.getLogger("MeshBot Messages Logger") @@ -56,7 +61,7 @@ today = datetime.now() # Create stdout handler for logging to the console stdout_handler = logging.StreamHandler() # Set level for stdout handler (logs DEBUG level and above) -stdout_handler.setLevel(logging.DEBUG) +stdout_handler.setLevel(LOGGING_LEVEL) # Set format for stdout handler stdout_handler.setFormatter(CustomFormatter(logFormat)) # Add handlers to the logger @@ -65,7 +70,7 @@ logger.addHandler(stdout_handler) if syslog_to_file: # Create file handler for logging to a file file_handler_sys = TimedRotatingFileHandler('logs/meshbot.log', when='midnight', backupCount=log_backup_count) - file_handler_sys.setLevel(logging.DEBUG) # DEBUG used by default for system logs to disk + file_handler_sys.setLevel(LOGGING_LEVEL) # DEBUG used by default for system logs to disk file_handler_sys.setFormatter(plainFormatter(logFormat)) logger.addHandler(file_handler_sys) diff --git a/modules/settings.py b/modules/settings.py index 0b1a0b0..d095713 100644 --- a/modules/settings.py +++ b/modules/settings.py @@ -189,6 +189,7 @@ try: log_messages_to_file = config['general'].getboolean('LogMessagesToFile', False) # default off log_backup_count = config['general'].getint('LogBackupCount', 32) # default 32 days syslog_to_file = config['general'].getboolean('SyslogToFile', True) # default on + LOGGING_LEVEL = config['general'].get('sysloglevel', 'DEBUG') # default DEBUG urlTimeoutSeconds = config['general'].getint('urlTimeout', 10) # default 10 seconds store_forward_enabled = config['general'].getboolean('StoreForward', True) storeFlimit = config['general'].getint('StoreLimit', 3) # default 3 messages for S&F @@ -208,7 +209,6 @@ try: llm_enabled = config['general'].getboolean('ollama', False) # https://ollama.com llmModel = config['general'].get('ollamaModel', 'gemma2:2b') # default gemma2:2b ollamaHostName = config['general'].get('ollamaHostName', 'http://localhost:11434') # default localhost - # emergency response emergency_responder_enabled = config['emergencyHandler'].getboolean('enabled', False) emergency_responder_alert_channel = config['emergencyHandler'].getint('alert_channel', 2) # default 2 diff --git a/modules/system.py b/modules/system.py index a550586..b838b5f 100644 --- a/modules/system.py +++ b/modules/system.py @@ -1,7 +1,7 @@ # helper functions and init for system related tasks # K7MHI Kelly Keeton 2024 -import meshtastic.serial_interface #pip install meshtastic +import meshtastic.serial_interface #pip install meshtastic or use launch.sh for venv import meshtastic.tcp_interface import meshtastic.ble_interface import time @@ -12,6 +12,7 @@ import io # for suppressing output on watchdog from modules.log import * # Global Variables +debugMetadata = False # packet debug for non text messages trap_list = ("cmd","cmd?") # default trap list help_message = "Bot CMD?:" asyncLoop = asyncio.new_event_loop() @@ -75,7 +76,7 @@ if location_enabled: trap_list = trap_list + trap_list_location # items tide, whereami, wxc, wx help_message = help_message + ", whereami, wx, wxc, rlist" if enableGBalerts: - from modules.locationdata_eu import * # from the spudgunman/meshing-around repo + from modules.globalalert import * # from the spudgunman/meshing-around repo trap_list = trap_list + trap_list_location_eu #help_message = help_message + ", ukalert, ukwx, ukflood" @@ -685,7 +686,7 @@ def handleAlertBroadcast(deviceID=1): ukAlert = alertUk if emergencyAlertBrodcastEnabled: - if NO_ALERTS not in femaAlert: + if NO_ALERTS not in femaAlert and ERROR_FETCHING_DATA not in femaAlert: if isinstance(emergencyAlertBroadcastCh, list): for channel in emergencyAlertBroadcastCh: send_message(femaAlert, int(channel), 0, deviceID) @@ -834,90 +835,92 @@ def displayNodeTelemetry(nodeID=0, rxNode=0, userRequested=False): positionMetadata = {} def consumeMetadata(packet, rxNode=0): - # keep records of recent telemetry data - debugMetadata = False - packet_type = '' - if packet.get('decoded'): - packet_type = packet['decoded']['portnum'] - nodeID = packet['from'] + try: + # keep records of recent telemetry data + packet_type = '' + if packet.get('decoded'): + packet_type = packet['decoded']['portnum'] + nodeID = packet['from'] - # TELEMETRY packets - if packet_type == 'TELEMETRY_APP': - #if debugMetadata: print(f"DEBUG TELEMETRY_APP: {packet}\n\n") - # get the telemetry data - telemetry_packet = packet['decoded']['telemetry'] - if telemetry_packet.get('deviceMetrics'): - deviceMetrics = telemetry_packet['deviceMetrics'] - if telemetry_packet.get('localStats'): - localStats = telemetry_packet['localStats'] - # Check if 'numPacketsTx' and 'numPacketsRx' exist and are not zero - if localStats.get('numPacketsTx') is not None and localStats.get('numPacketsRx') is not None and localStats['numPacketsTx'] != 0: - # Assign the values to the telemetry dictionary - keys = [ - 'numPacketsTx', 'numPacketsRx', 'numOnlineNodes', - 'numOfflineNodes', 'numPacketsTxErr', 'numPacketsRxErr', 'numTotalNodes'] - + # TELEMETRY packets + if packet_type == 'TELEMETRY_APP': + if debugMetadata: print(f"DEBUG TELEMETRY_APP: {packet}\n\n") + # get the telemetry data + telemetry_packet = packet['decoded']['telemetry'] + if telemetry_packet.get('deviceMetrics'): + deviceMetrics = telemetry_packet['deviceMetrics'] + if telemetry_packet.get('localStats'): + localStats = telemetry_packet['localStats'] + # Check if 'numPacketsTx' and 'numPacketsRx' exist and are not zero + if localStats.get('numPacketsTx') is not None and localStats.get('numPacketsRx') is not None and localStats['numPacketsTx'] != 0: + # Assign the values to the telemetry dictionary + keys = [ + 'numPacketsTx', 'numPacketsRx', 'numOnlineNodes', + 'numOfflineNodes', 'numPacketsTxErr', 'numPacketsRxErr', 'numTotalNodes'] + + for key in keys: + if localStats.get(key) is not None: + telemetryData[rxNode][key] = localStats.get(key) + + # POSITION_APP packets + if packet_type == 'POSITION_APP': + if debugMetadata: print(f"DEBUG POSITION_APP: {packet}\n\n") + # get the position data + keys = ['altitude', 'groundSpeed', 'precisionBits'] + position_data = packet['decoded']['position'] + try: + if nodeID not in positionMetadata: + positionMetadata[nodeID] = {} + for key in keys: - if localStats.get(key) is not None: - telemetryData[rxNode][key] = localStats.get(key) - - # POSITION_APP packets - if packet_type == 'POSITION_APP': - if debugMetadata: print(f"DEBUG POSITION_APP: {packet}\n\n") - # get the position data - keys = ['altitude', 'groundSpeed', 'precisionBits'] - position_data = packet['decoded']['position'] - try: - if nodeID not in positionMetadata: - positionMetadata[nodeID] = {} - - for key in keys: - positionMetadata[nodeID][key] = position_data.get(key, 0) - - # Keep the positionMetadata dictionary at 5 records - if len(positionMetadata) > 20: - # Remove the oldest entry - oldest_nodeID = next(iter(positionMetadata)) - del positionMetadata[oldest_nodeID] - except Exception as e: - logger.debug(f"System: POSITION_APP decode error: {e} packet {packet}") + positionMetadata[nodeID][key] = position_data.get(key, 0) + + # Keep the positionMetadata dictionary at 5 records + if len(positionMetadata) > 20: + # Remove the oldest entry + oldest_nodeID = next(iter(positionMetadata)) + del positionMetadata[oldest_nodeID] + except Exception as e: + logger.debug(f"System: POSITION_APP decode error: {e} packet {packet}") - # WAYPOINT_APP packets - if packet_type == 'WAYPOINT_APP': - if debugMetadata: print(f"DEBUG WAYPOINT_APP: {packet['decoded']['waypoint']}\n\n") - # get the waypoint data - waypoint_data = packet['decoded']['waypoint'] - keys = ['latitude', 'longitude',] + # WAYPOINT_APP packets + if packet_type == 'WAYPOINT_APP': + if debugMetadata: print(f"DEBUG WAYPOINT_APP: {packet['decoded']['waypoint']}\n\n") + # get the waypoint data + waypoint_data = packet['decoded'] - # NEIGHBORINFO_APP - if packet_type == 'NEIGHBORINFO_APP': - if debugMetadata: print(f"DEBUG NEIGHBORINFO_APP: {packet}\n\n") - # get the neighbor info data - neighbor_data = packet['decoded']['neighborInfo'] - - # TRACEROUTE_APP - if packet_type == 'TRACEROUTE_APP': - if debugMetadata: print(f"DEBUG TRACEROUTE_APP: {packet}\n\n") - # get the traceroute data - traceroute_data = packet['decoded']['traceroute'] + # NEIGHBORINFO_APP + if packet_type == 'NEIGHBORINFO_APP': + if debugMetadata: print(f"DEBUG NEIGHBORINFO_APP: {packet}\n\n") + # get the neighbor info data + neighbor_data = packet['decoded'] + + # TRACEROUTE_APP + if packet_type == 'TRACEROUTE_APP': + if debugMetadata: print(f"DEBUG TRACEROUTE_APP: {packet}\n\n") + # get the traceroute data + traceroute_data = packet['decoded'] - # DETECTION_SENSOR_APP - if packet_type == 'DETECTION_SENSOR_APP': - if debugMetadata: print(f"DEBUG DETECTION_SENSOR_APP: {packet}\n\n") - # get the detection sensor data - detection_data = packet['decoded']['detectionSensor'] + # DETECTION_SENSOR_APP + if packet_type == 'DETECTION_SENSOR_APP': + if debugMetadata: print(f"DEBUG DETECTION_SENSOR_APP: {packet}\n\n") + # get the detection sensor data + detection_data = packet['decoded'] - # PAXCOUNTER_APP - if packet_type == 'PAXCOUNTER_APP': - if debugMetadata: print(f"DEBUG PAXCOUNTER_APP: {packet}\n\n") - # get the paxcounter data - paxcounter_data = packet['decoded']['paxcounter'] + # PAXCOUNTER_APP + if packet_type == 'PAXCOUNTER_APP': + if debugMetadata: print(f"DEBUG PAXCOUNTER_APP: {packet}\n\n") + # get the paxcounter data + paxcounter_data = packet['decoded'] - # REMOTE_HARDWARE_APP - if packet_type == 'REMOTE_HARDWARE_APP': - if debugMetadata: print(f"DEBUG REMOTE_HARDWARE_APP: {packet}\n\n") - # get the remote hardware data - remote_hardware_data = packet['decoded']['remoteHardware'] + # REMOTE_HARDWARE_APP + if packet_type == 'REMOTE_HARDWARE_APP': + if debugMetadata: print(f"DEBUG REMOTE_HARDWARE_APP: {packet}\n\n") + # get the remote hardware data + remote_hardware_data = packet['decoded'] + except KeyError as e: + logger.critical(f"System: Error consuming metadata: {e} Device:{rxNode}") + logger.debug(f"System: Error Packet = {packet}") def get_sysinfo(nodeID=0, deviceID=1): # Get the system telemetry data for return on the sysinfo command diff --git a/pong_bot.py b/pong_bot.py index 5e03fd3..b0c4fe8 100755 --- a/pong_bot.py +++ b/pong_bot.py @@ -2,9 +2,15 @@ # Meshtastic Autoresponder PONG Bot # K7MHI Kelly Keeton 2024 +try: + from pubsub import pub +except ImportError: + print(f"Important dependencies are not met, try install.sh\n\n Did you mean to './launch.sh pong' using a virtual environment.") + exit(1) + import asyncio import time # for sleep, get some when you can :) -from pubsub import pub # pip install pubsub +import random from modules.log import * from modules.system import * diff --git a/runShell.sh b/runShell.sh index c626bde..3e67e7e 100644 --- a/runShell.sh +++ b/runShell.sh @@ -4,26 +4,4 @@ cd "$(dirname "$0")" program_path=$(pwd) -# get basic telemetry data. Free space, CPU, RAM, and temperature for a raspberry pi -free_space=$(df -h | grep ' /$' | awk '{print $4}') -cpu_usage=$(top -bn1 | grep "Cpu(s)" | sed "s/.*, *\([0-9.]*\)%* id.*/\1/" | awk '{print 100 - $1}') -ram_usage=$(free | grep Mem | awk '{print $3/$2 * 100.0}') - -# if command vcgencmd is found -if command -v vcgencmd &> /dev/null -then - # get temperature - temp=$(vcgencmd measure_temp | sed "s/temp=//" | sed "s/'C//") - # temp in fahrenheit - tempf=$(echo "scale=2; $temp * 9 / 5 + 32" | bc) -else - temp=$(paste <(cat /sys/class/thermal/thermal_zone*/type) <(cat /sys/class/thermal/thermal_zone*/temp) | grep "temp" | awk '{print $2/1000}' | awk '{s+=$1} END {print s/NR}') - tempf=$(echo "scale=2; $temp * 9 / 5 + 32" | bc) -fi - - -# print telemetry data -printf "Free Space: %s\n" "$free_space" -printf "CPU Usage: %.1f%%\n" "$cpu_usage" -printf "RAM Usage: %.2f%%\n" "$ram_usage" -printf "Temperature: %.1f°C (%.1f°F)\n" "$temp" "$tempf" \ No newline at end of file +printf "Running meshing-around demo script for shell scripting\n" \ No newline at end of file diff --git a/sysEnv.sh b/sysEnv.sh new file mode 100644 index 0000000..69e18f4 --- /dev/null +++ b/sysEnv.sh @@ -0,0 +1,30 @@ +#!/bin/bash +# meshing-around shell script for sysinfo +# runShell.sh +cd "$(dirname "$0")" +program_path=$(pwd) + +# get basic telemetry data. Free space, CPU, RAM, and temperature for a raspberry pi +free_space=$(df -h | grep ' /$' | awk '{print $4}') +cpu_usage=$(top -bn1 | grep "Cpu(s)" | sed "s/.*, *\([0-9.]*\)%* id.*/\1/" | awk '{print 100 - $1}') +ram_usage=$(free | grep Mem | awk '{print $3/$2 * 100.0}') +ram_free=$(echo "scale=2; 100 - $ram_usage" | bc) + +# if command vcgencmd is found, part of raspberrypi tools, use it to get temperature +if command -v vcgencmd &> /dev/null +then + # get temperature + temp=$(vcgencmd measure_temp | sed "s/temp=//" | sed "s/'C//") + # temp in fahrenheit + tempf=$(echo "scale=2; $temp * 9 / 5 + 32" | bc) +else + # get temperature from thermal zone + temp=$(paste <(cat /sys/class/thermal/thermal_zone*/type) <(cat /sys/class/thermal/thermal_zone*/temp) | grep "temp" | awk '{print $2/1000}' | awk '{s+=$1} END {print s/NR}') + tempf=$(echo "scale=2; $temp * 9 / 5 + 32" | bc) +fi + +# print telemetry data +printf "Disk:%s" "$free_space" +printf " RAM:%.2f%%" "$ram_usage" +printf " CPU:%.1f%%" "$cpu_usage" +printf " CPU-T:%.1f°C (%.1f°F)" "$temp" "$tempf" \ No newline at end of file