Automatic fan control - Linksys WRT1900AC

Automatic fan control

Runs as a daemon, MUCH FASTER than a cron job

Create two files "fan_control" "fan_monitor" and UL them into the proper dir(s)

/etc/init.d/fan_control
All this script file does is start/stop the daemon and auto-start up at bootup

/usr/sbin/fan_monitor
All this script file does is to monitor temperatures and turn on/off the fan

Delete the stock cron job for fan control.

start/stop from the command line

/etc/init.d/fan_control start
/etc/init.d/fan_control stop

fan_control

#!/bin/sh /etc/rc.common

# put in /etc/init.d/fan_control

START=99

PIDFILE=/var/run/fan_monitor_pid

start() {
    start-stop-daemon -b -S -x /usr/sbin/fan_monitor -m -p $PIDFILE
}

stop() {
    start-stop-daemon -K -p $PIDFILE
}

fan_monitor

#!/bin/sh

# put in /usr/sbin/fan_monitor
# fan_monitor
# Utility script to monitor temperatures and turn on/off the fan in accordance
# with the original Belkin specs.

INTERVAL=30 # Poll every 30 seconds

# The fan will turn on if any of these temperatures is exceeded
CPU_ON=58   # Belkin default is 85
DDR_ON=48   # Belkin default is 65
WIFI_ON=51  # Belkin default is 105

# The fan will turn off if all of the temperatures are below these values
CPU_OFF=80  # Belkin default is 80
DDR_OFF=60  # Belkin default is 60
WIFI_OFF=70 # Belkin default is 100

old_pwm=-1

fan_set() {
    if $1; then
        pwm=255
    else
        pwm=0
    fi
    if [ "$pwm" -ne "$old_pwm" ]; then
        echo "Setting fan PWM to: $pwm"
        echo "$pwm" > /sys/devices/platform/pwm_fan/hwmon/hwmon0/pwm1
        old_pwm=$pwm
    fi
}

# Turn fan off when exiting
trap "{ fan_set false; exit; }" SIGINT SIGTERM

# Main fan control loop
while true
do
    cpu=`cat /sys/class/hwmon/hwmon2/temp1_input`
    ddr=`cat /sys/class/hwmon/hwmon1/temp1_input`
    wifi=`cat /sys/class/hwmon/hwmon1/temp2_input`

# Divide by 1000 to get temp values in C
    cpu=`expr $cpu / 1000`
    ddr=`expr $ddr / 1000`
    wifi=`expr $wifi / 1000`

    if [ "$cpu" -ge $CPU_ON \
        -o "$ddr" -ge $DDR_ON \
        -o "$wifi" -ge $WIFI_ON ]
    then
        fan_set true
    elif [ "$cpu" -le $CPU_OFF \
        -a "$ddr" -le $DDR_OFF \
        -a "$wifi" -le $WIFI_OFF ]
    then
        fan_set false
    fi

    sleep $INTERVAL &
    wait %1
done

Tip

Just use this code, run it from the command line. it will show REAL-TIME info.

Much easer to set the thresholds.

while true; do a=`cat /sys/class/hwmon/hwmon2/temp1_input`; b=`cat /sys/class/hwmon/hwmon1/temp1_input`; c=`cat /sys/class/hwmon/hwmon1/temp2_input`; d=`date +"%H:%M:%S"`; f=`cat /sys/devices/platform/pwm_fan/hwmon/hwmon0/pwm1`; echo $d cputemp=$(($a/1000))" "ddrtemp=$(($b/1000))" "wifitemp=$(($c/1000)) fanstatus=$f;sleep 1; done
2 Likes

Thanks for this! Happy new year

EDIT:
aren't these odd, your default "ON" values?

The fan will turn on if any of these temperatures is exceeded

CPU_ON=58 # Belkin default is 85
DDR_ON=48 # Belkin default is 65
WIFI_ON=51 # Belkin default is 105

The fan will turn off if all of the temperatures are below these values

CPU_OFF=80 # Belkin default is 80
DDR_OFF=60 # Belkin default is 60
WIFI_OFF=70 # Belkin default is 100

Without knowing the device in question, nor about eventual sensor quirks, but Belkin's defaults appear to be a bit high and quite taxing on the hardware.

You may want to take a look at my modified @gufus scripts. That is how I run my mamba, inside a cabinet, and the fan pretty much stays at 50%, unless under load and then I have never seen it go above 75%. I added some granularity, and temperature variance.

Edit: Here

1 Like

I agree, but looking at the default values here, the fan would:
turn on at 58 and off when below 80
turn on at 48 and off when below 60
turn on at 51 and off when below 70

All of the on values are technically under the off value?
Am I missing something?

Would you be able to upload a copy to your usual spot? Your files.tar doesn't have anything script wise in it for the fan control, and the only other way I see would be flashing your actual image.

EDIT: Thanks, got it! Looks much better.

I am working off a base of these files, and a copy from @anomeome

So far so good, but I have one more question :slight_smile: It works great as long as I issue the "start" command.

How are you tackling auto starting this at boot (reboot)? Simply by placing the fan_control in /etc/init.d ? Don't we need to execute our actual command "start"?

Where are you guys adding "/etc/init/d/fan_control start" during boot? (in /etc/rc.common as is in the header of fan_control ?)

EDIT: N/M got it, https://wiki.openwrt.org/doc/techref/initscripts

Seems we need to make a S and a K symlink from /etc/rc.d back to ../init.d/fan_control to cleanly start at boot and stop and shutdown

EDIT2: /etc/init.d/fan_control enable :wink:

Wow... Hey guys. Can someone make a simple install program to add fan control and see it on the LEDE's "Overview" and program setups somewhere in the "System" tabs. PLEASE! Don't make it confusing for us non-Linux folk.
The simpler you make it, the more people will use it.

How to install this?

As I currently run:

/etc/init.d/fan_control
#!/bin/sh /etc/rc.common
# Copyright (C) 2016-2017 LEDE-Project.org

START=65
STOP=80
USE_PROCD=1
#PROCD_DEBUG=1

boot() {
. /lib/functions.sh

board=$(board_name)

case "$board" in
linksys,wrt1900ac-v1)
    rc_procd start_service
    ;;
esac
}

start_service() {
    procd_open_instance
    procd_set_param command /usr/sbin/fan_monitor -b -a
    procd_set_param stdout 1
    procd_set_param stderr 1
    procd_close_instance
}
/usr/sbin/fan_monitor
#!/bin/sh

# put in /usr/sbin/fan_monitor
# fan_monitor
# Utility script to monitor temperatures and run fan at 50%/75%/100%
# For Reference the original Belkin specs.

INTERVAL=20  # sleep time in seconds between temp check
FANLOW=127   # low fan speed, set to 0 for off
FANMID=191   # mid fan speed
FANHI=255    # high fan speed

# Set fan to 100% on >= these temperatures
#CPU_HI=80000    # Belkin default is 85
#DDR_HI=58000    # Belkin default is 65
#WIFI_HI=75000   # Belkin default is 105

# Set fan to 75% <= these, otherwise 100% 
CPU_MID=80000     # Belkin sets no default
DDR_MID=58000     # Belkin sets no default
WIFI_MID=75000    # Belkin sets no default

# Set fan to 50% <= these temperatures
CPU_LOW=72000     # Belkin default is 80
DDR_LOW=52000     # Belkin default is 60
WIFI_LOW=55000    # Belkin default is 100

cur_pwm=0
new_pwm="$FANHI"  # start fan at HI while coming up

fan_set() {
    local ppwm
    cur_pwm=$1

    if [ "$1" -eq $FANLOW ]; then
        ppwm="50%"
    elif [ "$1" -eq $FANMID ]; then
        ppwm="75%"
    else
        ppwm="100%"
    fi

    logger -t FAN_MONITOR "Setting Fan to $ppwm"
    echo "$1" > /sys/devices/platform/pwm_fan/hwmon/hwmon0/pwm1
}

# Crank fan on exit
trap "{ logger -t FAN_MONITOR Fan monitor exiting; fan_set $FANHI; logger -t FAN_MONITOR as a precaution; exit; }" SIGINT SIGTERM

# Main fan control loop
while :
do
    if [ "$new_pwm" -ne "$cur_pwm" ]
    then
        fan_set "$new_pwm"
    fi
    sleep $INTERVAL

    cpu=`cat /sys/class/hwmon/hwmon2/temp1_input`
    ddr=`cat /sys/class/hwmon/hwmon1/temp1_input`
    wifi=`cat /sys/class/hwmon/hwmon1/temp2_input`

    if [ "$cpu" -le $CPU_LOW -a "$ddr" -le $DDR_LOW -a "$wifi" -le $WIFI_LOW ]
    then
        new_pwm="$FANLOW"
    elif [ "$cpu" -le $CPU_MID -a "$ddr" -le $DDR_MID -a "$wifi" -le $WIFI_MID ]
    then
        new_pwm="$FANMID"
    else
        new_pwm="$FANHI"
    fi
done

comment out current in /etc/crontabs/root jobs, check attributes on two files copied to device, and setup to run

/etc/init.d/cron reload
/etc/init.d/fan_control enable
/etc/init.d/fan_control start

Thank you for the response, if you don't mind, and if you have time to explain step by step how to implement this, what I need and where should I go. Im not familiar with Linux.

Hi
i did all as you wrote but service don't start after reboot
only when I start manually from command line or luci

Nothing I can add to the above in terms of making it work. Given the number of partition switching w reboots I have been doing to test kernel 5.10.x vs 5.15.x behaviour as of late, I can certainly attest to it kicking off on a reboot.

Hi. I modified your script for me. But it's not working, original your script also not working for me. I have wrt1900acs v2 with openwrt/immortalwrt 21.02

I get root@ImmortalWrt:~# /etc/init.d/fan_control enable: No such file or directory.common
and

root@ImmortalWrt:~# /bin/sh /usr/sbin/fan_monitor
: not foundan_monitor: line 2:
: not foundan_monitor: line 7:
: not foundan_monitor: line 12:
: not foundan_monitor: line 17:
: not foundan_monitor: line 22:
: not foundan_monitor: line 27:
: not foundan_monitor: line 30:
: not foundan_monitor: line 33:
/usr/sbin/fan_monitor: line 76: syntax error: unexpected end of file (expecting "then")

My script:

#!/bin/sh

# put in /usr/sbin/fan_monitor
# fan_monitor
# Utility script to monitor temperatures and run fan at 50%/75%/100%
# For Reference the original Belkin specs.

INTERVAL=20  # sleep time in seconds between temp check
FANLOW=127   # low fan speed, set to 0 for off
FANMID=191   # mid fan speed
FANHI=255    # high fan speed

# Set fan to 100% on >= these temperatures
#CPU_HI=80000    # Belkin default is 85
#DDR_HI=58000    # Belkin default is 65
#WIFI_HI=75000   # Belkin default is 105

# Set fan to 75% <= these, otherwise 100% 
CPU_MID=80000     # Belkin sets no default
DDR_MID=58000     # Belkin sets no default
WIFI_MID=75000    # Belkin sets no default

# Set fan to 50% <= these temperatures
CPU_LOW=72000     # Belkin default is 80
DDR_LOW=52000     # Belkin default is 60
WIFI_LOW=55000    # Belkin default is 100

cur_pwm=0
new_pwm="$FANHI"  # start fan at HI while coming up

fan_set() {
    cur_pwm=$1

    if [ "$1" -eq $FANLOW ]
    then
        ppwm="0"
    
    if [ "$1" -eq $FANMID ]
    then
        ppwm="1"
    else
        ppwm="2"
    fi

    logger -t FAN_MONITOR "Setting Fan to $ppwm"
    echo "$1" > /sys/class/leds/pca963x:cobra:amber:wps/brightness
}

# Crank fan on exit
trap "{ logger -t FAN_MONITOR Fan monitor exiting; fan_set $FANHI; logger -t FAN_MONITOR as a precaution; exit; }" SIGINT SIGTERM

# Main fan control loop
while :
do
    if [ "$new_pwm" -ne "$cur_pwm" ]
    then
        fan_set "$new_pwm"
    fi
    sleep $INTERVAL

    cpu=`cat /sys/class/hwmon/hwmon2/temp1_input`
    ddr=`cat /sys/class/hwmon/hwmon1/temp1_input`
    wifi=`cat /sys/class/hwmon/hwmon3/temp1_input`

    if [ "$cpu" -le $CPU_LOW -a "$ddr" -le $DDR_LOW -a "$wifi" -le $WIFI_LOW ]
    then
        new_pwm="$FANLOW"

    if [ "$cpu" -le $CPU_MID -a "$ddr" -le $DDR_MID -a "$wifi" -le $WIFI_MID ]
    then
        new_pwm="$FANMID"
    else
        new_pwm="$FANHI"
    fi
done

Doesn’t have a fan.

I configured script to switch on WAN led.

Please, I need help. I make script for turning on WPS led when temp is 65-70°. And connected my BC548 transistor base to WPS led positive terminal, fan to ground and transistor. But My fan is working all time, I don't understand why this happens.
Fan - 5v.
Led - 1,8v.