news 2026/8/1 22:09:19

Home Assistant 读取 ESXi温度

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Home Assistant 读取 ESXi温度

目录

    • 一、先把走不通的路堵死
      • 顺便说清楚:风扇转速为什么没戏
    • 二、用 vsish 读 MSR
      • 两个容易踩的点
      • 顺手做个压力测试
    • 三、数据怎么送进 Home Assistant
      • HA 侧配置
    • 四、网络上的两个坑
      • 坑一:ESXi 防火墙默认丢弃出站流量
      • 坑二:用 IP 访问会被 nginx 拒绝
    • 五、采集脚本
    • 六、让配置扛住重启
    • 七、验证
    • 八、这个方案的局限
    • 小结

家里那台 ESXi 用的是消费级主板,一直想把 CPU 温度接到 Home Assistant 里看看曲线。本以为是个半小时的活,结果从"温度到底怎么读"到"数据怎么送进 HA"连着踩了四个坑,折腾了小半天。这篇把过程完整记下来,包括那些走不通的路——知道哪条路是死的,比知道哪条路能走同样有用。

先说结论:消费级主板上,ESXi 的风扇转速读不到,但 CPU 温度可以读,办法是绕过主板、直接读 CPU 内部的 MSR 寄存器。

环境:

  • ESXi 6.7,主板 MSI MS-7A74(B250 芯片组),CPU Pentium G4600(2 核 4 线程)
  • Home Assistant 2026.7(HAOS),装了 NGINX SSL proxy 插件
  • 文中 IP 均为示例:ESXi192.168.1.10,HA192.168.1.20,域名ha.example.com

一、先把走不通的路堵死

服务器主板的温度监控一般走 IPMI 或者厂商的 CIM provider。消费级主板这两样都没有。我把四个可能的通道全试了一遍,结论是全军覆没:

IPMI / BMC

[root@esxi:~]esxcli hardware platform get Platform Information Product Name: MS-7A74 Vendor Name: MSI IPMI Supported:false[root@esxi:~]esxcli hardware ipmi bmc get Retrieve IPMI Baseboard Management Configuration failed:No BMC Device found[root@esxi:~]esxcli hardware ipmi sdr list (空,一条都没有)

CIM 健康传感器

[root@esxi:~]vim-cmd hostsvc/hosthardware|grep-icE"numericSensorInfo|fan|rpm"0

一条传感器信息都没有。这个接口在服务器主板上会列出一堆温度、风扇、电压项,这里是空的。

WBEM 服务

[root@esxi:~]esxcli system wbem get Enabled:falseCIMObject Manager PID:0

服务本身没开。而且就算开了也没用——它需要厂商提供 CIM provider 来喂数据,消费级主板不会有。

vsish 的 IO 端口节点

[root@esxi:~]vsish-els/hardware/port/ size/

只有一个size/,不是能读写 IO 端口的接口。

顺便说清楚:风扇转速为什么没戏

很多人(包括当初的我)会想:温度能读,转速应该也能吧?不能。

风扇转速是由主板上的 Super I/O 芯片(常见的是 Nuvoton NCT6xxx 系列)通过 0x2E/0x4E 这两个 IO 端口提供的,需要nct6775这类 lm-sensors 驱动去解码。ESXi 是闭源的 VMkernel,既不带这个驱动,也不开放用户态的 IO 端口读写能力——它的设计里,风扇监控只走 IPMI/BMC 或者厂商 CIM,那是服务器主板才有的东西。

所以在 ESXi 上,消费级主板的风扇转速就是读不到。想监控只能走物理外挂:把 4pin 风扇的转速信号线(第 3 根)接到 ESP32,用 ESPHome 的pulse_counter组件读 RPM。

那 CPU 温度凭什么能读?因为它压根不经过主板。温度传感器在 CPU 硅片内部,读数通过 CPU 自己的 MSR(Model Specific Register)暴露,跟主板有没有 BMC、有没有 Super I/O 完全无关。


二、用 vsish 读 MSR

ESXi 自带vsish,可以直接读 MSR。用到两个寄存器:

  • 0x1a2(MSR_TEMPERATURE_TARGET):里面存着 TjMax,也就是这颗 CPU 的温度上限
  • 0x1b1(IA32_PACKAGE_THERM_STATUS):存的是"距离 TjMax 还差多少度",注意它是差值不是绝对温度

实际操作:

[root@esxi:~]vsish-eget /hardware/msr/pcpu/0/addr/0x1a2 0x641400[root@esxi:~]vsish-eget /hardware/msr/pcpu/0/addr/0x1b1 0x88390000

换算规则:

TjMax = (0x1a2 的值 >> 16) & 0xFF 温度 = TjMax - ((0x1b1 的值 >> 16) & 0x7F)

代入上面的数:

  • TjMax =0x641400 >> 16=0x64= 100 °C
  • 差值 =0x88390000 >> 16=0x8839,再& 0x7F=0x39= 57
  • 温度 = 100 − 57 =43 °C

两个容易踩的点

第一,只用 package 温度(0x1b1),别用单核的 0x19c。

0x19c(IA32_THERM_STATUS)是每个核心自己的温度。问题在于核心进入 C6 深度睡眠后,它的数字温度传感器会停止更新,读出来是 34 °C 这种明显偏低的假值。我一开始同时采了单核和 package,画出来的曲线单核那几条在 34 和 43 之间反复横跳,看着像散热出了问题,实际上只是核心在睡觉。

package 温度是整个 CPU 封装的温度,不受单核睡眠影响,稳定可靠。

第二,pcpu 编号别越界。

[root@esxi:~]vsish-eget /hardware/msr/pcpu/4/addr/0x19c VSISHCmdGetInt():Get failed: Not found

G4600 是 2 核 4 线程,所以只有 pcpu0~3,读 pcpu4 报 Not found 是正常的,不是故障。

顺手做个压力测试

温度能读了,正好验证一下散热。用md5sum /dev/zero起 4 个进程压满 CPU(纯计算,不涉及磁盘 IO):

# 注意:这会让宿主机上所有虚拟机卡顿,生产环境慎用P=""foriin1234;domd5sum /dev/zero>/dev/null2>&1&P="$P$!";done# 一定要加个看门狗兜底,防止 SSH 断开后进程留在后台(sleep200;kill-9$P2>/dev/null)&

vim-cmd hostsvc/hostsummary | grep overallCpuUsage确认真的压满了(我这里从空载的 1039 MHz 涨到 6845 MHz,满载 95%)。

实测数据(室温 27 °C):

工况package 温度
空载(跑着 n 台虚拟机)42~44 °C
满载稳态50~52 °C
停止负载 5 秒后47 °C
TjMax100 °C

满载和空载只差 9 °C,停载后 5 秒就掉 4 °C,说明散热器接触良好、导热路径通畅。如果硅脂没压开或者扣具没锁紧,这个温差会明显放大,停载后的回落也会变慢很多。


三、数据怎么送进 Home Assistant

温度能读了,接下来是怎么把它变成 HA 里的一个实体。
对比下几种方案:

Webhook(选用)MQTTREST API
凭证权限只是一个随机 ID,泄露最多能伪造温度读数需要 MQTT 账号全权限token
实体质量有 unique_id,可 UI 管理,重启不丢同左无 unique_id,重启短暂消失

HA 侧配置

configuration.yaml里确认有这行(大多数人的配置里已经有了):

template:!includetemplate.yaml

然后在template.yaml末尾追加:

-trigger:-trigger:webhookwebhook_id:!secretesxi_temp_webhookallowed_methods:-POSTlocal_only:true# 只接受内网请求,公网打不进来sensor:-unique_id:esxi_cpu_package_tempdefault_entity_id:sensor.esxi_cpu_tempname:ESXi CPU 温度state:"{{ trigger.json.temp_c | float }}"unit_of_measurement:"°C"device_class:temperaturestate_class:measurement# 加上它才会进入长期统计,能看月/年趋势attributes:tjmax:"{{ trigger.json.tjmax | int }}"raw_msr:"{{ trigger.json.raw }}"

secrets.yaml里加一行,值用随机串(openssl rand -hex 24生成):

esxi_temp_webhook:你生成的随机字符串

改完不用重启 HA,reload 一下 template 集成就行。在 SSH 插件里SUPERVISOR_TOKEN是现成的:

ha core check# 先验证配置语法,别改坏了curl-XPOST-H"Authorization: Bearer$SUPERVISOR_TOKEN"\http://supervisor/core/api/services/template/reload

四、网络上的两个坑

这部分花的时间比前面所有加起来都多。

坑一:ESXi 防火墙默认丢弃出站流量

脚本写好,一跑就超时:

urllib.error.URLError: <urlopen error timed out>

ping 得通,但端口不通。查了一下防火墙:

[root@esxi:~]esxcli network firewall get Default Action: DROP Enabled:true

ESXi 防火墙的默认动作是 DROP,而且对出站同样生效,只有被规则明确放行的端口才能出去。实测:

[root@esxi:~]nc-z-w3192.168.1.208123# HA 默认端口(不通)[root@esxi:~]nc-z-w3192.168.1.20443Connection to192.168.1.20443port[tcp/https]succeeded!

8123 被丢弃,443 通。

我没有去改防火墙规则。ESXi 加自定义规则要往/etc/vmware/firewall/写 XML,重启和升级之后都会丢失,得额外维护一套恢复机制,不值当。443 是现成的通路,上面跑着 HA 的 NGINX SSL proxy 插件,它会把请求转发给 HA core。

如果你的 HA 没装 SSL proxy 插件,也可以考虑在别的机器上做转发,思路是一样的:别跟 ESXi 防火墙较劲。

坑二:用 IP 访问会被 nginx 拒绝

改成https://192.168.1.20/api/webhook/xxx,换了个错误:

ssl.SSLError: [SSL: TLSV1_UNRECOGNIZED_NAME] tlsv1 unrecognized name

原因是 nginx 按 SNI(TLS 握手时携带的域名)来分流。用 IP 直连时,SNI 里带的不是ha.example.com,nginx 找不到匹配的 server 块,直接在 TLS 层就拒了。

解决办法是用域名访问但让它解析到内网 IP。注意 ESXi 6.7 没有esxcli network ip hosts这个命名空间:

[root@esxi:~]esxcli networkiphosts list Error: Unknowncommandor namespace networkiphosts list

直接写文件:

echo"192.168.1.20 ha.example.com">>/etc/hosts

这样既走了域名(SNI 正确),又不依赖内网 DNS 能否解析到内网地址。

至于证书校验,脚本里关掉了。ESXi 6.7 自带的 CA bundle 不含 Let’s Encrypt 的根证书,验不过。考虑到是同一个交换机下的内网直连,而且 webhook_id 本身就是凭证,这个取舍可以接受。


五、采集脚本

ESXi 上没有curl,也没有base64,但自带 Python 3.5,urllib 够用了。

/vmfs/volumes/datastore1/scripts/esxi_cputemp.py

#!/bin/python3# -*- coding: utf-8 -*-importjsonimportsslimportsubprocessimporturllib.request HA_WEBHOOK="https://ha.example.com/api/webhook/你的webhook_id"VSISH="/bin/vsish"TIMEOUT=10SSL_CTX=ssl._create_unverified_context()defread_msr(addr):"""读 pcpu0 的指定 MSR。vsish 输出形如 0x883a0000。"""out=subprocess.check_output([VSISH,"-e","get","/hardware/msr/pcpu/0/addr/"+addr])returnint(out.decode().strip(),16)defmain():tjmax=(read_msr("0x1a2")>>16)&0xFFraw=read_msr("0x1b1")temp_c=tjmax-((raw>>16)&0x7F)payload=json.dumps({"temp_c":temp_c,"tjmax":tjmax,"raw":hex(raw),}).encode("utf-8")req=urllib.request.Request(HA_WEBHOOK,data=payload,headers={"Content-Type":"application/json"})urllib.request.urlopen(req,timeout=TIMEOUT,context=SSL_CTX).read()if__name__=="__main__":main()

脚本放在 datastore 上(/vmfs/volumes/datastore1/),那是 VMFS,重启不会丢。权限给 700。

cron 条目写进/var/spool/cron/crontabs/root

* * * * * /bin/python3 /vmfs/volumes/datastore1/scripts/esxi_cputemp.py >/dev/null 2>&1

六、让配置扛住重启

这是 ESXi 特有的麻烦:crontab 和/etc/hosts在重启后会被重置。要靠/etc/rc.local.d/local.sh在开机时重建。

编辑local.sh,在末尾的exit 0之前插入:

grep-q"ha.example.com"/etc/hosts||echo"192.168.1.20 ha.example.com">>/etc/hostsgrep-qesxi_cputemp /var/spool/cron/crontabs/root||echo"* * * * * /bin/python3 /vmfs/volumes/datastore1/scripts/esxi_cputemp.py >/dev/null 2>&1">>/var/spool/cron/crontabs/root

改完用sh -n /etc/rc.local.d/local.sh验证语法,这是开机脚本,写坏了影响启动。

不需要重启 crond:busybox 的 crond 每分钟会检查 crontab 文件的 mtime,有变化会自动重新加载。

还有最后一步容易漏:local.sh/etc/hosts这些改动要写进 bootbank 才算真正持久化。ESXi 自带的 cron 里有一条1 * * * * /sbin/auto-backup.sh,每小时会做一次。如果你改完就打算重启 ESXi,先手动跑一次/sbin/auto-backup.sh,否则改动会丢。


七、验证

ESXi 侧手动跑一次,正常情况下无输出、退出码 0:

python3 /vmfs/volumes/datastore1/scripts/esxi_cputemp.pyecho$?

HA 侧查实体:

curl-s-H"Authorization: Bearer$SUPERVISOR_TOKEN"\http://supervisor/core/api/states/sensor.esxi_cpu_temp

返回:

{"entity_id":"sensor.esxi_cpu_temp","state":"43.0","attributes":{"state_class":"measurement","tjmax":100,"raw_msr":"0x88390000","unit_of_measurement":"°C","device_class":"temperature","friendly_name":"ESXi CPU 温度"},"last_updated":"2026-07-30T15:17:00.376483+00:00"}

验收看三点:state是合理温度、last_updated在一分钟以内、多查几次raw_msr会变(证明是新数据不是缓存)。


八、这个方案的局限

ESXi 宕机时,实体会一直保持最后一个温度值,不会变成 unavailable。

trigger-based template sensor 没有 TTL 机制,收不到新数据就一直显示旧值。也就是说,如果 ESXi 挂了,你在 HA 里看到的还是它挂之前那个温度,看起来一切正常。

要做"数据过期"检测,得再加一个基于last_updated的 binary_sensor,配合一个心跳实体(比如time_date集成提供的sensor.time)来触发重新计算。我暂时没做,先记在这里。


小结

几个可以直接拿走的结论:

  1. 消费级主板跑 ESXi,CPU 温度能读(走 MSR),风扇转速读不到,别在后者上浪费时间。
  2. 读温度只用 package 的0x1b1,单核的0x19c在核心睡眠时会给假值。
  3. ESXi 防火墙默认 DROP 出站,8123 这类非标端口出不去;别去加自定义防火墙 XML,重启就没了,走现成放行的 443 更省事。
  4. nginx 按 SNI 分流,所以要用域名 +/etc/hosts静态映射,不能用 IP 直连。
  5. ESXi 上没有 curl 和 base64,但有 Python 3.5。
  6. crontab 和/etc/hosts重启会丢,要靠local.sh重建,再靠auto-backup.sh落盘。

整套跑下来,HA 里就有了一条每分钟更新的温度曲线,还能进长期统计看趋势。对于家里放着的这种"没有带外管理"的机器,算是补上了一块比较重要的可观测性。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/1 22:07:17

4英寸电子墨水屏驱动全解析:从树莓派到STM32的低功耗显示方案

1. 从一块“会变”的屏幕说起&#xff1a;4英寸电子墨水屏的独特魅力如果你玩过树莓派、Arduino或者STM32&#xff0c;肯定对点亮一块LCD或者OLED屏幕不陌生。那种色彩鲜艳、响应迅速的显示效果&#xff0c;确实很酷。但今天我想聊点不一样的——一块4英寸的电子墨水屏&#xf…

作者头像 李华
网站建设 2026/8/1 22:03:37

从训练到部署:FfDL与Seldon集成实现ONNX模型的端到端流程

从训练到部署&#xff1a;FfDL与Seldon集成实现ONNX模型的端到端流程 【免费下载链接】FfDL Fabric for Deep Learning (FfDL, pronounced fiddle) is a Deep Learning Platform offering TensorFlow, Caffe, PyTorch etc. as a Service on Kubernetes 项目地址: https://git…

作者头像 李华
网站建设 2026/8/1 22:02:44

2026年程序员就业:为什么AI工具用得好,offer反而更难拿?

聊《别急着重做程序员就业&#xff0c;先看岗位到底在筛什么》之前&#xff0c;先说一句实在的&#xff1a;别急着背概念&#xff0c;先看它在真实项目里到底解决什么问题。摘要去年我面试了一个候选人&#xff0c;简历上写着"熟练使用Claude Code、Codex&#xff0c;独立…

作者头像 李华
网站建设 2026/8/1 21:59:09

Gripper-B自适应机械手:从设计到实现的刚柔并济与感知先行

1. 项目概述&#xff1a;从“抓手”到“Gripper-B”的进化之路在自动化与机器人技术日新月异的今天&#xff0c;末端执行器——也就是我们常说的“机械手”或“抓手”——扮演着至关重要的角色。它就像人的手&#xff0c;是机器人与物理世界交互的直接接口。一个抓手的性能&…

作者头像 李华
网站建设 2026/8/1 21:53:52

Muya Markdown编辑器:未来网页应用开发的终极选择

Muya Markdown编辑器&#xff1a;未来网页应用开发的终极选择 【免费下载链接】muya &#x1f4c4; Future markdown editor for web browser applications development 项目地址: https://gitcode.com/gh_mirrors/mu/muya Muya Markdown编辑器是一款面向网页应用开发的…

作者头像 李华