Eu tenho um laptop HP 4510s. O controle do ventilador funciona bem no Windows. Não funciona em nenhuma versão / distribuição Linux testada. Sob Linux / Ubuntu, o ventilador roda a uma velocidade muito baixa. Isso não é suficiente para manter as CPUs resfriadas o suficiente sob carga mais alta.
Eu tentei a maioria das dicas da internet sobre o controle do ventilador do laptop Linux, nenhum funcionou. Para listar, eu tentei lm_sensors, pwmconfig, acpi_os = configuração e inúmeras outras coisas sem sucesso. E eu atualizei o BIOS e não há nada além de "Fan always on on AC" e ele não faz o truque.
É possível obter os temps do sistema usando lm_sensors. Além disso, existem pontos de controle de ventilador
/ sys / devices / virtual / thermal / cooling_device * / cur_state (* de 0 a 4 estão ativos)
Acabei pegando o famoso script tp-fancontrol (para IBM ThinkPads) de
e estragou tudo como hp-fancontrol. Não me lembro o suficiente de meus estudos de automação (era 20 anos atrás), então ficou muito simples. Mas parece funcionar até agora. Ainda há muitos códigos que sobraram e é feio como ****. Eu instalei como / usr / bin / hp_fancontrol e adicionei o trigger para /etc/rc.local assim
# Start hp-fancontrol on multiuser
/usr/bin/hp-fancontrol -l -d
exit 0
Eu ficaria muito grato por qualquer coisa melhor, mesmo que seja apenas a parte control_loop, então por favor, comente. Além disso, seja gentil e leia as renúncias (feias como ... acima e código em si). O QUIET parece não funcionar, quebra 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