[pve-mod-gui-sensors.sh] support for mixed core cluster (#81)
* * Fixed to render correctly even if INTEL and AMD core nodes are mixed in the cluster. * Fixed the behavior of forcing configuration before being told "Mod is already installed". * Add motherboard information as an option in System Information settings. * Update to a simple CPU configuration. * Configure CPU temperature display settings independent of current sensor state. * Fixed a bug where AMD chiplet temperature was not displayed. * Add note about AMD only supports average * Update readme --------- Co-authored-by: Meliox <na>
This commit is contained in:
parent
81a3808a01
commit
3cb1ac83b9
@ -112,82 +112,28 @@ function configure {
|
|||||||
err "Sensor output error.\n\nCommand output:\n${sensorsOutput}\n\nExiting...\n"
|
err "Sensor output error.\n\nCommand output:\n${sensorsOutput}\n\nExiting...\n"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Check if CPU is part of known list for autoconfiguration
|
# Prompt user for which temperature to use
|
||||||
msg "\nDetecting support for CPU temperature sensors..."
|
while true; do
|
||||||
for item in "${KNOWN_CPU_SENSORS[@]}"; do
|
local choiceTempDisplayType=$(ask "Do you wish to display temperatures for all cores [C] or just an average temperature per CPU [a] (note: AMD only supports average)? (C/a)")
|
||||||
if (echo "$sensorsOutput" | grep -q "$item"); then
|
case "$choiceTempDisplayType" in
|
||||||
CPU_ADDRESS_PREFIX=$item
|
# Set temperature search criteria
|
||||||
fi
|
[cC] | "")
|
||||||
|
CPU_TEMP_TARGET="Core"
|
||||||
|
info "Temperatures will be displayed for all cores."
|
||||||
|
;;
|
||||||
|
[aA])
|
||||||
|
CPU_TEMP_TARGET="Package"
|
||||||
|
info "An average temperature will be displayed per CPU."
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
# If the user enters an invalid input, print an warning message and retry ask.
|
||||||
|
warn "Invalid input."
|
||||||
|
continue
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
break
|
||||||
done
|
done
|
||||||
|
|
||||||
if [ -n "$CPU_ADDRESS_PREFIX" ]; then
|
|
||||||
msg "Detected sensors:\n$(echo "$sensorsOutput" | grep -o "\"${CPU_ADDRESS_PREFIX}[^\"]*\"" | sed 's/"//g')"
|
|
||||||
|
|
||||||
# Populate search criterias for known CPUs
|
|
||||||
if (echo "$sensorsOutput" | grep -q "coretemp-"); then
|
|
||||||
# Intel CPU
|
|
||||||
# Prompt user for which temperature to use
|
|
||||||
local choiceTempDisplayType=$(ask "Do you wish to display temperatures for all cores [C] or just an average temperature per CPU [a]? (C/a)")
|
|
||||||
case "$choiceTempDisplayType" in
|
|
||||||
# Set temperature search criteria
|
|
||||||
[cC] | "")
|
|
||||||
if (echo "$sensorsOutput" | grep -A 10 "coretemp-" | grep -q "Core "); then
|
|
||||||
CPU_ITEM_PREFIX="Core "
|
|
||||||
CPU_TEMP_CAPTION="Core"
|
|
||||||
info "Temperatures will be displayed for all cores."
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
[aA])
|
|
||||||
if (echo "$sensorsOutput" | grep -A 10 "coretemp-" | grep -q "Package id "); then
|
|
||||||
CPU_ITEM_PREFIX="Package id"
|
|
||||||
CPU_TEMP_CAPTION="Package"
|
|
||||||
info "An average temperature will be displayed per CPU."
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
# If the user enters an invalid input, print an error message and exit the script with a non-zero status code
|
|
||||||
err "Invalid input. Exiting..."
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
elif (echo "$sensorsOutput" | grep -q "k10temp-"); then
|
|
||||||
# AMD CPU
|
|
||||||
# Find and set temperature search criteria
|
|
||||||
if (echo "$sensorsOutput" | grep -A 10 "$item" | grep -q "Tctl" && echo "$sensorsOutput" | grep -A 10 "$item" | grep -q "Tccd"); then
|
|
||||||
CPU_ADDRESS_PREFIX=$item
|
|
||||||
CPU_ITEM_PREFIX="Tccd"
|
|
||||||
CPU_TEMP_CAPTION="Temp"
|
|
||||||
elif (echo "$sensorsOutput" | grep -A 10 "$item" | grep -q -e "\"Tctl\""); then
|
|
||||||
CPU_ADDRESS_PREFIX=$item
|
|
||||||
CPU_ITEM_PREFIX="Tctl"
|
|
||||||
CPU_TEMP_CAPTION="Temp"
|
|
||||||
elif (echo "$sensorsOutput" | grep -A 10 "$item" | grep -q "\"temp1\""); then
|
|
||||||
CPU_ADDRESS_PREFIX=$item
|
|
||||||
CPU_ITEM_PREFIX="temp"
|
|
||||||
CPU_TEMP_CAPTION="Temp"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
# If cpu is not known, ask the user for input
|
|
||||||
warn "Could not automatically detect the CPU temperature sensor. Please configure it manually."
|
|
||||||
# Ask user for CPU information
|
|
||||||
# Inform the user and prompt them to press any key to continue
|
|
||||||
read -rsp $'Sensor output will be presented. Press any key to continue...\n' -n1 key
|
|
||||||
|
|
||||||
# Print the output to the user
|
|
||||||
msg "Sensor output:\n${sensorsOutput}"
|
|
||||||
|
|
||||||
# Prompt the user for adapter name and item name
|
|
||||||
read -p "Enter the CPU sensor address prefix (e.g.: coretemp-isa- or k10temp-pci-): " CPU_ADDRESS_PREFIX
|
|
||||||
read -p "Enter the CPU sensor input prefix (e.g.: Core or Tc): " CPU_ITEM_PREFIX
|
|
||||||
read -p "Enter the CPU temperature caption (e.g.: Core or Temp): " CPU_TEMP_CAPTION
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ -z "$CPU_ADDRESS_PREFIX" || -z "$CPU_ITEM_PREFIX" ]]; then
|
|
||||||
warn "The CPU configuration is not complete. Temperatures will not be available."
|
|
||||||
else
|
|
||||||
SENSORS_DETECTED=true
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Look for ram temps
|
# Look for ram temps
|
||||||
msg "\nDetecting support for RAM temperature sensors..."
|
msg "\nDetecting support for RAM temperature sensors..."
|
||||||
if (echo "$sensorsOutput" | grep -q '"SODIMM":'); then
|
if (echo "$sensorsOutput" | grep -q '"SODIMM":'); then
|
||||||
@ -271,12 +217,25 @@ function configure {
|
|||||||
esac
|
esac
|
||||||
fi
|
fi
|
||||||
|
|
||||||
local choiceEnableSystemInfo=$(ask "Do you wish to enable system information? (Y/n)")
|
# DMI Type:
|
||||||
|
# 1 ... System Information
|
||||||
|
# 2 ... Base Board Information (for self-made PC)
|
||||||
|
for i in 1 2; do
|
||||||
|
echo "type ${i})"
|
||||||
|
dmidecode -t ${i} | awk -F': ' '/Manufacturer|Product Name|Serial Number/ {print $1": "$2}'
|
||||||
|
done
|
||||||
|
local choiceEnableSystemInfo=$(ask "Do you wish to enable system information? (1/2/n)")
|
||||||
case "$choiceEnableSystemInfo" in
|
case "$choiceEnableSystemInfo" in
|
||||||
[yY] | "")
|
[1] | "")
|
||||||
ENABLE_SYSTEM_INFO=true
|
ENABLE_SYSTEM_INFO=true
|
||||||
|
SYSTEM_INFO_TYPE=1
|
||||||
info "System information will be displayed..."
|
info "System information will be displayed..."
|
||||||
;;
|
;;
|
||||||
|
[2])
|
||||||
|
ENABLE_SYSTEM_INFO=true
|
||||||
|
SYSTEM_INFO_TYPE=2
|
||||||
|
info "Motherboard information will be displayed..."
|
||||||
|
;;
|
||||||
[nN])
|
[nN])
|
||||||
ENABLE_SYSTEM_INFO=false
|
ENABLE_SYSTEM_INFO=false
|
||||||
info "System information will NOT be displayed..."
|
info "System information will NOT be displayed..."
|
||||||
@ -291,6 +250,11 @@ function configure {
|
|||||||
|
|
||||||
# Function to install the modification
|
# Function to install the modification
|
||||||
function install_mod {
|
function install_mod {
|
||||||
|
if [[ -n $(cat $NODES_PM_FILE | grep -e "$res->{sensorsOutput}") ]] && [[ -n $(cat $NODES_PM_FILE | grep -e "$res->{systemInfo}") ]]; then
|
||||||
|
err "Mod is already installed. Uninstall existing before installing."
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
msg "\nPreparing mod installation..."
|
msg "\nPreparing mod installation..."
|
||||||
|
|
||||||
# Provide sensor configuration
|
# Provide sensor configuration
|
||||||
@ -302,18 +266,13 @@ function install_mod {
|
|||||||
local timestamp=$(date '+%Y-%m-%d_%H-%M-%S')
|
local timestamp=$(date '+%Y-%m-%d_%H-%M-%S')
|
||||||
|
|
||||||
# Perform backup
|
# Perform backup
|
||||||
if [[ -z $(cat $NODES_PM_FILE | grep -e "$res->{sensorsOutput}") ]] || [[ -z $(cat $NODES_PM_FILE | grep -e "$res->{systemInfo}") ]]; then
|
# Create backup of original file
|
||||||
# Create backup of original file
|
cp "$NODES_PM_FILE" "$BACKUP_DIR/Nodes.pm.$timestamp"
|
||||||
cp "$NODES_PM_FILE" "$BACKUP_DIR/Nodes.pm.$timestamp"
|
msg "Backup of \"$NODES_PM_FILE\" saved to \"$BACKUP_DIR/Nodes.pm.$timestamp\"."
|
||||||
msg "Backup of \"$NODES_PM_FILE\" saved to \"$BACKUP_DIR/Nodes.pm.$timestamp\"."
|
|
||||||
|
|
||||||
# Create backup of original file
|
# Create backup of original file
|
||||||
cp "$PVE_MANAGER_LIB_JS_FILE" "$BACKUP_DIR/pvemanagerlib.js.$timestamp"
|
cp "$PVE_MANAGER_LIB_JS_FILE" "$BACKUP_DIR/pvemanagerlib.js.$timestamp"
|
||||||
msg "Backup of \"$PVE_MANAGER_LIB_JS_FILE\" saved to \"$BACKUP_DIR/pvemanagerlib.js.$timestamp\"."
|
msg "Backup of \"$PVE_MANAGER_LIB_JS_FILE\" saved to \"$BACKUP_DIR/pvemanagerlib.js.$timestamp\"."
|
||||||
else
|
|
||||||
err "Mod is already installed. Uninstall existing before installing."
|
|
||||||
exit
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ $SENSORS_DETECTED = true ]; then
|
if [ $SENSORS_DETECTED = true ]; then
|
||||||
local sensorsCmd
|
local sensorsCmd
|
||||||
@ -329,7 +288,7 @@ function install_mod {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if [ $ENABLE_SYSTEM_INFO = true ]; then
|
if [ $ENABLE_SYSTEM_INFO = true ]; then
|
||||||
local systemInfoCmd=$(dmidecode -t 1 | awk -F': ' '/Manufacturer|Product Name|Serial Number/ {print $1": "$2}' | awk '{$1=$1};1' | sed 's/$/ |/' | paste -sd " " - | sed 's/ |$//')
|
local systemInfoCmd=$(dmidecode -t ${SYSTEM_INFO_TYPE} | awk -F': ' '/Manufacturer|Product Name|Serial Number/ {print $1": "$2}' | awk '{$1=$1};1' | sed 's/$/ |/' | paste -sd " " - | sed 's/ |$//')
|
||||||
sed -i "/my \$dinfo = df('\/', 1);/i\\\t\$res->{systemInfo} = \"$(echo "$systemInfoCmd")\";\n" "$NODES_PM_FILE"
|
sed -i "/my \$dinfo = df('\/', 1);/i\\\t\$res->{systemInfo} = \"$(echo "$systemInfoCmd")\";\n" "$NODES_PM_FILE"
|
||||||
msg "System information output added to \"$NODES_PM_FILE\"."
|
msg "System information output added to \"$NODES_PM_FILE\"."
|
||||||
fi
|
fi
|
||||||
@ -470,9 +429,6 @@ Ext.define('PVE.mod.TempHelper', {\n\
|
|||||||
textField: 'sensorsOutput',\n\
|
textField: 'sensorsOutput',\n\
|
||||||
renderer: function(value){\n\
|
renderer: function(value){\n\
|
||||||
// sensors configuration\n\
|
// sensors configuration\n\
|
||||||
const addressPrefix = \"$CPU_ADDRESS_PREFIX\";\n\
|
|
||||||
const cpuItemPrefix = \"$CPU_ITEM_PREFIX\";\n\
|
|
||||||
const cpuTempCaption = \"$CPU_TEMP_CAPTION\";\n\
|
|
||||||
const cpuTempHelper = Ext.create('PVE.mod.TempHelper', $tempHelperCtorParams);\n\
|
const cpuTempHelper = Ext.create('PVE.mod.TempHelper', $tempHelperCtorParams);\n\
|
||||||
// display configuration\n\
|
// display configuration\n\
|
||||||
const itemsPerRow = $CPU_ITEMS_PER_ROW;\n\
|
const itemsPerRow = $CPU_ITEMS_PER_ROW;\n\
|
||||||
@ -483,7 +439,36 @@ Ext.define('PVE.mod.TempHelper', {\n\
|
|||||||
} catch(e) {\n\
|
} catch(e) {\n\
|
||||||
objValue = {};\n\
|
objValue = {};\n\
|
||||||
}\n\
|
}\n\
|
||||||
const cpuKeys = Object.keys(objValue).filter(item => String(item).startsWith(addressPrefix)).sort();\n\
|
const cpuKeysI = Object.keys(objValue).filter(item => String(item).startsWith('coretemp-isa-')).sort();\n\
|
||||||
|
const cpuKeysA = Object.keys(objValue).filter(item => String(item).startsWith('k10temp-pci-')).sort();\n\
|
||||||
|
const bINTEL = cpuKeysI.length > 0 ? true : false;\n\
|
||||||
|
const INTELPackagePrefix = '$CPU_TEMP_TARGET' == 'Core' ? 'Core ' : 'Package id';\n\
|
||||||
|
const INTELPackageCaption = '$CPU_TEMP_TARGET' == 'Core' ? 'Core' : 'Package';\n\
|
||||||
|
let AMDPackagePrefix = 'Tccd';\n\
|
||||||
|
let AMDPackageCaption = 'Chiplet';\n\
|
||||||
|
if (cpuKeysA.length > 0) {\n\
|
||||||
|
let bTccd = false;\n\
|
||||||
|
let bTctl = false;\n\
|
||||||
|
cpuKeysA.forEach((cpuKey, cpuIndex) => {\n\
|
||||||
|
let items = objValue[cpuKey];\n\
|
||||||
|
if (Object.keys(items).findIndex(item => { return String(item).startsWith('Tccd'); })) bTccd = true;\n\
|
||||||
|
if (Object.keys(items).findIndex(item => { return String(item).startsWith('Tctl'); })) bTctl = true;\n\
|
||||||
|
});\n\
|
||||||
|
if (bTccd && bTctl && '$CPU_TEMP_TARGET' == 'Core') {\n\
|
||||||
|
AMDPackagePrefix = 'Tccd';\n\
|
||||||
|
AMDPackageCaption = 'Chiplet';\n\
|
||||||
|
} else if (bTctl) {\n\
|
||||||
|
AMDPackagePrefix = 'Tctl';\n\
|
||||||
|
AMDPackageCaption = 'Temp';\n\
|
||||||
|
} else {\n\
|
||||||
|
AMDPackagePrefix = 'temp';\n\
|
||||||
|
AMDPackageCaption = 'Temp';\n\
|
||||||
|
}\n\
|
||||||
|
}\n\
|
||||||
|
const cpuKeys = bINTEL ? cpuKeysI : cpuKeysA;\n\
|
||||||
|
const cpuItemPrefix = bINTEL ? INTELPackagePrefix : AMDPackagePrefix;\n\
|
||||||
|
const cpuTempCaption = bINTEL ? INTELPackageCaption : AMDPackageCaption;\n\
|
||||||
|
const formatTemp = bINTEL ? '0' : '0.0';\n\
|
||||||
const cpuCount = cpuKeys.length;\n\
|
const cpuCount = cpuKeys.length;\n\
|
||||||
let temps = [];\n\
|
let temps = [];\n\
|
||||||
cpuKeys.forEach((cpuKey, cpuIndex) => {\n\
|
cpuKeys.forEach((cpuKey, cpuIndex) => {\n\
|
||||||
@ -514,9 +499,9 @@ Ext.define('PVE.mod.TempHelper', {\n\
|
|||||||
let tempIndex = coreKey.match(/\\\S+\\\s*(\\\d+)/);\n\
|
let tempIndex = coreKey.match(/\\\S+\\\s*(\\\d+)/);\n\
|
||||||
if (tempIndex !== null && tempIndex.length > 1) {\n\
|
if (tempIndex !== null && tempIndex.length > 1) {\n\
|
||||||
tempIndex = tempIndex[1];\n\
|
tempIndex = tempIndex[1];\n\
|
||||||
tempStr = \`\${cpuTempCaption} \${tempIndex}: <span style=\"\${tempStyle}\">\${Ext.util.Format.number(tempVal, '0.#')}\${cpuTempHelper.getUnit()}</span>\`;\n\
|
tempStr = \`\${cpuTempCaption} \${tempIndex}: <span style=\"\${tempStyle}\">\${Ext.util.Format.number(tempVal, formatTemp)}\${cpuTempHelper.getUnit()}</span>\`;\n\
|
||||||
} else {\n\
|
} else {\n\
|
||||||
tempStr = \`\${cpuTempCaption}: \${Ext.util.Format.number(tempVal, '0.#')}\${cpuTempHelper.getUnit()}\`;\n\
|
tempStr = \`\${cpuTempCaption}: \${Ext.util.Format.number(tempVal, formatTemp)}\${cpuTempHelper.getUnit()}\`;\n\
|
||||||
}\n\
|
}\n\
|
||||||
cpuTemps.push(tempStr);\n\
|
cpuTemps.push(tempStr);\n\
|
||||||
}\n\
|
}\n\
|
||||||
@ -592,7 +577,7 @@ Ext.define('PVE.mod.TempHelper', {\n\
|
|||||||
if (!isNaN(tempCrit) && tempVal >= tempCrit) {\n\
|
if (!isNaN(tempCrit) && tempVal >= tempCrit) {\n\
|
||||||
tempStyle = 'color: red; font-weight: bold;';\n\
|
tempStyle = 'color: red; font-weight: bold;';\n\
|
||||||
}\n\
|
}\n\
|
||||||
const tempStr = \`Drive \${index + 1}: <span style=\"\${tempStyle}\">\${Ext.util.Format.number(tempVal, '0.#')}\${tempHelper.getUnit()}</span>\`;\n\
|
const tempStr = \`Drive \${index + 1}: <span style=\"\${tempStyle}\">\${Ext.util.Format.number(tempVal, '0.0')}\${tempHelper.getUnit()}</span>\`;\n\
|
||||||
temps.push(tempStr);\n\
|
temps.push(tempStr);\n\
|
||||||
}\n\
|
}\n\
|
||||||
} catch(e) { /*_*/ }\n\
|
} catch(e) { /*_*/ }\n\
|
||||||
@ -655,7 +640,7 @@ Ext.define('PVE.mod.TempHelper', {\n\
|
|||||||
if (!isNaN(tempCrit) && tempVal >= tempCrit) {\n\
|
if (!isNaN(tempCrit) && tempVal >= tempCrit) {\n\
|
||||||
tempStyle = 'color: red; font-weight: bold;';\n\
|
tempStyle = 'color: red; font-weight: bold;';\n\
|
||||||
}\n\
|
}\n\
|
||||||
const tempStr = \`Drive \${index + 1}: <span style=\"\${tempStyle}\">\${Ext.util.Format.number(tempVal, '0.#')}\${tempHelper.getUnit()}</span>\`;\n\
|
const tempStr = \`Drive \${index + 1}: <span style=\"\${tempStyle}\">\${Ext.util.Format.number(tempVal, '0.0')}\${tempHelper.getUnit()}</span>\`;\n\
|
||||||
temps.push(tempStr);\n\
|
temps.push(tempStr);\n\
|
||||||
}\n\
|
}\n\
|
||||||
} catch(e) { /*_*/ }\n\
|
} catch(e) { /*_*/ }\n\
|
||||||
|
|||||||
@ -7,7 +7,7 @@ If you find this helpful, a small donation is appreciated, [
|
(Tested compatibility: 7.x - 8.3.2)
|
||||||

|

|
||||||
|
|
||||||
This bash script installs a modification to the Proxmox Virtual Environment (PVE) web user interface (UI) to display sensor readings in a flexible and readable manner. Supported are CPU, NVMe/HDD/SSD temperatures (Celsius/Fahrenheit), fan speeds and ram temperatures.
|
This bash script installs a modification to the Proxmox Virtual Environment (PVE) web user interface (UI) to display sensor readings in a flexible and readable manner. Supported are CPU, NVMe/HDD/SSD temperatures (Celsius/Fahrenheit), fan speeds, ram temperatures, mixed CPU's core nodes setups, motherboard information or system information.
|
||||||
|
|
||||||
The modification includes three main steps:
|
The modification includes three main steps:
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user