====== Read AP7940 PDU from script ======
The AP7940 from American Power Conversion ([[https://www.apc.com]]) is an older unit with limited ability to automatically read the values. I came up with a set of Perl scripts which will do this.
It is definitely a hack. The first thing you must do is set up an sftp server and tell the AP7940 to write the log files to that location (defined as $logdir in this script).
This is done asynchronously. The AP7940 ftp's the log files hourly. //processPDULogs// is then set up as a cron job which runs once an hour. It looks for the log file, processes it, then deletes it (so the next sftp upload can overwrite).
NOTE: processPDULogs must have read/write access to $logdir and, obviously, so must the sftp server.
The second script, //getPDU//, is used to read the file. When called with the name of the PDU and the key to be read, returns the value (useful for Zabbix monitoring, [[http://zabbix.com]])
#! /usr/bin/perl
# Script reads data log produced by APC AP7940 which if ftp'd to $logDir
# it finds the last entry read (from status file) and scrolls down through
# log file until it finds the next entry.
# then summarizes the entries (only happens once an hour) and stores the value
# in the out file.
# Copyright 2015, Rod, Daily Data, Inc.
# Free to use, modify, change, anything you want
# You do NOT have to give attribution, but it would be
# appreciated.
# Also, if you make changes and want to give them back, just send them to
# us. Visit the http://www.dailydata.net and select Contact Us
my $logDir = '/home/apcpdu'; # location where log is ftp'd to by AP7940
my @PDUNames = ('pdu1','pdu2'); # names of pdu's to look for
my $logFileExtension = 'log'; # extension expected for log file name
my $statusExtension = 'status'; # extension used for recording last record processed
my $outputFileExtension = 'out'; # extension used for most recent summary
my $voltage = 208; # could not figure out how to get voltage from pdu, so hard coded
my $pf = 1; # ditto power factor
foreach my $thisLog ( @PDUNames ) {
my $statusFile = $logDir . '/' . $thisLog . '.' . $statusExtension;
my $logFile = $logDir . '/' . $thisLog . '.' . $logFileExtension;
my $outFile = $logDir . '/' . $thisLog . '.' . $outputFileExtension;
my @log;
my $status = 0;
# print "Processing log from $thisLog\n";
if ( -f $statusFile ) {
# print "\tReading $statusFile\n";
open STATUS, "<$statusFile";
$status = ;
close STATUS;
}
if ( -f $logFile ) {
# print "\tReading $logFile\n";
open LOG,"<$logFile" or die "Could not read $logFile: $!\n";
my $log = join( '', );
@log = split( "\n", $log );
close LOG;
} else {
next;
}
chomp @log;
# print "\tTrying to find header\n";
my $line = 0;
while ( $line < @log ) {
last if $log[$line] =~ m/Date\s+Time\s+I\s+IMax\s+IMin/;
$line++;
};
# print "\tFinding first line to process\n";
if ( $status ) {
while ( $line < @log && $log[$line] ne $status ) {
$line++;
}
}
$line++;
# we should now be at the first entry AFTER the last one read
# print "First line to process would be line $line\n$log[$line]\n";
my $max = 0;
my $min = 1000;
my $sum = 0;
my $count = 0;
my $datetime; # last date and time read
while ( $line < @log ) {
my ($date,$time,$current,$currentMax,$currentMin) = split( /\s+/, $log[$line]);
$max = $currentMax if $currentMax > $max;
$min = $currentMin if $currentMin < $min;
$count++;
$sum += $current;
$datetime = "$date $time";
$line++;
}
next unless $count;
open LOG,">$outFile" or die "Could not write to $outFile: $!\n";
print LOG "timestamp\t$datetime\n";
print LOG "average\t" . $sum/$count . "\n";
print LOG "max\t$max\n";
print LOG "min\t$min\n";
print LOG "count\t$count\n";
print LOG "voltage\t$voltage\n";
print LOG "pf\t$pf\n";
close LOG;
`chmod 666 $outFile`;
open STATUS,">$statusFile" or die "Could not write to $statusFile: $!\n";
print STATUS $log[scalar(@log)-1];
close STATUS;
`mv $logFile $logFile.old`;
}
1;
#! /usr/bin/perl -w
# script to get pdu data from summary file created by
# processPDULogs. Simply reads file pduname.out in $outputDir
# with pduname being the value of the first parameter
# returns the entry from the tab delimited file in the form
# key value
# where key is passed in as the second value
# Copyright 2015, Rod, Daily Data, Inc.
# Free to use, modify, change, anything you want
# You do NOT have to give attribution, but it would be
# appreciated.
# Also, if you make changes and want to give them back, just send them to
# us. Visit the http://www.dailydata.net and fill out the contact form
my $pduName = shift;
my $key = shift;
my $outputExtension = 'out';
my $outputDir = '/home/apcpdu';
# retrieve one value (based on $key) from $datafile
sub getValue {
my $datafile = shift;
my $key = shift;
return -1 unless $key;
# open data file and get line with key in it
# maybe faster using grep???
open DATA, "<$datafile" or die "No data to read: $!\n";
my @lines = grep { /^$key\t/ } ;
close DATA;
# clean up line and return the value (second field of tab delim line)
chomp( $lines[0] );
($key,$value) = split ("\t", $lines[0] );
return $value;
}
die "Invalid PDU name" unless $pduName;
my $filename = "$outputDir/$pduName.$outputExtension";
die "No Datafile" unless -e $filename;
die "No key given" unless $key;
print getValue( $filename, $key );
1;