diff --git a/src/node_info/files/PveMod_pvemanagerlib.js b/src/node_info/files/PveMod_pvemanagerlib.js index 44ebb9f..7a091c9 100644 --- a/src/node_info/files/PveMod_pvemanagerlib.js +++ b/src/node_info/files/PveMod_pvemanagerlib.js @@ -636,7 +636,106 @@ 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 ''; + } + 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) { + this.hide(); + 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..0df7c99 100644 --- a/src/node_info/node_info.configure.sh +++ b/src/node_info/node_info.configure.sh @@ -251,6 +251,12 @@ node_info_configure() { fi #endregion NVMe + #region Other thermals + msgb "\n=== Detecting other thermal sensors ===" + local otherCount + + #region Other thermals + #region Fans msgb "\n=== Detecting fan speed sensors ===" local fanCount