Skip to content

Instantly share code, notes, and snippets.

@DrSpeedy
Created April 13, 2020 14:53
Show Gist options
  • Save DrSpeedy/1c489c31dbf45575d4a3d7c21c6ea2da to your computer and use it in GitHub Desktop.
Save DrSpeedy/1c489c31dbf45575d4a3d7c21c6ea2da to your computer and use it in GitHub Desktop.
#!/bin/local/bash
# cfan.sh
# Manaual control over fans in PfSense (FreeBSD) on a Dell PowerEdge R210 ii system
# Original script: https://www.garron.me/en/bits/specify-editor-crontab-file.html
# Install:
# sudo pkg install bash && sudo pkg install ipmitool
# Add ipmi_load="YES" to /boot/loader.conf
# Add this script to /usr/bin/
# Add * * * * * /usr/local/bin/bash /usr/bin/cfan.sh to cron file with sudo crontab -e
# Reboot
temp_min=30
temp_max=70
fan_min=20
fan_max=100
# Percentage of the old reading which will be used to calculate the new fan speed
force=75
# Seconds between each reading
delay=3
# Average only when difference is less than
avg_skip=15
echo "Fan control started"
fan_speed_old=64
if [ -f "/tmp/last_speed" ]; then
fan_speed_old=$(sed -n '1p' < "/tmp/last_speed")
echo "Last speed was $fan_speed_old"
fi
# Enable manual control
ipmitool raw 0x30 0x30 0x01 0x00 > /dev/null 2>&1
while true; do
# Edit to work on BSD systems
CURRENT_TEMP=`sysctl dev.cpu | grep temperature | awk '{print $2}'`
AVERAGE_TEMP=0
NUMBER_OF_CORES=0
#Take the average temperature reading of all cores
for core_temp in $CURRENT_TEMP; do
# Remove "C" from the end of the readings
core_temp=`echo "$core_temp" | sed 's/.$//'`
AVERAGE_TEMP=`echo "$AVERAGE_TEMP + $core_temp" | bc -l`
NUMBER_OF_CORES=`echo "$NUMBER_OF_CORES + 1" | bc -l`
done
temp=`echo "scale=0; $AVERAGE_TEMP / $NUMBER_OF_CORES" | bc -l`
# End edit
echo "CPU Temp: $temp"
fan_speed=$((($temp-$temp_min)*($fan_max-$fan_min)/($temp_max-$temp_min)+$fan_min))
res=$(echo "$fan_speed-$fan_speed_old" | bc)
if [[ "$res" -lt 0 ]] ; then
res=$(echo `expr 0 - $res`)
fi
if [[ $res -lt $avg_skip ]]; then
echo " Averaging:"
cforce=$(echo "scale=2;$force/100" | bc)
old=$(echo "scale=2;$fan_speed_old*$cforce" | bc -l)
echo -e " Old speed $old"
cforce=$(echo "scale=2;1-$cforce" | bc)
new=$(echo "scale=2;$fan_speed*$cforce" | bc -l)
echo -e " New speed $new"
fan_speed=$(echo "scale=0;$old+$new" | bc)
fan_speed=$(echo "($fan_speed+0.5)/1" | bc )
echo -e " Fan speed: $fan_speed"
fi
fan_speed_old=$fan_speed
if [[ $fan_speed -lt $fan_min ]]; then
fan_speed=$fan_min
elif [[ $fan_speed -gt $fan_max ]]; then
fan_speed=$fan_max
fi
cmd="0x30 0x30 0x02 0xff 0x$fan_speed"
echo "Command: $cmd"
# Set fan speed
ipmitool raw $cmd > /dev/null 2>&1
current=$(date +"%S")
current=$(echo $current | sed 's/^0*//')
if [[ $current -gt 51 ]]; then
echo $fan_speed_old > /tmp/last_speed
sleep 1
exit
fi
echo -e ""
sleep $delay
done
@sotiris-bos
Copy link

sotiris-bos commented May 1, 2021

Thanks for this, however there is a problem.

You are sending the $fan_speed variable as decimal while the DELL IPMI needs hex. This is problematic with low fan speed values.

I fixed it by modifying lines ~86-89:

 fan_speed_hex=$(printf '%x\n' $fan_speed)

cmd="0x30 0x30 0x02 0xff 0x$fan_speed_hex"
echo "Command: $cmd"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment