diff --git a/R710-IPMI-TEMP/R710-IPMIStatic.sh b/R710-IPMI-TEMP/R710-IPMIStatic.sh deleted file mode 100755 index a99dfa2..0000000 --- a/R710-IPMI-TEMP/R710-IPMIStatic.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/env bash - -# ---------------------------------------------------------------------------------- -# Script for setting manual fan speed to 2160 RPM (on my R710) -# -# Requires: -# ipmitool – apt-get install ipmitool -# slacktee.sh – https://github.com/course-hero/slacktee -# ---------------------------------------------------------------------------------- - - -# IPMI SETTINGS: -# Modify to suit your needs. -# DEFAULT IP: 192.168.0.120 -IPMIHOST=10.0.100.20 -IPMIUSER=root -IPMIPW=calvin -IPMIEK=0000000000000000000000000000000000000000 - -printf "Activating manual fan speeds! (2160 RPM)" | systemd-cat -t R710-IPMI-TEMP -echo "Activating manual fan speeds! (2160 RPM)" | slacktee.sh -t "R710-IPMI-TEMP [$(hostname)]" -ipmitool -I lanplus -H $IPMIHOST -U $IPMIUSER -P $IPMIPW -y $IPMIEK raw 0x30 0x30 0x01 0x00 -ipmitool -I lanplus -H $IPMIHOST -U $IPMIUSER -P $IPMIPW -y $IPMIEK raw 0x30 0x30 0x02 0xff 0x09 \ No newline at end of file diff --git a/R710-IPMI-TEMP/R710-IPMITemp.sh b/R710-IPMI-TEMP/R710-IPMITemp.sh deleted file mode 100755 index d2fcc00..0000000 --- a/R710-IPMI-TEMP/R710-IPMITemp.sh +++ /dev/null @@ -1,41 +0,0 @@ -#!/bin/bash - -# ---------------------------------------------------------------------------------- -# Script for checking the temperature reported by the ambient temperature sensor, -# and if deemed too high send the raw IPMI command to enable dynamic fan control. -# -# Requires: -# ipmitool – apt-get install ipmitool -# slacktee.sh – https://github.com/course-hero/slacktee -# ---------------------------------------------------------------------------------- - - -# IPMI SETTINGS: -# Modify to suit your needs. -# DEFAULT IP: 192.168.0.120 -IPMIHOST=10.0.100.20 -IPMIUSER=root -IPMIPW=calvin -IPMIEK=0000000000000000000000000000000000000000 - -# TEMPERATURE -# Change this to the temperature in celcius you are comfortable with. -# If the temperature goes above the set degrees it will send raw IPMI command to enable dynamic fan control -MAXTEMP=27 - -# This variable sends a IPMI command to get the temperature, and outputs it as two digits. -# Do not edit unless you know what you do. -TEMP=$(ipmitool -I lanplus -H $IPMIHOST -U $IPMIUSER -P $IPMIPW -y $IPMIEK sdr type temperature |grep Ambient |grep degrees |grep -Po '\d{2}' | tail -1) - - -if [[ $TEMP > $MAXTEMP ]]; - then - printf "Warning: Temperature is too high! Activating dynamic fan control! ($TEMP C)" | systemd-cat -t R710-IPMI-TEMP - echo "Warning: Temperature is too high! Activating dynamic fan control! ($TEMP C)" | /usr/bin/slacktee.sh -t "R710-IPMI-TEMP [$(hostname)]" - ipmitool -I lanplus -H $IPMIHOST -U $IPMIUSER -P $IPMIPW -y $IPMIEK raw 0x30 0x30 0x01 0x01 - else - # healthchecks.io - curl -fsS --retry 3 https://hchk.io/XXX >/dev/null 2>&1 - printf "Temperature is OK ($TEMP C)" | systemd-cat -t R710-IPMI-TEMP - echo "Temperature is OK ($TEMP C)" -fi diff --git a/R710-IPMI-TEMP/fan-speed-control.pl b/R710-IPMI-TEMP/fan-speed-control.pl new file mode 100755 index 0000000..9a3c6a3 --- /dev/null +++ b/R710-IPMI-TEMP/fan-speed-control.pl @@ -0,0 +1,165 @@ +#!/usr/bin/perl + +use strict; +use warnings; +use List::MoreUtils qw( apply ); + +my $static_speed_low=0x04; +my $static_speed_high=0x26; +my $ipmi_inlet_sensorname="Inlet Temp"; + +my $default_threshold=32; # the ambient temperature we use above + # which we default back to letting the drac + # control the fans +my $base_temp = 30; # no fans when below this temp +my $desired_temp1 = 40; # aim to keep the temperature below this +my $desired_temp2 = 50; # really ramp up fans above this +my $desired_temp3 = 55; # really ramp up fans above this +my $demand1 = 30; # demand at temp1 +my $demand2 = 100; # demand at temp2 +my $demand3 = 200; # demand at temp3 + +# check inlet temp every minute, hddtemp every minute (but FIXME: +# ensure doesn't spinup spundown disks), and sensors every few seconds + +my @ambient_ipmitemps=(); +my @hddtemps=(); +my @coretemps=(); +my @cputemps=(); + +my $current_mode; +my $lastfan; + +sub average { + my (@temps) = (@_); + + my $div = @temps; + my $tot = 0; + for (my $i = 0; $i < @temps ; $i++) { + $tot += $temps[$i]; + } + my $avg = sprintf "%.2f", $tot/$div; + return $avg; +} + +sub max { + my ($v1, $v2) = (@_); + + if ($v1 > $v2) { + return $v1; + } else { + return $v2; + } +} + +sub set_fans_default { + if (!defined $current_mode or $current_mode ne "default") { + $current_mode="default"; + $lastfan=undef; + print "--> enable dynamic fan control\n"; + system("ipmitool raw 0x30 0x30 0x01 0x01"); + } +} + +sub set_fans_servo { + my ($ambient_temp, $_cputemps, $_coretemps, $_hddtemps) = (@_); + my (@cputemps) = @$_cputemps; + my (@coretemps) = @$_coretemps; + my (@hddtemps) = @$_hddtemps; + + if (!defined $current_mode or $current_mode ne "set") { + $current_mode="set"; + print "--> disable dynamic fan control\n"; + system("ipmitool raw 0x30 0x30 0x01 0x00"); + } + + # two thirds weighted CPU temps vs hdd temps, but if the HDD temps + # creep above this value, use them exclusively (more important to + # keep them cool than the CPUs) + my $weighted_temp = max(average( + average(@cputemps), average(@coretemps), average(@hddtemps)), + average(@hddtemps)); + + print "weighted_temp = $weighted_temp ; ambient_temp $ambient_temp\n"; + + # FIXME: probably want to take into account ambient temperature - if + # the difference between weighted_temp and ambient_temp is small + # because ambient_temp is large, then less need to run the fans + # because there's still low power demands + my $demand = 0; # want demand to be a reading from 0-100% of + # $static_speed_low - $static_speed_high + if ($weighted_temp > $base_temp and + $weighted_temp < $desired_temp1) { + # slope m = (y2-y1)/(x2-x1) + # y - y1 = (x-x1)(y2-y1)/(x2-x1) + # y1 = 0 ; x1 = base_temp ; y2 = demand1 ; x2 = desired_temp1 + # x = weighted_temp + $demand = 0 + ($weighted_temp - $base_temp) * ($demand1 - 0)/($desired_temp1 - $base_temp); + } elsif ($weighted_temp >= $desired_temp2) { + # y1 = demand1 ; x1 = desired_temp1 ; y2 = demand2 ; x2 = desired_temp2 + $demand = $demand2 + ($weighted_temp - $desired_temp2) * ($demand3 - $demand2)/($desired_temp3 - $desired_temp2); + } elsif ($weighted_temp >= $desired_temp1) { + # y1 = demand1 ; x1 = desired_temp1 ; y2 = demand2 ; x2 = desired_temp2 + $demand = $demand1 + ($weighted_temp - $desired_temp1) * ($demand2 - $demand1)/($desired_temp2 - $desired_temp1); + } + $demand = int($static_speed_low + $demand/100*($static_speed_high-$static_speed_low)); + if ($demand>255) { + $demand=255; + } + if (!defined $lastfan or $demand < $lastfan or $demand > $lastfan + 1) { + $lastfan = $demand; + $demand = sprintf("0x%x", $demand); +# print "demand = $demand\n"; + print "--> ipmitool raw 0x30 0x30 0x02 0xff $demand\n"; + system("ipmitool raw 0x30 0x30 0x02 0xff $demand"); + } +} + +$SIG{TERM} = $SIG{INT} = sub { my $signame = shift ; $SIG{$signame} = 'DEFAULT' ; set_fans_default ; kill $signame, $$ }; + +my $last_reset_hddtemps=time; +my $last_reset_ambient_ipmitemps=time; +while () { + if (!@hddtemps) { + @hddtemps=`hddtemp /dev/sd? | grep [0-9]` + } + if (!@ambient_ipmitemps) { + @ambient_ipmitemps=`ipmitool sdr type temperature | grep "$ipmi_inlet_sensorname" | grep [0-9]` + } + @coretemps=`sensors | grep [0-9]`; + @cputemps=grep {/^Package id/} @coretemps; + @coretemps=grep {/^Core/} @coretemps; + + chomp @cputemps; + chomp @coretemps; + chomp @ambient_ipmitemps; + chomp @hddtemps; + + @cputemps = apply { s/.*: *([^ ]*)°C.*/$1/ } @cputemps; + @coretemps = apply { s/.*: *([^ ]*)°C.*/$1/ } @coretemps; + @ambient_ipmitemps = apply { s/.*\| ([^ ]*) degrees C.*/$1/ } @ambient_ipmitemps; + @hddtemps = apply { s/.*: *([^ ]*)°C.*/$1/ } @hddtemps; + + print "\n"; + + print "cputemps=", join (" ; ", @cputemps), "\n"; + print "coretemps=", join (" ; ", @coretemps), "\n"; + print "ambient_ipmitemps=", join (" ; ", @ambient_ipmitemps), "\n"; + print "hddtemps=", join (" ; ", @hddtemps), "\n"; + + my $ambient_temp = average(@ambient_ipmitemps); + # FIXME: hysteresis + if ($ambient_temp > $default_threshold) { + set_fans_default(); + } else { + set_fans_servo($ambient_temp, \@cputemps, \@coretemps, \@hddtemps); + } + + if (time - $last_reset_hddtemps > 60) { + @hddtemps=(); + } + if (time - $last_reset_ambient_ipmitemps > 60) { + @ambient_ipmitemps=(); + } + sleep 3; +} diff --git a/R710-IPMI-TEMP/hddtemp_smartctl-pinpoint=1576762993,1576823788.png b/R710-IPMI-TEMP/hddtemp_smartctl-pinpoint=1576762993,1576823788.png new file mode 100644 index 0000000..8b94a56 Binary files /dev/null and b/R710-IPMI-TEMP/hddtemp_smartctl-pinpoint=1576762993,1576823788.png differ diff --git a/R710-IPMI-TEMP/ipmi_fans-pinpoint=1576762993,1576823788.png b/R710-IPMI-TEMP/ipmi_fans-pinpoint=1576762993,1576823788.png new file mode 100644 index 0000000..0bb08c8 Binary files /dev/null and b/R710-IPMI-TEMP/ipmi_fans-pinpoint=1576762993,1576823788.png differ diff --git a/R710-IPMI-TEMP/ipmi_temp-pinpoint=1576762993,1576823788.png b/R710-IPMI-TEMP/ipmi_temp-pinpoint=1576762993,1576823788.png new file mode 100644 index 0000000..616de35 Binary files /dev/null and b/R710-IPMI-TEMP/ipmi_temp-pinpoint=1576762993,1576823788.png differ diff --git a/R710-IPMI-TEMP/readme.md b/R710-IPMI-TEMP/readme.md index eabfdfa..1e8df20 100755 --- a/R710-IPMI-TEMP/readme.md +++ b/R710-IPMI-TEMP/readme.md @@ -1,22 +1,46 @@ -# Safety BASH script -I made a BASH script to check the temperature, and if it's higher than XX (27 degrees C in my case) it sends a raw command to restore automatic fan control. +# fan speed controller for dell R710, R520 etc -I'm running this on an Ubuntu VM on ESXi (on the R710 box), but it should be able to run as long as you have ipmitools. It could be you need to modify the logging, to make it work with whatever your system use. +Dells don't like having third party cards installed, and ramp up the +fan speed to jetliner taking off. But you can override this. -I run the script via CRON every 5 minutes from my Ubuntu Server VM running on ESXi. +This speed controller uses ipmi raw commands that seem to be similar +across a wide range of dell server generations (google searches for +`ipmitool raw 0x30 0x30 0x01 0x00` show it works for R710, R730, T130, +and I run this on my R520 -`*/5 * * * * /bin/bash /path/to/script/R710-IPMITemp.sh > /dev/null 2>&1` +This script monitoring the ambient air temperature (you will likely +need to modify the $ipmi_inlet_sensorname variable to find the correct +sensor), the hdd temperatures, the core and socket temperatures +(weighted so one core shooting up if all the others are still cold - +let the heatsink do its job). -Notice that I use [healthchecks.io](https://healthchecks.io) in the script to notify if the temp goes to high (it would also trigger if the internet goes down for some reason). Remember to get your own check URL if you want it, or else just remove the curl command. +It uses setpoints and temperature ranges you can tune to your heart's +content. I use it to keep the fans low but increasing to a soft +volume up to 40 degrees, ramp it up quickly to 50degrees, then very +quickly towards full speed much beyond that. -I'm also currently testing out [slacktee.sh](https://github.com/course-hero/slacktee) to get notifications in my slack channel. +It's got a signal handler so it defaults to default behaviour when +killed by SIGINT/SIGTERM. + +I run it on my proxmox hypervisor directly, hence not needing any ipmi +passwords. I will start and stop it through proxmox's systemd system +once I have it firmly debugged. + +I wrote it the night before Australia's hottest December day on record +(hey we like our coal fondling prime-ministers). It seems to be +coping so far now that it has reached that predicted peak (I don't +believe it's only 26 in my un-air conditioned study). + +![Socket and ambient temperature on 20Dec2019](ipmi_temp-pinpoint=1576762993,1576823788.png) +![Hdd temp](hddtemp_smartctl-pinpoint=1576762993,1576823788.png) +![Core temp](sensors_temp-pinpoint=1576762993,1576823788.png) +![Resultant Fan speed](ipmi_fans-pinpoint=1576762993,1576823788.png) -The Scripts [Reddit thread](https://www.reddit.com/r/homelab/comments/779cha/manual_fan_control_on_r610r710_including_script/) ***** -# Howto: Setting the fan speed of the Dell R610/R710 +# Howto: Manually setting the fan speed of the Dell R610/R710 1. Enable IPMI in iDrac 2. Install ipmitool on linux, win or mac os @@ -61,8 +85,6 @@ _Note: The RPM may differ from model to model_ **Disclaimer** -I'm by no means good at IPMI, BASH scripting or regex, etc. but it seems to work fine for me. - TLDR; I take _NO_ responsibility if you mess up anything. ***** diff --git a/R710-IPMI-TEMP/sensors_temp-pinpoint=1576762993,1576823788.png b/R710-IPMI-TEMP/sensors_temp-pinpoint=1576762993,1576823788.png new file mode 100644 index 0000000..5aa8bb2 Binary files /dev/null and b/R710-IPMI-TEMP/sensors_temp-pinpoint=1576762993,1576823788.png differ