PVE概览界面增加CPU频率,温度显示
PVE安装后初始是不带CPU频率和各温度监控器显示的,本篇教程将带大家修改pve的文件,以实现自定义频率和温度显示!
一、安装sensors温度检测工具
1.1.安装
首先我们需要SSH连接PVE后,安装sensors温度检测工具
apt update -y && apt install sensors -y1.2.初始化设置
安装好后,使用sensors-detect进行初始化设置
sensors-detect这里通常情况全部ENTER回车键确认即可(即直接使用默认值)

1.3.测试温度传感器
这里我们使用命令  sensors  查看一下温度传感器是否正常获取到温度值了

可以看到温度获取正常,但是为了方便处理数据,我们后续使用的命令是:sensors -j
-j 表示用 JSON 格式输出传感器数据

二、修改PVE文件,添加修改代码
2.1 编辑api文件代码
文件路径:/usr/share/perl5/PVE/API2/Nodes.pm
可以使用sftp等工具copy到自己电脑上方便修改,或者使用vi和nano直接打开,我这里直接copy后使用notepad++打开修改
定位编辑位置,查找内容:$res->{ksm} = {
....
$res->{ksm} = {
        shared => $meminfo->{memshared},
    };
$res->{cpure} = `cat /proc/cpuinfo | grep -i  "cpu mhz"`; #cpu频率
$res->{sensinfo} = `sensors -j`; #JSON格式输出传感器数据
$res->{hddtemp} = `hddtemp /dev/sd?`;  #硬盘温度
$res->{apcaccess} = `apcaccess`; #ups信息
...参考上面示例,添加代码:
$res->{cpure} = cat /proc/cpuinfo | grep -i  "cpu mhz"; #cpu频率
$res->{sensinfo} = sensors -j; #JSON格式输出传感器数据
$res->{hddtemp} = hddtemp /dev/sd?;  #硬盘温度

2.2 编辑界面js文件代码
文件路径:/usr/share/pve-manager/js/pvemanagerlib.js
定位编辑位置,查找内容:Proxmox.Utils.render_cpu_model,
{
        itemId: 'cpus',
        colspan: 2,
        printBar: false,
        title: gettext('CPU(s)'),
        textField: 'cpuinfo',
        renderer: Proxmox.Utils.render_cpu_model,
        value: '',
    },
//在这后面添加以下内容
    {
        itemId: 'cpus',
        colspan: 2,
        printBar: false,
        title: gettext('CPU(s)'),
        textField: 'cpuinfo',
        renderer: Proxmox.Utils.render_cpu_model,
        value: '',
    },
    {
        itemId: 'cpumhz',
        colspan: 2,
        printBar: false,
        title: gettext('CPU频率'),
        textField: 'cpure',
        renderer: function(value) {
            const m = value.match(/(?<=:\s+)(\d+)/g);
            if (!m) {
                return 'CPUMHZ: 未知';
            }
            const defaultVal = '未知';
            return `CPUMHZ: ${m[0] || defaultVal} | ${m[1] || defaultVal} | ${m[2] || defaultVal} | ${m[3] || defaultVal}`;
        }
    },
    {
        itemId: 'sensinfo',
        colspan: 2,
        printBar: false,
        title: gettext('温度传感器'),
        textField: 'sensinfo',
        renderer: function(value) {
            let parsedValue;
            try {
                parsedValue = JSON.parse(value.replaceAll('Â', ''));
            } catch (error) {
                return '温度信息解析错误';
            }
            const getTemperature = (path) => {
                let current = parsedValue;
                for (const part of path) {
                    if (!current || !current.hasOwnProperty(part)) {
                        return '未知';
                    }
                    current = current[part];
                }
                return typeof current === 'number' ? current.toFixed(1) : '未知';
            };
            const cp = getTemperature(['coretemp-isa-0000', 'Package id 0', 'temp1_input']);
            const c0 = getTemperature(['coretemp-isa-0000', 'Core 0', 'temp2_input']);
            const c1 = getTemperature(['coretemp-isa-0000', 'Core 1', 'temp3_input']);
        //const c2 = value['coretemp-isa-0000']['Core 2']['temp4_input'].toFixed(1);
        //const c3 = value['coretemp-isa-0000']['Core 3']['temp5_input'].toFixed(1);
        //const f1 = value['it8786-isa-0a40']['fan1']['fan1_input'].toFixed(1);
            const pch = getTemperature(['pch_skylake-virtual-0', 'temp1', 'temp1_input']);
            const z1 = getTemperature(['acpitz-acpi-0', 'temp1', 'temp1_input']);
            const z2 = getTemperature(['acpitz-acpi-0', 'temp2', 'temp2_input']);
            const n0 = getTemperature(['nvme-pci-0500', 'Composite', 'temp1_input']);
            return `CPU温度: ${cp}℃ (${c0}℃,${c1}℃) <br> pch温度: ${pch}℃ <br> 主板温度:${z1}℃ | ${z2}℃ <br> 固态硬盘温度:${n0}℃`;
        }
    },
    {
        itemId: 'hddtemp',
        colspan: 2,
        printBar: false,
        title: gettext('HDD温度'),
        textField: 'hddtemp',
        renderer: function(value) {
            // 检查 value 是否为有效字符串
            if (typeof value !== 'string') {
                return '';
            }
            // 替换 Â 字符
            value = value.replace(/Â/g, '');
            // 替换换行符为 HTML 换行标签
            return value.replace(/\n/g, '<br>');
        }
    },  
    {
        itemId: 'apcaccess',
        colspan: 2,
        printBar: false,
        title: gettext('UPS信息'),
        textField: 'apcaccess',
        renderer: function(inputValue) { // 修改参数名避免冲突
            let result = {};
            const lines = inputValue.split(/\r?\n/); // 根据换行符分割字符串
            lines.forEach(line => {
                const parts = line.trim().split(/:\s*/); // 尝试按冒号和空格分割
                if (parts.length > 1) {
                    const key = parts[0].trim();
                    let lineValue = parts.slice(1).join(': ').trim(); // 修改变量名避免冲突
                    // 特殊处理 DATE 字段,假设它可能包含空格分隔的年、月、日、时、分、秒和时区
                    if (key === 'DATE') {
                        // 使用正则表达式来匹配并提取完整的日期时间字符串
                        const dateMatch = lineValue.match(/^(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2}) ([+-]\d{4})$/);
                        if (dateMatch) {
                            // 重新组合日期时间字符串(如果需要的话,这里可以根据实际格式进行调整)
                            lineValue = `${dateMatch[1]}-${dateMatch[2]}-${dateMatch[3]} ${dateMatch[4]}:${dateMatch[5]}:${dateMatch[6]} ${dateMatch[7]}`;
                        }
                    }
                    // 存储到对象中
                    result[key] = lineValue;
                }
            });
            return `UPS名称:${result.UPSNAME || '未知'} <br>
                    更新时间:${result.DATE || '未知'} <br>
                    状态:${result.STATUS || '未知'} <br>
                    输出电压:${result.OUTPUTV || '未知'} <br>
                    负载:${result.LOADPCT ? result.LOADPCT.replace(' Percent', '') : '未知'} % <br>
                    电池电量:${result.BCHARGE ? result.BCHARGE.replace(' Percent', '') : '未知'} % <br>
                    电池可供电时间:${result.TIMELEFT || '未知'}`;
        }
    },
代码解释:
回到文章前用 sensors -j 输出传感器参数那段

"coretemp-isa-0000" 是 CPU 传感器,其中 "Core 0" 是核心编号,"temp2_input": 56.000 是核心温度
"Package id 0" 是封装传感器,对应的 "temp1_input": xx.000 是封装温度,具体看代码
"acpitz-acpi-0" 是主板传感器,对应的参数大伙看自己的代码
nvme-pci-0500是硬盘温度传感器
PS:由于我的主板是技嘉z270n主板,直接biso接管机箱风扇控制,故风扇代码使用“//”注释了;cpu为双核4线程的G5500,注释了剩下两个核心温度
转速在 "it8786-isa-0a40" 模块中的 "fan1" 或者 "fan2",看具体插在 CPU 或者 SYS 针脚上
return 输出显示详解:
获取数据格式为【const xxxx = value['xxxx']['xxxx']['xxxx_input'].toFixed(1)】
【result】输出字符串的格式根据实际情况或者个人需求进行修改
2.3 修改布局显示
还是这个js文件:/usr/share/pve-manager/js/pvemanagerlib.js
定位编辑位置。
查找内容:Ext.create('Ext.window.Window', {

继续查找内容跳转:widget.pveNodeStatus

两处 height 的值需按情况修改,每多一行数据增加 20。根据实际情况修改,比如不想看到订阅,可适当调整
三、重启 PVE WEB 服务
输入代码:systemctl restart pveproxy
等待几秒钟后,刷新PVE管理网页或者重新打开PVE管理页面
 
           
                             
                    
Comments NOTHING