#!/usr/bin/perl
#-----------------------------------------------------------------
# By: johns@msli.com
#
# Purpouse:
# Keep fan as slow as possible for a given Target CPU Temp.
#
# Some Testing:
# speed temp
# 100 40-42
# 255-100 37-39
#
# REFERENCE: http://www.intel.com/support/processors/pentiumiii/sb/cs-007589.htm
# CPU MODEL: Intel(R) Pentium(R) III CPU - S 1266MHz
# Min temp: 45
#-----------------------------------------------------------------
my $debug= "1"; # debug 1=on, 0=off
my $graph= "1"; # graph 1=on, 0=off
my $pause= "5"; # Time between tests
my $sensors= "/usr/bin/sensors"; # Binary for sensors
my $Sensor_string= "pc87366-isa-1410"; # Header in sensors output
my $time=time( );
my $Speed= "100" ; # Setting default fan speed.
my $TargetTmp_upper="44"; # Target temp for CPU
my $TargetTmp_lower="42"; # Target temp for CPU
my $ProcFile= "/sys/devices/platform/i2c-9191/9191-1410/pwm2";
my $rrd_file= "/root/rrd/fan_temp.rrd";
my $graph_file_2hr= "/root/rrd/fan_temp_2hr.png";
my $graph_file_12hr="/root/rrd/fan_temp_12hr.png";
my $graph_file_1wk="/root/rrd/fan_temp_1wk.png";
#-----------------------------------------------------------------
# flush the buffer
$| = 1;
#-----------------------------------------------------------------
# daemonize the program
if ( $debug eq "0" ){ &daemonize; }
#-----------------------------------------------------------------
# Set initial fan speed to our base
&update_fanspeed($Speed);
#-----------------------------------------------------------------
# Main Loop,
# Runs forever
while ( 1 ){
#
# Get temp
#
chomp ( my $Temp=&get_temp );
if ( $debug eq "1" ){ print "Temp: $Temp\n"; }
#
# Get speed
#
chomp ( $Speed=&get_fanspeed );
if ( $debug eq "1" ){ print "Speed: $Speed\n"; }
#
# Calculate new speed
#
my $NewSpeed=&new_fanspeed($Temp,$Speed);
if ( $debug eq "1" ){ print "NewSpeed: $NewSpeed\n"; }
#
# If Speed and NewSpeed are not equal, update fan speed file.
#
if ( $NewSpeed ne $Speed ){
&update_fanspeed($NewSpeed);
if ( $debug eq "1" ){ print "Loading new speed\n"; }
}
#
# Create RRD file, if it does not exist
#
if ( ! -e "$rrd_file" ){
&create_graph($rrd_file);
};
#
# Record Fan speed
#
my $NewSpeed=&record_fanspeed($Temp,$Speed,$rrd_file);
#
# Graph from rrd
#
&graph_fanspeed($rrd_file,$graph_file_2hr,$graph_file_12hr,$graph_file_1wk);
#
#
# Sleep
#
system ( sleep $pause );
}
#-----------------------------------------------------------------
sub daemonize {
chdir '/' or die "Can't chdir to /: $!";
open STDIN, '/dev/null' or die "Can't read /dev/null: $!";
open STDOUT, '>>/dev/null' or die "Can't write to /dev/null: $!";
open STDERR, '>>/dev/null' or die "Can't write to /dev/null: $!";
defined(my $pid = fork) or die "Can't fork: $!";
exit if $pid;
setsid or die "Can't start a new session: $!";
umask 0;
}
#-----------------------------------------------------------------
sub create_graph {
chomp ( my $rrd_file=shift );
# rrdtool create $rrd_directory/fan_temp.rrd \
# --step 1 \ # 1 sec steps for RRA's blow
# DS:Temp:GAUGE:10:0:U \ # DataSource: over max of 10sec, "0" minimum and unknown max value as valid data
# DS:Speed:GAUGE:10:0:U \ # DataSource: over max of 10sec, "0" minimum and unknown max value as valid data
# RRA:AVERAGE:0.5:1:10 \ # Archive: Average over 1 measurement (10 sec), 10 values should be stroed
# RRA:AVERAGE:0.5:6:60 \ # Archive: Average over 6 measurements (1 min), 60 values should be stroed
# RRA:AVERAGE:0.5:24:240 \ # Archive: Average over 24 measurements (4 min), 240 values should be stroed
# RRA:AVERAGE:0.5:288:2880 \ # Archive: Average over 288 measurements (42 min),2880 values should be stroed
# RRA:MAX:0.5:1:10 \ # Archive: MAX over 1 measurements (10 sec), 10 values should be stroed
# RRA:MAX:0.5:6:60 \ # Archive: MAX over 6 measurements (1 min), 60 values should be stroed
# RRA:MAX:0.5:24:240 \ # Archive: MAX over 24 measurements (4 min), 240 values should be stroed
# RRA:MAX:0.5:288:2880 \ # Archive: MAX over 288 measurements (42 min),2880 values should be stroed
# RRA:LAST:0.5:1:10 \ # Archive: Last over 1 measurement (10 sec), 10 values should be stored
# RRA:LAST:0.5:6:60 \ # Archive: MAX over 6 measurements (1 min), 60 values should be stroed
# RRA:LAST:0.5:24:240 \ # Archive: MAX over 24 measurements (4 min), 240 values should be stroed
# RRA:LAST:0.5:288:2880 \ # Archive: MAX over 288 measurements (42 min),2880 values should be stroed
system( qq{rrdtool create $rrd_file \\
--step 1 \\
DS:Temp:GAUGE:10:0:U \\
DS:Speed:GAUGE:10:0:U \\
RRA:AVERAGE:0.5:1:10 \\
RRA:AVERAGE:0.5:6:60 \\
RRA:AVERAGE:0.5:24:240 \\
RRA:AVERAGE:0.5:288:2880 \\
RRA:MAX:0.5:1:10 \\
RRA:MAX:0.5:6:60 \\
RRA:MAX:0.5:24:240 \\
RRA:MAX:0.5:288:2880 \\
RRA:LAST:0.5:1:10 \\
RRA:LAST:0.5:6:60 \\
RRA:LAST:0.5:24:240 \\
RRA:LAST:0.5:288:2880} );
}
#-----------------------------------------------------------------
sub record_fanspeed{
my $temp=shift;
my $speed=shift;
my $rrd_file=shift ;
system ( "rrdtool update $rrd_file --template Temp:Speed N:$temp:$speed" );
}
#-----------------------------------------------------------------
sub graph_fanspeed {
my $rrd_file=shift;
my $graph_file_2hr=shift;
my $graph_file_12hr=shift;
my $graph_file_1wk=shift;
#####################################
# For the graph:
# Temp a=ave b=max c=last
# Speed d=ave e=max f=last
#####################################
#
# Draw 2 Hour png
#
system("rrdtool", "graph", "/root/rrd/fan_temp_2hr.png",
"--imgformat=PNG",
"--start=-2880",
"-c", "BACK#343435", "-c", "FONT#ffffff", "-c", "CANVAS#605f60",
"--title=2 Hour Fanspeed Tmp",
"--height=150", "--width=400",
"--vertical-label=Red=degreeC, Yellow=speed",
"--step", "10",
"DEF:a=$rrd_file:Temp:AVERAGE",
"DEF:b=$rrd_file:Temp:MAX",
"DEF:c=$rrd_file:Temp:LAST",
"DEF:d=$rrd_file:Speed:AVERAGE",
"DEF:e=$rrd_file:Speed:MAX",
"DEF:f=$rrd_file:Speed:LAST",
"LINE1:c#ea0e2b:Temp:",
"GPRINT:a:LAST:%6.0lf%s\\r",
"GPRINT:b:LAST:%6.0lf%s\\r",
"GPRINT:c:LAST:%6.0lf%s\\r",
"COMMENT:\\n",
"LINE1:f#EACC00:Speed:",
"GPRINT:d:LAST:%6.0lf%s\\r",
"GPRINT:e:LAST:%6.0lf%s\\r",
"GPRINT:f:LAST:%6.0lf%s\\r",
"COMMENT:\\n"
);
#
# Draw 12 Hour png
#
system ( qw{rrdtool graph $graph_file_12hr \\
--imgformat=PNG \\
--start=\'-86400\' \\
-c BACK#343435 -c FONT#ffffff -c CANVAS#605f60 \\
--title='12 Hour Fanspeed Tmp' \\
--height=150 --width=400 \\
--vertical-label='Red=degreeC, Yellow=speed' \\
--step 10 \\
DEF:a='$rrd_file':Temp:AVERAGE \\
DEF:b='$rrd_file':Temp:MAX \\
DEF:c='$rrd_file':Temp:LAST \\
DEF:d='$rrd_file':Speed:AVERAGE \\
DEF:e='$rrd_file':Speed:MAX \\
DEF:f='$rrd_file':Speed:LAST \\
LINE1:c#ea0e2b:'Temp\\:' \\
GPRINT:a:LAST:%6.0lf%s\r \\
GPRINT:b:LAST:%6.0lf%s\r \\
GPRINT:c:LAST:%6.0lf%s\r \\
COMMENT:'\\\n' \\
LINE1:f#EACC00:'Speed\\:' \\
GPRINT:d:LAST:%6.0lf%s\r \\
GPRINT:e:LAST:%6.0lf%s\r \\
GPRINT:f:LAST:%6.0lf%s\r \\
COMMENT:'\\n'}
);
#
# Draw 12 Hour png
#
system ( qw{rrdtool graph $graph_file_1wk \\
--imgformat=PNG \\
--start='-604800' \\
-c BACK#343435 -c FONT#ffffff -c CANVAS#605f60 \\
--title='1 Week Fanspeed Tmp' \\
--height=150 --width=400 \\
--vertical-label='Red=degreeC, Yellow=speed' \\
--step 10 \\
DEF:a='$rrd_file':Temp:AVERAGE \\
DEF:b='$rrd_file':Temp:MAX \\
DEF:c='$rrd_file':Temp:LAST \\
DEF:d='$rrd_file':Speed:AVERAGE \\
DEF:e='$rrd_file':Speed:MAX \\
DEF:f='$rrd_file':Speed:LAST \\
LINE1:c#ea0e2b:'Temp\\:' \\
GPRINT:a:LAST:%6.0lf%s\r \\
GPRINT:b:LAST:%6.0lf%s\r \\
GPRINT:c:LAST:%6.0lf%s\r \\
COMMENT:'\\\n' \\
LINE1:f#EACC00:'Speed\\:' \\
GPRINT:d:LAST:%6.0lf%s\r \\
GPRINT:e:LAST:%6.0lf%s\r \\
GPRINT:f:LAST:%6.0lf%s\r \\
COMMENT:'\\n'}
);
}
#-----------------------------------------------------------------
sub update_fanspeed {
my $NewSpeed=shift;
open ( FANSPEED, ">>$ProcFile") || die "Cannot read fanspeed file: $?\n";
print FANSPEED "$NewSpeed";
close ( FANSPEED ) || die "Cannot close fanspeed file: $?\n";
return;
}
#-----------------------------------------------------------------
sub new_fanspeed {
my $Temp=shift;
my $Speed=shift;
#
# If temp is over 42, increment fan speed.
#
if ( "$Temp" > $TargetTmp_upper ){ unless( $Speed eq 255){ ++$Speed ; } }
#
# If temp is under 42, decrement fan speed.
#
if ( $Temp < $TargetTmp_lower ){ unless( $Speed eq 0 ){ --$Speed ; } }
#
# Return the new speed
#
return ( $Speed );
}
#-----------------------------------------------------------------
sub get_fanspeed {
open ( FANSPEED, "<$ProcFile") || die "Cannot read fanspeed file: $?\n";
chomp ( my $Speed=<FANSPEED> );
close ( FANSPEED ) || die "Cannot close fanspeed file: $?\n";
return ( $Speed );
}
#-----------------------------------------------------------------
sub get_temp {
# Process output of `sensors` one line at a time.
open ( SENSORS, "$sensors |") || die "Cannot run sensors\n";
while (<SENSORS>){
########################################
# Screen for relevent sensor data
# - If lm_sensors modules are loade incorrectly,
# double output of incorrect values result.
# - This allows one to specify which to collect
########################################
# Start collecting data when this line is reached
if ( $_ =~ m/$Sensor_string/ ){
$Start="1";
# Stop Collecting data when this line is reached
} elsif ( $_ =~ m/^$/ ) {
$Start="0";
done;
}
# If Start is 1, we are working with good data
if ( $Start eq "1" ){
#
# Example string: CPU0 Temp: +42 C (low = +0 C, high = +70 C)
#
$bla=$_;
# print "$bla";
if ( $bla =~ m{
^CPU0
\W*
Temp: # Starts with temp:
\W* # NonWord characters
\+
(\d+) # digits are the temp
.* # Anything up to
\n # new line
}xig # allow comments, case insensetive, global
) {
#
# Debug: Print the captured value
#
if ( $debug eq "0" ){ print "CPU Tmep:\t$1\n"; }
# END of SENSORS data
close ( SENSORS );
return ($1);
}
}
}
# Should never get here.
close ( SENSORS );
return (0);
}
#-----------------------------------------------------------------