2015-12-11 14:03:37 -07:00

286 lines
11 KiB
Bash
Executable File

#!/bin/bash
#=======================================================================================
# Name: autofan
#=======================================================================================
# Description:
#
# A simple script to check for the highest hard disk temperature and then set the
# fan to an apropriate speed. Fan needs to be connected to a motherboard with pwm
# support.
#
# How to invoke in your "go" script (copy to /boot/scripts):
# chmod +x /boot/scripts/fan_speed.sh -- superseeded by Dynamix plugin
# /boot/fan_speed.sh -- superseeded by Dynamix plugin
#=======================================================================================
# Version 1.0 Authored by Aiden
# Version 1.1 Modified by Dan Stroot to run in a loop. Does not require the user
# to add this to cron - just start it in your go file.
# Version 1.2 Modified by Guzzi - removed -d ata to work on sas controllers
# Version 1.3 Modified by gfjardim - added to dynamix.system.autofan
# Version 1.4 Modified by Bergware - added additional line parameters
# start/stop control by Dynamix plugin
#=======================================================================================
# Dependencies: grep,awk,smartctl,hdparm
#=======================================================================================
version=1.4
program_name="autofan"
usage() {
echo "Usage: $program_name [-t min_temp] [-T max_temp] [-m loop in minutes] [-c controller] [-f fan] [-l low]"
echo " $program_name -V = print program version "
echo " $program_name -q = quit the program if it is running"
echo
echo " Argument descriptions:"
echo " -t NN = set the low disk temp, below this temp the fan is off (default=35)"
echo " -T NN = set the high disk temp, above this temp the fan is 100% (default=45)"
echo " -c name = specify name of the controller (default=/sys/class/hwmon/hwmon2/pwm1)"
echo " -f name = specify name of the fan (default=/sys/class/hwmon/hwmon2/fan1_input)"
echo " -l NN = set value to slow down the fan speed (default=35)"
echo " -m NN = number of minutes to wait between fan speed changes (default=5)"
}
#=======================================================================================
# USER DEFINED VARIABLES: *MUST* BE SET TO *YOUR* VALUES
#=======================================================================================
# Fan device. Depends on *your* system. pwmconfig can help with finding this out.
# pwm1 is usually the cpu fan. You can "cat /sys/class/hwmon/hwmon1/device/fan4_input"
# to see the current rpm of the fan. If 0 then fan is off or there is no fan connected
# or motherboard can't read rpm of fan.
PWM_CONTROLLER=/sys/class/hwmon/hwmon2/pwm1 # Power (speed) setting
PWM_FAN=/sys/class/hwmon/hwmon2/fan1_input # Used to track actual rpm values
# Temperature boundaries
TEMP_LOW=35 # Anything this number and below - fan is *off*
TEMP_HIGH=45 # Anything this number and above - fan is *full*
# Fan speed settings. Run pwmconfig (part of the lm_sensors package) to determine
# what numbers you want to use for your fan pwm settings. Should not need to
# change the OFF variable, only the LOW and maybe also HIGH to what you desire.
# Any real number between 0 and 255.
PWM_OFF=30 # Off Value (note: many PWM fans will not turn off)
PWM_LOW=35 # Value to make your fan go slow
PWM_HIGH=255 # Value to make your fan go fast
INTERVAL=5 # The default number of minutes to loop
#=======================================================================================
# PROGRAM LOGIC - CHANGE AT YOUR PERIL ;)
#=======================================================================================
# Get User Input
while getopts "t:T:m:c:f:l:qhV" opt; do
case $opt in
t) TEMP_LOW=$OPTARG ;;
T) TEMP_HIGH=$OPTARG ;;
m) INTERVAL=$OPTARG ;;
c) PWM_CONTROLLER=$OPTARG ;;
f) PWM_FAN=$OPTARG ;;
l) PWM_LOW=$OPTARG ;;
V) echo $program_name version: $version ; exit 0 ;;
h) usage >&2 ; exit 0 ;;
q) quit_flag="yes" ;;
\?) usage >&2 ; exit 0 ;;
esac
done
show_values() {
echo TEMP_LOW=$TEMP_LOW
echo TEMP_HIGH=$TEMP_HIGH
echo PWM_OFF=$PWM_OFF
echo PWM_LOW=$PWM_LOW
echo PWM_HIGH=$PWM_HIGH
echo INTERVAL=$INTERVAL
}
#show_values # uncomment for debugging
# validate the fan off temp
cc="$(echo $TEMP_LOW | sed 's/[0-9]//g')"
if [[ ! -z $cc ]]; then
echo "Error: min fan temp must be numeric (whole number, not negative)." >&2
usage >&2
exit 2
fi
# validate the fan high temp
cc="$(echo $TEMP_HIGH | sed 's/[0-9]//g')"
if [[ ! -z $cc ]]; then
echo "Error: max fan temp must be numeric (whole number, not negative)." >&2
usage >&2
exit 2
fi
# validate the minutes
cc="$(echo $INTERVAL | sed 's/[0-9]//g')"
if [[ ! -z $cc ]]; then
echo "Error: minutes must be numeric (whole number, not negative)." >&2
usage >&2
exit 2
fi
# Lockfile processing
lockfile="/var/run/${program_name}.pid"
if [[ -f $lockfile ]]; then
# The file exists so read the PID
# to see if it is still running
lock_pid=`head -n 1 "${lockfile}"`
pid_running=`ps -p "${lock_pid}" | grep ${lock_pid}`
if [[ -z $pid_running ]]; then
if [[ $quit_flag == no ]]; then
# The process is not running
# Echo current PID into lock file
echo $$ > "${lockfile}"
else
echo "$program_name ${lock_pid} is not currently running "
rm "${lockfile}"
fi
else
if [[ $quit_flag == yes ]]; then
echo killing $program_name process "$lock_pid"
echo killing $program_name process "$lock_pid" | logger -t$program_name
kill "$lock_pid"
rm "${lockfile}"
exit 0
else
echo "$program_name is already running [${lock_pid}]"
exit 2
fi
fi
else
if [[ $quit_flag == yes ]]; then
echo "$program_name not currently running "
exit 0
else
echo $$ > "${lockfile}"
fi
fi
# Obtain the ID of your flash drive (your flash drive is named "UnRaid" right?)
flash=/dev/`ls -l /dev/disk/by-label| grep UNRAID | cut -d/ -f3 | cut -c 1-3`
# Count the number of drives in your array (ignoring the flash drive we identified)
NUM_OF_DRIVES=$(ls /dev/[hs]d? | grep -v "$flash" | wc -l)
# Identify the drives in your array so we can test their temperature
COUNT=1
for d in $(ls /dev/[hs]d? | grep -v "$flash"); do
HD[$COUNT]=$d
#echo HDD=${HD[$COUNT]} # Uncomment for debugging
COUNT=$[$COUNT+1]
done
function_get_highest_hd_temp() {
HIGHEST_TEMP=0
for DISK in "${HD[@]}"; do
SLEEPING=`hdparm -C ${DISK} | grep -c standby`
if [[ $SLEEPING -eq 0 ]]; then
CURRENT_TEMP=`smartctl -A ${DISK} | grep -m 1 -i Temperature_Celsius | awk '{print $10}'`
if [[ $HIGHEST_TEMP -le $CURRENT_TEMP ]]; then
HIGHEST_TEMP=$CURRENT_TEMP
fi
fi
done
}
function_get_current_fan_speed() {
# Function to get current fan values
CURRENT_FAN_SPEED=`cat $PWM_CONTROLLER`
CURRENT_FAN_RPM=`cat $PWM_FAN`
CURRENT_PERCENT_SPEED=$(($(($CURRENT_FAN_SPEED*100))/$PWM_HIGH))
#echo Current Fan Speed = $CURRENT_FAN_SPEED # Uncomment for debugging
#echo Current Fan RPM = $CURRENT_FAN_RPM # Uncomment for debugging
#echo Current Percent Speed = $CURRENT_PERCENT_SPEED # Uncomment for debugging
if [[ $CURRENT_FAN_SPEED -le $PWM_OFF ]]; then
CURRENT_OUTPUT="OFF (0% @ 0rpm)"
#echo Current output = $CURRENT_OUTPUT # Uncomment for debugging
else
if [[ $CURRENT_FAN_SPEED -ge $PWM_HIGH ]]; then
CURRENT_OUTPUT="FULL (100% @ ${CURRENT_FAN_RPM}rpm)"
#echo Current output = $CURRENT_OUTPUT # Uncomment for debugging
else
CURRENT_OUTPUT="$CURRENT_FAN_SPEED (${CURRENT_PERCENT_SPEED}% @ ${CURRENT_FAN_RPM}rpm)"
#echo Current output = $CURRENT_OUTPUT # Uncomment for debugging
fi
fi
}
function_calc_new_fan_speed() {
# Calculate new fan values based on highest drive temperature
if [[ $HIGHEST_TEMP -le $TEMP_LOW ]]; then
ADJUSTED_FAN_SPEED=$PWM_OFF
ADJUSTED_PERCENT_SPEED=0
ADJUSTED_OUTPUT="OFF"
else
if [[ $HIGHEST_TEMP -ge $TEMP_HIGH ]]; then
ADJUSTED_FAN_SPEED=$PWM_HIGH
ADJUSTED_PERCENT_SPEED=100
ADJUSTED_OUTPUT="FULL"
else
ADJUSTED_FAN_SPEED=$(($(($(($HIGHEST_TEMP-$TEMP_LOW))*$FAN_PWM_INCREMENTS))+$PWM_LOW))
ADJUSTED_PERCENT_SPEED=$(($(($ADJUSTED_FAN_SPEED*100))/$PWM_HIGH))
ADJUSTED_OUTPUT=$ADJUSTED_FAN_SPEED
fi
fi
#echo Adjusted output = $ADJUSTED_OUTPUT # Uncomment for debugging
}
function_change_fan_speed() {
# Implemenent fan speed change if neeeded
if [[ $CURRENT_FAN_SPEED -ne $ADJUSTED_FAN_SPEED ]]; then
# Enable speed change on fan
if [[ `cat ${PWM_CONTROLLER}_enable` -ne 1 ]]; then
echo 1 > "${PWM_CONTROLLER}_enable"
fi
# set fan to new value
echo $ADJUSTED_FAN_SPEED > $PWM_CONTROLLER
sleep 5
# Get new rpm value
ADJUSTED_FAN_RPM=`cat $PWM_FAN`
ADJUSTED_OUTPUT="${ADJUSTED_OUTPUT} (${ADJUSTED_PERCENT_SPEED}% @ ${ADJUSTED_FAN_RPM}rpm)"
# Output the change
echo "$program_name: Highest disk temp is ${HIGHEST_TEMP}°C, adjusting fan speed from: $CURRENT_OUTPUT to: $ADJUSTED_OUTPUT"
echo "Highest disk temp is ${HIGHEST_TEMP}°C, adjusting fan speed from: $CURRENT_OUTPUT to: $ADJUSTED_OUTPUT" | logger -t$program_name
fi
}
# Main Loop
while [[ -f $lockfile ]]; do
# Just wait if modules aren't loaded
if [[ ! -f $PWM_FAN || ! -f $PWM_CONTROLLER ]]; then
sleep $(($INTERVAL*60));
continue;
fi
# Set PWM_OFF
PWM_OFF=$(($PWM_LOW-5)) # Off Value (note: many PWM fans will not turn off)
# Disable fan mininum RPM
FAN_RPM_MIN=$(echo ${PWM_FAN} | cut -d"_" -f1)"_min"
if [[ $(cat $FAN_RPM_MIN) -ne 0 ]]; then
echo 0 > $FAN_RPM_MIN
fi
# Calculate size of increments.
FAN_TEMP_INCREMENTS=$(($TEMP_HIGH-$TEMP_LOW))
FAN_PWM_INCREMENTS=$(($(($PWM_HIGH-$PWM_LOW))/$FAN_TEMP_INCREMENTS))
# Get highest drive temperature
function_get_highest_hd_temp
# Get current fan speed
function_get_current_fan_speed
# Calculate new fan speed
function_calc_new_fan_speed
# Change fan speed if necessary
function_change_fan_speed
#echo Sleeping for $INTERVAL minutes # uncomment for debugging
sleep $(($INTERVAL*60))
done &
# while loop was put into background, now disown it so it will continue to run when you log off.
# to get it to stop, type: rm /var/lock/fan_speed.LCK
background_pid=$!
echo $background_pid > "${lockfile}"
echo "$program_name process ID $background_pid started, To terminate it, type: $program_name -q" >&2
echo "$program_name process ID $background_pid started, To terminate it, type: $program_name -q" | logger -t$program_name
disown %%