From 0e7bcd6ca4673a0ff53617f7592958d81cb3ed31 Mon Sep 17 00:00:00 2001
From: Jory Pratt <anarchy@gentoo.org>
Date: Sat, 12 Apr 2025 21:16:10 -0500
Subject: [PATCH] Port Supermon2 node info display to Supermon 7.4+,
 rewritenthe bash script to python, update commands used in latest asterisk.
 Change config format for node_info.ini.

Signed-off-by: Jory Pratt <anarchy@gentoo.org>
---
 usr/local/sbin/ast_node_status_update.py | 233 +++++++++++++++++++++++
 usr/local/sbin/node_info.ini             |  10 +
 var/www/html/supermon/link.php           |  78 ++++----
 var/www/html/supermon/server.php         |  88 +++++++--
 4 files changed, 357 insertions(+), 52 deletions(-)
 create mode 100755 usr/local/sbin/ast_node_status_update.py
 create mode 100644 usr/local/sbin/node_info.ini

diff --git a/usr/local/sbin/ast_node_status_update.py b/usr/local/sbin/ast_node_status_update.py
new file mode 100755
index 0000000..2446cf1
--- /dev/null
+++ b/usr/local/sbin/ast_node_status_update.py
@@ -0,0 +1,233 @@
+#!/usr/bin/env python3
+
+"""
+ast_node_status_update.py
+
+This script updates various AllstarLink node variables on the local server
+using the `rpt set variable` Asterisk command. It gathers information
+such as system uptime, CPU load, CPU temperature, weather conditions,
+and log disk usage. It also displays any active AutoSky/SkywarnPlus
+weather alerts (if either is installed and configured), with the alert
+itself being a clickable link if available.
+
+Configuration:
+  The script reads its primary configuration from the 'node_info.ini' file
+  located in the same directory as this script. This file contains settings
+  for the Allstar nodes to update, weather information, and the preferred
+  temperature unit.
+
+Usage:
+  1. Ensure the script has execute permissions: `chmod +x ast_node_status_update.py`
+  2. Create a 'node_info.ini' file in the same directory with your configuration.
+  3. Run the script: `./ast_node_status_update.py`
+
+Configuration File (node_info.ini) Example:
+[general]
+NODE = node_number(s)
+WX_CODE = zip/airport
+WX_LOCATION = City, State
+TEMP_UNIT = F
+
+[autosky]
+MASTER_ENABLE = yes
+ALERT_INI = /usr/local/bin/AUTOSKY/AutoSky.ini
+WARNINGS_FILE = /var/www/html/AUTOSKY/warnings.txt
+"""
+
+import os
+import subprocess
+import re
+import configparser
+
+def run_command(command):
+    """Executes a shell command and returns its output."""
+    try:
+        process = subprocess.run(command, shell=True, capture_output=True, text=True, check=True)
+        return process.stdout.strip()
+    except subprocess.CalledProcessError as e:
+        print(f"Error running command '{command}': {e}")
+        return None
+    except FileNotFoundError:
+        print(f"Command not found: {command}")
+        return None
+
+def get_uptime():
+    """Gets the system uptime."""
+    uptime_output = run_command("uptime -p")
+    if uptime_output:
+        return f"Up {uptime_output.replace('up ', '')}"
+    return None
+
+def get_cpu_load():
+    """Gets the CPU load average."""
+    uptime_output = run_command("uptime")
+    if uptime_output:
+        load_match = re.search(r"load average: (.+)", uptime_output)
+        if load_match:
+            return f'"Load Average: {load_match.group(1)}"'
+    return None
+
+def get_cpu_temperature(temp_unit):
+    """Gets the CPU temperature from /sys/class/thermal/thermal_zone0/temp."""
+    temp_c = None
+
+    if os.path.exists("/sys/class/thermal/thermal_zone0/temp") and os.access("/sys/class/thermal/thermal_zone0/temp", os.R_OK):
+        temp_raw = run_command("cat /sys/class/thermal/thermal_zone0/temp")
+        if temp_raw and temp_raw.isdigit():
+            temp_c = int(temp_raw) / 1000
+
+    if temp_c is not None:
+        temp_unit_upper = temp_unit.upper()
+        if temp_unit_upper == "F":
+            temp_val = (temp_c * 9 / 5) + 32
+            unit_str = "F"
+        elif temp_unit_upper == "C":
+            temp_val = temp_c
+            unit_str = "C"
+        else:
+            return '"Temp Unit Invalid in config"'
+
+        temp_int = int(temp_val)
+        temp_display = f"{temp_int} {unit_str}"
+
+        if unit_str == "C":
+            if temp_int <= 50:
+                return f'"<span style=\'background-color:lightgreen;\'><b>{temp_display}</b></span>"'
+            elif temp_int <= 60:
+                return f'"<span style=\'background-color:yellow;\'><b>{temp_display}</b></span>"'
+            else:
+                return f'"<span style=\'background-color:#fa4c2d;\'><b>{temp_display}</b></span>"'
+        elif unit_str == "F":
+            if temp_int <= 140:
+                return f'"<span style=\'background-color:lightgreen;\'><b>{temp_display}</b></span>"'
+            elif temp_int <= 158:
+                return f'"<span style=\'background-color:yellow;\'><b>{temp_display}</b></span>"'
+            else:
+                return f'"<span style=\'background-color:#fa4c2d;\'><b>{temp_display}</b></span>"'
+    else:
+        return '"CPU Temp N/A"'
+
+def get_weather(wx_code, wx_location):
+    """Gets weather information using external scripts if configured."""
+    if not wx_code or not wx_location:
+        return '" "'
+    elif os.access("/usr/local/sbin/weather.pl", os.X_OK):
+        wx_raw = run_command(f"/usr/local/sbin/weather.pl \"{wx_code}\" v")
+        if wx_raw:
+            return f'"<b>{wx_location} &nbsp; ({wx_raw})</b>"'
+    elif os.access("/usr/local/sbin/weather.sh", os.X_OK):
+        wx_raw = run_command(f"/usr/local/sbin/weather.sh \"{wx_code}\" v")
+        if wx_raw:
+            return f'"<b>{wx_location} &nbsp; ({wx_raw})</b>"'
+    return '" "'
+
+def get_log_usage():
+    """Gets the disk usage of the /var/log partition."""
+    logsz_output = run_command("df -h /var/log")
+    if logsz_output:
+        lines = logsz_output.strip().split('\n')
+        if len(lines) > 1:
+            parts = lines[1].split()
+            if len(parts) >= 5:
+                used = parts[2]
+                percent = parts[4]
+                available = parts[3]
+                return f'"Logs - {used} {percent} used, {available} remains"'
+    return '"Logs - N/A"'
+
+def get_autosky_alerts(alert_ini, warnings_file, master_enable):
+    """Retrieves active weather alerts from AutoSky/SkywarnPlus, if configured."""
+    github_link = '<a href=\'https://github.com/mason10198/SkywarnPlus\' style=\'color: inherit; text-decoration: none;\'>SkywarnPlus</a>'
+    enabled_text = f'<span style=\'color: SpringGreen;\'><b><u>{github_link} Enabled</u></b></span>'
+    disabled_text = f'<span style=\'color: darkorange;\'><b><u>{github_link} Disabled</u></b></span>'
+
+    if master_enable.lower() != "yes":
+        return f'"{disabled_text}"'
+
+    if warnings_file and not os.path.exists(warnings_file):
+        print(f"Warning: warnings_file '{warnings_file}' not found. Create it as root: touch {warnings_file}")
+        return '" "'
+
+    if os.path.exists(warnings_file):
+        alert_url_command = f"grep '^OFILE=' \"{alert_ini}\" | sed 's/OFILE=//' | sed 's/&y=0/&y=1/' | sed 's/\"//g'"
+        alert_url = run_command(alert_url_command)
+        alert_url_link = f"<a target='WX ALERT' href='{alert_url}'>" if alert_url else ""
+        alert_url_link_end = "</a>" if alert_url else ""
+        alert_content = ""
+        try:
+            with open(warnings_file, 'r') as f:
+                alert_content = f.read().strip()
+        except FileNotFoundError:
+            return f'"{enabled_text}<br><span style=\'color: red;\'>No Alerts</span>"'
+
+        if not alert_content:
+            return f'"{enabled_text}<br><span style=\'color: red;\'>No Alerts</span>"'
+        else:
+            alert_content_cleaned = alert_content.replace("[", "").replace("]", "")
+            return f'"{enabled_text}<br><span style=\'color: red;\'>{alert_url_link}<b>{alert_content_cleaned}</b>{alert_url_link_end}</span>"'
+    else:
+        return '" "'
+
+def update_node_variables(node, cpu_up, cpu_load, cpu_temp_dsp, wx, logs, alert):
+    """Updates the Allstar node variables using the `rpt set variable` command."""
+    check_node_command = f"grep -q '[[:blank:]]*\\[{node}\\]' /etc/asterisk/rpt.conf"
+    if run_command(check_node_command) is not None:
+        command = [
+            "/usr/sbin/asterisk",
+            "-rx",
+            f"rpt set variable {node} cpu_up=\"{cpu_up}\" cpu_load={cpu_load} cpu_temp={cpu_temp_dsp} WX={wx} LOGS={logs}"
+        ]
+        result = subprocess.run(command, capture_output=True, text=True, check=False)
+        if result.returncode != 0:
+            print(f"Error setting variables for node {node}: {result.stderr}")
+        else:
+            print(f"Updated Variables Node {node} using rpt set variable")
+
+        command_alert = [
+            "/usr/sbin/asterisk",
+            "-rx",
+            f"rpt set variable {node} ALERT={alert}"
+        ]
+        result_alert = subprocess.run(command_alert, capture_output=True, text=True, check=False)
+        if result_alert.returncode != 0:
+            print(f"Error setting ALERT for node {node}: {result_alert.stderr}")
+        else:
+            print(f"Updated ALERT Node {node} using rpt set variable")
+    else:
+        print(f"Invalid Node {node} this server")
+
+if __name__ == "__main__":
+    script_dir = os.path.dirname(os.path.realpath(__file__))
+    config_file = os.path.join(script_dir, "node_info.ini")
+    config = configparser.ConfigParser()
+
+    if not os.path.exists(config_file):
+        print(f"Error: Configuration file '{config_file}' not found.")
+        exit(1)
+
+    config.read(config_file)
+
+    nodes = config.get("general", "NODE", fallback="").split()
+    wx_code = config.get("general", "WX_CODE", fallback="")
+    wx_location = config.get("general", "WX_LOCATION", fallback="")
+    temp_unit = config.get("general", "TEMP_UNIT", fallback="F")
+
+    master_enable = config.get("autosky", "MASTER_ENABLE", fallback="no")
+    alert_ini = config.get("autosky", "ALERT_INI", fallback="/usr/local/bin/AUTOSKY/AutoSky.ini")
+    warnings_file = config.get("autosky", "WARNINGS_FILE", fallback="/var/www/html/AUTOSKY/warnings.txt")
+
+    cpu_up = get_uptime()
+    cpu_load = get_cpu_load()
+    cpu_temp_dsp = get_cpu_temperature(temp_unit)
+    wx = get_weather(wx_code, wx_location)
+    logs = get_log_usage()
+    alert = get_autosky_alerts(alert_ini, warnings_file, master_enable)
+
+    if nodes:
+        for node in nodes:
+            if node.strip():
+                update_node_variables(node.strip(), cpu_up, cpu_load, cpu_temp_dsp, wx, logs, alert)
+    else:
+        print("No nodes specified in the configuration file.")
+
+    exit(0)
diff --git a/usr/local/sbin/node_info.ini b/usr/local/sbin/node_info.ini
new file mode 100644
index 0000000..a7724e4
--- /dev/null
+++ b/usr/local/sbin/node_info.ini
@@ -0,0 +1,10 @@
+[general]
+NODE = node_number(s)
+WX_CODE = zip/airport
+WX_LOCATION = City, State
+TEMP_UNIT = F
+
+[autosky]
+MASTER_ENABLE = yes
+ALERT_INI = /usr/local/bin/AUTOSKY/AutoSky.ini
+WARNINGS_FILE = /var/www/html/AUTOSKY/warnings.txt
diff --git a/var/www/html/supermon/link.php b/var/www/html/supermon/link.php
index 58ad706..7c45985 100644
--- a/var/www/html/supermon/link.php
+++ b/var/www/html/supermon/link.php
@@ -136,19 +136,49 @@ $(document).ready(function() {
 			tx_keyed = 1;
 
 	}
-        
-        if (cos_keyed == 0) { 
-                if (tx_keyed == 0)
-                        tablehtml += '<tr class="gColor"><td colspan="1" align="center">' + localNode + '</td><td colspan="1" align="center">Idle</td><td colspan="5"></td></tr>';
-                else
-                        tablehtml += '<tr class="tColor"><td colspan="1" align="center">' + localNode + '</td><td colspan="1" align="center">PTT-Keyed</td><td colspan="5"></td></tr>';
-        }
-        else {
-                if (tx_keyed == 0)
-                        tablehtml += '<tr class="lColor"><td colspan="1" align="center">' + localNode + '</td><td colspan="1" align="center">COS-Detected</td><td colspan="5"></td></tr>';
-                else
-                        tablehtml += '<tr class="bColor"><td colspan="1" align="center">' + localNode + '</td><td colspan="2" align="center">COS-Detected and PTT-Keyed (Full-Duplex)</td><td colspan="4"></td></tr>';
-        }
+	
+		// WA3DSP - 12/2020
+	var cpu_temp=tabledata[localNode].remote_nodes[row].cpu_temp;
+
+	if (!cpu_temp) {
+
+	        if (cos_keyed == 0) { 
+        	        if (tx_keyed == 0)
+                	        tablehtml += '<tr class="gColor"><td colspan="1" align="center">' + localNode + '</td><td colspan="1" align="center"><b>Idle</b></td><td colspan="5"></td></tr>';
+                	else
+                        	tablehtml += '<tr class="tColor"><td colspan="1" align="center">' + localNode + '</td><td colspan="1" align="center"><b>PTT-Keyed</b></td><td colspan="5"></td></tr>';
+        	} else {
+                	if (tx_keyed == 0)
+                        	tablehtml += '<tr class="lColor"><td colspan="1" align="center">' + localNode + '</td><td colspan="1" align="center"><b>COS-Detected</b></td><td colspan="5"></td></tr>';
+                	else
+                        	tablehtml += '<tr class="bColor"><td colspan="1" align="center">' + localNode + '</td><td colspan="2" align="center"><b>COS-Detected and PTT-Keyed (Full-Duplex)</b></td><td colspan="4"></td></tr>';
+        	}
+
+	} else {
+
+        	if (cos_keyed == 0) { 
+                	if (tx_keyed == 0)
+
+			        tablehtml += '<tr class="gColor"><td colspan="1" align="center">' + localNode + '</td><td colspan="1" align="center"><b>Idle<br>'+tabledata[localNode].remote_nodes[row].ALERT + '<br>' + tabledata[localNode].remote_nodes[row].WX + '</b><br>CPU='+tabledata[localNode].remote_nodes[row].cpu_temp + ' - ' + tabledata[localNode].remote_nodes[row].cpu_up + '<br>' + tabledata[localNode].remote_nodes[row].cpu_load + '<br>' + tabledata[localNode].remote_nodes[row].LOGS + '</td><td colspan="5"></td></tr>';
+        	else
+
+tablehtml += '<tr class="tColor"><td colspan="1" align="center">' + localNode + '</td><td colspan="1" align="center"><b>PTT-KEYED<br>'+tabledata[localNode].remote_nodes[row].ALERT + '<br>' + tabledata[localNode].remote_nodes[row].WX + '</b><br>CPU='+tabledata[localNode].remote_nodes[row].cpu_temp + ' - ' + tabledata[localNode].remote_nodes[row].cpu_up + '<br>' + tabledata[localNode].remote_nodes[row].cpu_load + '<br>' + tabledata[localNode].remote_nodes[row].LOGS + '</td><td colspan="5"></td></tr>';
+
+
+        	} else {
+                	if (tx_keyed == 0)
+
+tablehtml += '<tr class="lColor"><td colspan="1" align="center">' + localNode + '</td><td colspan="1" align="center"><b>COS-DETECTED<br>'+tabledata[localNode].remote_nodes[row].ALERT + '<br>' + tabledata[localNode].remote_nodes[row].WX + '</b><br>CPU='+tabledata[localNode].remote_nodes[row].cpu_temp + ' - ' + tabledata[localNode].remote_nodes[row].cpu_up + '<br>' + tabledata[localNode].remote_nodes[row].cpu_load + '<br>' + tabledata[localNode].remote_nodes[row].LOGS + '</td><td colspan="5"></td></tr>';
+
+
+                	else
+
+tablehtml += '<tr class="bColor"><td colspan="1" align="center">' + localNode + '</td><td colspan="1" align="center"><b>COS-Detected and PTT-Keyed (Full Duplex)<br>'+tabledata[localNode].remote_nodes[row].ALERT + '<br>' + tabledata[localNode].remote_nodes[row].WX + '</b><br>CPU='+tabledata[localNode].remote_nodes[row].cpu_temp + ' - ' + tabledata[localNode].remote_nodes[row].cpu_up + '<br>' + tabledata[localNode].remote_nodes[row].cpu_load + '<br>' + tabledata[localNode].remote_nodes[row].LOGS + '</td><td colspan="5"></td></tr>';
+
+        	}
+}
+
+// END WA3DSP - 12/2020
 
 	for (row in tabledata[localNode].remote_nodes) {
 
@@ -405,7 +435,7 @@ if ($myip == $mylanip) {
 }
 } #endif (count($nodes) > 0)
 print "<br>";
-print "[ $myday - $uptime ]";
+print "[ $myday ]";
 
 ?>
 </div>
@@ -430,12 +460,6 @@ if (isset($DVM_URL) && isset($DVM_URL_NAME)) {
 }
 // END KN2R
 
-// ADDED KN2R - CPU temp indicator for RPi only - irrelevant for PC Cloud
-if (file_exists("/sys/class/thermal/thermal_zone0/temp")) {
-    $CPUTemp = exec("/usr/local/sbin/supermon/get_temp");
-    print " &nbsp; [ $CPUTemp]";
-}
-
 // ADDED KN2R - 11/7/2018 - Core dump file indicator
 if (isset($SHOW_COREDUMPS) && ($SHOW_COREDUMPS == 'yes')) {
     $Cores = `ls /var/lib/systemd/coredump |wc -w`;
@@ -465,20 +489,6 @@ print "</p>";
 
 // END KN2R
 
-// Added WA3DSP Weather conditions
-if (isset($LOCALZIP)) {
-    $WX = exec("/usr/local/sbin/supermon/weather.sh $LOCALZIP v");
-    print "<p style=\"margin-top:0px;\">[ Weather conditions for $LOCATION - $LOCALZIP: ";
-    print "<span style=\"margin-top:0px; font-weight: bold; background-color: GAINSBORO;\">&nbsp;$WX&nbsp;</span> ]";
-}
-
-if (file_exists("/var/www/html/AUTOSKY/warnings.txt")) {
-    if (filesize("/var/www/html/AUTOSKY/warnings.txt")) {
-        $warnings = file_get_contents ("/var/www/html/AUTOSKY/warnings.txt");
-        print "<span style=\"color: red;\"><br><b>$warnings</b></span>";
-    }
-}
-
 print "</p>";
 
 #print '<pre>'; print_r($nodes); print '</pre>';
diff --git a/var/www/html/supermon/server.php b/var/www/html/supermon/server.php
index 3f6b5d5..4b6769b 100644
--- a/var/www/html/supermon/server.php
+++ b/var/www/html/supermon/server.php
@@ -148,27 +148,34 @@ while(TRUE) {
             $current[$node]['remote_nodes'][$i]['mode']=$arr['mode'];
             $current[$node]['remote_nodes'][$i]['elapsed'] = '&nbsp;';
 
+            // WA3DSP
+            // Change to return "Never" so test can be made in link.php
 
-// WA3DSP
-// Change to return "Never" so test can be made in link.php
+            if ( $arr['last_keyed'] == "Never" ) {
+                 $current[$node]['remote_nodes'][$i]['last_keyed'] = 'Never';
+            } else {   
+                 $current[$node]['remote_nodes'][$i]['last_keyed'] = '&nbsp';
+            }
 
-      if ( $arr['last_keyed'] == "Never" ) {
-           $current[$node]['remote_nodes'][$i]['last_keyed'] = 'Never';
-      } else {   
-           $current[$node]['remote_nodes'][$i]['last_keyed'] = '&nbsp';
-      }
+            // WA3DSP 3/2018    
+            // Change to add local RXKEYED COS display
+            $current[$node]['remote_nodes'][$i]['cos_keyed']=$arr['cos_keyed'];
+            $current[$node]['remote_nodes'][$i]['info']=$arr['info'];
+            $current[$node]['remote_nodes'][$i]['node']=$arr['node'];
+            // END
 
-// WA3DSP 3/2018    
-// Change to add local RXKEYED COS display
-$current[$node]['remote_nodes'][$i]['cos_keyed']=$arr['cos_keyed'];
-$current[$node]['remote_nodes'][$i]['info']=$arr['info'];
-$current[$node]['remote_nodes'][$i]['node']=$arr['node'];
-// END
+            // ADDED KN2R 9/2018
+            // Change to add local TXKEYED PTT display
+            $current[$node]['remote_nodes'][$i]['tx_keyed']=$arr['tx_keyed'];
+            // END KN2R
 
-// ADDED KN2R 9/2018
-// Change to add local TXKEYED PTT display
-$current[$node]['remote_nodes'][$i]['tx_keyed']=$arr['tx_keyed'];
-// END KN2R
+            // WA3DSP 12/2020  1/3/2021
+            $current[$node]['remote_nodes'][$i]['cpu_temp']=$arr['cpu_temp'];
+            $current[$node]['remote_nodes'][$i]['cpu_up']=$arr['cpu_up'];
+            $current[$node]['remote_nodes'][$i]['cpu_load']=$arr['cpu_load'];
+            $current[$node]['remote_nodes'][$i]['ALERT']=$arr['ALERT'];
+            $current[$node]['remote_nodes'][$i]['WX']=$arr['WX'];
+            $current[$node]['remote_nodes'][$i]['LOGS']=$arr['LOGS'];
 
         $i++;
         }
@@ -325,9 +332,36 @@ function parseNode($fp, $rptStatus, $sawStatus) {
 // ADDED KN2R 9/2018
 	if (preg_match('/Var: RPT_TXKEYED=./', $line, $matches)) {
            $txKeyed=substr($matches[0], strpos($matches[0], "=") + 1);
-        }
+    }
 // END KN2R
 
+// WA3DSP 12/2020  1/3/2021
+    if (preg_match('/Var: cpu_temp=.*/', $line, $matches)) {
+                   $cputemp=substr($matches[0], strpos($matches[0], "=") + 1);
+    }
+
+    if (preg_match('/Var: cpu_up=.*/', $line, $matches)) {
+                   $cpuup=substr($matches[0], strpos($matches[0], "=") + 1);
+    }
+
+    if (preg_match('/Var: cpu_load=.*/', $line, $matches)) {
+                  $cpuload=substr($matches[0], strpos($matches[0], "=") + 1);
+    }
+
+    if (preg_match('/Var: ALERT=.*/', $line, $matches)) {
+                   $ALERT=substr($matches[0], strpos($matches[0], "=") + 1);
+    }
+
+    if (preg_match('/Var: WX=.*/', $line, $matches)) {
+                   $WX=substr($matches[0], strpos($matches[0], "=") + 1);
+    }
+
+    if (preg_match('/Var: LOGS=.*/', $line, $matches)) {
+                   $LOGS=substr($matches[0], strpos($matches[0], "=") + 1);
+    }
+
+// END WA3DSP
+
     }
 
     #print "<pre>Conns: \n"; print_r($conns); print "</pre>";
@@ -364,6 +398,14 @@ function parseNode($fp, $rptStatus, $sawStatus) {
             $curNodes[$n]['direction'] = $node[3];
             $curNodes[$n]['elapsed'] = $node[4];
             $curNodes[$n]['link'] = @$node[5];
+            
+            // WA3DSP 12/2020   1/3/2021
+	        $curNodes[$n]['cpu_temp'] = $cputemp;
+	        $curNodes[$n]['cpu_up'] = $cpuup;
+	        $curNodes[$n]['cpu_load'] = $cpuload;
+	        $curNodes[$n]['ALERT'] = $ALERT;
+	        $curNodes[$n]['WX'] = $WX;
+	        $curNodes[$n]['LOGS'] = $LOGS;
 
             ## Fix for table display bug of IRLP nodes - Paul Aidukas, KN2R ;)
             #
@@ -425,6 +467,16 @@ if ($txKeyed === "1") {
 }
 // END KN2R
 
+// WA3DSP 12/2020  1/3/2021
+$curNodes[1]['cpu_temp'] = $cputemp;
+$curNodes[1]['cpu_up'] = $cpuup;
+$curNodes[1]['cpu_load'] = $cpuload;
+$curNodes[1]['ALERT'] = $ALERT;
+$curNodes[1]['WX'] = $WX;
+$curNodes[1]['LOGS'] = $LOGS;
+$curNodes[1]['REGISTRATIONS'] = $REGISTRATIONS;
+// END WA3DSP
+
     return $curNodes;
 }
 ?>
-- 
2.49.0

