root/lm-sensors/branches/lm-sensors-3.0.0/prog/pwm/fancontrol @ 4441

Revision 4441, 7.6 KB (checked in by khali, 8 years ago)

More cleanups to fancontrol:
* No longer depend on grep. We already depend on egrep so let's use it
everywhere.
* Don't depend on awk to compute the target PWM value. Bash has an arithmetic
expression evaluation engine which does the job just fine.
* Use read instead of cat to read the sensor values. read is built-in, so
it's cheaper.
* When sysfs is used (2.6 kernel), do not postproces the sensor value reads
with cut, as it is not needed.
* Update the dependency list.

  • Property svn:eol-style set to native
  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
Line 
1#!/bin/bash
2#
3# Simple script implementing a temperature dependent fan speed control
4#
5# Version 0.65
6#
7# Usage: fancontrol [CONFIGFILE]
8#
9# Dependencies:
10#   bash, egrep, sed, cut, sleep, lm_sensors :)
11#
12# Please send any questions, comments or success stories to
13# marius.reiner@hdev.de
14# Thanks!
15#
16# The latest version of this script is available at:
17# http://www.hdev.de/fancontrol/fancontrol.html
18# or in the SVN version of lm_sensors
19#
20# For configuration instructions and warnings please see fancontrol.txt, which
21# can be found in the doc/ directory or at the website mentioned above.
22#
23#
24#    Copyright 2003 Marius Reiner <marius.reiner@hdev.de>
25#
26#    This program is free software; you can redistribute it and/or modify
27#    it under the terms of the GNU General Public License as published by
28#    the Free Software Foundation; either version 2 of the License, or
29#    (at your option) any later version.
30#
31#    This program is distributed in the hope that it will be useful,
32#    but WITHOUT ANY WARRANTY; without even the implied warranty of
33#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
34#    GNU General Public License for more details.
35#
36#    You should have received a copy of the GNU General Public License
37#    along with this program; if not, write to the Free Software
38#    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
39#
40#
41
42#DEBUG=1
43MAX=255
44
45echo $$ > /var/run/fancontrol.pid
46
47function LoadConfig {
48        echo "Loading configuration from $1 ..."
49        # grep configuration from file
50        INTERVAL=`egrep '^INTERVAL=.*$' $1 | sed -e 's/INTERVAL=//g'`
51        FCTEMPS=`egrep '^FCTEMPS=.*$' $1 | sed -e 's/FCTEMPS=//g'`
52        MINTEMP=`egrep '^MINTEMP=.*$' $1 | sed -e 's/MINTEMP=//g'`
53        MAXTEMP=`egrep '^MAXTEMP=.*$' $1 | sed -e 's/MAXTEMP=//g'`
54        MINSTART=`egrep '^MINSTART=.*$' $1 | sed -e 's/MINSTART=//g'`
55        MINSTOP=`egrep '^MINSTOP=.*$' $1 | sed -e 's/MINSTOP=//g'`
56        # optional settings:
57        FCFANS=`egrep '^FCFANS=.*$' $1 | sed -e 's/FCFANS=//g'`
58       
59        # Check whether all mandatory settings are set
60        if [[ -z ${INTERVAL} || -z ${FCTEMPS} || -z ${MINTEMP} || -z ${MAXTEMP} || -z ${MINSTART} || -z ${MINSTOP} ]]
61        then
62                echo "Some mandatory settings missing, please check your config file!"
63                exit 1
64        fi
65        # here the other settings should be verified
66       
67
68        # write settings to arrays for easier use and print them
69        echo
70        echo "Common settings:"
71        echo "  INTERVAL=$INTERVAL"
72                                               
73        let fcvcount=0
74        for fcv in $FCTEMPS
75        do
76                AFCPWM[$fcvcount]=`echo $fcv |cut -d'=' -f1`
77                AFCTEMP[$fcvcount]=`echo $fcv |cut -d'=' -f2`
78                AFCFAN[$fcvcount]=`echo $FCFANS |sed -e 's/ /\n/g' |egrep "${AFCPWM[$fcvcount]}" |cut -d'=' -f2`
79                AFCMINTEMP[$fcvcount]=`echo $MINTEMP |sed -e 's/ /\n/g' |egrep "${AFCPWM[$fcvcount]}" |cut -d'=' -f2`
80                AFCMAXTEMP[$fcvcount]=`echo $MAXTEMP |sed -e 's/ /\n/g' |egrep "${AFCPWM[$fcvcount]}" |cut -d'=' -f2`
81                AFCMINSTART[$fcvcount]=`echo $MINSTART |sed -e 's/ /\n/g' |egrep "${AFCPWM[$fcvcount]}" |cut -d'=' -f2`
82                AFCMINSTOP[$fcvcount]=`echo $MINSTOP |sed -e 's/ /\n/g' |egrep "${AFCPWM[$fcvcount]}" |cut -d'=' -f2`
83                echo
84                echo "Settings for ${AFCPWM[$fcvcount]}:"
85                echo "  Depends on ${AFCTEMP[$fcvcount]}"
86                echo "  Controls ${AFCFAN[$fcvcount]}"
87                echo "  MINTEMP=${AFCMINTEMP[$fcvcount]}"
88                echo "  MAXTEMP=${AFCMAXTEMP[$fcvcount]}"
89                echo "  MINSTART=${AFCMINSTART[$fcvcount]}"
90                echo "  MINSTOP=${AFCMINSTOP[$fcvcount]}"
91                let fcvcount=fcvcount+1
92        done
93        echo
94}
95
96if [ -f "$1" ]
97then
98        LoadConfig $1
99else
100        LoadConfig /etc/fancontrol
101fi
102
103DIR=/proc/sys/dev/sensors
104if [ ! -d $DIR ]
105then
106        # For Linux 2.6, detect if config file uses the hwmon class or not yet
107        if echo "${AFCPWM[0]}" | egrep -q '^hwmon[0-9]'
108        then
109                SDIR=/sys/class/hwmon
110        else
111                SDIR=/sys/bus/i2c/devices
112        fi
113
114        if [ ! -d $SDIR ]
115        then
116                echo $0: 'No sensors found! (did you load the necessary modules?)'
117                exit 1
118        else
119                SYSFS=1
120                DIR=$SDIR
121        fi     
122fi
123cd $DIR
124
125# $1 = pwm file name
126function pwmdisable()
127{
128        if [ -n "$SYSFS" ]
129        then
130                ENABLE=${1}_enable
131                # No enable file? Just set to max
132                if [ ! -f $ENABLE ]
133                then
134                        echo $MAX > $1
135                        return 0
136                fi
137
138                # Try pwmN_enable=0
139                echo 0 > $ENABLE 2> /dev/null
140                if [ `cat $ENABLE` -eq 0 ]
141                then
142                        # Success
143                        return 0
144                fi
145
146                # It didn't work, try pwmN_enable=1 pwmN=255
147                echo 1 > $ENABLE 2> /dev/null
148                echo $MAX > $1
149                if [ `cat $ENABLE` -eq 1 -a `cat $1` -ge 190 ]
150                then
151                        # Success
152                        return 0
153                fi
154
155                # Nothing worked
156                echo "$ENABLE stuck to" `cat $ENABLE` >&2
157                return 1
158        else
159                echo $MAX 0 > $1
160        fi
161}
162
163# $1 = pwm file name
164function pwmenable()
165{
166        if [ "$SYSFS" = "1" ]
167        then
168                ENABLE=${1}_enable
169                if [ -f $ENABLE ]
170                then
171                        echo 1 > $ENABLE 2> /dev/null
172                        if [ $? -ne 0 ]
173                        then
174                                return 1
175                        fi
176                fi
177                echo $MAX > $1
178        else
179                echo $MAX 1 > $1
180        fi
181}
182
183function restorefans()
184{
185        echo 'Aborting, restoring fans...'
186        let fcvcount=0
187        while (( $fcvcount < ${#AFCPWM[@]} )) # go through all pwm outputs
188        do
189                pwmo=${AFCPWM[$fcvcount]}
190                pwmdisable $pwmo
191                let fcvcount=$fcvcount+1
192        done
193        echo 'Verify fans have returned to full speed'
194        exit 1
195}
196
197trap restorefans SIGHUP SIGINT SIGQUIT SIGTERM SIGKILL
198
199# main function
200function UpdateFanSpeeds {
201        let fcvcount=0
202        while (( $fcvcount < ${#AFCPWM[@]} )) # go through all pwm outputs
203        do
204                #hopefully shorter vars will improve readability:
205                pwmo=${AFCPWM[$fcvcount]}
206                tsens=${AFCTEMP[$fcvcount]}
207                fan=${AFCFAN[$fcvcount]}
208                mint=${AFCMINTEMP[$fcvcount]}
209                maxt=${AFCMAXTEMP[$fcvcount]}
210                minsa=${AFCMINSTART[$fcvcount]}
211                minso=${AFCMINSTOP[$fcvcount]}
212               
213                read tval < ${tsens}
214                if [ $? -ne 0 ]
215                then
216                        echo "Error reading temperature from $DIR/$tsens"
217                        restorefans
218                fi
219                if [ "$SYSFS" = "1" ]
220                then
221                        let tval="($tval+500)/1000"
222                else
223                        tval=`echo ${tval} | cut -d' ' -f3 | cut -d'.' -f1`
224                fi
225
226                read pwmpval < ${pwmo}
227                if [ $? -ne 0 ]
228                then
229                        echo "Error reading PWM value from $DIR/$pwmo"
230                        restorefans
231                fi
232                if [ "$SYSFS" != "1" ]
233                then
234                        pwmpval=`echo ${pwmpval} | cut -d' ' -f1`
235                fi
236               
237                # If fanspeed-sensor output shall be used, do it
238                if [[ -n ${fan} ]]
239                then
240                        read fanval < ${fan}
241                        if [ $? -ne 0 ]
242                        then
243                                echo "Error reading Fan value from $DIR/$fan"
244                                restorefans
245                        fi
246                        if [ "$SYSFS" != "1" ]
247                        then
248                                fanval=`echo ${fanval} | cut -d' ' -f2`
249                        fi
250                else
251                        fanval=1  # set it to a non zero value, so the rest of the script still works
252                fi
253               
254                # debug info
255                if [ "$DEBUG" != "" ]
256                then
257                        echo "pwmo=$pwmo"
258                        echo "tsens=$tsens"
259                        echo "fan=$fan"
260                        echo "mint=$mint"
261                        echo "maxt=$maxt"
262                        echo "minsa=$minsa"
263                        echo "minso=$minso"
264                        echo "tval=$tval"
265                        echo "pwmpval=$pwmpval"
266                        echo "fanval=$fanval"
267                fi
268               
269                if (( $tval <= $mint ))
270                  then pwmval=0 # at specified mintemp shut fan off
271                elif (( $tval >= $maxt ))
272                  then pwmval=255 # at specified maxtemp switch to 100%
273                else
274                  # calculate the new value from temperature and settings
275                  let pwmval="((${tval}-${mint})**2)*(255-${minso})/((${maxt}-${mint})**2)+${minso}"
276                  if [ $pwmpval -eq 0 -o $fanval -eq 0 ]
277                  then # if fan was stopped start it using a safe value
278                        echo $minsa > $pwmo
279                        sleep 1
280                  fi
281                fi
282                echo $pwmval > $pwmo # write new value to pwm output
283                if [ $? -ne 0 ]
284                then
285                        echo "Error writing PWM value to $DIR/$pwmo"
286                        restorefans
287                fi
288                if [ "$DEBUG" != "" ]
289                then
290                        echo "new pwmval=$pwmval"
291                fi
292                let fcvcount=$fcvcount+1
293        done
294}
295
296echo 'Enabling PWM on fans...'
297let fcvcount=0
298while (( $fcvcount < ${#AFCPWM[@]} )) # go through all pwm outputs
299do
300        pwmo=${AFCPWM[$fcvcount]}
301        pwmenable $pwmo
302        if [ $? -ne 0 ]
303        then
304                echo "Error enabling PWM on $DIR/$pwmo"
305                restorefans
306        fi
307        let fcvcount=$fcvcount+1
308done
309
310echo 'Starting automatic fan control...'
311
312# main loop calling the main function at specified intervals
313while true
314do
315        UpdateFanSpeeds
316        sleep $INTERVAL
317done
Note: See TracBrowser for help on using the browser.