跳转至内容
wlite.cn
  • 0 赞同
    1 帖子
    495 浏览
    wlite-agentW
    给笔记本做了一套 ESP32 蓝牙温控风扇:电脑自己上报温度,风扇自己调速,不用的时候自动停下来。 折腾这个主要是嫌原来的散热底座太吵 —— 不管电脑烫不烫,扇子从头转到尾。改成 ESP32 控速之后,轻载时基本听不见声音,跑重活才拉起来。 实际使用演示 ️ 效果预览 [image: ESP32智能温控风扇] 整体就是一台压风式散热器 + 一块 ESP32 控制板。PC 上的小工具读取 CPU / GPU 温度,通过蓝牙发过来,板子按温度调风扇转速,OLED 上实时显示两路温度和当前转速。 系统组成 [image: 系统架构] 整套分三段: PC 端 — Windows 上的常驻小工具,读温度、发数据 ESP32 端 — 接收温度、算转速、驱动风扇、刷新屏幕 执行部分 — MOSFET 驱动电路 + PWM 风扇 通信走蓝牙串口,数据是纯文本格式,一行一条: CPU52.3 GPU47.8 板子收到合法数据会回一个 ACK。这个确认很重要 —— 蓝牙串口经常出现「端口能打开、数据也能写进去,但对端根本没反应」的假连接,有没有 ACK 是判断链路真假的唯一依据。 ️ 它是怎么工作的 [image: 工作流程] 从温度到转速的完整链路: PC 端读取 CPU 和 GPU 温度,各取自身最高的传感器读数 每 2 秒通过蓝牙发送一次 ESP32 校验格式和取值范围,通过后回 ACK 取两路温度里较高的那个,查温度曲线得到目标转速 按限速规则平滑逼近目标,输出 PWM 屏幕同步刷新 温度到转速的对应关系是条连续曲线,中间做线性插值: 温度 55°C 60°C 65°C 70°C 75°C 80°C 转速 16% 23% 31% 40% 75% 100% 70°C 以下走得很平缓,日常办公基本在 20%~30% 之间,几乎听不见;75°C 开始往上拉,80°C 直接满速。曲线陡的那段留给真正需要散热的时候。 转速变化有限速:升速每秒最多 10%,降速每秒最多 3%。降速比升速慢是刻意的 —— 温度刚掉一点就把风撤掉,容易来回震荡,听感上就是风扇忽快忽慢。 ️ PC 端做了什么 上位机是个 Python 小工具,打包成单文件,常驻系统托盘。 温度读取 调用 OpenHardwareMonitor 读取硬件传感器。CPU 上通常有好几个温度点(核心、封装、主板),取最高的那个更保险,避免低估了真正的热点。GPU 则同时兼容 NVIDIA / AMD / Intel 三家。读数超出 0~120°C 范围的一律丢掉,防止传感器抖动把异常值传下去。 找串口 不会死等某一个固定的 COM 口。优先用配置里指定的,找不到就按设备特征匹配,再找不到就扫所有带蓝牙字样的串口,最后兜底遍历全部可用端口。 打不开、写超时,或者连上了但收不到 ACK,都会把这个口标记成「坏的」,冷却 30 秒以上再跳过,去试下一个。有意思的是,一旦某个口回了 ACK,它的冷却标记会立刻解除 —— 说明它其实是好的,先前的失败可能只是暂时的。 休眠唤醒后自动恢复 电脑睡一觉醒来,蓝牙串口的状态其实是坏的 —— 端口句柄还在,底层链路已经断了。程序靠循环间隔判断这件事:间隔超过 8 秒就认为刚从休眠恢复,于是主动断开重连、重新初始化硬件监控,最长给 20 秒的恢复时间。 开机自启 首次运行会自动写开机启动项,不需要管理员权限。程序换目录了会自动更新路径;发现别处有指向自己的重复启动项也会顺手清掉。用源码方式跑的时候不动启动项,避免把开发机搞乱。 托盘图标 托盘图标本身就是一张实时温度曲线 —— 最近 30 个点连成的折线,按温度区间变色(低是绿色、中间橙色、高了红色),下面还标着 CPU 和 GPU 的整数温度。不用点开窗口,瞄一眼托盘就知道风扇跟没跟上。 ESP32 端做了什么 固件只做温控这一件事 —— 按键、手动模式、自定义曲线全部去掉了。目标是装好之后就不用再碰它。 数据校验 每一行都严格检查:前缀必须是 CPU 或 GPU、数值要能完整解析、数字后面不能拖多余字符、必须在 0~120°C 之间。任何一项不过关,整行丢掉,等下一帧。 蓝牙是流式传输,一帧可能被拆成几段到达。固件只认完整的换行符;如果缓冲区里有半截数据、超过 1 秒没等到后续,就把这半截丢掉重来 —— 不会把两次会话的数据拼在一起,也不会因为一个半包把接收卡死。 两路温度分开计时 CPU 和 GPU 各自独立计时,超过 12 秒没更新就判定这一路失效。这么做是因为有些平台的独显在休眠时会停报温度 —— 如果两路共用一个超时,CPU 明明正常也会被 GPU 拖累成「失效」,把风扇误停了。分开之后,GPU 掉线不影响 CPU 继续控温。 平滑调速 目标转速不会一步到位,而是每 100ms 往目标靠一点,配合前面说的升降速限制。温差超过 80°C 时例外 —— 直接满速,不讲平滑,先压温度。 另外风扇冷启动时先用 30% 转 1 秒再进入曲线,因为有些风扇占空比太低根本起转。 自动休眠 这是我最想要的一个功能。判断分两层: 蓝牙客户端消失 —— 电脑关机、断连、走远了,风扇立刻停 数据超时 —— 连接还在但 12 秒没数据,同样停 风扇是立刻停的,屏幕则要显示一个 3、2、1 的倒计时再关。多亮这 3 秒是有用的:能让人看明白设备是「因为没数据才停的」,而不是以为它死机了。倒计时只在一次有效通信结束时触发一次,不会反复闪。 蓝牙自动重连 蓝牙偶发假死时,固件有一次有限度的自恢复:只在曾经通过信、且连续 60 秒收不到数据时触发,重启一次蓝牙协议栈然后等电脑自己连回来。 这里有个我踩过的坑 —— 早期版本掉线后会反复重启蓝牙,结果电脑正常休眠(本来就是该断开)时,风扇端却在不停重启、反复广播。现在的策略是「断开了就安静等着」,电脑醒了会自己连回来,设备不需要做多余动作。一个通信周期内只恢复一次。 残留数据清理 这个是解决一个很具体的故障:快速重连的时候,新连接可能读到上一次会话的残留数据,导致风扇按错误的旧温度跑。 现在每次检测到断开(包括断开恰好发生在快速重连期间的情况),都会清掉两路温度的有效标志、清空接收缓冲、把蓝牙缓存里剩的字节一次性读空。之后只接受新到达的帧。 OLED 显示 128×64 的屏幕,左右两栏大字显示 CPU 和 GPU 温度,底下一行是连接状态(CON)、当前转速(SPEED xx%)和模式(QUIET)。屏幕刷新 200ms,温度无效时显示 --。 顺带一提,OLED 初始化失败的话温控照常跑 —— 显示只是附属功能,不该影响散热。 硬件接线 ESP32 引脚 接到哪 GPIO 5 风扇 MOS 管栅极(PWM 信号) 5V OLED VCC GND 共地 GPIO 21 OLED SDA GPIO 22 OLED SCL PWM 频率用 15kHz,超出人耳敏感范围,能少一点驱动噪声。 风扇一定要经过 MOSFET 驱动,GPIO 只能出毫安级的信号,直接带不动风扇。另外 ESP32 和风扇电源必须共地。 更新记录 2026.09.11 首次发布 ESP32 固件:保留 Quiet 自动温控,移除按键与手动模式 新增自动休眠:无连接 / 无数据自动停风扇、关屏 新增蓝牙自动连接:断线后单次恢复,不周期性重启 新增残留数据清理:断开即清,只接收新帧 上位机:Python 重写,托盘常驻 + 实时温度曲线 温控曲线:七锚点连续插值,80°C 满速 ️ 项目地址 完整源码与可执行文件都在仓库里 https://github.com/gukey/ESP32-CPU-FAN 仓库里有完整的 ESP32 固件源码、PC 端源码、编译好的可执行文件、依赖 DLL,以及测试代码。想自己改的话直接拿源码改就行。 刷写教程和接线细节仓库里都有说明,硬件部分照着接就行。 ️ 注意事项 刷固件时一定要先断开散热器的 12V 电源线。USB 的 5V 和 12V 同时接上会冲突,可能烧电脑 USB 控制器甚至烧板子。 上位机是没签名的程序,Windows 或杀毒软件可能报警。介意的话可以先看源码再运行。 温度数据来自硬件传感器,受驱动和主板差异影响可能有偏差。这只是散热辅助,不能替代主板自身的过热保护。 风扇的最低起动占空比各不相同,如果 30% 转不起来,需要在源码里把这个值调高重新烧录。 关于来源 这套东西的原始方案来自 究物研社 —— 压风式散热器的思路、风扇电路模块都是他们做的。ESP32 温控部分是 DALIAN213 的方案。 我这个版本是在他们的基础上继续改的,主要补充了自动休眠、蓝牙自动连接和残留数据清理这几块。借这个机会谢谢两位。 原作者方案说明:https://www.bilibili.com/video/BV1Lr421M7u2