当然!这个 fnOS 风扇温控的实现从底层到上层分以下几个层次:
🧱 完整架构一览
**─────────────────────────────────────**
** Docker: fnos-fan-webui (端口 8080) ** ← Web UI 面板
** Python http.server **
**─────────────────────────────────────**
** sysfs 接口 ** ← 内核暴露的硬件接口
** /sys/class/hwmon/hwmon3/ **
**─────────────────────────────────────**
** 内核模块 qnap8528.ko ** ← 底层驱动
** (控制 ITE8528E EC 芯片) **
**─────────────────────────────────────**
** 硬件: iEi SA145 (QNAP QU-605) **
** ITE8528E EC @ ports 0x6c/0x68 **
** 2x 9cm 风扇 **
**─────────────────────────────────────**
1️⃣ 底层:内核模块 qnap8528.ko
因为直接通过 /dev/port 写 EC 寄存器只能微调 ~300 RPM,效果很差。所以编译了一个内核模块 qnap8528.ko,它通过 ITE8528E EC 芯片暴露标准的 hwmon sysfs
接口,让上层可以像控制普通风扇一样读写:
| sysfs 路径 |
作用 |
/sys/class/hwmon/hwmon3/pwm1 |
PWM 值 (0~255) |
/sys/class/hwmon/hwmon3/fan1_input |
风扇原始计数值 |
/sys/class/thermal/thermal_zone0/temp |
CPU 温度/1000 |
RPM 换算公式: RPM = 3932160 / fan1_input
源码在 /root/qnap8528/,系统升级内核后需要重新编译。
2️⃣ 中间层:Docker 容器 fnos-fan-webui
关键启动参数(踩过坑的教训 ⚠️):
docker run -d --name=fnos-fan-webui --restart=unless-stopped \
--privileged \
-v /sys/class/hwmon:/sys/class/hwmon:rw \
-v /sys/class/thermal:/sys/class/thermal:ro \
-v /root/fnan-webui/data:/data \
-p 8080:8080 fnos-fan-webui
⚠️ 关键坑: 一开始没加 --privileged 而且 sysfs 挂载为 :ro,导致所有 PWM 写入静默失败,还以为在正常工作。最终方案是 --privileged + :rw
才能正常写入硬件。
3️⃣ 上层:Python Web UI
代码在 /root/fnan-webui/fan_webui.py,提供:
- 实时监控: CPU 温度、PWM、RPM
- 温控曲线: 拖拽式温度-PWM 曲线,持久化到
/data/curve-config.json
- 手动模式: 滑条调 PWM → 点 「✅ 确认应用」 按钮才生效(防止误操作)
- 自动/手动切换
API:
| 端点 |
功能 |
GET /api/status |
温度/PWM/RPM/模式/曲线 |
POST /api/set-pwm-pending |
暂存手动 PWM |
POST /api/apply |
确认应用到硬件 |
POST /api/curve |
更新温控曲线 |
4️⃣ Web UI 界面效果
我买的是qu605,我的方法的比较简单,也可以完美适配fnos。
1,Bios里面禁用emmc,将飞牛os刷到m2固态里面,这样在建立存储池的时候也不会识别到emmc导致误删。
2,关于风扇问题,我交给了ai帮我处理,我开了账户ssh,并把账户和密码都交给了他,然后他就在docker里面帮我部署,自动在社区里面参考别人的方法然后进行编译,最后就可以了。再次感受到ai的方便。
3,