插入电源时风扇持续开启,但仅使用电池时风扇静音

插入电源时风扇持续开启,但仅使用电池时风扇静音

问题

当笔记本电脑插上电源且未充电时,风扇会一直打开。噪音不大,但肯定能听到。
然而,当笔记本电脑未插上电源或仍在充电时,风扇偶尔会保持静音(旋转速度较慢或根本不旋转)。

问题

当机器一直插着电源却没有充电时,如何实现同样的效果?
也许解决方案就这么简单:https://askubuntu.com/a/300921/69296


机器:

  • 惠普 Elitebook 8470p
  • Ubuntu 13.10 LTS(全新安装,实际上是 Lubuntu 风格,但没什么区别)
  • 英特尔 i5-3360M
  • uname -a: Linux elite 3.11.0-12-generic #19-Ubuntu SMP 星期三 十月 9 16:20:46 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux
  • 8GB 内存
  • SATA3 固态硬盘
  • AMD Radeon HD 7570M
  • power_methodprofilepower_profileauto

答案1

我有一台 HP 4510s 笔记本电脑。风扇控制在 Windows 下工作正常。在任何尝试过的 Linux 发行版/版本下都不起作用。在 Linux/Ubuntu 下,风扇以非常低的速度运行。这不足以在高负载下保持 CPU 足够凉爽。

我尝试了互联网上关于 Linux 笔记本电脑风扇控制的大多数提示,但都不起作用。我尝试了 lm_sensors、pwmconfig、acpi_os= 设置和许多其他方法,但都无济于事。我更新了 BIOS,除了“交流电时风扇始终打开”外什么也没有,而且它不起作用。

可以使用 lm_sensors 获取系统温度。此外,风扇控制点位于

/sys/devices/virtual/thermal/cooling_device*/cur_state (* 0-4 处于活动状态)

我最终从

http://thinkwiki.org/wiki/ACPI_fan_control_script

并将其改成 hp-fancontrol。我对自动化研究的记忆不够深刻(那是 20 年前的事了),所以它变得非常简单。但到目前为止它似乎可以正常工作。仍然有很多剩余的代码,而且它丑陋得要命。我将其安装为 /usr/bin/hp_fancontrol,并像这样将触发器添加到 /etc/rc.local

# Start hp-fancontrol on multiuser
/usr/bin/hp-fancontrol -l -d

exit 0

如果有更好的办法,我将不胜感激,即使只是 control_loop 部分,所以请发表评论。另外,请保持礼貌并阅读免责声明(丑陋如……上面和代码本身)。QUIET 似乎不起作用,它破坏了 DAEMONIZE。

#!/bin/bash

# hp-fancontrol 0.1 
# Based on tp-fancontrol (http://thinkwiki.org/wiki/ACPI_fan_control_script)
# Provided under the GNU General Public License version 2 or later or
# the GNU Free Documentation License version 1.2 or later, at your option.
# See http://www.gnu.org/copyleft/gpl.html for the Warranty Disclaimer.

# This script dynamically(?) controls fan speed on some HP laptop models 
# (ProBook 4510s) according to user-defined temperature thresholds.  It 
# implements its own decision algorithm, overriding the any embedded
# controller.
#
# Run 'hp-fancontrol --help' for options.
#
# For optimal fan behavior during suspend and resume, invoke 
# "hp-fancontrol -u" during the suspend process.
# 
# WARNING: This script relies on undocumented hardware features and
# overrides nominal hardware behavior. It may thus cause arbitrary
# damage to your laptop or data. Watch your temperatures!
#
# WARNING: The list of temperature ranges used below is much more liberal
# than the rules used by the embedded controller firmware, and is
# derived mostly from anecdotal evidence, hunches and wishful thinking.
# It is also model-specific (see http://thinkwiki.org/wiki/Thermal_sensors).

# Temperature ranges, per core:
# (min temperature: when to step up from 0-th fan level,
#  max temperature: when to step up to maximum fan level)
THRESHOLDS=( #  Core
# min  max   #  ----
  43   65    #  0
  43   65    #  1
)

# LEVELS=0 - 31 (5 bits)             # Fan speed levels
ANTIPULSE=1                          # Prevent fan pulsing noise
                                     # (reduces frequency of fan RPM updates)

OFF_THRESH_DELTA=3 # when gets this much cooler than 'min' above, may turn off fan
MIN_THRESH_SHIFT=0 # increase min thresholds by this much
MAX_THRESH_SHIFT=0 # increase max thresholds by this much
MIN_WAIT=180       # minimum time (seconds) to spend in a given level before 
                   # stepping down

HP_ACPI=/sys/devices/virtual/thermal/cooling_device

PID_FILE=/var/run/hp-fancontrol.pid
LOGGER=/usr/bin/logger
INTERVAL=3        # sample+refresh interval
SETTLE_TIME=6     # wait this many seconds long before applying anti-pulsing
RESETTLE_TIME=600 # briefly disable anti-pulsing at every N seconds
SUSPEND_TIME=5    # seconds to sleep when receiving SIGUSR1

SEP=','           # Separator char for display

WATCHDOG_DELAY=$(( 3 * INTERVAL ))
HAVE_WATCHDOG=false
HAVE_LEVELCMD=true

QUIET=false
DRY_RUN=false
DAEMONIZE=false
AM_DAEMON=false
KILL_DAEMON=false
SUSPEND_DAEMON=false
SYSLOG=false

usage() {
    echo "
Usage: $0 [OPTION]...

Available options:
   -s N   Shift up the min temperature thresholds by N degrees
          (positive for quieter, negative for cooler).
          Max temperature thresholds are not affected.
   -S N   Shift up the max temperature thresholds by N degrees
          (positive for quieter, negative for cooler). DANGEROUS.
   -t     Test mode
   -q     Quiet mode
   -d     Daemon mode, go into background (implies -q)
   -l     Log to syslog
   -k     Kill already-running daemon
   -u     Tell already-running daemon that the system is being suspended
   -p     Pid file location for daemon mode, default: $PID_FILE
"
    exit 1;
}

while getopts 's:S:qtdlp:kuh' OPT; do
    case "$OPT" in
        s) # shift thresholds
            MIN_THRESH_SHIFT="$OPTARG"
            ;;
        S) # shift thresholds
            MAX_THRESH_SHIFT="$OPTARG"
            ;;
        t) # test mode
            DRY_RUN=true
            ;;
        q) # quiet mode
            QUIET=true
            ;;
        d) # go into background and daemonize
            DAEMONIZE=true
            ;;
        l) # log to syslog
            SYSLOG=true
            ;;
        p) # different pidfile
            PID_FILE="$OPTARG"
            ;;
        k) # kill daemon
            KILL_DAEMON=true
            ;;
        u) # suspend daemon
            SUSPEND_DAEMON=true
            ;;
        h) # short help
            usage
            ;;
        \?) # error
            usage
            ;;
    esac
done
[ $OPTIND -gt $# ] || usage  # no non-option args

# no logger found, no syslog capabilities
$SYSLOG && [ ! -x $LOGGER ] && SYSLOG=false || :

if $DRY_RUN; then
    echo "$0: Dry run, will not change fan state."
    QUIET=false
    DAEMONIZE=false
fi

thermometer() { # output list of temperatures
    # 2 basic temperatures from CPU cores:
    CPU0=`/usr/bin/sensors | /usr/bin/awk '/Core 0/ { print $3 }' | sed -e s/[^0-9]//g`
    CPU1=`/usr/bin/sensors | /usr/bin/awk '/Core 1/ { print $3 }' | sed -e s/[^0-9]//g`
    echo -n "$CPU0 $CPU1 ";
    return 0
}

speedometer() { # output fan speed RPM
    read F0 < /sys/devices/virtual/thermal/cooling_device0/cur_state
    read F1 < /sys/devices/virtual/thermal/cooling_device1/cur_state
    read F2 < /sys/devices/virtual/thermal/cooling_device2/cur_state
    read F3 < /sys/devices/virtual/thermal/cooling_device3/cur_state
    read F4 < /sys/devices/virtual/thermal/cooling_device4/cur_state
    FAN=$(($F4+$F3*2+$F2*4+$F1*8+$F0*16))
    echo -n $FAN;
    return 0
}

setlevel() { # set fan speed level
    local LEVEL=$1
    if ! $DRY_RUN; then
        if $HAVE_LEVELCMD; then
        BLEVEL=$(echo "obase=2;$LEVEL" | bc)
        LEN=$(echo ${#BLEVEL})
        BLEVEL5=`echo "0000"$BLEVEL`
        B5=${BLEVEL5:(-5)}
        echo ${B5:0:1} > /sys/devices/virtual/thermal/cooling_device0/cur_state
        echo ${B5:1:1} > /sys/devices/virtual/thermal/cooling_device1/cur_state
        echo ${B5:2:1} > /sys/devices/virtual/thermal/cooling_device2/cur_state
        echo ${B5:3:1} > /sys/devices/virtual/thermal/cooling_device3/cur_state
        echo ${B5:4:1} > /sys/devices/virtual/thermal/cooling_device4/cur_state
    else
        case "$LEVEL" in
        (auto)        LEVEL=0x80 ;;
        (disengaged)  LEVEL=0x40 ;;
        esac
            #echo 0x2F $LEVEL > $IBM_ACPI/ecdump
    fi
    fi
}

getlevel() { # get fan speed level
    # perl -e 'm/^EC 0x20: .* .(..)$/ and print $1 and exit 0 while <>; exit 1' < $IBM_ACPI/ecdump
    read F0 < /sys/devices/virtual/thermal/cooling_device0/cur_state
    read F1 < /sys/devices/virtual/thermal/cooling_device1/cur_state
    read F2 < /sys/devices/virtual/thermal/cooling_device2/cur_state
    read F3 < /sys/devices/virtual/thermal/cooling_device3/cur_state
    read F4 < /sys/devices/virtual/thermal/cooling_device4/cur_state
    FAN=$(($F4+$F3*2+$F2*4+$F1*8+$F0*16))
    echo -n $FAN;
}

log() {
    # $QUIET || echo "> $*"
    ! $SYSLOG || $LOGGER -t "`basename $0`[$$]" "$*"
}

cleanup() { # clean up after work
    $AM_DAEMON && rm -f "$PID_FILE" 2> /dev/null
    log "Shutting down, fan turned up"
    if ! $DRY_RUN; then
        if $HAVE_LEVELCMD; then
            setlevel 31
        fi
    fi
}

floor_div() {
    echo $(( (($1)+1000*($2))/($2) - 1000 ))
}

set_priority() {
    ! $DRY_RUN && renice -10 -p $$
}

init_state() {
    IDX=0
    NEW_IDX=0
    START_TIME=0
    MAX_IDX=31
    SETTLE_LEFT=0
    RESETTLE_LEFT=0
    FIRST=true
    RESTART=false
}

control_fan() {
    # Enable the fan in default mode if anything goes wrong:
    set -e -E -u
    trap "cleanup; exit 2" HUP INT ABRT QUIT SEGV TERM
    trap "cleanup" EXIT
    trap "log 'Got SIGUSR1'; setlevel 0; RESTART=true; sleep $SUSPEND_TIME" USR1

    init_state
    log "Starting dynamic fan control"

    # Control loop:
    while true; do
        # Get readouts
        TEMPS=`thermometer`
        $QUIET || SPEED=`speedometer`
        $QUIET || ECLEVEL=`getlevel`
        NOW=`date +%s`
        if echo "$TEMPS" | grep -q "[^ 0-9$SEP\n-]"; then
            echo "Invalid character in temperatures: $TEMPS" >&2; exit 1;
        fi

    OLDLEVEL=$ECLEVEL
    NEWLEVEL=$OLDLEVEL
    CHANGE=0

    for TEMP in $TEMPS; do
        if [ $TEMP -gt 430 ] ; then
        if [ $OLDLEVEL -lt 31 ] ; then
            CHANGE=$(($CHANGE+1)) ;
            # NEWLEVEL=$(($OLDLEVEL+1)) ;
        fi
        elif [ $TEMP -gt 410 ] ; then
                # No change between 41-43C
        CHANGE=$(($CHANGE)) ;
        else
        if [ $OLDLEVEL -gt 0 ] ; then
            CHANGE=$(($CHANGE-1)) ;
            # NEWLEVEL=$(($OLDLEVEL-1)) ;
        fi
        fi
        NEWLEVEL=$(($OLDLEVEL+$CHANGE)) ;
        if [ $NEWLEVEL -gt 31 ] ; then
        NEWLEVEL=31 ;
        fi
        if [ $NEWLEVEL -lt 0 ] ; then
                NEWLEVEL=0 ;
            fi
            OLDLEVEL=$NEWLEVEL ;
        done

        # Interrupted by a signal?
        if $RESTART; then
            init_state
            log "Resetting state"
            continue
        fi

        # Transition
        if [ "$ECLEVEL" != "$NEWLEVEL" ]; then
            START_TIME=$NOW
            log "Changing fan level: $ECLEVEL->$NEWLEVEL  (temps: $TEMPS)"
        fi

        setlevel $NEWLEVEL

        sleep $INTERVAL

        IDX=$NEW_IDX
        FIRST=false
    done
}

if $KILL_DAEMON || $SUSPEND_DAEMON; then 
    if [ -f "$PID_FILE" ]; then
    set -e
    DPID="`cat \"$PID_FILE\"`" 
    if $KILL_DAEMON; then
            kill "$DPID"
        rm "$PID_FILE"
        $QUIET || echo "Killed process $DPID"
    else # SUSPEND_DAEMON
        kill -USR1 "$DPID"
        $QUIET || echo "Sent SIGUSR1 to $DPID"
    fi
    else
        $QUIET || echo "Daemon not running."
        exit 1
    fi
elif $DAEMONIZE ; then
    if [ -e "$PID_FILE" ]; then
        echo "$0: File $PID_FILE already exists, refusing to run."
        exit 1
    else
        set_priority
        AM_DAEMON=true QUIET=false control_fan 0<&- 1>&- 2>&- &
    echo "$0: Starting as daemon"
        echo $! > "$PID_FILE"
        exit 0
    fi
else
    [ -e "$PID_FILE" ] && echo "WARNING: daemon already running"
    set_priority
    control_fan
fi

答案2

风扇速度设置明确不受操作系统的控制,否则我可能是错的。

但我知道适用于 Windows 的实用程序很少。不过,有些 BIOS 会为您提供控制风扇行为的选项。您应该先在 BIOS 中检查这些选项。

不建议使用会改变某些关键硬件行为的实用程序。

相关内容