From 7bc72fe6d4adcf6bd19cfe53ff879895e4c95037 Mon Sep 17 00:00:00 2001 From: Marc Hoppe Date: Thu, 28 Oct 2010 23:05:10 +0200 Subject: [PATCH] fancontrol hinzu --- fancontrol | 392 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 392 insertions(+) create mode 100755 fancontrol diff --git a/fancontrol b/fancontrol new file mode 100755 index 0000000..b07ccfd --- /dev/null +++ b/fancontrol @@ -0,0 +1,392 @@ +#!/bin/bash +# +# Simple script implementing a temperature dependent fan speed control +# +# Version 0.67 +# +# Usage: fancontrol [CONFIGFILE] +# +# Dependencies: +# bash, egrep, sed, cut, sleep, lm_sensors :) +# +# Please send any questions, comments or success stories to +# marius.reiner@hdev.de +# Thanks! +# +# 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 +# Copyright (C) 2007-2008 Jean Delvare +# +# 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., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301 USA. +# +# + +PIDFILE="/var/run/fancontrol.pid" + +DEBUG=1 +MAX=255 + +if [ -f "$PIDFILE" ] +then + echo "File $PIDFILE exists, is fancontrol already running?" + exit 1 +fi +echo $$ > "$PIDFILE" + +declare -i pwmval + +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'` + OFFTEMP=`egrep '^OFFTEMP=.*$' $1 | sed -e 's/OFFTEMP=//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'` + MINPWM=`egrep '^MINPWM=.*$' $1 | sed -e 's/MINPWM=//g'` + MAXPWM=`egrep '^MAXPWM=.*$' $1 | sed -e 's/MAXPWM=//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 + if [ "$INTERVAL" -le 0 ] + then + echo "Error in configuration file:" + echo "INTERVAL must be at least 1" + exit 1 + fi + + # 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 + if ! echo $fcv | egrep -q '=' + then + echo "Error in configuration file:" + echo "FCTEMPS value is improperly formatted" + exit 1 + fi + + 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` + AFCOFFTEMP[$fcvcount]=`echo $OFFTEMP |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` + AFCMINPWM[$fcvcount]=`echo $MINPWM |sed -e 's/ /\n/g' |egrep "${AFCPWM[$fcvcount]}" |cut -d'=' -f2` + [ -z "${AFCMINPWM[$fcvcount]}" ] && AFCMINPWM[$fcvcount]=0 + AFCMAXPWM[$fcvcount]=`echo $MAXPWM |sed -e 's/ /\n/g' |egrep "${AFCPWM[$fcvcount]}" |cut -d'=' -f2` + [ -z "${AFCMAXPWM[$fcvcount]}" ] && AFCMAXPWM[$fcvcount]=255 + + # verify the validity of the settings + if [ "${AFCMINTEMP[$fcvcount]}" -ge "${AFCMAXTEMP[$fcvcount]}" ] + then + echo "Error in configuration file (${AFCPWM[$fcvcount]}):" + echo "MINTEMP must be less than MAXTEMP" + exit 1 + fi + if [ "${AFCMAXPWM[$fcvcount]}" -gt 255 ] + then + echo "Error in configuration file (${AFCPWM[$fcvcount]}):" + echo "MAXPWM must be at most 255" + exit 1 + fi + if [ "${AFCMINSTOP[$fcvcount]}" -ge "${AFCMAXPWM[$fcvcount]}" ] + then + echo "Error in configuration file (${AFCPWM[$fcvcount]}):" + echo "MINSTOP must be less than MAXPWM" + exit 1 + fi + if [ "${AFCMINSTOP[$fcvcount]}" -lt "${AFCMINPWM[$fcvcount]}" ] + then + echo "Error in configuration file (${AFCPWM[$fcvcount]}):" + echo "MINSTOP must be greater than or equal to MINPWM" + exit 1 + fi + if [ "${AFCMINPWM[$fcvcount]}" -lt 0 ] + then + echo "Error in configuration file (${AFCPWM[$fcvcount]}):" + echo "MINPWM must be at least 0" + exit 1 + fi + + echo + echo "Settings for ${AFCPWM[$fcvcount]}:" + echo " Depends on ${AFCTEMP[$fcvcount]}" + echo " Controls ${AFCFAN[$fcvcount]}" + echo " OFFTEMP=${AFCOFFTEMP[$fcvcount]}" + echo " MINTEMP=${AFCMINTEMP[$fcvcount]}" + echo " MAXTEMP=${AFCMAXTEMP[$fcvcount]}" + echo " MINSTART=${AFCMINSTART[$fcvcount]}" + echo " MINSTOP=${AFCMINSTOP[$fcvcount]}" + echo " MINPWM=${AFCMINPWM[$fcvcount]}" + echo " MAXPWM=${AFCMAXPWM[$fcvcount]}" + let fcvcount=fcvcount+1 + done + echo +} + +if [ -f "$1" ] +then + LoadConfig $1 +else + LoadConfig /etc/fancontrol +fi + +DIR=/proc/sys/dev/sensors +if [ ! -d $DIR ] +then + # For Linux 2.6, detect if config file uses the hwmon class or not yet + if echo "${AFCPWM[0]}" | egrep -q '^hwmon[0-9]' + then + SDIR=/sys/class/hwmon + else + SDIR=/sys/bus/i2c/devices + fi + + 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 [ -n "$SYSFS" ] + then + ENABLE=${1}_enable + # No enable file? Just set to max + if [ ! -f $ENABLE ] + then + echo $MAX > $1 + return 0 + fi + + # Try pwmN_enable=0 + echo 0 > $ENABLE 2> /dev/null + if [ `cat $ENABLE` -eq 0 ] + then + # Success + return 0 + fi + + # It didn't work, try pwmN_enable=1 pwmN=255 + echo 1 > $ENABLE 2> /dev/null + echo $MAX > $1 + if [ `cat $ENABLE` -eq 1 -a `cat $1` -ge 190 ] + then + # Success + return 0 + fi + + # Nothing worked + echo "$ENABLE stuck to" `cat $ENABLE` >&2 + return 1 + 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 2> /dev/null + if [ $? -ne 0 ] + then + return 1 + fi + fi + echo $MAX > $1 + else + echo $MAX 1 > $1 + fi +} + +function restorefans() +{ + local status=$1 + echo 'Aborting, restoring fans...' + let fcvcount=0 + while (( $fcvcount < ${#AFCPWM[@]} )) # go through all pwm outputs + do + pwmo=${AFCPWM[$fcvcount]} + pwmdisable $pwmo + let fcvcount=$fcvcount+1 + done + echo 'Verify fans have returned to full speed' + rm -f "$PIDFILE" + exit $status +} + +trap 'restorefans 0' SIGQUIT SIGTERM +trap 'restorefans 1' SIGHUP SIGINT + +# 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]} + offt=${AFCOFFTEMP[$fcvcount]} + mint=${AFCMINTEMP[$fcvcount]} + maxt=${AFCMAXTEMP[$fcvcount]} + minsa=${AFCMINSTART[$fcvcount]} + minso=${AFCMINSTOP[$fcvcount]} + minpwm=${AFCMINPWM[$fcvcount]} + maxpwm=${AFCMAXPWM[$fcvcount]} + + read tval < ${tsens} + if [ $? -ne 0 ] + then + echo "Error reading temperature from $DIR/$tsens" + restorefans 1 + fi + if [ "$SYSFS" = "1" ] + then + let tval="($tval+500)/1000" + else + tval=`echo ${tval} | cut -d' ' -f3 | cut -d'.' -f1` + fi + + read pwmpval < ${pwmo} + if [ $? -ne 0 ] + then + echo "Error reading PWM value from $DIR/$pwmo" + restorefans 1 + fi + if [ "$SYSFS" != "1" ] + then + pwmpval=`echo ${pwmpval} | cut -d' ' -f1` + fi + + # If fanspeed-sensor output shall be used, do it + if [[ -n ${fan} ]] + then + read fanval < ${fan} + if [ $? -ne 0 ] + then + echo "Error reading Fan value from $DIR/$fan" + restorefans 1 + fi + if [ "$SYSFS" != "1" ] + then + fanval=`echo ${fanval} | cut -d' ' -f2` + fi + 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 "minpwm=$minpwm" + echo "maxpwm=$maxpwm" + echo "tval=$tval" + echo "pwmpval=$pwmpval" + echo "fanval=$fanval" + fi + + if (( $tval <= $offt )) + then pwmval=$minpwm # below min temp, use defined min pwm + elif (( $tval >= $maxt )) + then pwmval=$maxpwm # over max temp, use defined max pwm + elif(( $tval > $mint )) + then + # calculate the new value from temperature and settings + pwmval="(${tval}-${mint})*(${maxpwm}-${minso})/(${maxt}-${mint})+${minso}" + if [ $pwmpval -eq 0 -o $fanval -eq 0 ] + then # if fan was stopped start it using a safe value + echo $minsa > $pwmo + # Sleep while still handling signals + read < <(exec sleep 1) + fi + #else ( > offt and < mint ) + # keep running on current value + fi + echo $pwmval > $pwmo # write new value to pwm output + if [ $? -ne 0 ] + then + echo "Error writing PWM value to $DIR/$pwmo" + restorefans 1 + fi + if [ "$DEBUG" != "" ] + then + echo "new pwmval=$pwmval" + fi + let 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 1 + fi + let fcvcount=$fcvcount+1 +done + +echo 'Starting automatic fan control...' + +# main loop calling the main function at specified intervals +while true +do + UpdateFanSpeeds + # Sleep while still handling signals + read < <(exec sleep $INTERVAL) +done