Fancontrol
This program monitors temperatures of both system and hard drives and changes fan speeds accordingly.
C program fwcontrol.c
# Configuration file for fwcontrol
#
# Parameter Value Description
# ================+=============+===============================================
# control_by_sys | 0 or 1 | If set to 1 the fan is controlled by system
# | | temperatures like CPU/GPU or other internal
# | | sensors.
# control_by_hdd | 0 or 1 | If set to 1 the fan is controlled by hard
# | | drive temperatures.
# pwm_enable | filename | Used to set the fan mode.
# pwm_write | filename | Used to change the fan speed.
# sys_input | filename(s) | Defines which system temperature sensors
# | | should be checked. Values can be written comma
# | | separated and/or in multiple lines:
# | | sys_input=/path1/filename1,/path2/filename2...
# | | sys_input=/path6/filename6,/path7/filename7...
# | | ...
# temp_pwm_sys | temp,pwm | Defines the PWM value for a given system
# | | temperature: temp1,pwm1,temp2,pwm2,...
# interpolate_sys | 0 or 1 | If set to 1 the program calculates
# | | intermediate values between the data points
# | | defined in "temp_pwm_sys".
# hyst_sys | temp | System temperature must be decreased by at
# | | least this value until fan speed can be
# | | reduced.
# scan_hdd | device(s) | Defines which hard drives should be checked.
# | | Values can be written comma separated and/or
# | | in multiple lines:
# | | scan_hdd=/dev/<hdd1>,/dev/<hdd2>...
# | | scan_hdd=/dev/<hhd6>,/dev/<hdd7>...
# | | ...
# temp_pwm_hdd | temp,pwm | Defines the PWM value for a given hard drive
# | | temperature: temp1,pwm1,temp2,pwm2,...
# interpolate_hdd | 0 or 1 | If set to 1 the program calculates
# | | intermediate values between the data points
# | | defined in "temp_pwm_hdd".
# hyst_hdd | temp | Hard drive temperature must be decreased by at
# | | least this value until fan speed can be
# | | reduced.
# decrease_delay | seconds | Defines how many seconds must have passed
# | | since last speed increase until the speed can
# | | be decreased.
# stop_delay | seconds | Defines how many seconds must have passed
# | | since start of the fan until the fan can be
# | | stopped.
# idle_pwm | 0-255 | If the fan should be stopped but stop delay
# | | time has not yet passed, then the fan speed
# | | is set to this value.
# error_pwm_sys | 0-255 | If something goes wrong when reading the
# | | system temperatures then the fan speed is set
# | | to this value (default is 255).
# error_pwm_hdd | 0-255 | If something goes wrong when reading the hard
# | | drive temperatures then the fan speed is set
# | | to this value (default is 255).
# interval_sys | seconds | Check system temperatures every n seconds.
# interval_hdd | seconds | Check hard drive temperatures every n seconds.
# loglevel | 0 or 1 | If set to 1 then every speed change will be
# | | written to the logfile.
# ================+=============+===============================================
[CPU Cooler]
control_by_sys=1
control_by_hdd=0
pwm_enable=/sys/class/hwmon/hwmon2/pwm2_enable
pwm_write=/sys/class/hwmon/hwmon2/pwm2
sys_input=/sys/class/hwmon/hwmon1/temp1_input
temp_pwm_sys=0,34,41,34,61,114,70,255
interpolate_sys=1
hyst_sys=4
decrease_delay=30
stop_delay=120
idle_pwm=34
interval_sys=3
loglevel=1
[Front left]
control_by_sys=1
control_by_hdd=1
pwm_enable=/sys/class/hwmon/hwmon2/pwm3_enable
pwm_write=/sys/class/hwmon/hwmon2/pwm3
sys_input=/sys/class/hwmon/hwmon1/temp1_input
scan_hdd=/dev/sdb
temp_pwm_sys=0,76,42,108,48,144,54,186,60,255
temp_pwm_hdd=35,108,36,144,37,186,38,228,39,255
interpolate_sys=0
interpolate_hdd=0
hyst_sys=4
hyst_hdd=2
decrease_delay=30
stop_delay=120
idle_pwm=76
interval_sys=15
interval_hdd=60
loglevel=1
[Front right]
control_by_sys=1
control_by_hdd=1
pwm_enable=/sys/class/hwmon/hwmon2/pwm4_enable
pwm_write=/sys/class/hwmon/hwmon2/pwm4
sys_input=/sys/class/hwmon/hwmon1/temp1_input
scan_hdd=/dev/sdc,/dev/sdd,/dev/sde,/dev/sdf
temp_pwm_sys=60,255
temp_pwm_hdd=34,76,35,88,36,102,37,138,38,178,39,255
interpolate_sys=0
interpolate_hdd=0
hyst_sys=4
hyst_hdd=2
decrease_delay=30
stop_delay=120
idle_pwm=78
interval_sys=15
interval_hdd=60
loglevel=1
[Rear left]
control_by_sys=1
control_by_hdd=1
pwm_enable=/sys/class/hwmon/hwmon2/pwm1_enable
pwm_write=/sys/class/hwmon/hwmon2/pwm1
sys_input=/sys/class/hwmon/hwmon1/temp1_input
scan_hdd=/dev/sdb,/dev/sdc,/dev/sdd,/dev/sde,/dev/sdf
temp_pwm_sys=0,70,42,88,52,106,54,146,56,192,58,218,60,255
temp_pwm_hdd=36,106,37,146,38,192,39,255
interpolate_sys=0
interpolate_hdd=0
hyst_sys=4
hyst_hdd=2
decrease_delay=30
stop_delay=120
idle_pwm=70
interval_sys=15
interval_hdd=60
loglevel=1
[Rear right]
control_by_sys=1
control_by_hdd=1
pwm_enable=/sys/class/hwmon/hwmon2/pwm5_enable
pwm_write=/sys/class/hwmon/hwmon2/pwm5
sys_input=/sys/class/hwmon/hwmon1/temp1_input
scan_hdd=/dev/sdb,/dev/sdc,/dev/sdd,/dev/sde,/dev/sdf
temp_pwm_sys=50,86,52,104,54,142,56,188,58,210,60,255
temp_pwm_hdd=36,104,37,142,38,188,39,255
interpolate_sys=0
interpolate_hdd=0
hyst_sys=4
hyst_hdd=2
decrease_delay=30
stop_delay=120
idle_pwm=86
interval_sys=15
interval_hdd=60
loglevel=1
Configuration file /etc/fwcontrol.conf
# Configuration file for fwcontrol
#
# Parameter Value Description
# ================+=============+===============================================
# control_by_sys | 0 or 1 | If set to 1 the fan is controlled by system
# | | temperatures like CPU/GPU or other internal
# | | sensors.
# control_by_hdd | 0 or 1 | If set to 1 the fan is controlled by hard
# | | drive temperatures.
# pwm_enable | filename | Used to set the fan mode.
# pwm_write | filename | Used to change the fan speed.
# sys_input | filename(s) | Defines which system temperature sensors
# | | should be checked. Values can be written comma
# | | separated and/or in multiple lines:
# | | sys_input=/path1/filename1,/path2/filename2...
# | | sys_input=/path6/filename6,/path7/filename7...
# | | ...
# temp_pwm_sys | temp,pwm | Defines the PWM value for a given system
# | | temperature: temp1,pwm1,temp2,pwm2,...
# interpolate_sys | 0 or 1 | If set to 1 the program calculates
# | | intermediate values between the data points
# | | defined in "temp_pwm_sys".
# hyst_sys | temp | System temperature must be decreased by at
# | | least this value until fan speed can be
# | | reduced.
# scan_hdd | device(s) | Defines which hard drives should be checked.
# | | Values can be written comma separated and/or
# | | in multiple lines:
# | | scan_hdd=/dev/<hdd1>,/dev/<hdd2>...
# | | scan_hdd=/dev/<hhd6>,/dev/<hdd7>...
# | | ...
# temp_pwm_hdd | temp,pwm | Defines the PWM value for a given hard drive
# | | temperature: temp1,pwm1,temp2,pwm2,...
# interpolate_hdd | 0 or 1 | If set to 1 the program calculates
# | | intermediate values between the data points
# | | defined in "temp_pwm_hdd".
# hyst_hdd | temp | Hard drive temperature must be decreased by at
# | | least this value until fan speed can be
# | | reduced.
# decrease_delay | seconds | Defines how many seconds must have passed
# | | since last speed increase until the speed can
# | | be decreased.
# stop_delay | seconds | Defines how many seconds must have passed
# | | since start of the fan until the fan can be
# | | stopped.
# idle_pwm | 0-255 | If the fan should be stopped but stop delay
# | | time has not yet passed, then the fan speed
# | | is set to this value.
# error_pwm_sys | 0-255 | If something goes wrong when reading the
# | | system temperatures then the fan speed is set
# | | to this value (default is 255).
# error_pwm_hdd | 0-255 | If something goes wrong when reading the hard
# | | drive temperatures then the fan speed is set
# | | to this value (default is 255).
# interval_sys | seconds | Check system temperatures every n seconds.
# interval_hdd | seconds | Check hard drive temperatures every n seconds.
# loglevel | 0 or 1 | If set to 1 then every speed change will be
# | | written to the logfile.
# ================+=============+===============================================
[CPU Cooler]
control_by_sys=1
control_by_hdd=0
pwm_enable=/sys/class/hwmon/hwmon2/pwm2_enable
pwm_write=/sys/class/hwmon/hwmon2/pwm2
sys_input=/sys/class/hwmon/hwmon1/temp1_input
temp_pwm_sys=0,20,29,20,30,40,41,40,61,200,70,255
interpolate_sys=1
hyst_sys=4
decrease_delay=30
stop_delay=120
idle_pwm=20
interval_sys=3
loglevel=1
[Front left]
control_by_sys=1
control_by_hdd=1
pwm_enable=/sys/class/hwmon/hwmon2/pwm3_enable
pwm_write=/sys/class/hwmon/hwmon2/pwm3
sys_input=/sys/class/hwmon/hwmon1/temp1_input
scan_hdd=/dev/sdb
temp_pwm_sys=0,108,44,144,48,186,60,255
temp_pwm_hdd=35,108,36,144,37,186,38,228,39,255
interpolate_sys=0
interpolate_hdd=0
hyst_sys=4
hyst_hdd=2
decrease_delay=30
stop_delay=120
idle_pwm=78
interval_sys=15
interval_hdd=60
loglevel=1
[Front right]
control_by_sys=1
control_by_hdd=1
pwm_enable=/sys/class/hwmon/hwmon2/pwm4_enable
pwm_write=/sys/class/hwmon/hwmon2/pwm4
sys_input=/sys/class/hwmon/hwmon1/temp1_input
scan_hdd=/dev/sdc,/dev/sdd,/dev/sde,/dev/sdf
temp_pwm_sys=60,255
temp_pwm_hdd=34,120,35,138,36,156,37,178,38,222,39,255
interpolate_sys=0
interpolate_hdd=0
hyst_sys=4
hyst_hdd=2
decrease_delay=30
stop_delay=120
idle_pwm=78
interval_sys=15
interval_hdd=60
loglevel=1
[Rear left]
control_by_sys=1
control_by_hdd=1
pwm_enable=/sys/class/hwmon/hwmon2/pwm1_enable
pwm_write=/sys/class/hwmon/hwmon2/pwm1
sys_input=/sys/class/hwmon/hwmon1/temp1_input
scan_hdd=/dev/sdb,/dev/sdc,/dev/sdd,/dev/sde,/dev/sdf
temp_pwm_sys=0,80,42,88,46,106,50,146,54,218,60,255
temp_pwm_hdd=36,106,37,146,38,192,39,255
interpolate_sys=0
interpolate_hdd=0
hyst_sys=4
hyst_hdd=2
decrease_delay=30
stop_delay=120
idle_pwm=80
interval_sys=15
interval_hdd=60
loglevel=1
[Rear right]
control_by_sys=1
control_by_hdd=1
pwm_enable=/sys/class/hwmon/hwmon2/pwm5_enable
pwm_write=/sys/class/hwmon/hwmon2/pwm5
sys_input=/sys/class/hwmon/hwmon1/temp1_input
scan_hdd=/dev/sdb,/dev/sdc,/dev/sdd,/dev/sde,/dev/sdf
temp_pwm_sys=0,78,42,86,46,104,50,142,54,210,60,255
temp_pwm_hdd=36,104,37,142,38,188,39,255
interpolate_sys=0
interpolate_hdd=0
hyst_sys=4
hyst_hdd=2
decrease_delay=30
stop_delay=120
idle_pwm=78
interval_sys=15
interval_hdd=60
loglevel=1
Start fwcontrol during boot
Option 1: Using init script /etc/init.d/fwcontrol
#! /bin/sh
### BEGIN INIT INFO
# Provides: fwcontrol
# Required-Start: $syslog $remote_fs
# Required-Stop: $syslog $remote_fs
# Default-Start: 2 3 4 5
# Default-Stop:
# Short-Description: fwcontrol
# Description: Control of fan speeds
### END INIT INFO
NAME="fwcontrol"
DESC="Control of fan speeds"
DAEMON=/usr/sbin/${NAME}
FWUSER=root
PATH=/sbin:/bin:/usr/sbin:/usr/bin
test -f $DAEMON || exit 0
mkdir -p /var/run
PIDFILE=/var/run/${NAME}.pid
RETVAL=0
case "$1" in
start)
echo -n "Starting ${DESC}: "
start-stop-daemon --start --oknodo --quiet --background --make-pidfile --pidfile ${PIDFILE} --chuid ${FWUSER} --exec ${DAEMON}
RETVAL=$?
echo "${NAME}"
;;
stop)
echo -n "Stopping ${DESC}: "
start-stop-daemon --stop --oknodo --quiet --pidfile ${PIDFILE} --remove-pidfile --chuid ${FWUSER} --exec ${DAEMON}
RETVAL=$?
echo "${NAME}"
;;
restart|force-reload)
$0 stop
sleep 5
$0 start
RETVAL=$?
;;
*)
echo "Usage: /etc/init.d/${NAME} {start|stop|restart|force-reload}" >&2
exit 1
;;
esac
exit $RETVAL
Option 2: Using systemd service /etc/systemd/system/fwcontrol.service
[Unit]
Description=fwcontrol daemon
[Service]
Type=simple
Restart=on-failure
ExecStartPre=-/bin/bash -c '/usr/bin/killall -q fwcontrol; exit 0'
ExecStart=/usr/sbin/fwcontrol
ExecStop=/usr/bin/killall fwcontrol
[Install]
WantedBy=multi-user.target
Logfile Configuration
File /etc/rsyslog.d/10-fwcontrol.conf:
local0.* /var/log/fwcontrol.log
& stop
Logfile rotation configured in file /etc/logrotate.d/fwcontrol:
/var/log/fwcontrol.log {
weekly
rotate 4
compress
delaycompress
notifempty
missingok
}