| 1 | #!/usr/bin/perl -w |
|---|
| 2 | # |
|---|
| 3 | # copyright Freek Reedeker 2009 |
|---|
| 4 | # |
|---|
| 5 | # After a script "rrd_hddtemp.pl" by Martin Pot |
|---|
| 6 | # http://martybugs.net/linux/download/rrd_hddtemp.txt |
|---|
| 7 | # |
|---|
| 8 | # /usr/local/bin/lmsensor.pl |
|---|
| 9 | |
|---|
| 10 | use RRDs; |
|---|
| 11 | |
|---|
| 12 | # define location of rrdtool databases |
|---|
| 13 | my $rrd = '/var/lib/rrd'; |
|---|
| 14 | # define location of images |
|---|
| 15 | my $img = '/var/www/html/rrdtool'; |
|---|
| 16 | # Initialize variables |
|---|
| 17 | my ($sensor_name, $sensor_value, $sensor_units) = ""; |
|---|
| 18 | |
|---|
| 19 | # Check for number of commandline arguments |
|---|
| 20 | my $numberOfArguments= $#ARGV; |
|---|
| 21 | if (abs($numberOfArguments) != 1) # Exit if the wrong number of arguments are passed (0 or 2) |
|---|
| 22 | { |
|---|
| 23 | print STDERR "Error: invalid number of arguments.\nOnly 0 or 2 arguments \nUsage: lmsensor.pl [-d|-debug 0|1|2 ] \n"; |
|---|
| 24 | exit(1); |
|---|
| 25 | } |
|---|
| 26 | |
|---|
| 27 | # Debugmode = 0 is for normal operation and is the default |
|---|
| 28 | # Debugmode = 1 is to check the parsing process |
|---|
| 29 | # Debugmode = 2 is to generate the contents of the %monitor array. |
|---|
| 30 | # The debugmode can be set from the commandline with the option -d|-debug followed by a 0, 1 or 2 |
|---|
| 31 | # |
|---|
| 32 | # I am not familiar with all the possible outputs of the <sensor> command |
|---|
| 33 | # The script might need some tweeking for different sensor setups |
|---|
| 34 | # Therefore the debugging options are included. |
|---|
| 35 | |
|---|
| 36 | # default debugmode |
|---|
| 37 | my $debugmode = 0; |
|---|
| 38 | # If debugmode set from commandline -> lmsensor.pl -d (0|1|2) |
|---|
| 39 | # 2 commandline argument, first == "-d", second is 0, 1 or 2 |
|---|
| 40 | if ($numberOfArguments == 1) # no of arguments is two and debugmode needs to be changed |
|---|
| 41 | { |
|---|
| 42 | if (($ARGV[0] =~ m/^-(d|debug)$/) && ($ARGV[1]=~ m/^(0|1|2)$/)){ |
|---|
| 43 | $debugmode= $ARGV[1]; |
|---|
| 44 | }else { |
|---|
| 45 | print STDERR "Error: invalid arguments.\nUsage: lmsensor.pl -d|-debug 0|1|2 \n"; |
|---|
| 46 | exit(1); |
|---|
| 47 | } |
|---|
| 48 | } |
|---|
| 49 | |
|---|
| 50 | # Select which sensors to graph. Uncomment the sensors you are interested in. |
|---|
| 51 | # Array is of form -- %monitor ( 'sensor_name', 'Graphcolor' ) |
|---|
| 52 | # If you need a different list for your sensors run the script with debugmode = 2 |
|---|
| 53 | # Paste the output into the %monitor array assignment below, remove the last "," |
|---|
| 54 | my %monitor = ( |
|---|
| 55 | #'+2.5V', 'Magenta', |
|---|
| 56 | #'VCore', 'Default', |
|---|
| 57 | #'+3.3V', 'Default', |
|---|
| 58 | #'+5V', 'Default', |
|---|
| 59 | #'+12V', 'Default', |
|---|
| 60 | #'VCC', 'Default', |
|---|
| 61 | #'+1.5V', 'Default', |
|---|
| 62 | #'+1.8V', 'Default', |
|---|
| 63 | 'Chip Temp', 'Dark Faded Cyan', |
|---|
| 64 | 'CPU Temp', 'Green', |
|---|
| 65 | 'Sys Temp', 'Magenta', |
|---|
| 66 | #'cpu0_vid', 'Default', |
|---|
| 67 | 'fan1', 'Default', |
|---|
| 68 | 'fan2', 'Dark Faded Red' |
|---|
| 69 | ); |
|---|
| 70 | |
|---|
| 71 | # Which graphcolors to use for the different graphs. |
|---|
| 72 | # Change the colour in the monitor array to suite your taste. Default = Blue |
|---|
| 73 | # Colourcodes taken from http://www.visibone.com/colorlab/ . |
|---|
| 74 | my %graphcolors = ( 'Default', '0000FF', |
|---|
| 75 | 'Blue', '0000FF', |
|---|
| 76 | 'Green', '00FF00', |
|---|
| 77 | 'Yellow','FFFF00' , |
|---|
| 78 | 'Magenta','FF00FF' , |
|---|
| 79 | 'Light Hard Orange' , 'FF9933' , |
|---|
| 80 | 'Red' , 'FF0000', |
|---|
| 81 | 'Cyan', '00FFFF', |
|---|
| 82 | 'Dark Faded Blue', '000099', |
|---|
| 83 | 'Dark Faded Red', '990000', |
|---|
| 84 | 'Dark Faded Green', '009900', |
|---|
| 85 | 'Dark Faded Cyan', '009999', |
|---|
| 86 | 'Dark Faded Magenta', '990099' ); |
|---|
| 87 | |
|---|
| 88 | my %scalarprintout = ( 'V', 'volt', |
|---|
| 89 | 'C', 'degrees C', |
|---|
| 90 | 'F', 'degrees F', |
|---|
| 91 | 'RPM', 'rotations/minute' ); |
|---|
| 92 | |
|---|
| 93 | # Get the output from sensors. You need to install lmsensors first. |
|---|
| 94 | my $lmsensor_string=`sensors`; |
|---|
| 95 | |
|---|
| 96 | # motherboard data |
|---|
| 97 | my $mobo=`/usr/sbin/dmidecode -s baseboard-manufacturer`."-"; |
|---|
| 98 | $mobo .= `/usr/sbin/dmidecode -s baseboard-product-name`; |
|---|
| 99 | # remove eol chars |
|---|
| 100 | $mobo =~ s/[\n]//g; |
|---|
| 101 | if ($debugmode == 1) {print "mobo = ".$mobo."\n";} |
|---|
| 102 | |
|---|
| 103 | # for debugmode == 2 |
|---|
| 104 | if ($debugmode == 2) |
|---|
| 105 | { |
|---|
| 106 | print "\n<----- Copy the following output and past it into the \%monitor array ----->\n\n "; # for %monitor array |
|---|
| 107 | } |
|---|
| 108 | # Parse output one line at a time |
|---|
| 109 | while($lmsensor_string =~ m/\G(.*)\n/g) |
|---|
| 110 | { |
|---|
| 111 | $lmsensor_outputline=$1; |
|---|
| 112 | # All sensor output lines contain a ":". skip lines without colon. |
|---|
| 113 | if ($lmsensor_outputline !~ /:/i) { |
|---|
| 114 | if ($debugmode == 1) {print "Line does not contain <:> \n";} |
|---|
| 115 | next; |
|---|
| 116 | } |
|---|
| 117 | # Some lines with a colon only specify the adapter. Skip these |
|---|
| 118 | if ($lmsensor_outputline =~ /adapter/i) { |
|---|
| 119 | if ($debugmode == 1) {print "Skipped Adapter line! \n";} |
|---|
| 120 | next; |
|---|
| 121 | } |
|---|
| 122 | # Parse remaining lines. |
|---|
| 123 | ($sensor_name, $sensor_value, $sensor_units) = ($lmsensor_outputline =~ m/^(.*):\s*[+ -](\S*?)[\s°].*?(F|C|V|RPM).*/); |
|---|
| 124 | # m/^(.*):\s*[+ -](\S*?)[\s°].*?(F|C|V|RPM).*/ |
|---|
| 125 | # First match is from beginning of line upto the semicolon -> $sensor_name |
|---|
| 126 | # Skip the spaces and the +/- sign or <space> upto the second group of nonwhite characters |
|---|
| 127 | # Second match is non-white characters upto a space or degree character -> $sensor_value |
|---|
| 128 | # There is some nonprintable character associated with the degree character, skip this |
|---|
| 129 | # Third match is either F, C, V or RPM -> $sensor_units |
|---|
| 130 | # Skip rest of line. |
|---|
| 131 | if ($debugmode == 2) # for %monitor array |
|---|
| 132 | { |
|---|
| 133 | print "\t\t\#'"; |
|---|
| 134 | print $sensor_name; |
|---|
| 135 | print "', \'Default\',"; |
|---|
| 136 | print "\n"; |
|---|
| 137 | } |
|---|
| 138 | if ($debugmode == 1) # To check parsing |
|---|
| 139 | { |
|---|
| 140 | print $sensor_name; |
|---|
| 141 | print "\t"; |
|---|
| 142 | print $sensor_value."\t"; |
|---|
| 143 | print $sensor_units."\t"; |
|---|
| 144 | # This works but following is better |
|---|
| 145 | # if (grep {$_ eq $sensor_name} @monitor) {print "<-- monitored" ;} |
|---|
| 146 | # This is better with an Associative Array |
|---|
| 147 | # This will show in the debug output which sensors are monitored. |
|---|
| 148 | if ($monitor{$sensor_name}) { print "\t\t\t<-- monitored" ;} |
|---|
| 149 | print "\n"; |
|---|
| 150 | print $lmsensor_outputline."\n"; # line by line to verify what is parsed |
|---|
| 151 | } |
|---|
| 152 | # This is the real stuff, after you've confirmed that the parsing works |
|---|
| 153 | # as wanted and have selected some sensors to monitor and |
|---|
| 154 | # switched off debug mode. |
|---|
| 155 | if (! $debugmode) # Only do the following when not in debugmode |
|---|
| 156 | { |
|---|
| 157 | if ($monitor{$sensor_name}) # Sensor is being monitored |
|---|
| 158 | { |
|---|
| 159 | # if rrdtool database doesn't exist, create it |
|---|
| 160 | if (! -e "$rrd/$sensor_name.rrd") |
|---|
| 161 | { |
|---|
| 162 | print "creating rrd database for $sensor_name...\n"; |
|---|
| 163 | RRDs::create "$rrd/$sensor_name.rrd", |
|---|
| 164 | "-s 300", |
|---|
| 165 | "DS:Values:GAUGE:600:0:U", |
|---|
| 166 | "RRA:AVERAGE:0.5:1:576", |
|---|
| 167 | "RRA:AVERAGE:0.5:6:672", |
|---|
| 168 | "RRA:AVERAGE:0.5:24:732", |
|---|
| 169 | "RRA:AVERAGE:0.5:144:1460"; |
|---|
| 170 | } |
|---|
| 171 | # insert value into rrd |
|---|
| 172 | RRDs::update "$rrd/$sensor_name.rrd", |
|---|
| 173 | "-t", "Values", |
|---|
| 174 | "N:$sensor_value"; |
|---|
| 175 | # create graphs |
|---|
| 176 | &CreateGraph($sensor_name, "day", $mobo, $sensor_units); |
|---|
| 177 | &CreateGraph($sensor_name, "week", $mobo, $sensor_units); |
|---|
| 178 | &CreateGraph($sensor_name, "month", $mobo, $sensor_units); |
|---|
| 179 | &CreateGraph($sensor_name, "year", $mobo, $sensor_units); |
|---|
| 180 | |
|---|
| 181 | # |
|---|
| 182 | # Delete daily graph if it exists but sensor is no longer monitored |
|---|
| 183 | # If the daily graph is deleted, the hddtemp.cgi and sensormc.cgi script will no longer load the graph |
|---|
| 184 | # The rrd will remain. If you later reenable monitoring of the sensor only the daily |
|---|
| 185 | # graph will be recreated. |
|---|
| 186 | # If you want to get rid of the rrd's as well, uncomment the second exec() line |
|---|
| 187 | }elsif(-e "$img/$sensor_name-day.png") # Sensor is NOT being monitored but graph exists |
|---|
| 188 | { |
|---|
| 189 | # Only for commandline debugging |
|---|
| 190 | # ********************************* |
|---|
| 191 | # print $sensor_name." is not monitored but graph exists !!!\n"; |
|---|
| 192 | # print "Removing $sensor_name-day.png !!!\n"; |
|---|
| 193 | exec("rm $img/$sensor_name-day.png"); |
|---|
| 194 | # exec("rm $rrd/$sensor_name.rrd"); |
|---|
| 195 | } |
|---|
| 196 | } |
|---|
| 197 | } |
|---|
| 198 | |
|---|
| 199 | # the whole output of the sensor command |
|---|
| 200 | if ($debugmode == 1) {print "\n\n".$lmsensor_string."\n";} |
|---|
| 201 | |
|---|
| 202 | sub CreateGraph |
|---|
| 203 | { |
|---|
| 204 | # creates graph |
|---|
| 205 | # inputs: $_[0]: sensor name (ie +2.5V, Chip Temp, fan1) |
|---|
| 206 | # $_[1]: interval (ie day, week, month, year) |
|---|
| 207 | # $_[2]: MOBO description |
|---|
| 208 | # $_[3]: Sensor units ( C, F, V, RPM) |
|---|
| 209 | |
|---|
| 210 | RRDs::graph "$img/$_[0]-$_[1].png", |
|---|
| 211 | "--lazy", |
|---|
| 212 | "-s -1$_[1]", |
|---|
| 213 | "-t Sensor :: $_[2] ($_[0])", |
|---|
| 214 | "-h", "80", "-w", "600", |
|---|
| 215 | "-a", "PNG", |
|---|
| 216 | "-v $scalarprintout{$_[3]}", |
|---|
| 217 | "DEF:temp=$rrd/$_[0].rrd:Values:AVERAGE", |
|---|
| 218 | "LINE2:temp#$graphcolors{$monitor{$_[0]}}: $_[0]", |
|---|
| 219 | "GPRINT:temp:MIN: Min\\: %2.lf", |
|---|
| 220 | "GPRINT:temp:MAX: Max\\: %2.lf", |
|---|
| 221 | "GPRINT:temp:AVERAGE: Avg\\: %4.1lf", |
|---|
| 222 | "GPRINT:temp:LAST: Current\\: %2.lf $scalarprintout{$_[3]}\\n"; |
|---|
| 223 | if ($ERROR = RRDs::error) { print "$0: unable to generate $_[0] graph: $ERROR\n"; } |
|---|
| 224 | } |
|---|
| 225 | |
|---|