#!/usr/bin/perl #----------------------------------------------------------------- # # Title: # sensors.rrd.pl # # Purpouse: # Chart temp and fan stats # Keep fan as slow as possible given safe Target CPU Temp. # # To find the correct settings, run: pwmconfig # 9191-0290/fan1_input current speed: 17307 RPM # 9191-0290/fan2_input current speed: 17307 RPM # 9191-0290/fan3_input current speed: 15000 RPM # # Fan's controlled by: # /sys/devices/platform/i2c-9191/9191-0290/pwm1 # /sys/devices/platform/i2c-9191/9191-0290/pwm2 # #----------------------------------------------------------------- my $debug= "1"; # debug 1=on, 0=off my $graph= "1"; # graph 1=on, 0=off my $quiet= "0"; # change fan speed 1=on, 0=off my $do_rrd= "0"; # rrd create/update 1=on, 0=off my $pause= "5"; # Time between tests my $sensors= "/usr/bin/sensors"; # Binary for sensors my $Sensor_string= "w83627hf-isa-0290"; # Header in sensors output my $time=time( ); my $Speed1= "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"; my %stats=( temp1 => "0", temp2 => "0", temp3 => "0", rpm1 => "0", rpm2 => "0", rpm3 => "0" ); #----------------------------------------------------------------- # flush the buffer $| = 1; #----------------------------------------------------------------- # daemonize the program if ( $debug eq "0" ){ &daemonize; } #----------------------------------------------------------------- # Set initial fan speed to our base #&update_fanspeed($Speed1); #----------------------------------------------------------------- # Main Loop, # Runs forever while ( 1 ){ if ( $debug eq "1" ){ print "Contents of hash before.\n"; for my $key ( sort ( keys ( %stats ) ) ){ print "\t$key:\t$stats{$key}\n"; } } # # Get temp # &get_i2c( \%stats ) || die "can't check sensors:\t $!\n"; if ( $debug eq "1" ){ print "Contents of hash after\n"; for my $key ( sort ( keys ( %stats ) ) ){ print "\t$key:\t$stats{$key}\n"; } } if ( $quiet eq "1" ){ # # Get speed # chomp ( $Speed1 = &get_file_fanspeed ); if ( $debug eq "1" ){ print "Speed: $Speed1\n"; } # # Calculate new speed # my $NewSpeed=&new_fanspeed($Temp,$Speed1); if ( $debug eq "1" ){ print "NewSpeed: $NewSpeed\n"; } # # If Speed and NewSpeed are not equal, update fan speed file. # if ( $NewSpeed ne $Speed1 ){ &update_fanspeed($NewSpeed); if ( $debug eq "1" ){ print "Loading new speed\n"; } } } if ( $do_rrdeq eq "1" ){ # # Create RRD file, if it does not exist # if ( ! -e "$rrd_file" ){ &create_graph($rrd_file); }; # # Record Fan speed # $Rpm=($Rpm/100); if ( $debug eq "1" ){ print "$Temp,$Speed1,$Rpm,$rrd_file\n"; } my $NewSpeed=&record_fanspeed($Temp,$Speed1,$Rpm,$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 # DS:Rpm: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 \\ DS:Rpm: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 $Speed1=shift; my $rpm=shift; my $rrd_file=shift ; system ( "rrdtool update $rrd_file --template Temp:Speed:Rpm N:$temp:$Speed1:$rpm" ); } #----------------------------------------------------------------- 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 # Rpm g=ave h=max i=last ##################################### # # Draw 2 Hour png # system( "rrdtool", "graph", "$graph_file_2hr", "--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, Blue=rpm", "--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", "DEF:g=$rrd_file:Rpm:AVERAGE", "DEF:h=$rrd_file:Rpm:MAX", "DEF:i=$rrd_file:Rpm:LAST", "LINE1:c#ea0e2b:Temp\\r:", "GPRINT:a:AVERAGE:Average\\t%6.0lf%s\\r", "GPRINT:b:MAX:Max\\t%6.0lf%s\\r", "GPRINT:c:LAST:Last\\t%6.0lf%s\\r", "COMMENT:\\n", "LINE1:f#EACC00:Speed\\r:", "GPRINT:d:AVERAGE:Average\\t%6.0lf%s\\r", "GPRINT:e:MAX:Max\\t%6.0lf%s\\r", "GPRINT:f:LAST:Last\\t%6.0lf%s\\r", "COMMENT:\\n", "LINE1:g#d4dcf8:Rpm\\r:", "GPRINT:g:AVERAGE:Average\\t%6.0lf%s\\r", "GPRINT:h:MAX:Max\\t%6.0lf%s\\r", "GPRINT:i:LAST:Last\\t%6.0lf%s\\r", "COMMENT:\\n" ); # # Draw 12 Hour png # system( "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, Blue=rpm", "--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", "DEF:g=$rrd_file:Rpm:AVERAGE", "DEF:h=$rrd_file:Rpm:MAX", "DEF:i=$rrd_file:Rpm:LAST", "LINE1:c#ea0e2b:Temp\\r:", "GPRINT:a:AVERAGE:Average\\t%6.0lf%s\\r", "GPRINT:b:MAX:Max\\t%6.0lf%s\\r", "GPRINT:c:LAST:Last\\t%6.0lf%s\\r", "COMMENT:\\n", "LINE1:f#EACC00:Speed\\r:", "GPRINT:d:AVERAGE:Average\\t%6.0lf%s\\r", "GPRINT:e:MAX:Max\\t%6.0lf%s\\r", "GPRINT:f:LAST:Last\\t%6.0lf%s\\r", "COMMENT:\\n", "LINE1:g#d4dcf8:Rpm\\r:", "GPRINT:g:AVERAGE:Average\\t%6.0lf%s\\r", "GPRINT:h:MAX:Max\\t%6.0lf%s\\r", "GPRINT:i:LAST:Last\\t%6.0lf%s\\r", "COMMENT:\\n" ); # # Draw 1week png # system( "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, Blue=rpm", "--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", "DEF:g=$rrd_file:Rpm:AVERAGE", "DEF:h=$rrd_file:Rpm:MAX", "DEF:i=$rrd_file:Rpm:LAST", "LINE1:c#ea0e2b:Temp\\r:", "GPRINT:a:AVERAGE:Average\\t%6.0lf%s\\r", "GPRINT:b:MAX:Max\\t%6.0lf%s\\r", "GPRINT:c:LAST:Last\\t%6.0lf%s\\r", "COMMENT:\\n", "LINE1:f#EACC00:Speed\\r:", "GPRINT:d:AVERAGE:Average\\t%6.0lf%s\\r", "GPRINT:e:MAX:Max\\t%6.0lf%s\\r", "GPRINT:f:LAST:Last\\t%6.0lf%s\\r", "COMMENT:\\n", "LINE1:g#d4dcf8:Rpm\\r:", "GPRINT:g:AVERAGE:Average\\t%6.0lf%s\\r", "GPRINT:h:MAX:Max\\t%6.0lf%s\\r", "GPRINT:i:LAST:Last\\t%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 $Speed1=shift; # # If temp is over 42, increment fan speed. # if ( "$Temp" > $TargetTmp_upper ){ unless( $Speed1 eq 255){ ++$Speed1 ; } } # # If temp is under 42, decrement fan speed. # if ( $Temp < $TargetTmp_lower ){ unless( $Speed1 eq 0 ){ --$Speed1 ; } } # # Return the new speed # return ( $Speed1 ); } #----------------------------------------------------------------- sub get_file_fanspeed { open ( FANSPEED, "<$ProcFile") || die "Cannot read fanspeed file: $?\n"; chomp ( my $Speed1= ); close ( FANSPEED ) || die "Cannot close fanspeed file: $?\n"; return ( $Speed1 ); } #----------------------------------------------------------------- sub get_i2c { my $stat_ref = $_; my $temp1; my $temp2; my $temp3; my $rpm1; my $rpm2; my $rpm3; if ( $debug eq "1" ){ print "Parsing lm_sensors output\n"; } # Process output of `sensors` one line at a time. open ( SENSORS, "$sensors |") || die "Cannot run sensors\n"; while (){ ######################################## # 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" ){ # # Grab the main # $bla=$_; # print "$bla"; # # Example string: temp1: +18°C (high = -1°C, hyst = -17°C) sensor = thermistor ALARM # if ( $bla =~ m{ temp1: # 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 "1" ){ print "\tTemp1:\t$1\n"; } $temp1="$1"; } # # Example string: temp2: +18°C (high = -1°C, hyst = -17°C) sensor = thermistor ALARM # if ( $bla =~ m{ temp2: # 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 "1" ){ print "\tTemp2:\t$1\n"; } $temp2="$1"; } # # Example string: temp3: +18°C (high = -1°C, hyst = -17°C) sensor = thermistor ALARM # if ( $bla =~ m{ temp3: # 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 "1" ){ print "\tTemp3:\t$1\n"; } $temp3="$1"; } # # Example string: fan1: 4528 RPM (min = 941 RPM, div = 2) # if ( $bla =~ m{ ^fan1: # starts with fan \W* # NonWord characters (\d+) # rpm number \W* # NonWord characters RPM # text RPM .* # Anything up to \n # new line }xig # allow comments, case insensetive, global ) { # # Debug: Print the captured value # if ( $debug eq "1" ){ print "\tFan1:\t$1\n"; } $rpm1="$1"; } # # Example string: fan2: 4528 RPM (min = 941 RPM, div = 2) # if ( $bla =~ m{ ^fan2: # starts with fan \W* # NonWord characters (\d+) # rpm number \W* # NonWord characters RPM # text RPM .* # Anything up to \n # new line }xig # allow comments, case insensetive, global ) { # # Debug: Print the captured value # if ( $debug eq "1" ){ print "\tFan2:\t$1\n"; } $rpm2="$1"; } # # Example string: fan3: 4528 RPM (min = 941 RPM, div = 2) # if ( $bla =~ m{ ^fan3: # starts with fan \W* # NonWord characters (\d+) # rpm number \W* # NonWord characters RPM # text RPM .* # Anything up to \n # new line }xig # allow comments, case insensetive, global ) { # # Debug: Print the captured value # if ( $debug eq "1" ){ print "\tFan3:\t$1\n"; } $rpm3="$1"; } } } # Should never get here. close ( SENSORS ); if ( 1 ){ $stats_ref->{temp1} = "$temp1"; $stats_ref->{temp2} = "$temp2"; $stats_ref->{temp3} = "$temp3"; $stats_ref->{rpm1} = "$rpm1"; $stats_ref->{rpm2} = "$rpm2"; $stats_ref->{rpm3} = "$rpm3"; if ( $debug eq "1" ){ print "Contents of hash_reference\n"; for my $key ( sort ( keys ( %$stats_ref )) ){ print "\t$key:\t$stats_ref->{$key}\n"; } } return ( 1 ) ; } else { exit 1; } } #-----------------------------------------------------------------