- 1. 环境说明
- 2. 为什么原来的电源检测集成会失效
- 3. 在HAOS中安装Mosquitto broker
- 3.1 创建MQTT登录账号
- 3.2 添加MQTT集成
- 3.3 应用安装时Docker Hub超时
- 4. 在Debian宿主机安装MQTT客户端
- 5. 测试MQTT账号和消息收发
- 6. 检查树莓派电源和温度命令
- 7. 保存MQTT连接信息
- 8. 创建树莓派状态上报脚本
- 9. 手动运行测试
- 10. 在Home Assistant中查看设备
- 11. 创建systemd自动上报服务
- 12. 检查定时器状态
- 13. 创建欠压通知
- 14. 几个踩坑记录
- 14.1 Connection Refused: not authorised
- 14.2 DEVICE_JSON: unbound variable
- 14.3 service显示inactive或dead
- 14.4 实体显示不可用
- 14.5 CPU温度五十多度正常吗
- 15. 常用管理命令
- 16. 总结
前面把树莓派5上的 Home Assistant OS 改成了 KVM 虚拟机运行,HAOS、Supervisor 和应用商店都可以正常使用了。可以参考:https://www.machunjie.com/linux/2189.html
不过迁移完成后,我发现原来自动添加的 Raspberry Pi Power Supply Checker 集成失效了,后台提示:
|
1 |
设置失败: Under-voltage monitoring is not supported on this device. |
这个提示其实是正常的。
因为现在的结构已经变成:
|
1 2 3 4 |
树莓派5物理机 └── Debian 13宿主机 └── KVM虚拟机 └── Home Assistant OS |
HAOS 看到的是 QEMU/KVM 提供的通用 ARM 虚拟硬件,无法直接读取树莓派宿主机的固件状态,所以也就无法检测真实的欠压、节流和温度。
最后采用的办法是:
|
1 2 3 4 5 6 7 8 9 10 11 12 |
Debian宿主机 │ ├── vcgencmd读取欠压、节流和CPU温度 │ ▼ MQTT │ ▼ HAOS中的Mosquitto broker │ ▼ Home Assistant自动创建设备和实体 |
这样 Home Assistant 虽然运行在虚拟机里,仍然可以看到物理树莓派5的真实电源和温度状态。
这里把完整配置过程记录一下~
1. 环境说明
我这里的环境如下:
|
1 2 3 4 5 6 7 8 |
设备:Raspberry Pi 5 宿主系统:Debian 13 Trixie ARM64 Debian地址:192.168.110.48 虚拟化:KVM / QEMU / libvirt HAOS地址:192.168.110.28 MQTT Broker:Mosquitto broker MQTT端口:1883 MQTT用户名:rpi_mqtt |
其中 Mosquitto broker 运行在 HAOS 中,宿主机每分钟读取一次状态并通过 MQTT 上报。
2. 为什么原来的电源检测集成会失效
Raspberry Pi Power Supply Checker 只能检查 Home Assistant 当前运行设备的树莓派固件状态。
以前 HAOS 直接安装在树莓派上时,可以访问底层的欠压接口;改成虚拟机以后,HAOS 只能看到虚拟 CPU、虚拟硬盘和 VirtIO 网卡,无法再访问物理树莓派的固件接口。
所以会出现:
|
1 |
Under-voltage monitoring is not supported on this device. |
这个集成可以直接删除,不会影响 Home Assistant 的其他功能。
真正的树莓派状态应该在 Debian 宿主机中读取:
|
1 2 |
vcgencmd get_throttled vcgencmd measure_temp |
3. 在HAOS中安装Mosquitto broker
进入 Home Assistant:
|
1 2 3 4 |
设置 → 应用 → 安装应用 → 搜索 Mosquitto broker |
安装完成后,打开:
|
1 2 |
开机启动 自动恢复 |
新版界面中的“自动恢复”,就是以前的 Watchdog,也就是应用异常退出后自动重启。
然后点击“启动”。
3.1 创建MQTT登录账号
打开:
|
1 2 3 4 |
Mosquitto broker → 配置 → Logins → 添加 |
填写:
|
1 2 3 |
用户名:rpi_mqtt 密码:设置一个独立密码 Password pre-hashed:关闭 |
保存后重启 Mosquitto broker。
不要使用下面两个用户名:
|
1 2 |
homeassistant addons |
它们是 Home Assistant 内部保留账号。
3.2 添加MQTT集成
进入:
|
1 2 3 4 |
设置 → 设备与服务 → 添加集成 → MQTT |
通常安装 Mosquitto broker 后会自动发现,直接点击配置即可。
如果需要手动填写:
|
1 2 3 4 |
Broker:192.168.110.28 端口:1883 用户名:rpi_mqtt 密码:刚才设置的密码 |
3.3 应用安装时Docker Hub超时
我第一次安装 Mosquitto 时还遇到了:
|
1 2 3 |
failed to resolve reference registry-1.docker.io i/o timeout |
最后确认是 HAOS 无法直连 Docker Hub。
我这里临时把 HAOS 的网关和 DNS 指向运行 Surge 的 Mac,让 HAOS 通过 Surge 增强模式访问 Docker Hub,Mosquitto 就可以正常安装了。
HAOS 后台可以直接在:
|
1 2 3 |
设置 → 系统 → 网络 |
修改静态 IP、网关和 DNS,不一定非要在命令行中设置。
只要下面的测试能够快速返回 401 Unauthorized,就说明 Docker Registry 已经可以访问:
|
1 2 |
curl -4 -I --connect-timeout 15 \ https://registry-1.docker.io/v2/ |
4. 在Debian宿主机安装MQTT客户端
下面的命令全部在 Debian 宿主机执行,不是在 HAOS 控制台执行。
安装客户端:
|
1 2 |
sudo apt update sudo apt install -y mosquitto-clients |
检查命令:
|
1 2 |
command -v mosquitto_pub command -v mosquitto_sub |
正常应该显示:
|
1 2 |
/usr/bin/mosquitto_pub /usr/bin/mosquitto_sub |
5. 测试MQTT账号和消息收发
先在 Debian 宿主机执行下面这组测试:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
read -rsp "MQTT密码: " MQTT_PASS echo timeout 10 mosquitto_sub \ -h 192.168.110.28 \ -p 1883 \ -u rpi_mqtt \ -P "$MQTT_PASS" \ -t 'rpi5/test/#' \ -C 1 \ -v & SUB_PID=$! sleep 1 mosquitto_pub \ -h 192.168.110.28 \ -p 1883 \ -u rpi_mqtt \ -P "$MQTT_PASS" \ -t 'rpi5/test/hello' \ -m 'MQTT OK' wait "$SUB_PID" unset MQTT_PASS |
正常应该输出:
|
1 |
rpi5/test/hello MQTT OK |
如果出现:
|
1 |
Connection Refused: not authorised |
说明网络和端口已经正常,只是用户名或密码不正确。检查 Mosquitto 的 Logins 配置,保存后记得重启应用。
6. 检查树莓派电源和温度命令
在 Debian 宿主机执行:
|
1 2 3 |
command -v vcgencmd vcgencmd get_throttled vcgencmd measure_temp |
我这里输出:
|
1 2 3 |
/usr/bin/vcgencmd throttled=0x0 temp=53.8'C |
throttled=0x0 表示当前和本次开机以来都没有检测到欠压或节流。
常用状态位:
|
1 2 3 4 |
0x1 当前欠压 0x4 当前发生性能节流 0x10000 本次开机后曾经欠压 0x40000 本次开机后曾经发生性能节流 |
7. 保存MQTT连接信息
创建配置文件:
|
1 2 3 4 5 6 |
sudo tee /etc/rpi5-mqtt.conf >/dev/null <<'EOF' MQTT_HOST='192.168.110.28' MQTT_PORT='1883' MQTT_USER='rpi_mqtt' MQTT_PASSWORD='替换成你的MQTT密码' EOF |
设置权限:
|
1 2 |
sudo chown root:root /etc/rpi5-mqtt.conf sudo chmod 600 /etc/rpi5-mqtt.conf |
8. 创建树莓派状态上报脚本
创建脚本:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 |
sudo tee /usr/local/sbin/rpi5-ha-mqtt >/dev/null <<'SCRIPT' #!/usr/bin/env bash set -euo pipefail CONFIG_FILE="/etc/rpi5-mqtt.conf" STATE_TOPIC="rpi5_host/status" if [[ ! -r "$CONFIG_FILE" ]]; then echo "无法读取 $CONFIG_FILE" >&2 exit 1 fi source "$CONFIG_FILE" VCGENCMD="$(command -v vcgencmd || true)" MOSQUITTO_PUB="$(command -v mosquitto_pub || true)" if [[ -z "$VCGENCMD" ]]; then echo "找不到 vcgencmd" >&2 exit 1 fi if [[ -z "$MOSQUITTO_PUB" ]]; then echo "找不到 mosquitto_pub,请安装 mosquitto-clients" >&2 exit 1 fi PUB=( "$MOSQUITTO_PUB" -h "$MQTT_HOST" -p "${MQTT_PORT:-1883}" -u "$MQTT_USER" -P "$MQTT_PASSWORD" ) publish_config() { local component="$1" local object_id="$2" local payload="$3" "${PUB[@]}" \ -r \ -t "homeassistant/${component}/rpi5_host/${object_id}/config" \ -m "$payload" } RAW="$("$VCGENCMD" get_throttled)" HEX="${RAW#throttled=}" VALUE=$((HEX)) flag_state() { local mask="$1" if (( VALUE & mask )); then printf 'ON' else printf 'OFF' fi } UNDER_VOLTAGE="$(flag_state 0x1)" THROTTLED_NOW="$(flag_state 0x4)" UNDER_VOLTAGE_OCCURRED="$(flag_state 0x10000)" THROTTLED_OCCURRED="$(flag_state 0x40000)" TEMP_RAW="$("$VCGENCMD" measure_temp 2>/dev/null || true)" TEMP="$( printf '%s\n' "$TEMP_RAW" | sed -n "s/^temp=\([0-9.]*\).*/\1/p" )" if [[ -z "$TEMP" && -r /sys/class/thermal/thermal_zone0/temp ]]; then TEMP="$( awk '{printf "%.1f", $1 / 1000}' \ /sys/class/thermal/thermal_zone0/temp )" fi if [[ -n "$TEMP" ]]; then TEMP_JSON="$TEMP" else TEMP_JSON="null" fi DEVICE_JSON='"device":{ "identifiers":["rpi5_host"], "name":"Raspberry Pi 5 宿主机", "manufacturer":"Raspberry Pi", "model":"Raspberry Pi 5" }' publish_config \ "binary_sensor" \ "under_voltage" \ "{ \"name\":\"当前欠压\", \"unique_id\":\"rpi5_host_under_voltage\", \"state_topic\":\"$STATE_TOPIC\", \"value_template\":\"{{ value_json.under_voltage }}\", \"payload_on\":\"ON\", \"payload_off\":\"OFF\", \"device_class\":\"problem\", \"entity_category\":\"diagnostic\", \"expire_after\":180, $DEVICE_JSON }" publish_config \ "binary_sensor" \ "under_voltage_occurred" \ "{ \"name\":\"本次启动曾欠压\", \"unique_id\":\"rpi5_host_under_voltage_occurred\", \"state_topic\":\"$STATE_TOPIC\", \"value_template\":\"{{ value_json.under_voltage_occurred }}\", \"payload_on\":\"ON\", \"payload_off\":\"OFF\", \"device_class\":\"problem\", \"entity_category\":\"diagnostic\", \"expire_after\":180, $DEVICE_JSON }" publish_config \ "binary_sensor" \ "throttled_now" \ "{ \"name\":\"当前性能节流\", \"unique_id\":\"rpi5_host_throttled_now\", \"state_topic\":\"$STATE_TOPIC\", \"value_template\":\"{{ value_json.throttled_now }}\", \"payload_on\":\"ON\", \"payload_off\":\"OFF\", \"device_class\":\"problem\", \"entity_category\":\"diagnostic\", \"expire_after\":180, $DEVICE_JSON }" publish_config \ "binary_sensor" \ "throttled_occurred" \ "{ \"name\":\"本次启动曾节流\", \"unique_id\":\"rpi5_host_throttled_occurred\", \"state_topic\":\"$STATE_TOPIC\", \"value_template\":\"{{ value_json.throttled_occurred }}\", \"payload_on\":\"ON\", \"payload_off\":\"OFF\", \"device_class\":\"problem\", \"entity_category\":\"diagnostic\", \"expire_after\":180, $DEVICE_JSON }" publish_config \ "sensor" \ "cpu_temperature" \ "{ \"name\":\"CPU温度\", \"unique_id\":\"rpi5_host_cpu_temperature\", \"state_topic\":\"$STATE_TOPIC\", \"value_template\":\"{{ value_json.cpu_temperature }}\", \"device_class\":\"temperature\", \"state_class\":\"measurement\", \"unit_of_measurement\":\"°C\", \"suggested_display_precision\":1, \"entity_category\":\"diagnostic\", \"expire_after\":180, $DEVICE_JSON }" publish_config \ "sensor" \ "throttled_code" \ "{ \"name\":\"电源节流状态码\", \"unique_id\":\"rpi5_host_throttled_code\", \"state_topic\":\"$STATE_TOPIC\", \"value_template\":\"{{ value_json.throttled_code }}\", \"icon\":\"mdi:code-braces\", \"entity_category\":\"diagnostic\", \"expire_after\":180, $DEVICE_JSON }" STATE="$( printf \ '{"throttled_code":"%s","under_voltage":"%s","under_voltage_occurred":"%s","throttled_now":"%s","throttled_occurred":"%s","cpu_temperature":%s}' \ "$HEX" \ "$UNDER_VOLTAGE" \ "$UNDER_VOLTAGE_OCCURRED" \ "$THROTTLED_NOW" \ "$THROTTLED_OCCURRED" \ "$TEMP_JSON" )" "${PUB[@]}" \ -t "$STATE_TOPIC" \ -m "$STATE" printf '%s\n' "$STATE" SCRIPT |
设置权限:
|
1 2 |
sudo chown root:root /usr/local/sbin/rpi5-ha-mqtt sudo chmod 750 /usr/local/sbin/rpi5-ha-mqtt |
检查脚本语法:
|
1 |
sudo bash -n /usr/local/sbin/rpi5-ha-mqtt |
没有输出就说明语法正常。
9. 手动运行测试
执行:
|
1 |
sudo /usr/local/sbin/rpi5-ha-mqtt |
我这里输出:
|
1 |
{"throttled_code":"0x0","under_voltage":"OFF","under_voltage_occurred":"OFF","throttled_now":"OFF","throttled_occurred":"OFF","cpu_temperature":53.8} |
其中:
|
1 2 3 |
OFF = 没有故障 ON = 检测到对应问题 0x0 = 本次开机没有检测到欠压和节流 |
脚本发布的 MQTT Discovery 配置会让 Home Assistant 自动创建设备和实体,不需要手工修改 configuration.yaml。
10. 在Home Assistant中查看设备
进入:
|
1 2 3 4 |
设置 → 设备与服务 → MQTT → 设备 |
应该出现:
|
1 |
Raspberry Pi 5 宿主机 |
设备中包含:
|
1 2 3 4 5 6 |
当前欠压 本次启动曾欠压 当前性能节流 本次启动曾节流 CPU温度 电源节流状态码 |
正常情况下:
|
1 2 3 4 5 |
当前欠压:关闭 本次启动曾欠压:关闭 当前性能节流:关闭 本次启动曾节流:关闭 电源节流状态码:0x0 |
这里的“关闭”表示没有检测到故障。
11. 创建systemd自动上报服务
创建 service:
|
1 2 3 4 5 6 7 8 9 10 |
sudo tee /etc/systemd/system/rpi5-ha-mqtt.service >/dev/null <<'EOF' [Unit] Description=Publish Raspberry Pi 5 diagnostics to Home Assistant Wants=network-online.target After=network-online.target [Service] Type=oneshot ExecStart=/usr/local/sbin/rpi5-ha-mqtt EOF |
创建 timer:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
sudo tee /etc/systemd/system/rpi5-ha-mqtt.timer >/dev/null <<'EOF' [Unit] Description=Publish Raspberry Pi 5 diagnostics every minute [Timer] OnBootSec=30s OnUnitActiveSec=60s AccuracySec=5s Persistent=true Unit=rpi5-ha-mqtt.service [Install] WantedBy=timers.target EOF |
重新加载并启动:
|
1 2 3 |
sudo systemctl daemon-reload sudo systemctl enable --now rpi5-ha-mqtt.timer sudo systemctl start rpi5-ha-mqtt.service |
12. 检查定时器状态
查看 timer:
|
1 2 |
systemctl status rpi5-ha-mqtt.timer --no-pager systemctl list-timers rpi5-ha-mqtt.timer |
正常应该看到:
|
1 2 |
Active: active (waiting) Trigger: 约60秒后 |
查看最近一次上报日志:
|
1 2 3 4 |
journalctl \ -u rpi5-ha-mqtt.service \ -n 30 \ --no-pager |
我这里输出:
|
1 2 3 4 |
Starting rpi5-ha-mqtt.service... {"throttled_code":"0x0","under_voltage":"OFF","under_voltage_occurred":"OFF","throttled_now":"OFF","throttled_occurred":"OFF","cpu_temperature":53.8} rpi5-ha-mqtt.service: Deactivated successfully. Finished rpi5-ha-mqtt.service. |
Deactivated successfully 是正常现象,因为这个服务使用的是 Type=oneshot,执行完成后就会退出。
真正需要确认的是:
|
1 2 |
timer:active (waiting) service:status=0/SUCCESS |
13. 创建欠压通知
进入 Home Assistant:
|
1 2 3 4 |
设置 → 自动化与场景 → 创建自动化 → 创建新的自动化 |
触发条件选择“状态”:
|
1 2 3 |
实体:当前欠压 从:关闭 到:开启 |
动作可以选择手机通知:
|
1 2 |
标题:树莓派电源异常 消息:树莓派5宿主机检测到当前欠压,请检查电源和供电线。 |
还可以针对“本次启动曾欠压”再创建一个告警。
这个实体表示从本次开机到现在是否曾经出现过欠压,一旦变成开启,通常会保持到宿主机下次重启。
14. 几个踩坑记录
14.1 Connection Refused: not authorised
如果 MQTT 测试出现:
|
1 |
Connection Refused: not authorised |
说明 Broker 地址和端口已经可以连接,只是认证失败。
检查:
|
1 2 3 |
Mosquitto broker → 配置 → Logins |
确认用户名和密码正确,保存后重启 Mosquitto。
14.2 DEVICE_JSON: unbound variable
我第一次创建脚本时,变量名写成了:
|
1 |
DEVICE= |
后面却引用成:
|
1 |
$DEVICE_JSON |
因为脚本启用了 set -u,所以直接报:
|
1 |
DEVICE_JSON: unbound variable |
修复方法:
|
1 2 |
sudo sed -i 's/^DEVICE=/DEVICE_JSON=/' \ /usr/local/sbin/rpi5-ha-mqtt |
然后检查:
|
1 |
sudo bash -n /usr/local/sbin/rpi5-ha-mqtt |
本文上面的完整脚本已经使用了正确的 DEVICE_JSON,不需要再修改。
14.3 service显示inactive或dead
如果执行:
|
1 |
systemctl status rpi5-ha-mqtt.service |
看到:
|
1 2 |
inactive (dead) Deactivated successfully |
不代表服务故障。
因为这是一次性任务,每次执行完就自动退出。真正负责每分钟重新触发它的是:
|
1 |
rpi5-ha-mqtt.timer |
14.4 实体显示不可用
脚本中的实体设置了:
|
1 |
"expire_after":180 |
如果超过3分钟没有收到新状态,Home Assistant 会把实体标记为不可用。
检查:
|
1 2 3 4 5 6 |
systemctl status rpi5-ha-mqtt.timer --no-pager journalctl \ -u rpi5-ha-mqtt.service \ -n 30 \ --no-pager |
还可以手动执行一次:
|
1 |
sudo /usr/local/sbin/rpi5-ha-mqtt |
14.5 CPU温度五十多度正常吗
我这里树莓派5同时运行 Debian、HAOS 虚拟机和其他服务,CPU 温度大约是:
|
1 |
53.8°C |
只要散热正常,并且没有出现节流状态,一般没有问题。
可以同时观察:
|
1 2 3 |
当前性能节流 本次启动曾节流 CPU温度 |
15. 常用管理命令
手动上报一次:
|
1 |
sudo /usr/local/sbin/rpi5-ha-mqtt |
查看定时器:
|
1 2 |
systemctl status rpi5-ha-mqtt.timer --no-pager systemctl list-timers rpi5-ha-mqtt.timer |
查看上报日志:
|
1 2 3 4 |
journalctl \ -u rpi5-ha-mqtt.service \ -n 30 \ --no-pager |
实时查看日志:
|
1 |
journalctl -fu rpi5-ha-mqtt.service |
停止自动上报:
|
1 |
sudo systemctl disable --now rpi5-ha-mqtt.timer |
重新启用:
|
1 |
sudo systemctl enable --now rpi5-ha-mqtt.timer |
修改 MQTT 密码:
|
1 |
sudo nano /etc/rpi5-mqtt.conf |
修改后测试:
|
1 |
sudo /usr/local/sbin/rpi5-ha-mqtt |
16. 总结
OK,到这里,虚拟机中的 Home Assistant 就可以监控物理树莓派5宿主机的真实电源和温度状态了。
最终结构:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
Debian宿主机 ├── vcgencmd读取硬件状态 ├── systemd timer每分钟执行 └── MQTT发布状态 │ ▼ HAOS虚拟机 ├── Mosquitto broker ├── MQTT Discovery └── Raspberry Pi 5 宿主机设备 ├── 当前欠压 ├── 本次启动曾欠压 ├── 当前性能节流 ├── 本次启动曾节流 ├── CPU温度 └── 电源节流状态码 |
相比原来的 Raspberry Pi Power Supply Checker,这种方法稍微复杂一些,但读取的是物理宿主机的真实状态,而且还可以继续扩展:
|
1 2 3 4 5 6 7 |
CPU负载 内存占用 NVME温度 磁盘剩余空间 风扇转速 虚拟机运行状态 宿主机在线状态 |
以后即使 Home Assistant 继续运行在虚拟机里,也可以通过 MQTT 把 Debian 宿主机中的各种状态统一送进 HA。
记录一下,给同样在树莓派5上使用 KVM 虚拟机运行 Home Assistant OS 的朋友做个参考~





最新评论
牛牛牛
同样
站长您好,亚马逊云咨询推广资源,望建立联系,可邮件,谢谢。
换友情链接吗?
看你的站做的挺不错的
恭喜!!太强了,硕博连读啊
雁过留毛,人过留名。
看不懂但大受震撼