『瀚思彼岸』» 智能家居技术论坛

标题: Linux系统下基于CPU核心温度的PWM温控散热风扇 [打印本页]

作者: inevitab    时间: 2024-5-16 09:01
标题: Linux系统下基于CPU核心温度的PWM温控散热风扇
买了个小主机,安装了PVE做all in one,目前虚拟了爱快,以后还打算虚拟HA和其他系统。
这个小主机有12V风扇接口,但没有温控。所以我要加一个温控风扇。
[attach]59126[/attach]
[attach]59134[/attach]


一般的外挂温控风扇都是用外部温度探头,将探头贴在机器里面某个地方,cpu热量从内部传导到外面需要一定的时间,这样会导致CPU的温度不能及时反映到探头上,风扇转速不能及时改变。

解决方案:
在Linux系统里用sensors软件读取CPU温度,再用PHP部署一个WEB服务将温度数据发布出去,ESP模块接收到温度数据后,动态调整CPU转速。

元件:
[attach]59127[/attach]

我是使用esp8285,但我建议你们使用esp32,因为pwm性能更好。
还有就是一个小巧的12v降到3.3v的降压模块,随便买一个就好。
全部成本不到10元。

成品:
[attach]59128[/attach]

电路:
风扇接12V电源,然后风扇的测速线接esp的GPIO13脚,pwm控制线接esp的GPIO04脚。

Linux系统里安装sensors软件:

  1. apt install sensors
复制代码


Linux系统里安装php软件:

  1. apt install php
复制代码


将以下代码保存成文件temp.php放到根目录/root:
  1. <?php
  2. // 执行 sensors 命令
  3. exec('sensors', $output, $return_var);

  4. if ($return_var === 0) {
  5.     $temperatures = []; // 存储温度数据的关联数组

  6.     // 遍历输出数组,查找 Package id 0 和 Core 温度值
  7.     foreach ($output as $line) {
  8.         if (preg_match('/(Package id 0|Core \d+):\s+\+(\d+\.\d+)°C/', $line, $matches)) {
  9.             $sensor_name = $matches[1];
  10.             $temperature = (float) $matches[2];
  11.             $temperatures[$sensor_name] = $temperature;
  12.         }
  13.     }

  14.     // 找出最高温度
  15.     $maxTemperature = max($temperatures);

  16.     // 输出JSON格式的温度数据
  17.     echo json_encode([
  18.         'temperatures' => $temperatures,
  19.         'max_temperature' => $maxTemperature
  20.     ]);
  21. } else {
  22.     echo json_encode(['error' => '执行 sensors 命令失败']);
  23. }
复制代码


创建一个php webserver服务:
创建文件 /etc/systemd/system/temp-server.service:
  1. [Unit]
  2. Description=Temp Server
  3. After=network.target

  4. [Service]
  5. Type=simple
  6. ExecStart=/usr/bin/php -S 0.0.0.0:8000 /root/temp.php
  7. Restart=always

  8. [Install]
  9. WantedBy=multi-user.target
复制代码


启用服务:

  1. systemctl daemon-reload
  2. systemctl start temp-server
复制代码


在另一台电脑浏览器试试访问:
http://你的linux主机ip:8000

如果这样显示就说明正确了:
[attach]59129[/attach]

ESP代码:

  1. substitutions:
  2.   device_name: "fan_pwm_01"
  3.   friendly_name: "Fan Pwm 01"

  4. esphome:
  5.   name: "${device_name}"
  6.   friendly_name: "${friendly_name}"
  7.   on_boot:
  8.     then:
  9.       - delay: 2s
  10.       - fan.turn_off:
  11.           id: ${device_name}_fan
  12.       - delay: 2s
  13.       - fan.turn_on:
  14.           id: ${device_name}_fan
  15.           speed: "100"
  16.       - delay: 2s
  17.       - fan.turn_on:
  18.           id: ${device_name}_fan
  19.           speed: "1"

  20. esp8266:
  21.   board: esp8285

  22. # Enable logging
  23. logger:

  24. # Enable Home Assistant API
  25. api:
  26.   encryption:
  27.     key: "xxxxxxxxxxx"

  28. ota:
  29.   password: "xxxxxxxxxxxxxx"

  30. wifi:
  31.   ssid: !secret wifi_ssid
  32.   password: !secret wifi_password

  33.   # Enable fallback hotspot (captive portal) in case wifi connection fails
  34.   ap:
  35.     ssid: "Fan-Pwm-01 Fallback Hotspot"
  36.     password: ""

  37. captive_portal:

  38. fan:
  39.   - platform: speed
  40.     id: "${device_name}_fan"
  41.     output: pwm_output
  42.     speed_count: 100
  43.     name: "${device_name} 开关"

  44. output:
  45.   - platform: esp8266_pwm
  46.     pin: GPIO04
  47.     frequency: 35000 Hz # 频率如果太低,我的风扇会吱吱响
  48.     id: pwm_output

  49. button:
  50.   - platform: restart
  51.     name: "${device_name} 重启"

  52. sensor:
  53.   - platform: wifi_signal
  54.     name: "WiFi Signal"
  55.     id: "sensor_wifi_signal"
  56.     force_update: True
  57.     update_interval: 5s

  58.   - platform: template
  59.     id: ${device_name}_sensor_fanspeed
  60.     icon: "mdi:fan"
  61.     name: "风扇速度"
  62.     lambda: |-
  63.       return id(${device_name}_fan).speed;
  64.     accuracy_decimals: 0
  65.     unit_of_measurement: "%"
  66.     update_interval: 1s

  67.   - platform: pulse_counter
  68.     id: sensor_pulse_counter
  69.     pin:
  70.       number: GPIO13
  71.       inverted: true
  72.       mode:
  73.         input: true
  74.         pullup: true
  75.     name: ${friendly_name} 风扇转速
  76.     unit_of_measurement: 'RPM'
  77.     filters:
  78.       - multiply: 0.5
  79.       - lambda: |-
  80.           if (x <= 5000) return x;
  81.           else return {};
  82.     count_mode:
  83.       rising_edge: INCREMENT
  84.       falling_edge: DISABLE
  85.     update_interval: 2s


  86. text_sensor:
  87.   - platform: template
  88.     name: "温度"
  89.     id: text_temp
  90.     update_interval: 2s

  91.   # 测试用的
  92.   - platform: template
  93.     name: "期望速度"
  94.     id: text_expected_speed
  95.     internal: True
  96.     update_interval: 2s

  97. http_request:
  98.   id: http_request_data
  99.   timeout: 10s

  100. interval:
  101.   - interval: 1s
  102.     then:
  103.       - http_request.get:
  104.           url: "http://192.168.3.11:8000/"
  105.           verify_ssl: false
  106.           on_response:
  107.             then:
  108.               - lambda: |-
  109.                   if( status_code == 200 ){
  110.                     json::parse_json(id(http_request_data).get_string(), [](JsonObject root) {
  111.                       float temp;
  112.                       int speed;

  113.                       temp = root["max_temperature"];

  114.                       if(temp>=50){
  115.                         speed = (temp - 50)/20*100;
  116.                       }else{
  117.                         speed = 1;
  118.                       }

  119.                       id(text_expected_speed).publish_state(to_string(speed) + "%");
  120.                       id(text_temp).publish_state(to_string(temp));

  121.                       auto call = id(${device_name}_fan).make_call();
  122.                       call.set_speed(speed);
  123.                       call.perform();
  124.                     });
  125.                   }else{
  126.                     auto call = id(${device_name}_fan).make_call();
  127.                     call.set_speed(50);
  128.                     call.perform();
  129.                     id(text_expected_speed).publish_state("temperature api error");
  130.                     id(text_temp).publish_state("temperature api error");
  131.                   }
复制代码
代码参(抄)考(袭)自:https://bbs.hassbian.com/thread-25335-1-3.html

记得修改里面的密码、Linux主机网址等。
设置是当温度小于50度时,风扇以1%固定速度运行,70度时全速运行,50-70之间线性增加速度。如果获取不到温度数据就以50%的速度运行。可自行修改上面的速度调整代码。

实测:
当Linux主机的温度是43度时:
[attach]59130[/attach]

风扇速度是1%:
[attach]59131[/attach]

当Linux主机的温度是57度时:
[attach]59132[/attach]

风扇速度是35%:
[attach]59133[/attach]

----------------------------------------

费了九牛二虎之力做好了温控风扇,然后发现我这台小机子就算CPU持续100%运行,温度也不是很高,不需要散热,白费力气了。

----------------------------------------

真人真事:
我在PDD某家店买的这台小主机,发现BIOS里显示的CPU温度不正确,CPU温度比室温还低,我向商家反映这个问题,商家热心地接受了我的意见,然后发布了新版本的BIOS升级文件————把BIOS里显示CPU温度的功能去掉了!
这台机子没有厂家名称、地址、电话,所以我也不知道是哪家出产的,只知道叫4网口N4120软路由。






作者: jjss520    时间: 2024-5-16 09:16
解决不了问题,就解决发现问题的
作者: 点来点去    时间: 2024-5-16 10:33
我的直接串联几个二极管降压,一直慢速转,没有噪音。
作者: bainiu    时间: 2024-5-16 11:11
PVE里可以安装mqtt,可直接将温度数据发送至mqtt服务器
作者: inevitab    时间: 2024-5-16 11:43
bainiu 发表于 2024-5-16 11:11
PVE里可以安装mqtt,可直接将温度数据发送至mqtt服务器

这样需要mqtt服务器中转数据,多了一份不稳定性,还是esp直接读取pve上的温度更好。
作者: leung    时间: 2024-5-16 18:19
Linux系统里安装sensors软件

Linux系统是指在PVE下安装?
作者: inevitab    时间: 2024-5-16 18:30
leung 发表于 2024-5-16 18:19
Linux系统是指在PVE下安装?

包括但不限于PVE,只要是debian、ubuntu等常见的linux系统都可以。
作者: leung    时间: 2024-5-16 20:33
inevitab 发表于 2024-5-16 18:30
包括但不限于PVE,只要是debian、ubuntu等常见的linux系统都可以。

我有个问题,怎么把网页显示温度数据转化为ha实体?
作者: inevitab    时间: 2024-5-16 21:26
leung 发表于 2024-5-16 20:33
我有个问题,怎么把网页显示温度数据转化为ha实体?

可以看代码,用esphome的http_request组件读取网上数据,然后赋值给text_sensor组件,自动就会在HA里显示成实体。
作者: zmqo1234    时间: 2024-6-2 14:06
黑群晖可以这样吗
作者: inevitab    时间: 2024-6-2 14:20
zmqo1234 发表于 2024-6-2 14:06
黑群晖可以这样吗

如果是在pve里安装黑群晖可以的
作者: zmqo1234    时间: 2024-6-2 14:23
inevitab 发表于 2024-6-2 14:20
如果是在pve里安装黑群晖可以的

黑裙物理机呢
作者: inevitab    时间: 2024-6-2 14:34
zmqo1234 发表于 2024-6-2 14:23
黑裙物理机呢

这个我不懂了,我没用过群晖




欢迎光临 『瀚思彼岸』» 智能家居技术论坛 (https://bbs.hassbian.com/) Powered by Discuz! X3.5