收起左侧

Linux 下基于硬盘温度的 NAS 风扇智能温控方案(ASRock B250M-HDV + nct6791)

4
回复
182
查看
[ 复制链接 ]

2

主题

4

回帖

0

牛值

江湖小虾

背景与需求

我有一台自组 NAS,配置大致是:

  • 主板**:ASRock B250M-HDV**
  • 硬盘**:目前 4 块 3.6TB 机械盘(后续计划扩展到 10 盘位)**
  • 系统**:Linux(带 **<span class="ne-text">systemd</span>,可用 <span class="ne-text">smartctl</span><span class="ne-text">sensors</span> 等工具)

关注点**:**

  • NAS 的主要热源在 硬盘**,CPU 负载较低且不易过热。**
  • **希望在 **操作系统层面 精细控制机箱风扇(硬盘风道风扇),而不是每次进 BIOS 调整。
  • 目标是:
    • **风扇转速 **跟随硬盘最高温度 自动变化;
    • **保持 **尽量安静 的前提下,确保硬盘温度在合理范围;
    • 支持硬盘扩容**(10 盘位),脚本不绑定具体盘数量;**
    • 有日志、有轮转**,行为可观测,不是黑盒;**
    • 开机自启**,挂了能自动重启;**
    • 不妨碍硬盘休眠**(5 分钟无访问自动进入 standby)。**

整体设计思路

设计原则

  • 控制对象**:机箱中负责硬盘风道的风扇(通过主板风扇控制芯片 nct6791 的 **<span class="ne-text">pwm4/pwm5</span> 控制)。

  • 温度指标**:**

    • 主指标:所有机械盘中的最高温度**(SMART 属性 194 Temperature_Celsius)。**
    • **次指标:**CPU 包温 只用于高温兜底。
  • 控制策略**:**

    • **每 **6 分钟(360 秒) 读取一次硬盘温度(配合硬盘 5 分钟休眠,确保盘有机会睡着);
    • 使用 <span class="ne-text">smartctl -n standby -A</span>不唤醒已休眠的硬盘
    • 根据最高盘温映射到几档 PWM 值(偏静音的分级策略);
    • CPU 温度超阈值时强制提高风扇转速;
    • 防止风扇频繁大幅度抖动,档位设计相对粗但稳定。
  • 其他要求**:**

    • 脚本输出 中文日志**;**
    • 日志文件 单个最大 10MB**,轮转时最多保留 10 个历史文件;**
    • 使用 <span class="ne-text">systemd</span> 实现 开机自启 + 异常自动重启

实战过程与关键步骤

一、确认主板与风扇控制芯片

查看主板信息:

sudo dmidecode -t baseboard

输出示例(关键部分):

Manufacturer: ASRock
Product Name: B250M-HDV

说明确认为 ASRock B250M-HDV 主板。

二、寻找硬件监控(hwmon)设备

先看系统中有哪些 hwmon 设备:

ls /sys/class/hwmon
for h in /sys/class/hwmon/hwmon*; do
  echo "=== $h ==="
  cat "$h/name" 2>/dev/null || true
  ls "$h"
  echo
done

初始只看到类似:

  • <span class="ne-text">hwmon0</span>: <span class="ne-text">nvme</span>(NVMe 硬盘温度)
  • <span class="ne-text">hwmon1</span>: <span class="ne-text">coretemp</span>(CPU 温度)

没有任何 <span class="ne-text">fanX_input</span> <span class="ne-text">pwmX</span>,说明风扇控制芯片还没被驱动识别。

三、加载 nct6791 风扇控制芯片驱动

检查已加载模块:

lsmod | egrep "nct|it8|w836|hwmon" || echo "no related modules"

若尚未加载,尝试:

modprobe nct6775 2>/dev/null || echo "nct6775 not available"
modprobe it87    2>/dev/null || echo "it87 not available"

**在这块主板上,实际加载成功的是 **<span class="ne-text">nct6791</span> 软硬件组合,加载后再次查看:

ls /sys/class/hwmon
for h in /sys/class/hwmon/hwmon*; do
  echo "=== $h ==="
  cat "$h/name" 2>/dev/null || true
  ls "$h"
  echo
done

这时多出一项:

=== /sys/class/hwmon/hwmon2 ===
nct6791
...
fan1_input fan2_input ... fan6_input
pwm1 pwm1_enable ...
pwm4 pwm4_enable ...
pwm5 pwm5_enable ...
...

说明主板风扇/电压/温度的监控和控制接口已经暴露出来。

**为了让驱动开机自动加载,可以写入 **<span class="ne-text">/etc/modules</span>

echo "nct6791" | sudo tee -a /etc/modules

(确认不重复即可。)

四、验证哪一路 PWM 控制哪只风扇

**进入对应 hwmon 目录(具体编号以实际为准,这里是 **<span class="ne-text">hwmon2</span>):

cd /sys/class/hwmon/hwmon2

查看当前 PWM 和风扇转速:

for x in pwm1 pwm2 pwm3 pwm4 pwm5 pwm6; do
  printf "%s: " "$x"; cat "$x" 2>/dev/null || echo "(不存在)";
  printf "%s_enable: " "$x"; cat "${x}_enable" 2>/dev/null || echo "(不存在)";
  echo;
done

for f in fan1_input fan2_input fan3_input fan4_input fan5_input fan6_input; do
  printf "%s: " "$f"; cat "$f" 2>/dev/null || echo "(不存在)";
done

示例输出(关键段):

pwm4: 76
pwm4_enable: 5

pwm5: 76
pwm5_enable: 5

fan4_input: 675
fan5_input: 683

**此时 **<span class="ne-text">pwm4/pwm5</span> 处于主板自动模式(enable=5),<span class="ne-text">fan4/fan5</span> 转速约 680 RPM。

实验验证**:将 **<span class="ne-text">pwm4/pwm5</span> 切换为手动并提高占空比(只往上调,避免停转):

cd /sys/class/hwmon/hwmon2

echo 1   > pwm4_enable
echo 1   > pwm5_enable
echo 160 > pwm4
echo 160 > pwm5

sleep 5

cat pwm4; cat pwm4_enable
cat pwm5; cat pwm5_enable
cat fan4_input; cat fan5_input

结果类似:

pwm4: 160
pwm4_enable: 1

pwm5: 160
pwm5_enable: 1

fan4_input: 1215
fan5_input: 1215

说明:

  • <span class="ne-text">pwm4</span> <span class="ne-text">fan4_input</span>
  • <span class="ne-text">pwm5</span> <span class="ne-text">fan5_input</span>
  • 且两路风扇就是硬盘风道对应的风扇(转速明显上升)

五、读取硬盘温度(SMART)

列出磁盘:

lsblk -o NAME,TYPE,SIZE,MODEL

**确认机械盘设备名为 **<span class="ne-text">/dev/sda</span><span class="ne-text">/dev/sdb</span><span class="ne-text">/dev/sdc</span><span class="ne-text">/dev/sdd</span> 等。

**使用 **<span class="ne-text">smartctl</span> 读取 SMART 信息:

smartctl -A /dev/sda | egrep '^194|^190|Temperature'

示例温度信息:

190 Airflow_Temperature_Cel ...
194 Temperature_Celsius     ... 42 (0 17 0 0 0)

整机硬盘温度概览命令:

for d in /dev/sd?; do
  smartctl -A "$d" 2>/dev/null | awk "/^194 Temperature_Celsius/ {print \"$d:\", \$10\"°C\"}";
done

**我们定义 **控制指标 为:所有 <span class="ne-text">/dev/sd?</span> 中温度最高的那一块盘。

六、硬盘休眠与监控频率的配合

为了让硬盘能正常休眠(用户设置为 5 分钟无访问自动进入 standby):

  • 监控间隔必须大于休眠时间**:设置 **<span class="ne-text">INTERVAL=360</span> 秒(6 分钟),确保硬盘有完整的 5 分钟空档可以进入休眠。
  • 使用 <span class="ne-text">smartctl -n standby -A</span>:如果盘已经进入 standby,该命令不会唤醒它,只是拿不到温度(视为 0)。

这样既能根据硬盘温度调风扇,又不会妨碍硬盘休眠。


核心温控脚本:按硬盘最高温调节 pwm4/pwm5(带中文日志 + 日志轮转)

脚本路径建议:<span class="ne-text">/usr/local/sbin/nas-hdd-fanctl.sh</span>
内容如下:

#!/bin/bash

LOG_FILE="/var/log/nas-hdd-fanctl.log"
MAX_SIZE=$((10 * 1024 * 1024))   # 10MB
MAX_FILES=10

lo**sg() {
  # 日志滚动:大于 10MB 时,nas-hdd-fanctl.log -> .1 -> .2 ...,最多 10 个
  if [ -f "$LOG_FILE" ]; then
    size=$(stat -c%s "$LOG_FILE" 2>/dev/null || echo 0)
    if [ "$size" -ge "$MAX_SIZE" ]; then
      # 从高编号往低编号滚动
      for ((i=MAX_FILES-1; i>=1; i--)); do
        if [ -f "${LOG_FILE}.${i}" ]; then
          if [ "$i" -eq "$MAX_FILES-1" ]; then
            rm -f "${LOG_FILE}.${i}"
          else
            mv "${LOG_FILE}.${i}" "${LOG_FILE}.$((i+1))"
          fi
        fi
      done
      mv "$LOG_FILE" "${LOG_FILE}.1"
    fi
  fi

  # 追加写中文日志:时间戳 + 文本
  echo "$(date '+%Y-%m-%d %H:%M:%S') $*" >> "$LOG_FILE"
}

# 动态找到 nct6791 的 hwmon 目录
HWMON_DIR=""
for h in /sys/class/hwmon/hwmon*; do
  if [ -f "$h/name" ] && grep -q "^nct6791$" "$h/name"; then
    HWMON_DIR="$h"
    break
  fi
done

if [ -z "$HWMON_DIR" ]; then
  lo**sg "[错误] 未找到 nct6791 的 hwmon 设备,脚本退出"
  sleep 60
  exit 1
fi

lo**sg "[信息] 使用 hwmon 目录: $HWMON_DIR"

PWM4="$HWMON_DIR/pwm4"
PWM5="$HWMON_DIR/pwm5"
PWM4_EN="$HWMON_DIR/pwm4_enable"
PWM5_EN="$HWMON_DIR/pwm5_enable"

# 确认 pwm4/pwm5 存在
if [ ! -f "$PWM4" ] || [ ! -f "$PWM5" ]; then
  lo**sg "[错误] 在 $HWMON_DIR 下未找到 pwm4/pwm5,脚本退出"
  sleep 60
  exit 1
fi

# 切换 pwm4/pwm5 到手动模式
[ -f "$PWM4_EN" ] && echo 1 > "$PWM4_EN"
[ -f "$PWM5_EN" ] && echo 1 > "$PWM5_EN"
lo**sg "[信息] 已将 pwm4/pwm5 设置为手动模式"

# 初始较安静又不算太低的转速
SPEED=110
echo "$SPEED" > "$PWM4"
echo "$SPEED" > "$PWM5"
lo**sg "[信息] 初始风扇转速设为 $SPEED"

# 读取所有 /dev/sd? 的最高硬盘温度(SMART 194 Temperature_Celsius)
# 使用 -n standby:如果磁盘已休眠则不唤醒,返回空温度
get_max_hdd_temp() {
  local max=0
  local found=0
  for d in /dev/sd?; do
    [ -b "$d" ] || continue
    t=$(smartctl -n standby -A "$d" 2>/dev/null | awk '/^194 Temperature_Celsius/ {print $10; exit}')
    if echo "$t" | grep -q '^[0-9][0-9]*$'; then
      found=1
      [ "$t" -gt "$max" ] && max="$t"
    fi
  done
  if [ "$found" -eq 0 ]; then
    echo 0
  else
    echo "$max"
  fi
}

# 获取 CPU 包温(Package id 0),整数 °C;失败则输出空
get_cpu_temp() {
  sensors 2>/dev/null | awk '
    /Package id 0:/ {
      gsub(/[^0-9.]/,"",$4);
      printf "%d", $4;
      exit
    }'
}

# 检测间隔(秒)——与硬盘休眠 5 分钟配合使用:这里用 360 秒(6 分钟)
INTERVAL=360
lo**sg "[信息] 开始温控循环,检测间隔 ${INTERVAL} 秒(使用 -n standby 保护硬盘休眠)"

while true; do
  max_hdd=$(get_max_hdd_temp)
  cpu_t=$(get_cpu_temp)

  # 以"硬盘最高温"为主的风扇档位策略(偏静音)
  if [ "$max_hdd" -lt 32 ]; then
    SPEED=90       # 很凉,尽量安静
  elif [ "$max_hdd" -lt 37 ]; then
    SPEED=110      # 正常温度,轻微风
  elif [ "$max_hdd" -lt 42 ]; then
    SPEED=150      # 稍热,适度提高
  else
    SPEED=200      # 偏热,显著加强风量
  fi

  # CPU 高温兜底:CPU >= 70°C 强制提速
  if echo "$cpu_t" | grep -q '^[0-9][0-9]*$' && [ "$cpu_t" -ge 70 ]; then
    SPEED=220
  fi

  # 保险:限制在 [80,230]
  if [ "$SPEED" -lt 80 ]; then
    SPEED=80
  elif [ "$SPEED" -gt 230 ]; then
    SPEED=230
  fi

  # 应用到硬盘风道两个风扇
  echo "$SPEED" > "$PWM4"
  echo "$SPEED" > "$PWM5"

  lo**sg "[循环] 硬盘最高温=${max_hdd}°C CPU温度=${cpu_t:-NA}°C 设定转速=${SPEED}"

  sleep "$INTERVAL"
done

注意事项:

  • **控制对象仅为 **<span class="ne-text">pwm4/pwm5</span> 对应的风扇(硬盘风道),CPU 风扇依然由主板 BIOS / SmartFan 负责;
  • <span class="ne-text">/dev/sd?</span> 会动态适配将来扩展到 10 盘位甚至更多;
  • **日志文件路径为 **<span class="ne-text">/var/log/nas-hdd-fanctl.log</span>,单个文件 10MB 自动轮转,最多保留 10 个历史文件。

使用 systemd 配置开机自启

1. 赋予脚本执行权限

chmod +x /usr/local/sbin/nas-hdd-fanctl.sh

2. 创建 systemd 服务单元

文件路径:<span class="ne-text">/etc/systemd/system/nas-hdd-fan.service</span>

内容:

[Unit]
Description=NAS HDD temperature based fan control (pwm4/pwm5)
After=multi-user.target
Wants=multi-user.target

[Service]
Type=simple
ExecStart=/usr/local/sbin/nas-hdd-fanctl.sh
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target

3. 重新加载并启用服务

systemctl daemon-reload
systemctl enable --now nas-hdd-fan.service

查看状态:

systemctl status nas-hdd-fan.service

查看日志:

tail -f /var/log/nas-hdd-fanctl.log

实际效果与可调参数

关注指标

  • 硬盘温度**:通过 SMART 194 属性查看长期稳定区间(建议长期控制在 40–45°C 内)。**
  • 风扇转速**:通过 **<span class="ne-text">sensors</span> 查看 <span class="ne-text">fan4</span><span class="ne-text">fan5</span> 的 RPM。
  • 硬盘休眠状态**:通过 **<span class="ne-text">hdparm -C /dev/sdX</span> 查看盘是否处于 standby。

可调参数

  • 检测间隔**:**<span class="ne-text">INTERVAL=360</span>(可按需求改为 300/600 秒等,注意要大于硬盘休眠时间)。
  • 档位温度阈值**:**<span class="ne-text">32/37/42°C</span> 可根据实际盘温和噪音感受微调。
  • PWM 档位**:**<span class="ne-text">90/110/150/200/220</span> 可根据风扇特性和噪音容忍度微调。
  • 日志轮转大小**:**<span class="ne-text">MAX_SIZE=$((10 * 1024 * 1024))</span>(单文件 10MB,可按需调整)。

辅助监控脚本

**为了方便实时观察温度和转速,可以使用 **<span class="ne-text">/root/check-nas-therm.sh</span>(持续刷新版):

bash /root/check-nas-therm.sh

默认每 10 秒刷新一次,也可以自定义间隔:

INTERVAL=5 bash /root/check-nas-therm.sh

总结

这套方案主要解决了以下几个问题:

  • **利用 **nct6791 芯片,在 Linux 系统层面直接接管风扇控制,不再依赖 BIOS,支持脚本化/自动化。
  • **以 **硬盘最高温度 为核心指标,结合 CPU 高温兜底,实现更符合 NAS 场景的温控策略。
  • 通过 中文日志 + 日志轮转**(单文件 10MB,最多 10 个)保证脚本行为可观测、可审计,便于日后优化与排障。**
  • **使用 **systemd 实现 开机自启 + 异常自动重启,真正做到"设置一次,长期托管"。
  • 使用 <span class="ne-text">smartctl -n standby -A</span> + 合理的监控间隔(6 分钟),确保硬盘能正常进入 5 分钟休眠,不会被监控脚本频繁唤醒。

如果你也用类似的主板/NAS 方案,可以在此基础上根据自己的硬盘温度/噪音偏好/休眠需求,微调几个关键参数,就能获得一套非常贴合自己使用习惯的自动温控系统。

收藏
送赞 1
分享

0

主题

3

回帖

0

牛值

江湖小虾

这是大佬 对于新手小白来说我得好好消化消化,,,以前只接触windows 现在看来得学习linux的运行逻辑和命令啥的 好难

这只是我平时的工作而已,没必要专门去学,如果在使用这个脚本的过程有什么问题可以留言,我看到就会回复  详情 回复
昨天 09:07

2

主题

4

回帖

0

牛值

江湖小虾

昨天 09:07 楼主 显示全部楼层
Like-Smile造? 发表于 2025-12-10 20:54
这是大佬 对于新手小白来说我得好好消化消化,,,以前只接触windows  现在看来得学习linux的运行逻辑和命 ...

这只是我平时的工作而已,没必要专门去学,如果在使用这个脚本的过程有什么问题可以留言,我看到就会回复

1

主题

10

回帖

0

牛值

江湖小虾

fnOS1.0上线纪念勋章

支持一下,一直以来我都被这个问题困扰,机箱风扇只能已CPU或者芯片组温度来控制,希望以后能用硬盘温度来控制

观察两天了,蛮稳定的,你也可以试试,有什么问题可以在微信群522群找我,或者留言我会跟进  详情 回复
昨天 14:59

2

主题

4

回帖

0

牛值

江湖小虾

昨天 14:59 楼主 显示全部楼层
motonas 发表于 2025-12-11 12:51
支持一下,一直以来我都被这个问题困扰,机箱风扇只能已CPU或者芯片组温度来控制,希望以后能用硬盘温度来 ...

观察两天了,蛮稳定的,你也可以试试,有什么问题可以在微信群522群找我,或者留言我会跟进
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则