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

Revision 4442, 9.3 KB (checked in by khali, 6 years ago)

fancontrol:
* Check for configuration file validity
fancontrol and pwmconfig:
* Support optional min and max PWM values
Documentation updated accordingly.

  • 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.66
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#    Copyright (C) 2007 Jean Delvare <khali@linux-fr.org>
26#
27#    This program is free software; you can redistribute it and/or modify
28#    it under the terms of the GNU General Public License as published by
29#    the Free Software Foundation; either version 2 of the License, or
30#    (at your option) any later version.
31#
32#    This program is distributed in the hope that it will be useful,
33#    but WITHOUT ANY WARRANTY; without even the implied warranty of
34#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
35#    GNU General Public License for more details.
36#
37#    You should have received a copy of the GNU General Public License
38#    along with this program; if not, write to the Free Software
39#    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
40#
41#
42
43#DEBUG=1
44MAX=255
45
46echo $$ > /var/run/fancontrol.pid
47
48function LoadConfig {
49        echo "Loading configuration from $1 ..."
50        # grep configuration from file
51        INTERVAL=`egrep '^INTERVAL=.*$' $1 | sed -e 's/INTERVAL=//g'`
52        FCTEMPS=`egrep '^FCTEMPS=.*$' $1 | sed -e 's/FCTEMPS=//g'`
53        MINTEMP=`egrep '^MINTEMP=.*$' $1 | sed -e 's/MINTEMP=//g'`
54        MAXTEMP=`egrep '^MAXTEMP=.*$' $1 | sed -e 's/MAXTEMP=//g'`
55        MINSTART=`egrep '^MINSTART=.*$' $1 | sed -e 's/MINSTART=//g'`
56        MINSTOP=`egrep '^MINSTOP=.*$' $1 | sed -e 's/MINSTOP=//g'`
57        # optional settings:
58        FCFANS=`egrep '^FCFANS=.*$' $1 | sed -e 's/FCFANS=//g'`
59        MINPWM=`egrep '^MINPWM=.*$' $1 | sed -e 's/MINPWM=//g'`
60        MAXPWM=`egrep '^MAXPWM=.*$' $1 | sed -e 's/MAXPWM=//g'`
61       
62        # Check whether all mandatory settings are set
63        if [[ -z ${INTERVAL} || -z ${FCTEMPS} || -z ${MINTEMP} || -z ${MAXTEMP} || -z ${MINSTART} || -z ${MINSTOP} ]]
64        then
65                echo "Some mandatory settings missing, please check your config file!"
66                exit 1
67        fi
68        if [ "$INTERVAL" -le 0 ]
69        then
70                echo "Error in configuration file:"
71                echo "INTERVAL must be at least 1"
72                exit 1
73        fi
74
75        # write settings to arrays for easier use and print them
76        echo
77        echo "Common settings:"
78        echo "  INTERVAL=$INTERVAL"
79                                               
80        let fcvcount=0
81        for fcv in $FCTEMPS
82        do
83                AFCPWM[$fcvcount]=`echo $fcv |cut -d'=' -f1`
84                AFCTEMP[$fcvcount]=`echo $fcv |cut -d'=' -f2`
85                AFCFAN[$fcvcount]=`echo $FCFANS |sed -e 's/ /\n/g' |egrep "${AFCPWM[$fcvcount]}" |cut -d'=' -f2`
86                AFCMINTEMP[$fcvcount]=`echo $MINTEMP |sed -e 's/ /\n/g' |egrep "${AFCPWM[$fcvcount]}" |cut -d'=' -f2`
87                AFCMAXTEMP[$fcvcount]=`echo $MAXTEMP |sed -e 's/ /\n/g' |egrep "${AFCPWM[$fcvcount]}" |cut -d'=' -f2`
88                AFCMINSTART[$fcvcount]=`echo $MINSTART |sed -e 's/ /\n/g' |egrep "${AFCPWM[$fcvcount]}" |cut -d'=' -f2`
89                AFCMINSTOP[$fcvcount]=`echo $MINSTOP |sed -e 's/ /\n/g' |egrep "${AFCPWM[$fcvcount]}" |cut -d'=' -f2`
90                AFCMINPWM[$fcvcount]=`echo $MINPWM |sed -e 's/ /\n/g' |egrep "${AFCPWM[$fcvcount]}" |cut -d'=' -f2`
91                [ -z "${AFCMINPWM[$fcvcount]}" ] && AFCMINPWM[$fcvcount]=0
92                AFCMAXPWM[$fcvcount]=`echo $MAXPWM |sed -e 's/ /\n/g' |egrep "${AFCPWM[$fcvcount]}" |cut -d'=' -f2`
93                [ -z "${AFCMAXPWM[$fcvcount]}" ] && AFCMAXPWM[$fcvcount]=255
94
95                # verify the validity of the settings
96                if [ "${AFCMINTEMP[$fcvcount]}" -ge "${AFCMAXTEMP[$fcvcount]}" ]
97                then
98                        echo "Error in configuration file (${AFCPWM[$fcvcount]}):"
99                        echo "MINTEMP must be less than MAXTEMP"
100                        exit 1
101                fi
102                if [ "${AFCMAXPWM[$fcvcount]}" -gt 255 ]
103                then
104                        echo "Error in configuration file (${AFCPWM[$fcvcount]}):"
105                        echo "MAXPWM must be at most 255"
106                        exit 1
107                fi
108                if [ "${AFCMINSTOP[$fcvcount]}" -ge "${AFCMAXPWM[$fcvcount]}" ]
109                then
110                        echo "Error in configuration file (${AFCPWM[$fcvcount]}):"
111                        echo "MINSTOP must be less than MAXPWM"
112                        exit 1
113                fi
114                if [ "${AFCMINSTOP[$fcvcount]}" -lt "${AFCMINPWM[$fcvcount]}" ]
115                then
116                        echo "Error in configuration file (${AFCPWM[$fcvcount]}):"
117                        echo "MINSTOP must be greater than or equal to MINPWM"
118                        exit 1
119                fi
120                if [ "${AFCMINPWM[$fcvcount]}" -lt 0 ]
121                then
122                        echo "Error in configuration file (${AFCPWM[$fcvcount]}):"
123                        echo "MINPWM must be at least 0"
124                        exit 1
125                fi
126
127                echo
128                echo "Settings for ${AFCPWM[$fcvcount]}:"
129                echo "  Depends on ${AFCTEMP[$fcvcount]}"
130                echo "  Controls ${AFCFAN[$fcvcount]}"
131                echo "  MINTEMP=${AFCMINTEMP[$fcvcount]}"
132                echo "  MAXTEMP=${AFCMAXTEMP[$fcvcount]}"
133                echo "  MINSTART=${AFCMINSTART[$fcvcount]}"
134                echo "  MINSTOP=${AFCMINSTOP[$fcvcount]}"
135                echo "  MINPWM=${AFCMINPWM[$fcvcount]}"
136                echo "  MAXPWM=${AFCMAXPWM[$fcvcount]}"
137                let fcvcount=fcvcount+1
138        done
139        echo
140}
141
142if [ -f "$1" ]
143then
144        LoadConfig $1
145else
146        LoadConfig /etc/fancontrol
147fi
148
149DIR=/proc/sys/dev/sensors
150if [ ! -d $DIR ]
151then
152        # For Linux 2.6, detect if config file uses the hwmon class or not yet
153        if echo "${AFCPWM[0]}" | egrep -q '^hwmon[0-9]'
154        then
155                SDIR=/sys/class/hwmon
156        else
157                SDIR=/sys/bus/i2c/devices
158        fi
159
160        if [ ! -d $SDIR ]
161        then
162                echo $0: 'No sensors found! (did you load the necessary modules?)'
163                exit 1
164        else
165                SYSFS=1
166                DIR=$SDIR
167        fi     
168fi
169cd $DIR
170
171# $1 = pwm file name
172function pwmdisable()
173{
174        if [ -n "$SYSFS" ]
175        then
176                ENABLE=${1}_enable
177                # No enable file? Just set to max
178                if [ ! -f $ENABLE ]
179                then
180                        echo $MAX > $1
181                        return 0
182                fi
183
184                # Try pwmN_enable=0
185                echo 0 > $ENABLE 2> /dev/null
186                if [ `cat $ENABLE` -eq 0 ]
187                then
188                        # Success
189                        return 0
190                fi
191
192                # It didn't work, try pwmN_enable=1 pwmN=255
193                echo 1 > $ENABLE 2> /dev/null
194                echo $MAX > $1
195                if [ `cat $ENABLE` -eq 1 -a `cat $1` -ge 190 ]
196                then
197                        # Success
198                        return 0
199                fi
200
201                # Nothing worked
202                echo "$ENABLE stuck to" `cat $ENABLE` >&2
203                return 1
204        else
205                echo $MAX 0 > $1
206        fi
207}
208
209# $1 = pwm file name
210function pwmenable()
211{
212        if [ "$SYSFS" = "1" ]
213        then
214                ENABLE=${1}_enable
215                if [ -f $ENABLE ]
216                then
217                        echo 1 > $ENABLE 2> /dev/null
218                        if [ $? -ne 0 ]
219                        then
220                                return 1
221                        fi
222                fi
223                echo $MAX > $1
224        else
225                echo $MAX 1 > $1
226        fi
227}
228
229function restorefans()
230{
231        echo 'Aborting, restoring fans...'
232        let fcvcount=0
233        while (( $fcvcount < ${#AFCPWM[@]} )) # go through all pwm outputs
234        do
235                pwmo=${AFCPWM[$fcvcount]}
236                pwmdisable $pwmo
237                let fcvcount=$fcvcount+1
238        done
239        echo 'Verify fans have returned to full speed'
240        exit 1
241}
242
243trap restorefans SIGHUP SIGINT SIGQUIT SIGTERM SIGKILL
244
245# main function
246function UpdateFanSpeeds {
247        let fcvcount=0
248        while (( $fcvcount < ${#AFCPWM[@]} )) # go through all pwm outputs
249        do
250                #hopefully shorter vars will improve readability:
251                pwmo=${AFCPWM[$fcvcount]}
252                tsens=${AFCTEMP[$fcvcount]}
253                fan=${AFCFAN[$fcvcount]}
254                mint=${AFCMINTEMP[$fcvcount]}
255                maxt=${AFCMAXTEMP[$fcvcount]}
256                minsa=${AFCMINSTART[$fcvcount]}
257                minso=${AFCMINSTOP[$fcvcount]}
258                minpwm=${AFCMINPWM[$fcvcount]}
259                maxpwm=${AFCMAXPWM[$fcvcount]}
260               
261                read tval < ${tsens}
262                if [ $? -ne 0 ]
263                then
264                        echo "Error reading temperature from $DIR/$tsens"
265                        restorefans
266                fi
267                if [ "$SYSFS" = "1" ]
268                then
269                        let tval="($tval+500)/1000"
270                else
271                        tval=`echo ${tval} | cut -d' ' -f3 | cut -d'.' -f1`
272                fi
273
274                read pwmpval < ${pwmo}
275                if [ $? -ne 0 ]
276                then
277                        echo "Error reading PWM value from $DIR/$pwmo"
278                        restorefans
279                fi
280                if [ "$SYSFS" != "1" ]
281                then
282                        pwmpval=`echo ${pwmpval} | cut -d' ' -f1`
283                fi
284               
285                # If fanspeed-sensor output shall be used, do it
286                if [[ -n ${fan} ]]
287                then
288                        read fanval < ${fan}
289                        if [ $? -ne 0 ]
290                        then
291                                echo "Error reading Fan value from $DIR/$fan"
292                                restorefans
293                        fi
294                        if [ "$SYSFS" != "1" ]
295                        then
296                                fanval=`echo ${fanval} | cut -d' ' -f2`
297                        fi
298                else
299                        fanval=1  # set it to a non zero value, so the rest of the script still works
300                fi
301               
302                # debug info
303                if [ "$DEBUG" != "" ]
304                then
305                        echo "pwmo=$pwmo"
306                        echo "tsens=$tsens"
307                        echo "fan=$fan"
308                        echo "mint=$mint"
309                        echo "maxt=$maxt"
310                        echo "minsa=$minsa"
311                        echo "minso=$minso"
312                        echo "minpwm=$minpwm"
313                        echo "maxpwm=$maxpwm"
314                        echo "tval=$tval"
315                        echo "pwmpval=$pwmpval"
316                        echo "fanval=$fanval"
317                fi
318               
319                if (( $tval <= $mint ))
320                  then pwmval=$minpwm # below min temp, use defined min pwm
321                elif (( $tval >= $maxt ))
322                  then pwmval=$maxpwm # over max temp, use defined max pwm
323                else
324                  # calculate the new value from temperature and settings
325                  let pwmval="((${tval}-${mint})**2)*(${maxpwm}-${minso})/((${maxt}-${mint})**2)+${minso}"
326                  if [ $pwmpval -eq 0 -o $fanval -eq 0 ]
327                  then # if fan was stopped start it using a safe value
328                        echo $minsa > $pwmo
329                        sleep 1
330                  fi
331                fi
332                echo $pwmval > $pwmo # write new value to pwm output
333                if [ $? -ne 0 ]
334                then
335                        echo "Error writing PWM value to $DIR/$pwmo"
336                        restorefans
337                fi
338                if [ "$DEBUG" != "" ]
339                then
340                        echo "new pwmval=$pwmval"
341                fi
342                let fcvcount=$fcvcount+1
343        done
344}
345
346echo 'Enabling PWM on fans...'
347let fcvcount=0
348while (( $fcvcount < ${#AFCPWM[@]} )) # go through all pwm outputs
349do
350        pwmo=${AFCPWM[$fcvcount]}
351        pwmenable $pwmo
352        if [ $? -ne 0 ]
353        then
354                echo "Error enabling PWM on $DIR/$pwmo"
355                restorefans
356        fi
357        let fcvcount=$fcvcount+1
358done
359
360echo 'Starting automatic fan control...'
361
362# main loop calling the main function at specified intervals
363while true
364do
365        UpdateFanSpeeds
366        sleep $INTERVAL
367done
Note: See TracBrowser for help on using the browser.