diff --git a/power-fancontrol.pl b/power-fancontrol.pl new file mode 100644 index 0000000..c735947 --- /dev/null +++ b/power-fancontrol.pl @@ -0,0 +1,124 @@ +#!/usr/bin/perl + +# notable changes: this uses corsairpsu power to adjust sys fans, see line +# 59 onwards on re: how to adjust the used sensor. + +use strict; +use warnings; +use List::Util qw[min max]; + +my $min_temp_change = 3; # °C minimum change to actually cause a fan speed update +my $min_power_change = 30; # W, minimum change to do something +my $seconds_to_sleep = 4; # Number of seconds to sleep between update loops + +# 0x64 = 100, 0x00 = 0. +# CPU Temp -> Fan Speed Mappings +my %cpu_temp_to_fan_speed; + $cpu_temp_to_fan_speed{80} = 0x64; + $cpu_temp_to_fan_speed{75} = 0x62; + $cpu_temp_to_fan_speed{70} = 0x56; + $cpu_temp_to_fan_speed{65} = 0x52; + $cpu_temp_to_fan_speed{60} = 0x48; + $cpu_temp_to_fan_speed{55} = 0x46; + $cpu_temp_to_fan_speed{50} = 0x42; + $cpu_temp_to_fan_speed{45} = 0x40; + $cpu_temp_to_fan_speed{40} = 0x36; + $cpu_temp_to_fan_speed{35} = 0x34; + $cpu_temp_to_fan_speed{30} = 0x32; + +# SYS Power -> Fan Speed Mappings +my %sys_power_to_fan_speed; + $sys_power_to_fan_speed{550} = 0x64; + $sys_power_to_fan_speed{525} = 0x62; + $sys_power_to_fan_speed{500} = 0x60; + $sys_power_to_fan_speed{475} = 0x56; + $sys_power_to_fan_speed{450} = 0x54; + $sys_power_to_fan_speed{425} = 0x52; + $sys_power_to_fan_speed{400} = 0x50; + $sys_power_to_fan_speed{375} = 0x46; + $sys_power_to_fan_speed{350} = 0x44; + $sys_power_to_fan_speed{325} = 0x42; + $sys_power_to_fan_speed{300} = 0x38; + $sys_power_to_fan_speed{275} = 0x36; + $sys_power_to_fan_speed{250} = 0x32; + $sys_power_to_fan_speed{225} = 0x30; + $sys_power_to_fan_speed{200} = 0x30; + $sys_power_to_fan_speed{175} = 0x30; + $sys_power_to_fan_speed{150} = 0x30; + $sys_power_to_fan_speed{125} = 0x30; + $sys_power_to_fan_speed{100} = 0x30; + +my $g_current_sys_fan_duty_cycle = 0; +my $g_current_cpu_fan_duty_cycle = 0; +my $g_current_cpu_temp = 0; +my $g_current_sys_power = 0; +my $g_last_set_cpu_temp = 0; +my $g_last_set_sys_power = 0; + +sub UpdateFanSpeed { + my $current_cpu_temp = `sensors k10temp-pci-00c3 | grep 'Tctl:' | cut -c 16-17 | tr -d '\n'`; + my $current_sys_power = `sensors \$(sensors |grep corsairpsu) | grep 'power total:' | cut -c 14-16 | tr -d '\n'`; + my $cpu_temp_difference = 0; + my $sys_power_difference = 0; + + $g_current_cpu_temp = $current_cpu_temp; + $g_current_sys_power = $current_sys_power; + + my $desired_cpu_fan_speed = 0x0; + my $desired_sys_fan_speed = 0x0; + + my @cpu_temps = keys %cpu_temp_to_fan_speed; + for my $cpu_temp (@cpu_temps) { + if( $current_cpu_temp >= $cpu_temp ) { + $desired_cpu_fan_speed = max( $cpu_temp_to_fan_speed{ $cpu_temp }, $desired_cpu_fan_speed ); + } + } + + my @sys_powers = keys %sys_power_to_fan_speed; + for my $sys_power (@sys_powers) { + #for my $sys_temp (@sys_temps) { + if( $current_sys_power >= $sys_power ) { + $desired_sys_fan_speed = max( $sys_power_to_fan_speed{ $sys_power }, $desired_sys_fan_speed ); + } + } + + if( $desired_cpu_fan_speed == 0x0 ) { + print "\n***** ERROR: Failed to determine a desired fan speed. Forcing CPU fans to 100% duty cycle as a safety fallback measure. *****\n"; + $desired_cpu_fan_speed = 0x64; + } + + if( $desired_sys_fan_speed == 0x0 ) { + print "\n***** ERROR: Failed to determine a desired fan speed. Forcing SYS fans to 100% duty cycle as a safety fallback measure. *****\n"; + $desired_sys_fan_speed = 0x64; + } + + $cpu_temp_difference = $g_current_cpu_temp - $g_last_set_cpu_temp; + $sys_power_difference = $g_current_sys_power - $g_last_set_sys_power; + + if( (abs $sys_power_difference) > $min_power_change ) { + print "(SYS) Power change of $sys_power_difference W, current $g_current_sys_power W, fan speed set to $desired_sys_fan_speed %\n"; + + $g_last_set_sys_power = $g_current_sys_power; + $g_current_sys_fan_duty_cycle = $desired_sys_fan_speed; + + `ipmitool raw 0x30 0x70 0x66 0x01 0x00 $desired_sys_fan_speed`; + } + + if( (abs $cpu_temp_difference) > $min_temp_change ) { + print "(CPU) Temp change of $cpu_temp_difference °C, current $g_current_cpu_temp °C, fan speed set to $desired_cpu_fan_speed %\n"; + + $g_last_set_cpu_temp = $g_current_cpu_temp; + $g_current_cpu_fan_duty_cycle = $desired_cpu_fan_speed; + + `ipmitool raw 0x30 0x70 0x66 0x01 0x01 $desired_cpu_fan_speed`; + } + +} + +print "Setting Fan mode to FULL SPEED.\n"; +`ipmitool raw 0x30 0x45 0x01 0x01`; + +while( 1 ) { + UpdateFanSpeed(); + sleep $seconds_to_sleep; +} \ No newline at end of file