Ubuntu: Fan is constantly on when power supply plugged, but goes silent when only on battery



Fan is constantly on when a laptop is plugged and not charging. Not noisy, but definitely audible.
However, it occasionally stays silent (spinning slower or not spinning at all) when laptop is not plugged or still charging.


How to achieve the same when the machine stays plugged and isn't charging ?
Perhaps the solution is as simple as this: https://askubuntu.com/a/300921/69296


  • HP Elitebook 8470p
  • Ubuntu 13.10 LTS (clean install, actually Lubuntu flavour, but it doesn't make a difference)
  • intel i5-3360M
  • uname -a: Linux elite 3.11.0-12-generic #19-Ubuntu SMP Wed Oct 9 16:20:46 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux
  • 8GB RAM
  • sata3 SSD
  • AMD Radeon HD 7570M
  • power_method: profile, power_profile: auto


I have a HP 4510s laptop. The fan control works ok under Windows. Does not work under any tried Linux distro/version. Under Linux/Ubuntu, the fan runs at some very low speed. This is not sufficient to keep CPUs cool enough under higher load.

I tried most of the hints from the internet regarding the Linux laptop fancontrol, none worked. To list, I tried lm_sensors, pwmconfig, acpi_os= setting and numerous other things to no avail. And I've updated BIOS and there's nothing except "Fan always on on AC" and it does not do the trick.

It is possible to get the system temps using lm_sensors. Furthermore, there are fan control points at

/sys/devices/virtual/thermal/cooling_device*/cur_state (* from 0-4 are active)

I ended up taking the famous tp-fancontrol (for IBM ThinkPads) script from


and botched it up as hp-fancontrol. I don't remember enough from my automation studies (it was 20 years ago) so it turned out very simple. But it seems to work so far. There are lots of left-over code still and it's ugly as ****. I installed it as /usr/bin/hp_fancontrol and added trigger to /etc/rc.local like this

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

I'd be very grateful for anything better, even if it is just the control_loop part, so please comment. Also, be gentle and read the disclaimers (ugly as... above and code itself). The QUIET seems not to work, it breaks 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  


Fan speed settings explicitly not under the control of OS or I might be wrong.

But there are few utilities which I know for Windows. However some BIOSs give you options to control the fan behaviour. You should check for those options in BIOS first.

Using utilities which would change the behaviour of some crucial hardware is not recommended.

Note:If u also have question or solution just comment us below or mail us on toontricks1994@gmail.com
Next Post »