diff --git a/src/node_info/files/Collector/LmSensors.pm b/src/node_info/files/Collector/LmSensors.pm index 9fc952d..9d3ca5d 100644 --- a/src/node_info/files/Collector/LmSensors.pm +++ b/src/node_info/files/Collector/LmSensors.pm @@ -92,11 +92,12 @@ sub _get_temperature_sensors { } $data = JSON->new->pretty->encode({ - cpu => $config{lm_sensors}{enable_cpu} ? \1 : \0, - nvme => $config{lm_sensors}{enable_nvme_temp} ? \1 : \0, - fans => $config{lm_sensors}{enable_fan_speed} ? \1 : \0, - hdd => $config{lm_sensors}{enable_hdd_temp} ? \1 : \0, - data => { 'PVE MOD lm-sensors Enhanced' => $sensors_json }, + cpu => $config{lm_sensors}{enable_cpu} ? \1 : \0, + nvme => $config{lm_sensors}{enable_nvme_temp} ? \1 : \0, + fans => $config{lm_sensors}{enable_fan_speed} ? \1 : \0, + hdd => $config{lm_sensors}{enable_hdd_temp} ? \1 : \0, + other => $config{lm_sensors}{enable_other_temp} ? \1 : \0, + data => { 'PVE MOD lm-sensors Enhanced' => $sensors_json }, }); return $data; diff --git a/src/node_info/files/Config.pm b/src/node_info/files/Config.pm index 2ccadc2..5d31db2 100644 --- a/src/node_info/files/Config.pm +++ b/src/node_info/files/Config.pm @@ -69,6 +69,7 @@ our %config = ( enable_ram_temp => 0, enable_hdd_temp => 0, enable_nvme_temp => 0, + enable_other_temp => 0, enable_fan_speed => 0, display_zero_speed_fans => 0, temp_unit => 'C', diff --git a/src/node_info/files/PveMod_pvemanagerlib.js b/src/node_info/files/PveMod_pvemanagerlib.js index a08fc71..2f03726 100644 --- a/src/node_info/files/PveMod_pvemanagerlib.js +++ b/src/node_info/files/PveMod_pvemanagerlib.js @@ -656,7 +656,108 @@ Ext.define('PVE.node.StatusView', { return '
' + html + '
'; } }, - + { + itemId: 'otherThermals', + colspan: 2, + printBar: false, + title: gettext('Other Temperatures'), + iconCls: 'fa fa-fw fa-thermometer-half', + textField: 'PveMod_JsonSensorInfo', + renderer: function(value) { + // Prefixes belonging to other known categories (excluded from this view) + const excludePrefixes = [ + 'nvme-pci-', + 'coretemp-isa-', + 'k10temp-pci-', + 'cpu_thermal-virtual-', + 'drivetemp-', + 'spd5118-', + ]; + const tempHelper = Ext.create('PVE.mod.TempHelper', {srcUnit: PVE.mod.TempHelper.CELSIUS, dstUnit: PVE.mod.TempHelper.CELSIUS}); + // --- + let objValue; + try { + const parsed = value || {}; + if (parsed.disabled === true) { + this.hide(); + return ''; + } else if (parsed.other !== true) { + this.hide(); + return ''; + } + objValue = (parsed.data && parsed.data[Object.keys(parsed.data)[0]]) || {}; + } catch(e) { + objValue = {}; + } + + // Keep only keys that do not belong to known categories + const otherKeys = Object.keys(objValue).filter(key => + !excludePrefixes.some(prefix => String(key).startsWith(prefix)) + ).sort(); + + let rows = []; + + otherKeys.forEach(sensorKey => { + try { + const sensorObj = objValue[sensorKey]; + if (!sensorObj || typeof sensorObj !== 'object') { return; } + + // Collect all nested temp* sub-objects + const tempKeys = Object.keys(sensorObj).filter(k => String(k).startsWith('temp')).sort(); + if (tempKeys.length === 0) { return; } + + let tempParts = []; + tempKeys.forEach(tempKey => { + try { + const tempData = sensorObj[tempKey]; + if (!tempData || typeof tempData !== 'object') { return; } + + let tempVal = NaN, tempMax = NaN, tempCrit = NaN; + Object.keys(tempData).forEach(subKey => { + if (subKey.endsWith('_input')) { + tempVal = tempHelper.getTemp(parseFloat(tempData[subKey])); + } else if (subKey.endsWith('_max')) { + tempMax = tempHelper.getTemp(parseFloat(tempData[subKey])); + } else if (subKey.endsWith('_crit')) { + tempCrit = tempHelper.getTemp(parseFloat(tempData[subKey])); + } + }); + + if (!isNaN(tempVal)) { + let tempStyle = ''; + if (!isNaN(tempMax) && tempVal >= tempMax) { + tempStyle = 'color: #FFC300; font-weight: bold;'; + } + if (!isNaN(tempCrit) && tempVal >= tempCrit) { + tempStyle = 'color: red; font-weight: bold;'; + } + tempParts.push(`${tempKey}: ${Ext.util.Format.number(tempVal, '0.0')}${tempHelper.getUnit()}`); + } + } catch(e) { /*_*/ } + }); + + if (tempParts.length > 0) { + rows.push({ label: sensorKey, temps: tempParts.join(' | ') }); + } + } catch(e) { /*_*/ } + }); + + if (rows.length === 0) { + return ''; + } + + let html = ''; + rows.forEach(row => { + html += ''; + html += ``; + html += ``; + html += ''; + }); + html += '
${row.label}${row.temps}
'; + return '
' + html + '
'; + } + }, + // ========== TERTIARY DIAGNOSTICS (Tier 3) ========== { xtype: 'box', diff --git a/src/node_info/node_info.configure.sh b/src/node_info/node_info.configure.sh index feef1a8..3362cd8 100644 --- a/src/node_info/node_info.configure.sh +++ b/src/node_info/node_info.configure.sh @@ -64,7 +64,7 @@ _check_nvidia_tool() { node_info_defaults() { LM_SENSORS_ENABLED=0 ENABLE_CPU=0; CPU_TEMP_TARGET="Core" - ENABLE_RAM_TEMP=0; ENABLE_HDD_TEMP=0; ENABLE_NVME_TEMP=0 + ENABLE_RAM_TEMP=0; ENABLE_HDD_TEMP=0; ENABLE_NVME_TEMP=0; ENABLE_OTHER_TEMP=0 ENABLE_FAN_SPEED=0; DISPLAY_ZERO_SPEED_FANS=0; TEMP_UNIT="C" ENABLE_INTEL_GPU_INFO=0; ENABLE_NVIDIA_GPU_INFO=0; ENABLE_AMD_GPU_INFO=0 ENABLE_GPU_HISTORY=0 @@ -101,6 +101,7 @@ node_info_load_conf() { lm_sensors.enable_ram_temp) ENABLE_RAM_TEMP="$val" ;; lm_sensors.enable_hdd_temp) ENABLE_HDD_TEMP="$val" ;; lm_sensors.enable_nvme_temp) ENABLE_NVME_TEMP="$val" ;; + lm_sensors.enable_other_temp) ENABLE_OTHER_TEMP="$val" ;; lm_sensors.enable_fan_speed) ENABLE_FAN_SPEED="$val" ;; lm_sensors.display_zero_speed_fans) DISPLAY_ZERO_SPEED_FANS="$val" ;; lm_sensors.temp_unit) TEMP_UNIT="$val" ;; @@ -131,7 +132,7 @@ node_info_configure() { # Initialize all variables to off LM_SENSORS_ENABLED=0 ENABLE_CPU=0; CPU_TEMP_TARGET="Core" - ENABLE_RAM_TEMP=0; ENABLE_HDD_TEMP=0; ENABLE_NVME_TEMP=0 + ENABLE_RAM_TEMP=0; ENABLE_HDD_TEMP=0; ENABLE_NVME_TEMP=0; ENABLE_OTHER_TEMP=0 ENABLE_FAN_SPEED=0; DISPLAY_ZERO_SPEED_FANS=0; TEMP_UNIT="C" ENABLE_INTEL_GPU_INFO=0; ENABLE_NVIDIA_GPU_INFO=0; ENABLE_AMD_GPU_INFO=0 ENABLE_GPU_HISTORY=0 @@ -251,6 +252,21 @@ node_info_configure() { fi #endregion NVMe + #region Other thermals + msgb "\n=== Detecting other thermal sensors ===" + local otherTempCount + otherTempCount=$(echo "$sanitisedSensorsOutput" \ + | grep -Ev '"(coretemp|k10temp-pci|cpu_thermal-virtual|nvme|drivetemp-scsi|SODIMM|spd5118)[^"]*"' \ + | grep -c '"temp[0-9]*_input"' || true) + + if [[ "$otherTempCount" -gt 0 ]]; then + info "Detected $otherTempCount other temperature reading(s)." + ENABLE_OTHER_TEMP=1; sensors_detected=true + else + warn "No other temperature sensors found." + fi + #region Other thermals + #region Fans msgb "\n=== Detecting fan speed sensors ===" local fanCount @@ -459,6 +475,7 @@ cpu_temp_target=${CPU_TEMP_TARGET} enable_ram_temp=${ENABLE_RAM_TEMP} enable_hdd_temp=${ENABLE_HDD_TEMP} enable_nvme_temp=${ENABLE_NVME_TEMP} +enable_other_temp=${ENABLE_OTHER_TEMP} enable_fan_speed=${ENABLE_FAN_SPEED} display_zero_speed_fans=${DISPLAY_ZERO_SPEED_FANS} temp_unit=${TEMP_UNIT} diff --git a/src/node_info/readme.md b/src/node_info/readme.md index ed49996..c102355 100644 --- a/src/node_info/readme.md +++ b/src/node_info/readme.md @@ -6,7 +6,7 @@ Extends the Proxmox VE node status view with live hardware sensor data. A backgr ### Temperature Sensors (lm-sensors) -Reads hardware sensor data via `lm-sensors` and enriches each chip/adapter entry with context. +Reads hardware sensor data via `lm-sensors` and enriches each chip/adapter entry with context. CPU, RAM, HDD/SSD, NVME are directly supported and other temperature sensors can be bundled and displayed together. ### NVIDIA GPU