#!/bin/bash # # Simple script implementing a temperature dependent fan speed control # # Version 0.63 # # Usage: fancontrol [CONFIGFILE] # # Dependencies: # bash, awk, egrep, sed, lm_sensors :) # # Please send any questions, comments or success stories to # marius.reiner@hdev.de # Thanks! # # The latest version of this script is available at: # http://www.hdev.de/fancontrol/fancontrol.html # or in the CVS version of lm_sensors # # For configuration instructions and warnings please see fancontrol.txt, which # can be found in the doc/ directory or at the website mentioned above. # # # Copyright 2003 Marius Reiner # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # # #DEBUG=1 MAX=255 echo $$ > /var/run/fancontrol.pid function LoadConfig { echo "Loading configuration from $1 ..." # grep configuration from file INTERVAL=`egrep '^INTERVAL=.*$' $1 | sed -e 's/INTERVAL=//g'` FCTEMPS=`egrep '^FCTEMPS=.*$' $1 | sed -e 's/FCTEMPS=//g'` MINTEMP=`egrep '^MINTEMP=.*$' $1 | sed -e 's/MINTEMP=//g'` MAXTEMP=`egrep '^MAXTEMP=.*$' $1 | sed -e 's/MAXTEMP=//g'` MINSTART=`egrep '^MINSTART=.*$' $1 | sed -e 's/MINSTART=//g'` MINSTOP=`egrep '^MINSTOP=.*$' $1 | sed -e 's/MINSTOP=//g'` # optional settings: FCFANS=`egrep '^FCFANS=.*$' $1 | sed -e 's/FCFANS=//g'` # Check whether all mandatory settings are set if [[ -z ${INTERVAL} || -z ${FCTEMPS} || -z ${MINTEMP} || -z ${MAXTEMP} || -z ${MINSTART} || -z ${MINSTOP} ]] then echo "Some mandatory settings missing, please check your config file!" exit 1 fi # here the other settings should be verified # write settings to arrays for easier use and print them echo echo "Common settings:" echo " INTERVAL=$INTERVAL" let fcvcount=0 for fcv in $FCTEMPS do AFCPWM[$fcvcount]=`echo $fcv |cut -d'=' -f1` AFCTEMP[$fcvcount]=`echo $fcv |cut -d'=' -f2` AFCFAN[$fcvcount]=`echo $FCFANS |sed -e 's/ /\n/g' |egrep "${AFCPWM[$fcvcount]}" |cut -d'=' -f2` AFCMINTEMP[$fcvcount]=`echo $MINTEMP |sed -e 's/ /\n/g' |egrep "${AFCPWM[$fcvcount]}" |cut -d'=' -f2` AFCMAXTEMP[$fcvcount]=`echo $MAXTEMP |sed -e 's/ /\n/g' |egrep "${AFCPWM[$fcvcount]}" |cut -d'=' -f2` AFCMINSTART[$fcvcount]=`echo $MINSTART |sed -e 's/ /\n/g' |egrep "${AFCPWM[$fcvcount]}" |cut -d'=' -f2` AFCMINSTOP[$fcvcount]=`echo $MINSTOP |sed -e 's/ /\n/g' |egrep "${AFCPWM[$fcvcount]}" |cut -d'=' -f2` echo echo "Settings for ${AFCPWM[$fcvcount]}:" echo " Depends on ${AFCTEMP[$fcvcount]}" echo " Controls ${AFCFAN[$fcvcount]}" echo " MINTEMP=${AFCMINTEMP[$fcvcount]}" echo " MAXTEMP=${AFCMAXTEMP[$fcvcount]}" echo " MINSTART=${AFCMINSTART[$fcvcount]}" echo " MINSTOP=${AFCMINSTOP[$fcvcount]}" let fcvcount=fcvcount+1 done echo } if [ -f "$1" ] then LoadConfig $1 else LoadConfig /etc/fancontrol fi DIR=/proc/sys/dev/sensors SDIR=/sys/bus/i2c/devices if [ ! -d $DIR ] then if [ ! -d $SDIR ] then echo $0: 'No sensors found! (did you load the necessary modules?)' exit 1 else SYSFS=1 DIR=$SDIR fi fi cd $DIR # $1 = pwm file name function pwmdisable() { if [ "$SYSFS" = "1" ] then echo $MAX > $1 ENABLE=${1}_enable if [ -f $ENABLE ] then echo 0 > $ENABLE fi else echo $MAX 0 > $1 fi } # $1 = pwm file name function pwmenable() { if [ "$SYSFS" = "1" ] then ENABLE=${1}_enable if [ -f $ENABLE ] then echo 1 > $ENABLE fi else echo $MAX 1 > $1 fi } function restorefans() { echo 'Aborting, restoring fans...' let fcvcount=0 while (( $fcvcount < ${#AFCPWM[@]} )) # go through all pwm outputs do pwmo=${AFCPWM[$fcvcount]} pwmdisable $pwmo fcvcount=$fcvcount+1 done echo 'Verify fans have returned to full speed' exit 1 } trap restorefans SIGHUP SIGINT SIGQUIT SIGTERM SIGKILL # function doing all the math function calc () { awk "BEGIN { print $@ }" } # main function function UpdateFanSpeeds { let fcvcount=0 while (( $fcvcount < ${#AFCPWM[@]} )) # go through all pwm outputs do #hopefully shorter vars will improve readability: pwmo=${AFCPWM[$fcvcount]} tsens=${AFCTEMP[$fcvcount]} fan=${AFCFAN[$fcvcount]} mint=${AFCMINTEMP[$fcvcount]} maxt=${AFCMAXTEMP[$fcvcount]} minsa=${AFCMINSTART[$fcvcount]} minso=${AFCMINSTOP[$fcvcount]} tval=`cat ${tsens}` if [ $? -ne 0 ] then echo "Error reading temperature from $DIR/$tsens" restorefans fi tval=`echo ${tval} |cut -d' ' -f3 |cut -d'.' -f1` if [ "$SYSFS" = "1" ] then let tval="$tval / 1000" fi pwmpval=`cat ${pwmo}` if [ $? -ne 0 ] then echo "Error reading PWM value from $DIR/$pwmo" restorefans fi pwmpval=`echo ${pwmpval} | cut -d' ' -f1` # If fanspeed-sensor output shall be used, do it if [[ -n ${fan} ]] then fanval=`cat ${fan}` if [ $? -ne 0 ] then echo "Error reading Fan value from $DIR/$fan" restorefans fi fanval=`echo ${fanval} | cut -d' ' -f2` else fanval=1 # set it to a non zero value, so the rest of the script still works fi # debug info if [ "$DEBUG" != "" ] then echo "pwmo=$pwmo" echo "tsens=$tsens" echo "fan=$fan" echo "mint=$mint" echo "maxt=$maxt" echo "minsa=$minsa" echo "minso=$minso" echo "tval=$tval" echo "pwmpval=$pwmpval" echo "fanval=$fanval" fi if (( $tval <= $mint )) then pwmval=0 # at specified mintemp shut fan off elif (( $tval >= $maxt )) then pwmval=255 # at specified maxtemp switch to 100% else # calculate the new value from temperature and settings pwmval=`calc "(((${tval}-${mint})/(${maxt}-${mint}))^2*(255-${minso})+${minso})" |cut -d'.' -f1` if [ $pwmpval -eq 0 -o $fanval -eq 0 ] then # if fan was stopped start it using a safe value echo $minsa > $pwmo sleep 1 fi fi echo $pwmval > $pwmo # write new value to pwm output if [ $? -ne 0 ] then echo "Error writing PWM value to $DIR/$pwmo" restorefans fi if [ "$DEBUG" != "" ] then echo "new pwmval=$pwmval" fi fcvcount=$fcvcount+1 done } echo 'Enabling PWM on fans...' let fcvcount=0 while (( $fcvcount < ${#AFCPWM[@]} )) # go through all pwm outputs do pwmo=${AFCPWM[$fcvcount]} pwmenable $pwmo if [ $? -ne 0 ] then echo "Error enabling PWM on $DIR/$pwmo" restorefans fi fcvcount=$fcvcount+1 done echo 'Starting automatic fan control...' # main loop calling the main function at specified intervals while true do UpdateFanSpeeds sleep $INTERVAL done # some old stuff/missing features, will clean this up soon #if ( test "$regulationtype" = "quad" ) ; then # while true ; do # temp=`cat ${temp1} | cut -b 12-13` # if (( ${temp} < ${mintemp} )) ; # then pwm=0 # elif (( ${temp} > ${maxtemp} )) ; # then pwm=255 # else # pwm=`calc "((10/(${maxtemp}-${mintemp})*(${temp}-${mintemp}))^2/1000*(${maxtemp}-${mintemp})*(255-${minspeed})+${minspeed})"` # #no optimization here for readability (or sloth :)) # fi ; # echo $pwm > ${pwm1} ; # # sleep 10 ; # done ; #elif ( test "$regulationtype" = "exp" ) ; then #add support for exponential calculation here #else # pwmconst=$[(255-${minspeed})/(${maxtemp}-${mintemp})] # while true ; do # let temp=`cat temp1 | cut -b 12-13` ; # if (( ${temp} < ${mintemp} )) ; # then pwm=0 # elif (( ${temp} > ${maxtemp} )) ; # then pwm=255 # else # pwm=$[(${temp}-${mintemp})*${pwmconst}+${minspeed}] # fi ; # echo $pwm > pwm2 ; # # sleep 10 ; # done ; #fi