1
0
Fork 0
mirror of https://github.com/munin-monitoring/contrib.git synced 2025-07-21 18:41:03 +00:00

Plugin-Gallery: Get better 2nd level headings

sensors, weather, snmp
This commit is contained in:
dipohl 2017-02-24 17:30:35 +01:00
parent 37d658526b
commit 95de964ec9
24 changed files with 10 additions and 10 deletions

55
plugins/power/apc_status Executable file
View file

@ -0,0 +1,55 @@
#!/bin/sh
#
# (c) Andreas Kreisl extended by Tobias Schramm
#
# Link name will be used as title: apc_{$title}
#
# env.keys LOADPCT BCHARGE LINEV BATTV TIMELEFT
#
if [ -z "$keys" ]; then
keys="LINEV LOADPCT BCHARGE NUMXFERS TIMELEFT"
fi
apcinfo=`/sbin/apcaccess`
if [ "$1" = "config" ]; then
title=`basename $0 | sed 's/^apc_//g' | awk '{ sub(/^./,toupper(substr($0,1,1))); print; }'`
echo 'multigraph apc_status'
echo "graph_title UPS Status - $title"
echo 'graph_args --base 1000'
echo 'graph_category sensors'
title=`/sbin/apcaccess | egrep "^MODEL" | awk '{print $3" "$4" "$5" "$6" "$7" "$8" "$9;}'`
echo "graph_info $title"
for key in $keys; do
echo "$key.label $key"
echo "$key.info Value of $key"
echo "$key.draw LINE1"
done
for key in $keys; do
key_lower=`echo "$key" | awk '{print tolower($0);}'`
unit=`echo "$apcinfo" | egrep "^$key" | awk '{print $4;}'`
echo "multigraph apc_status.$key_lower"
echo "graph_title $key"
echo 'graph_args --base 1000'
if [ -n "$unit" ]; then
echo "graph_vlabel $unit"
fi
echo 'graph_category sensors'
echo "$key.label $key"
echo "$key.info $key."
echo "$key.draw LINE1"
done
exit 0
fi
echo 'multigraph apc_status'
for key in $keys; do
echo "$apcinfo" | egrep "^$key" | awk '{print $1".value "$3;}'
done
for key in $keys; do
key_lower=`echo "$key" | awk '{print tolower($0)}'`
echo "multigraph apc_status.$key_lower"
echo "$apcinfo" | egrep "^$key" | awk '{print $1".value "$3;}'
done

259
plugins/power/apcupsd_pct Executable file
View file

@ -0,0 +1,259 @@
#!/usr/bin/env perl
use strict;
use warnings;
use Carp;
use Pod::Usage;
our $APCACCESS = $ENV{apcaccess} || "/sbin/apcaccess";
our $UPS_MODEL = $ENV{ups_model} || "ES 725";
our $VERSION = 1.0;
my %Graph;
my %Metric;
MAIN: {
decide_monitor_type();
my $mode = $ARGV[0] || "fetch";
$mode =~ /^-/ && pod2usage();
### $mode
eval "do_${mode}();"
or croak "do_${mode}: $@";
### end
exit 0;
}
=begin comment
pct
LOADPCT is the percentage of load capacity as estimated by the UPS.
15.0 Percent Load Capacity
BCHARGE is the percentage charge on the batteries.
100.0 Percent
volt
LINEV is the current line voltage as returned by the UPS.
102.0 Volts
BATTV is the battery voltage as supplied by the UPS.
13.5 Volts
time
TIMELEFT is the remaining runtime left on batteries as estimated by the UPS.
38.4 Minutes
pwr
LOADPCT is the percentage of load capacity as estimated by the UPS.
15.0 Percent Load Capacity
NOMPOWER
330 Watts
LOADMETRIC=LOADPCT/100*NOMPOWER gives realtime power consumption in WATTS
=end comment
=cut
sub decide_monitor_type {
my $type = $0 =~ /_pct/ ? "pct" :
$0 =~ /_volt/ ? "volt" :
$0 =~ /_time/ ? "time" :
$0 =~ /_pwr/ ? "pwr" : undef
or croak "unknown monitor type: $0";
# common
%Graph = (
graph_title => "APC Status".($UPS_MODEL?" ($UPS_MODEL)":"")." - ",
graph_category => "sensors",
graph_info => "This graph shows information about your APC UPS",
graph_args => "--base 1000 --lower-limit 0",
);
if ($type eq "pct") {
$Graph{graph_title} .= "Percentage";
$Graph{graph_vlabel} = "%";
%Metric =(
LOADPCT => {
label => "load capacity pct",
},
BCHARGE => {
label => "charge on the batteries pct",
},
);
} elsif ($type eq "volt") {
$Graph{graph_title} .= "Voltage";
$Graph{graph_vlabel} = "Volts";
%Metric =(
LINEV => {
label => "line voltage as returned by the UPS",
},
BATTV => {
label => "battery voltage as supplied by the UPS",
},
);
} elsif ($type eq "time") {
$Graph{graph_title} .= "Time";
$Graph{graph_vlabel} = "minutes";
%Metric =(
TIMELEFT => {
label => "remaining runtime left on batteries",
},
);
} elsif ($type eq "pwr") {
$Graph{graph_title} .= "Power";
$Graph{graph_vlabel} = "watts";
%Metric =(
LOADMETRIC => {
label => "absolute power consumption",
},
);
}
}
sub do_fetch {
### do_fetch
my @status_data = retrieve_apcupsd_status()
or croak "failed: retrieve_apcupsd_status";
### status_data: \@status_data
my $status = parse_status_data(@status_data);
### status: $status
my $prod_status = proccess_status($status);
my $FIELD;
while (my($field,$attr) = each %Metric) {
$field = lc $field;
$FIELD = uc $field;
printf "%s.value %.1f\n", $field, (exists $status->{$FIELD} ? ($status->{$FIELD} =~ /([\d]+\.?[\d]*)/) : ( exists $prod_status->{$FIELD} ? ( $prod_status->{$FIELD} =~ /([\d]+\.?[\d]*)/) : 0 ) );
}
return 1;
}
sub do_config {
### do_config
while (my($k,$v) = each %Graph) {
printf "%s %s\n", $k, $v;
}
while (my($field,$attr) = each %Metric) {
$field = lc $field;
while (my($k,$v) = each %$attr) {
printf "%s.%s %s\n", $field, $k, $v;
}
}
return 1;
}
sub do_autoconf {
### do_config
print "yes\n";
}
sub retrieve_apcupsd_status {
open my $apc, '-|', $APCACCESS
or croak $!;
my @status_data = <$apc>;
close $apc;
chomp @status_data;
return @status_data;
}
sub proccess_status {
my $prod = {};
my($status) = @_;
if (exists $status->{NOMPOWER} && exists $status->{LOADPCT}) {
my $pwr_pct = sprintf "%.1f", ($status->{LOADPCT} =~ /([\d]+\.?[\d]*)/) ;
my $nom_pwr = sprintf "%.1f", ($status->{NOMPOWER} =~ /([\d]+\.?[\d]*)/) ;
$prod->{LOADMETRIC} = $pwr_pct/100 * $nom_pwr ;
}
return $prod;
}
sub parse_status_data {
my $status = {};
my($k,$v);
for (@_) {
($k,$v) = split /\s*:\s*/, $_, 2;
$status->{$k} = $v;
}
return $status;
}
__END__
=head1 NAME
B<apcupsd_pct>, B<apcupsd_volt>, B<apcupsd_time>, B<apcupsd_pwr>- munin plugin for APC UPS
=head1 SYNOPSIS
B<apcupsd_pct> [ I<config>|I<fetch> ]
B<apcupsd_volt> [ I<config>|I<fetch> ]
B<apcupsd_time> [ I<config>|I<fetch> ]
B<apcupsd_pwr> [ I<config>|I<fetch> ]
=head1 DESCRIPTION
munin plugin to monitor APC UPS via apcupsd by apcaccess.
=head1 INSTALLATION
cp apcupsd_pct $MUNIN_LIBDIR/plugsin/
cd YOUR_MUNIN_PLUGINS_DIR
(make symbolic links different name)
ln -s $MUNIN_LIBDIR/plugsin/apcupsd_pct apcupsd_pct
ln -s $MUNIN_LIBDIR/plugsin/apcupsd_pct apcupsd_volt
ln -s $MUNIN_LIBDIR/plugsin/apcupsd_pct apcupsd_time
ln -s $MUNIN_LIBDIR/plugsin/apcupsd_pwr apcupsd_pwr
restart munin-node
=head1 REPOSITORY
L<http://github.com/hirose31/munin-apcupsd>
git clone git://github.com/hirose31/munin-apcupsd.git
patches and collaborators are welcome.
=head1 SEE ALSO
L<http://exchange.munin-monitoring.org/plugins/apcupsd_pct/details>
L<http://munin.projects.linpro.no/wiki/HowToWritePlugins>,
L<http://munin.projects.linpro.no/wiki/protocol-config>
=head1 AUTHOR
HIROSE, Masaaki E<lt>hirose31 _at_ gmail.comE<gt>
=head1 CHANGELOG
* 10/11/2010 - basos - added support for absolute power display
=head1 COPYRIGHT & LICENSE
This program is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.
=cut
# for Emacsen
# Local Variables:
# mode: cperl
# cperl-indent-level: 4
# indent-tabs-mode: nil
# coding: utf-8
# End:
# vi: set ts=4 sw=4 sts=0 :

343
plugins/power/apcupsd_ww Executable file
View file

@ -0,0 +1,343 @@
#!/usr/bin/perl -w
#
# Plugin to monitor apcupsd via apcaccess
#
# Version 1.3
#
# Copyright (C) 2005-2008 Behan Webster <behanw AT websterwood DOT com>
# Licenced under GPL 2.0
#
# Written by: Behan Webster <behanw AT websterwood DOT com>
# German translation by: Bianco Veigel <bianco.veigel AT zivillian DOT de>
#
#%# family=auto
#%# capabilities=autoconf
use strict;
use warnings;
use vars qw(%attrs %data %num);
my $apcaccess='/sbin/apcaccess';
#$apcaccess='/home/behanw/bin/apcaccess';
my $config='/etc/munin/plugin-conf.d/apcupsd_ww';
my $language = $ENV{LANG} || 'en';
# Example apcaccess output
# KEY : VALUE
#
# UPSNAME : Elfhild
# MODEL : SMART-UPS 1400 RM XL
# STATUS : ONLINE
# LINEV : 123.5 Volts
# LOADPCT : 24.9 Percent Load Capacity
# BCHARGE : 100.0 Percent
# TIMELEFT : 63.0 Minutes
# OUTPUTV : 123.5 Volts
# ITEMP : 39.1 C Internal
# BATTV : 54.5 Volts
# NOMOUTV : 115 Volts
# NOMBATTV : 48.0 Volts
# Possible values to graph in munin
# Only the ones which are available will be graphed
%attrs = (
# APCACCESS_KEY => {
# name => 'attribute_name',
# label => {
# en => 'English title',
# de => 'Titel in Deutsch',
# fr => 'titre en Francais',
# },
# type => 'name_of_functio_for_type', # Default is 'num'
# # Can use one value, or list of values. If the first value can't be used, try the next.
# # KEY Key from apcaccess
# # num,num,num Specify a list of possible nominal values to guess from
# # num Specify fixed nominal value
# nominal => [ 'KEY', '100' ],
# # KEY Key from apcaccess
# # +-num% Calculate percentage min:max from nominal value
# # +-num Calculate min:max from nominal value
# # -num:+num Calculate min:max from nominal value
# # num:num Specify fixed min:max values
# # num or :num Specify fixed max value
# # num: Specify fixed min value
# warning => [ 'KEY:KEY', '+-10%', '-10:+15' ],
# critical => [ 'KEY:KEY', '+-10%', '-10:+15' ],
# },
BCHARGE => { # BCHARGE : 100.0 Percent
name => 'battery',
label => {
en => 'Percent battery charge',
de => 'Batterieladung in Prozent',
},
warning => '33:', # %
critical => '5:', # %
},
LOADPCT => { # LOADPCT : 28.6 Percent Load Capacity
name => 'upsload',
label => {
en => 'Percent load capacity',
de => 'Auslastung in Prozent',
},
warning => '75', # %
critical => '90', # %
},
TIMELEFT => { # TIMELEFT : 17.0 Minutes
name => 'timeleft',
label => {
en => 'Minutes of run time',
de => 'Akkulaufzeit in Minuten',
},
warning => '5:', # mins
critical => [ 'DLOWBATT:', '2:' ], # DLOWBATT : 02 Minutes
},
LINEV => { # LINEV : 121.5 Volts
name => 'linevolts',
label => {
en => 'Line voltage',
de => 'Eingangsspannung',
},
nominal => [ 'NOMINV', 'NOMOUTV', '115,230' ], # NA=115V, Europe=230V
warning => [ '+-10%', '108:128' ],
critical => [ 'LOTRANS:HITRANS', '+-15%', '104:132' ],
},
BATTV => { # BATTV : 27.7 Volts
name => 'batteryvolts',
label => {
en => 'Battery voltage',
de => 'Batteriespannung',
},
nominal => [ 'NOMBATTV', '12,24,48' ], # NOMBATTV : 48.0 Volts
warning => '-5%:+15%',
critical => '-10%:+25%',
},
OUTPUTV => { # OUTPUTV : 122.2 Volts
name => 'outputvolts',
label => {
en => 'Output voltage',
de => 'Ausgangsspannung',
},
nominal => [ 'NOMOUTV', '115,230' ], # NOMOUTV : 115 Volts
warning => [ '+-10%', '108:128' ],
critical => [ 'LOTRANS:HITRANS', '+-15%', '104:132' ],
},
ITEMP => { # ITEMP : 44.1 C Internal
name => 'temperature',
label => {
en => 'UPS temperature',
de => 'USV Temperatur',
},
warning => 50, # C
critical => 60, # C
},
LINEFAIL => { # LINEFAIL : OK
name => 'linefail',
label => {
en => 'Line voltage status',
de => 'Status Eingangsspannung',
},
type => 'bool',
critical => '0:', # Failed
},
BATTSTAT => { # BATTSTAT : OK
name => 'battstat',
label => {
en => 'Battery status',
de => 'Batteriestatus',
},
type => 'bool',
critical => '0:', # Failed
},
MAINS => { # MAINS : OK
name => 'mains',
label => {
en => 'Mains status',
de => 'Status Eingangsspannung',
},
type => 'bool',
critical => '0:', # Failed
},
#STATUS => { # STATUS : ONLINE
# name => 'status',
# label => {
# en => 'Status',
# },
# type => 'status',
# critical => 0,
#},
);
# Read config file
# Can be used to override settings in %attrs
if (-f $config) {
require $config;
}
# Determine plugin capabilities
if (defined $ARGV[0] && $ARGV[0] =~ /autoconf|detect/) {
if (-x $apcaccess) {
print "yes\n";
exit 0;
} else {
print "no (apcaccess not found)\n";
exit 1;
}
}
# Read info from apcupsd using apcaccess
die "$apcaccess: not found\n" unless -x $apcaccess;
open (APCACCESS, "$apcaccess 2>&1 |") || die "$apcaccess: $!\n";
while (<APCACCESS>) {
chomp;
die "$apcaccess: $_\n" if /Error contacting apcupsd/;
$data{$1} = $2 if /^(\S+?)\s*:\s+(.+?)$/;
$num{$1} = $2 if /^(\S+?)\s*:\s+([\d.x]+)/;
}
close APCACCESS;
# Auto-configure plugin
if (defined $ARGV[0] && $ARGV[0] eq 'config') {
if (defined $data{UPSNAME}) {
print "graph_title $data{UPSNAME} ($data{MODEL})\n";
} else {
print "graph_title $data{MODEL}\n";
}
#print "graph_vlabel Units\n";
print "graph_category sensors\n";
print "graph_info This graph shows information about your APC uninterruptible power supply.\n";
foreach my $what (sort keys %attrs) {
&label("$what");
}
# Print current values
} else {
foreach my $what (sort keys %attrs) {
next unless defined $data{$what};
my $func = $attrs{$what}{type} || 'num';
my $value = eval "\&$func('$what')";
print "$attrs{$what}{name}.value $value\n";
}
}
exit 0;
##############################################################################
# Print label/title for value
sub label {
my $what = shift;
return unless defined $data{$what};
my $attr = $attrs{$what};
# Determine language to use for labels
my $lang = $language;
$lang =~ s/_.*$// unless defined $attr->{label}{$lang};
# Failback to english if translation isn't available
$lang = 'en' unless defined $attr->{label}{$lang};
print "$attr->{name}.label $attr->{label}{$lang}\n";
&info($what, 'warning');
&info($what, 'critical');
}
##############################################################################
# Makes a scalar or array into an array (used in &info)
sub list {
return (ref($_[0]) eq 'ARRAY') ? @{$_[0]} : @_;
}
##############################################################################
# Used to setup warning or critical levels for munin
sub info {
my $what = shift;
my $level = shift; # 'warning' or 'critical'
my $attr = $attrs{$what};
return unless defined $attr->{$level};
# Determine nominal value for info calculation
my $nom = undef;
if (defined $attr->{nominal}) {
for my $n (&list($attr->{nominal})) {
# Guess list: compare guesses to value of $num{$what}
if ($n =~ /,/) {
my $fitness = ~0;
next unless $num{$what};
foreach my $possibility (split /[,\s]+/, $n) {
my $diff = abs($num{$what} - $possibility);
($nom, $fitness) = ($possibility, $diff) if $fitness >= $diff;
}
# Absolute nominal value
} elsif ($n =~ /^[\d.]+$/) {
$nom = $n;
last;
# Lookup nominal value as an APCUPSD key
} elsif (defined $num{$n}) {
$nom = $num{$n};
last;
}
}
}
# Calculate info value for $level
foreach my $value (&list($attr->{$level})) {
$value =~ s/([^:]+)/&calc($1,$nom)/eg;
if ($value =~ /^[\d.:]+$/) {
print "$attr->{name}.$level $value\n";
return;
}
}
}
##############################################################################
# Change warning/critical ranges into numbers for munin
sub calc {
my $v = shift;
my $nom = shift;
return $v if $v =~ /^[\d.]+$/;
return $num{$v} if defined $num{$v};
return '' unless defined $nom;
if ($v =~ /^\+-([\d.]+)%$/) {
return sprintf "%.0f:%.0f", (100 - $1) * $nom / 100, (100 + $1) * $nom / 100;
} elsif ($v =~ /^([-+][\d.]+)%$/) {
return sprintf "%.0f", (100 + $1) * $nom / 100;
} elsif ($v =~ /^\+-([\d.]+)$/) {
return sprintf "%d:%d", $nom - $1, $nom + $1;
} elsif ($v =~ /^([-+][\d.]+)$/) {
return $nom + $1;
} elsif ($v =~ /^\*([\d.]+)$/) {
return $nom * $1;
} elsif ($v =~ /^\/([\d.]+)$/) {
return sprintf "%.0f", $nom / $1;
}
return '';
}
##############################################################################
# Default "type" routine to display values
sub num {
my $what = shift;
return $num{$what};
}
##############################################################################
# "type" routine to change Ok/Not Ok into 1/0
sub bool {
my $what = shift;
return $num{$what} eq "OK" ? "1" : "0";
}
#sub status {
# my $what = shift;
# return unless defined $data{$what};
# print "$attrs{$what}{name}.value ";
# print $num{$what} eq "ONLINE" ? "1" : "0";
# print "\n";
#}
# vim: sw=4 ts=4

281
plugins/power/eatonups_ Normal file
View file

@ -0,0 +1,281 @@
#!/bin/sh
###################################################################################################
#
# Multigraph munin plugin to monitor Eaton UPS-es through the web interface of the SNMP add-on card.
# The plugin script simply parses the /PSummary.html page and extracts the values from there.
#
# To use this plugin, copy it to the munin's plugin directory (eg. /usr/share/munin/plugins)
# under the name "eatonups_". Don't change this filename! Follow these steps:
#
# 1. Give names to your UPSes, in fqdn style. Like "ups.server1" or "ups.server2". Make sure
# you can resolve these names as DNS names from the munin machine. You can simply add them
# as entries in /etc/hosts.
#
# 2. Then symlink it to munin's configured plugins directory (eg. /etc/munin/plugins) with names
# according to the devices you wish to monitor, eg:
#
# eatonups_ups.server1
# eatonups_ups.server2
#
# 3. In /etc/munin/munin.conf just add these lines for them. Yes, 127.0.0.1 is correct
# because that points to the munin-node address not the UPS address.
#
# [eatonups_ups.server1]
# address 127.0.0.1
#
# [eatonups_ups.server2]
# address 127.0.0.1
#
# 4. Restart the munin node by 'service munin-node restart'.
#
# If all went well, after 5 minutes or so you should have two additional nodes listed
# on the Web Interface of munin.
#
# Tested & working with Eaton USP model PW9130 1500VA-R, with installed ConnectUPS Web/SNMP Card
# firmware revision V4.36 with munin v.2.0.14 and Ubuntu LTS 12.04
# Created in 2013 by robi
# v0.2 - fixed frequency graph scale to center at 50Hz (correct value for Europe)
# v0.1 - initial version
##################################################################################################
case $0 in
*eatonups_*)
hostname=${0##*/eatonups_}
;;
esac
case $1 in
config)
echo "multigraph volt_ac"
echo "host_name $hostname"
echo "graph_args --base 1000"
echo "graph_title AC Voltage Mains"
echo "graph_vlabel Volts"
echo "graph_category sensors"
echo "graph_scale no"
echo "graph_info Input and Output voltage of the UPS."
echo "volt_in.label Input"
echo "volt_in.critical 210:250"
echo "volt_in.info Input mains voltage of the UPS."
echo "volt_out.label Output"
echo "volt_out.critical 210:250"
echo "volt_out.info Output mains voltage of the UPS."
echo
echo "multigraph volt_batt"
echo "host_name $hostname"
echo "graph_args --base 1000"
echo "graph_title DC Voltage Battery"
echo "graph_vlabel Volts"
echo "graph_category sensors"
echo "graph_scale no"
echo "graph_info Voltage of the internal battery of the UPS."
echo "volt_batt.label Battery"
echo "volt_batt.critical 45:65"
echo "volt_batt.info Battery voltage of the UPS."
echo
echo "multigraph curr_out"
echo "host_name $hostname"
echo "graph_args --base 1000"
echo "graph_title Output Current"
echo "graph_vlabel Ampers"
echo "graph_category sensors"
echo "graph_scale no"
echo "graph_info Output current of the UPS."
echo "curr_out.label Current"
echo "curr_out.critical 40"
echo "curr_out.info Output current of the UPS."
echo
echo "multigraph power"
echo "host_name $hostname"
echo "graph_args --base 1000"
echo "graph_title Power"
echo "graph_vlabel W or VA"
echo "graph_category sensors"
echo "graph_scale no"
echo "graph_info Output Power of the UPS."
echo "power_true.label True"
echo "power_true.critical 800"
echo "power_true.info True Power output of the UPS (Watts)."
echo "power_appr.label Apparent"
echo "power_appr.critical 1500"
echo "power_appr.info Apparent Power output of the UPS (VA)."
echo
echo "multigraph runtime"
echo "host_name $hostname"
echo "graph_args --base 1000"
echo "graph_title Runtime"
echo "graph_vlabel minutes"
echo "graph_category sensors"
echo "graph_scale no"
echo "graph_info Remaining runtime of the UPS."
echo "runtime.label Runtime"
echo "runtime.critical 30:"
echo "runtime.info Remaining runtime of the UPS (minutes)."
echo
echo "multigraph load"
echo "host_name $hostname"
echo "graph_args --base 1000"
echo "graph_title Load"
echo "graph_vlabel %"
echo "graph_category sensors"
echo "graph_scale no"
echo "graph_info Load of the UPS."
echo "load.label Load"
echo "load.critical 60"
echo "load.info Load of the UPS (percent)."
echo
echo "multigraph freq_in"
echo "host_name $hostname"
echo "graph_args --base 1000 -l 48.8 -u 51.2 --rigid --alt-y-grid"
echo "graph_title Frequency Input"
echo "graph_vlabel Hz"
echo "graph_category sensors"
echo "graph_scale no"
echo "graph_info Input frequency of the UPS."
echo "freq_in.label Hz in"
echo "freq_in.critical 49:51"
echo "freq_in.info Input frequency of the UPS."
echo
echo "multigraph freq_out"
echo "host_name $hostname"
echo "graph_args --base 1000 -l 48.8 -u 51.2 --rigid --alt-y-grid"
echo "graph_title Frequency Output"
echo "graph_vlabel Hz"
echo "graph_category sensors"
echo "graph_scale no"
echo "graph_info Output frequency of the UPS."
echo "freq_out.label Hz out"
echo "freq_out.critical 49:51"
echo "freq_out.info Output frequency of the UPS."
echo
echo "multigraph temp"
echo "host_name $hostname"
echo "graph_args --base 1000"
echo "graph_title Temperature"
echo "graph_vlabel degrees Celsius"
echo "graph_category sensors"
echo "graph_scale no"
echo "graph_info Internal Temperature of the UPS."
echo "temp.label Load"
echo "temp.critical 80"
echo "temp.info Internal Temperature of the UPS (degrees Celsius)."
echo
exit 0;;
esac
statusfile=/tmp/eatonups_munin_$hostname.html
wget -O $statusfile http://$hostname/PSummary.html -o /dev/null --timeout 9
if [ -f "$statusfile" ]
then
volt_in=`sed -n -e '/Voltage In/{n;p;}' $statusfile | sed 's/<[^>]*>//g'`
volt_out=`sed -n -e '/Voltage Out/{n;p;}' $statusfile | sed 's/<[^>]*>//g'`
volt_batt=`sed -n -e '/Voltage</{n;p;}' $statusfile | sed 's/<[^>]*>//g'`
curr_out=`sed -n -e '/Current Out/{n;p;}' $statusfile | sed 's/<[^>]*>//g'`
power_true=`sed -n -e '/True Power/{n;p;}' $statusfile | sed 's/<[^>]*>//g'`
power_appr=`sed -n -e '/Apparent Power/{n;p;}' $statusfile | sed 's/<[^>]*>//g'`
runtime=`sed -n -e '/Runtime/{n;p;}' $statusfile | sed 's/<[^>]*>//g'`
freq_in=`sed -n -e '/Frequency/{n;p;}' $statusfile | sed 's/<[^>]*>//g' | sed -n '1p'`
freq_out=`sed -n -e '/Frequency/{n;p;}' $statusfile | sed 's/<[^>]*>//g' | sed -n '2p'`
load=`sed -n -e '/UPS Load/{n;p;}' $statusfile | sed 's/<[^>]*>//g'`
temp=`sed -n -e '/UPS Internal Temperature/{n;p;}' $statusfile | sed 's/<[^>]*>//g'`
rm -f $statusfile
fi
echo "multigraph volt_ac"
echo -n "volt_in.value "
if [ -n "$volt_in" ]; then
echo "$volt_in"
else
echo "U"
fi
echo -n "volt_out.value "
if [ -n "$volt_out" ]; then
echo "$volt_out"
else
echo "U"
fi
echo
echo "multigraph volt_batt"
echo -n "volt_batt.value "
if [ -n "$volt_batt" ]; then
echo "$volt_batt"
else
echo "U"
fi
echo
echo "multigraph curr_out"
echo -n "curr_out.value "
if [ -n "$curr_out" ]; then
echo "$curr_out"
else
echo "U"
fi
echo
echo "multigraph power"
echo -n "power_true.value "
if [ -n "$power_true" ]; then
echo "$power_true"
else
echo "U"
fi
echo -n "power_appr.value "
if [ -n "$power_appr" ]; then
echo "$power_appr"
else
echo "U"
fi
echo
echo "multigraph runtime"
echo -n "runtime.value "
if [ -n "$runtime" ]; then
echo "$runtime"
else
echo "U"
fi
echo
echo "multigraph load"
echo -n "load.value "
if [ -n "$load" ]; then
echo "$load"
else
echo "U"
fi
echo
echo "multigraph freq_in"
echo -n "freq_in.value "
if [ -n "$freq_in" ]; then
echo "$freq_in"
else
echo "U"
fi
echo
echo "multigraph freq_out"
echo -n "freq_out.value "
if [ -n "$freq_out" ]; then
echo "$freq_out"
else
echo "U"
fi
echo
echo "multigraph temp"
echo -n "temp.value "
if [ -n "$temp" ]; then
echo "$temp"
else
echo "U"
fi
echo

93
plugins/power/nut Executable file
View file

@ -0,0 +1,93 @@
#!/bin/bash
# This script is intended for use with Munin to monitor
# UPS Load, Battery Charge, Input and Output Voltages
# querying data from NUT (www.networkupstools.org), tested under Ubuntu Linux
# v. 1.1, 12/16/2007
# (c) Alex Yanchenko (yanchenko{at}gmail.com), 2007
# Distributed under GPL v.3 (http://www.gnu.org/licenses/gpl-3.0.txt)
#
# The plugin can utilize automatic configuration,
# here are the basic steps (require root privileges):
# 1. Copy it as /usr/share/munin/plugins/nut_
# 2. Make executable: "chmod 755 /usr/share/munin/plugins/nut_"
# 3. Run "munin-node-configure --shell", you should see smth like
# "ln -s /usr/share/munin/plugins/nut_ /etc/munin/plugins/nut_apc_AT_localhost"
# with "apc@localhost" been UPS configured in upsmon.conf (see NUT docs).
# Note that "@" is replaced with "_AT_".
# Multiple UPS monitoring is supported as well.
# 4. Run the proposed command to create a link.
# 5. To verify, run "munin-node-configure", you should notice the "nut_" record
#
# Plugin | Used | Suggestions
# ------ | ---- | -----------
# nut_ | yes | apc_AT_localhost
#
# 6. Restart munin: "/etc/init.d/munin-node restart"
# 7. Hold on for 5 minutes at most and watch the graph appear.
# 8. Customize voltage warning that are commented out for now.
#
#%# family=contrib
#%# capabilities=autoconf suggest
function FETCH_DATA() {
# UPS address, fetched from file name
UPS=$(basename $0 | sed 's|^nut_||g' | sed 's|_AT_|@|g')
# Save data into variables
model=$(upsc $UPS | grep ups.model: | cut -d" " -f2)
in=$(upsc $UPS | grep input.voltage: | cut -d" " -f2)
out=$(upsc $UPS | grep output.voltage: | cut -d" " -f2)
load=$(upsc $UPS | grep ups.load: | cut -d" " -f2)
charge=$(upsc $UPS | grep battery.charge: | cut -d" " -f2)
}
# Munin routines
case "$1" in
autoconf)
grep ^MONITOR < /etc/nut/upsmon.conf &> /dev/null
if [[ "$?" = "0" ]]; then
echo yes
exit 0
else
echo "no (NUT not installed or no UPS info available in /etc/nut/upsmon.conf)"
exit 1
fi
;;
config)
FETCH_DATA
cat << EOM
graph_title UPS: $model - $UPS
graph_category sensors
graph_info The graph shows UPS info monitored by NUT.
graph_args --base 1000 --lower-limit 0
in.label Input Voltage (v)
in.warning 190:260
out.label Output Voltage (v)
out.critical 208:253
charge.label Battery Charge (%)
charge.draw AREA
charge.colour 00aaaa
charge.warning 30:
load.label UPS Load (%)
load.colour ff0000
load.warning :80
EOM
exit 0
;;
suggest)
grep ^MONITOR < /etc/nut/upsmon.conf | cut -d" " -f2 | sed 's|@|_AT_|g'
exit 0
;;
*)
FETCH_DATA
# Print data for Munin
cat << EOM
in.value $in
out.value $out
charge.value $charge
load.value $load
EOM
exit 0
;;
esac

318
plugins/power/nutups2_ Executable file
View file

@ -0,0 +1,318 @@
#! /usr/bin/perl -w
=head1 NAME
nutups2_ - Plugin to monitor UPSes managed by NUT
=head1 CONFIGURATION
Generally none needed.
If you have installed NUT at a non-standard location, then you can specify its
location like:
[nutups2_*]
env.upsc /some/location/bin/upsc
=head1 WARNING AND CRITICAL SETTINGS
If upsc reports 'high' and 'low' values for some attribute, those will used
as the critical range. Otherwise the following environment variables can be
used to set the defaults for all fields:
env.warning
env.critical
You can also control individual fields like:
env.input_L1.warning
env.output.critical
=head1 MAGIC MARKERS
#%# family=auto
#%# capabilities=autoconf suggest
=head1 FEATURES
The plugin supports reporting battery charge, UPS load, input/output
frequencies/currents/voltages, apparent and real power output, humidity and
temperature readings. Note however that different UPS models report different
levels of detail; the plugin reports whatever information the NUT UPS driver
(and in turn the UPS itself) provides.
Although the 'suggest' command will only offer UPSes for which the local host
is the master, you can also monitor remote UPSes if you include the host name
in the symlink, like:
nutups2_<upsname>@<hostname or address>_frequency
etc.
=head1 AUTHOR
Gábor Gombás <gombasg@sztaki.hu>
=head1 LICENSE
GPLv2 or later
=cut
use strict;
use Munin::Plugin;
use Carp;
my $UPSC = $ENV{'upsc'} || 'upsc';
# For the 'filter' field, the first sub-match should contain the name to
# display, and the second sub-match should indicate if it is a nominal
# value instead of a sensor reading.
my %config = (
charge => {
filter => qr/^(.*)\.(?:charge|load)$/,
title => 'UPS load and battery charge',
args => '--base 1000 -l 0 -u 100',
vlabel => '%',
config => \&common_config,
fetch => \&common_fetch,
},
current => {
filter => qr/^(.*)\.current(\.nominal)?$/,
title => 'UPS current',
args => '--base 1000 -l 0',
vlabel => 'Amper',
config => \&common_config,
fetch => \&common_fetch,
},
frequency => {
filter => qr/^(.*)\.frequency(\.nominal)?$/,
title => 'UPS frequency',
args => '--base 1000 -l 0',
vlabel => 'Hz',
config => \&common_config,
fetch => \&common_fetch,
},
humidity => {
filter => qr/^(.*)\.humidity$/,
title => 'UPS humidity',
args => '--base 1000 -l 0',
vlabel => '%',
config => \&common_config,
fetch => \&common_fetch,
},
power => {
filter => qr/^(.*)\.power(\.nominal)?$/,
title => 'UPS apparent power',
args => '--base 1000 -l 0',
vlabel => 'VA',
config => \&common_config,
fetch => \&common_fetch,
},
realpower => {
filter => qr/^(.*)\.realpower(\.nominal)?$/,
title => 'UPS real power',
args => '--base 1000 -l 0',
vlabel => 'Watt',
config => \&common_config,
fetch => \&common_fetch,
},
temperature => {
filter => qr/^(.*)\.temperature$/,
title => 'UPS temperature',
args => '--base 1000 -l 0',
vlabel => 'Celsius',
config => \&common_config,
fetch => \&common_fetch,
},
voltage => {
filter => qr/^(.*)\.voltage(\.nominal)?$/,
title => 'UPS voltage',
args => '--base 1000 -l 0',
vlabel => 'Volt',
config => \&common_config,
fetch => \&common_fetch,
},
);
sub read_ups_values {
my $ups = shift;
my @lines = `$UPSC $ups 2>/dev/null`;
my $values = {};
for my $line (@lines) {
chomp $line;
my ($key, $value) = $line =~ m/^([^:]+):\s+(\S.*)$/;
$values->{$key} = $value;
}
return $values;
}
sub graph_config {
my ($func, $ups, $values) = @_;
print "graph_title " . $config{$func}->{'title'} . " ($ups)\n";
print "graph_vlabel " . $config{$func}->{'vlabel'} . "\n";
print "graph_args " . $config{$func}->{'args'} . "\n";
print "graph_category sensors\n";
my @info;
push @info, 'Manufacturer: "' . $values->{'ups.mfr'} . '"'
if exists $values->{'ups.mfr'} and $values->{'ups.mfr'} ne 'unknown';
push @info, 'Model: "' . $values->{'ups.model'} . '"'
if exists $values->{'ups.model'};
push @info, 'Serial: "' . $values->{'ups.serial'} . '"'
if exists $values->{'ups.serial'};
map { s/\s+/ /g } @info;
print "graph_info " . join(', ', @info) . "\n"
if @info;
}
sub print_range_warning {
my ($id, $key, $values) = @_;
if (exists $values->{$key . '.minimum'}) {
print $id . ".min " . $values->{$key . '.minimum'} . "\n";
}
if (exists $values->{$key . '.maximum'}) {
print $id . ".max " . $values->{$key . '.maximum'} . "\n";
}
my $range = '';
if (exists $values->{$key . '.high'}) {
$range = $values->{$key . '.high'};
}
if (exists $values->{$key . '.low'}) {
$range = $values->{$key . '.low'} . ':' . $range;
}
# print_thresholds() needs 'undef' for no range
undef $range unless $range;
print_thresholds($id, undef, undef, undef, $range);
}
# Example keys for voltages:
# battery.voltage
# battery.voltage.minimum
# battery.voltage.maximum
# battery.voltage.nominal
# input.voltage
# input.voltage.minimum
# input.voltage.maximum
# input.bypass.L1-N.voltage
# input.L1-N.voltage
# output.voltage
# output.voltage.nominal
# output.L1-N.voltage
#
# Replace 'voltage' with 'current' in the above list to get an example
# for current keys.
#
# Frequency keys:
# input.frequency
# input.frequency.nominal
# input.bypass.frequency
# input.bypass.frequency.nominal
# output.frequency
# output.frequency.nominal
# output.frequency.minimum
# output.frequency.maximum
sub common_config {
my ($func, $ups) = @_;
my $values = read_ups_values($ups);
graph_config($func, $ups, $values);
for my $key (sort keys %$values) {
my ($field, $nominal) = $key =~ $config{$func}->{'filter'};
next unless $field;
$field .= $nominal if $nominal;
my $id = clean_fieldname($field);
# These labels look better this way and are still short enough
$field = $key if $func =~ m/(charge|temperature|humidity)/;
# Beautification
$field = ucfirst($field);
$field =~ s/\./ /g;
print $id . ".label " . $field . "\n";
print $id . ".type GAUGE\n";
# Draw nominal values a litle thinner
print $id . ".draw LINE1\n" if $nominal;
print_range_warning($id, $key, $values);
}
}
sub common_fetch {
my ($func, $ups) = @_;
my $values = read_ups_values($ups);
for my $key (sort keys %$values) {
my ($field, $nominal) = $key =~ $config{$func}->{'filter'};
next unless $field;
$field .= $nominal if $nominal;
my $id = clean_fieldname($field);
print $id . ".value " . $values->{$key} . "\n";
}
}
if ($ARGV[0] and $ARGV[0] eq 'autoconf') {
# The former nutups_ plugin parsed upsmon.conf. But for a large UPS
# that powers dozens or hundreds of machines, that would mean
# monitoring the same UPS from every host it powers, which does not
# make sense. Using upsc and defaulting to localhost means that
# 'autoconf' will only enable the plugin on the UPS master node, where
# upsd is running.
my @upses = `$UPSC -l 2>/dev/null`;
if ($?) {
if ($? == -1) {
print "no (program '$UPSC' was not found)\n";
}
else {
print "no (program '$UPSC -l' returned error)\n";
}
exit 0;
}
map { chomp $_ } @upses;
unless (@upses and $upses[0]) {
print "no (program '$UPSC' listed no units)\n";
}
else {
print "yes\n";
}
exit 0;
}
if ($ARGV[0] and $ARGV[0] eq 'suggest') {
my @upses = `$UPSC -l 2>/dev/null`;
for my $ups (@upses) {
chomp $ups;
for my $metric (keys %config) {
my $values = read_ups_values($ups);
my @keys = grep { +$_ =~ $config{$metric}->{'filter'} } keys(%$values);
print $ups . '_' . $metric . "\n" if @keys;
}
}
exit 0;
}
croak("Unknown command line arguments") if $ARGV[0] and $ARGV[0] ne 'config';
# The UPS name may contain underscores
my $fn_re = join('|', keys %config);
my ($ups, $func) = $0 =~ m/nutups2_(.*)_($fn_re)$/;
if ($ARGV[0] and $ARGV[0] eq 'config') {
$config{$func}->{'config'}($func, $ups);
}
else {
$config{$func}->{'fetch'}($func, $ups);
}
exit 0;

533
plugins/power/snmp__apc_ups Executable file
View file

@ -0,0 +1,533 @@
#!/usr/bin/perl
=head1 NAME
snmp__apc_ups - Munin multigraph plugin for APC UPSes
=head1 APPLICABLE SYSTEMS
The UPS must support the PowerNet-MIB published by APC. This includes
the APC Smart-UPS series on which this plugin was tested.
=head1 CONFIGURATION
As a rule SNMP plugins need site specific configuration. The default
configuration (shown here) will only work on insecure sites/devices.
[snmp_*]
env.version 2
env.community public
In general SNMP is not very secure at all unless you use SNMP version
3 which supports authentication and privacy (encryption). But in any
case the community string for your devices should not be "public".
Please see 'perldoc Munin::Plugin::SNMP' for further configuration
information.
=head1 INTERPRETATION
Please refer to the PowerNet-MIB when in doubt.
=head1 MIB INFORMATION
This plugin requires support for the PowerNet-MIB published by APC.
=head1 PROGRAMMERS
This plugin is actually a generic SNMP multigraph plugin. If you
customize the data structures, especially %oidList and %label which is
used to drive the loops. Take care that labels and structure of these
hashes match otherwise things will disappear with not much warning.
But se munin-node.log, munin-update.log and run the plugin with
munin-run.
=head1 MAGIC MARKERS
#%# family=snmpauto
#%# capabilities=snmpconf
=head1 BUGS
Probably.
=head1 AUTHOR
Based on work by Gorlow Maxim and Andrey Yakovlev. Totaly reworked by
Nicolai Langfeldt, BroadNet AS, Oslo, Norway.
(C) 2013 BroadNet AS, Nicolai Langfeldt
=head1 LICENSE
GPLv2 only.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 dated June, 1991.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
USA.
=cut
use strict;
use warnings;
use feature qw(say);
use Carp;
use Data::Dumper;
use Munin::Plugin;
use Munin::Plugin::SNMP;
use vars qw($DEBUG);
$DEBUG = $Munin::Plugin::DEBUG;
# ################ Change here to customize
# oidList - things to graph - must be complete
my %oidList =
# _meta will be fetched but not graphed. The values can be placed in
# texts by [OID:1.3.6.....] notation in any text in the "config"
# output from the plugin. _meta is not used anywhere else than for
# this.
( _meta =>
{ upsBasicIdentModel => '1.3.6.1.4.1.318.1.1.1.1.1.1.0',
upsAdvIdentSerialNumber => '1.3.6.1.4.1.318.1.1.1.1.2.3.0',
upsAdvConfigRatedOutputVoltage => '1.3.6.1.4.1.318.1.1.1.5.2.1.0', # 230
upsAdvConfigHighTransferVolt => '1.3.6.1.4.1.318.1.1.1.5.2.2.0', # 208
upsAdvConfigLowTransferVolt => '1.3.6.1.4.1.318.1.1.1.5.2.3.0', # 253
},
time =>
{ upsAdvBatteryRunTimeRemaining => '1.3.6.1.4.1.318.1.1.1.2.2.3.0',
upsAdvConfigLowBatteryRunTime => '1.3.6.1.4.1.318.1.1.1.5.2.8.0' },
volt =>
{ upsAdvOutputVoltage => '1.3.6.1.4.1.318.1.1.1.4.2.1.0',
upsAdvInputLineVoltage => '1.3.6.1.4.1.318.1.1.1.3.2.1.0',
upsAdvInputMaxLineVoltage => '1.3.6.1.4.1.318.1.1.1.3.2.2.0',
upsAdvInputMinLineVoltage => '1.3.6.1.4.1.318.1.1.1.3.2.3.0' },
batteryvolt =>
{ upsAdvBatteryActualVoltage => '1.3.6.1.4.1.318.1.1.1.2.2.8.0' },
frequency =>
{ upsAdvOutputFrequency => '1.3.6.1.4.1.318.1.1.1.4.2.2.0',
upsAdvInputFrequency => '1.3.6.1.4.1.318.1.1.1.3.2.4.0' },
status =>
{ upsBasicOutputStatus => '1.3.6.1.4.1.318.1.1.1.4.1.1.0',
upsBasicBatteryStatus => '1.3.6.1.4.1.318.1.1.1.2.1.1.0',
upsAdvBatteryReplaceIndicator => '1.3.6.1.4.1.318.1.1.1.2.2.4.0',
upsCommStatus => '1.3.6.1.4.1.318.1.1.1.8.1.0',
upsAdvTestDiagnosticsResults => '1.3.6.1.4.1.318.1.1.1.7.2.3.0' },
temperature =>
{ upsAdvBatteryTemperature => '1.3.6.1.4.1.318.1.1.1.2.2.2.0',
iemStatusProbeCurrentTemp => '1.3.6.1.4.1.318.1.1.10.2.3.2.1.4.1' },
load =>
{ upsAdvOutputLoad => '1.3.6.1.4.1.318.1.1.1.4.2.3.0',
upsAdvBatteryCapacity => '1.3.6.1.4.1.318.1.1.1.2.2.1.0' },
current =>
{ upsAdvOutputCurrent => '1.3.6.1.4.1.318.1.1.1.4.2.4.0',
upsAdvBatteryCurrent => '1.3.6.1.4.1.318.1.1.1.2.2.9.0',
upsAdvTotalDCCurrent => '1.3.6.1.4.1.318.1.1.1.2.2.10.0' },
);
# Customize data series labels here. Must be complete otherwise the
# data series will not appear in graphs.
my %label =
( time => { upsAdvBatteryRunTimeRemaining => 'Time left',
upsAdvConfigLowBatteryRunTime => 'Alarm' },
volt => { upsAdvOutputVoltage => 'Output',
upsAdvInputLineVoltage => 'Input',
upsAdvInputMaxLineVoltage => 'Max In',
upsAdvInputMinLineVoltage => 'Min In' },
batteryvolt => { upsAdvBatteryActualVoltage => 'Battery' },
frequency => { upsAdvOutputFrequency => 'Output',
upsAdvInputFrequency => 'Input' },
status => { upsBasicOutputStatus => 'Output',
upsBasicBatteryStatus => 'Battery',
upsCommStatus => 'Comms',
upsAdvTestDiagnosticsResults => 'Diag',
upsAdvBatteryReplaceIndicator => 'Replace' },
temperature => { upsAdvBatteryTemperature => 'Battery',
iemStatusProbeCurrentTemp => 'Probe' },
load => { upsAdvOutputLoad => 'Usage',
upsAdvBatteryCapacity => 'Total' },
current => { upsAdvOutputCurrent => 'Output',
upsAdvBatteryCurrent => 'Battery',
upsAdvTotalDCCurrent => 'Total DC' }
);
# http://munin-monitoring.org/wiki/fieldname.type for more
# information. Overrides here:
# Default
my $tstype = 'GAUGE';
# Overrides
my %tstype = ();
# How to draw.
#
# By default drawing is LINE1, overrides here. It will be hard to do
# the STACK types in this plugin since they are ordering sensitive.
# If you want that you will need to expand this plugin to define and
# use a %ordering hash that enforces field order so that stacks come
# out right.
my %tsdraw =
(
batteryvolt => { upsAdvBatteryActualVoltage => 'LINE2' },
);
# Minimum and maximum values. Values outside the ragne given by these
# will be tossed. None needed by default, add as needed in the same
# nested fashion as %label.
my %tsmin = ();
my %tsmax = ();
# Example:
#
# my %tsmin =
# ( temperature => { upsAdvBatteryTemperature => 10 } );
#
# my %tsmax =
# ( temperature => { upsAdvBatteryTemperature => 150 } );
# Warning and Critical ranges. None needed by default. Add as
# needed.
my %tswarn =
( status => { upsBasicOutputStatus => '2:5' },
time => { upsAdvBatteryRunTimeRemaining => '90:' },
);
my %tscrit =
( status => { upsAdvBatteryReplaceIndicator => '1:1',
upsBasicBatteryStatus => '2:2',
upsBasicOutputStatus => '2:6',
upsCommStatus => '1:1',
upsAdvTestDiagnosticsResults => '1:1' },
frequency => { upsAdvInputFrequency => '49:51',
upsAdvOutputFrequency => '49:51' },
time => { upsAdvBatteryRunTimeRemaining => '60:' },
volt => { upsAdvOutputVoltage =>
'[OID:1.3.6.1.4.1.318.1.1.1.5.2.3.0]:'.
'[OID:1.3.6.1.4.1.318.1.1.1.5.2.2.0]',
upsAdvInputLineVoltage =>
'[OID:1.3.6.1.4.1.318.1.1.1.5.2.3.0]:'.
'[OID:1.3.6.1.4.1.318.1.1.1.5.2.2.0]' },
);
my %cdef =
( time =>
{ upsAdvBatteryRunTimeRemaining => 'upsAdvBatteryRunTimeRemaining,6000,/',
upsAdvConfigLowBatteryRunTime => 'upsAdvConfigLowBatteryRunTime,6000,/' }
);
my %title =
( time => 'Time left on battery',
volt => 'Line Voltages',
batteryvolt => 'Battery Voltage',
frequency => 'Line frequency',
status => 'Status codes',
temperature => 'Temperatures',
load => 'Load/Capacity',
current => 'Currents'
);
# Vertical labels on the graph
my %vlabel =
( time => 'minutes',
volt => 'Volt',
batteryvolt => 'Volt',
frequency => 'Hz',
status => 'code value',
temperature => 'Celsius',
load => 'Percent',
current => 'Ampere',
);
# Extra information on the whole graph.
my %info =
( time => 'Time left on battery and when shutdown occurs. In minutes.',
volt => 'Current input and output voltages. The min and max '.
'readings are for the last minute. Note that the values '.
'are collected every 5 minutes. Nominal voltage is '.
'[OID:1.3.6.1.4.1.318.1.1.1.5.2.1.0]',
status => 'Coded statuses. UPS Model: '.
'[OID:1.3.6.1.4.1.318.1.1.1.1.1.1.0]. '.
'Serial number: [OID:1.3.6.1.4.1.318.1.1.1.1.2.3.0]',
load => 'Current load and capacity on/of the UPS in percent.',
current => 'The current in amperes.',
temperature => 'Current temperatures. Possebly only the battery.',
batteryvolt => 'Current battery bus DC voltage. For a 24V battery pack '.
'this should be around 26-27V.',
frequency => 'Current input and output AC frequency',
);
# Extra information for a time series
my %subinfo =
( load =>
{ upsAdvOutputLoad => 'The current UPS load expressed in percent '.
'of rated capacity.',
upsAdvBatteryCapacity => 'The remaining battery capacity expressed '.
'in percent of full capacity.' },
status =>
{ upsBasicOutputStatus => 'Codes: 1: unknown, 2: onLine (GREEN), '.
'3: onBattery (YELLOW) 4: onSmartBoost 5: timedSleeping, '.
'6: softwareBypass 7: off 8: rebooting, '.
'9: switchedBypass 10: hardwareFailureBypass, '.
'11: sleepingUntilPowerReturn 12: onSmartTrim '.
'13: ecoMode 14: hotStandby 15: onBatteryTest',
upsBasicBatteryStatus => 'The status of the UPS batteries. A '.
'batteryLow(3) value indicates the UPS will be unable '.
'to sustain the current load, and its services will be '.
'lost if power is not restored. The amount of run time '.
'in reserve at the time of low battery can be configured '.
'by the upsAdvConfigLowBatteryRunTime.',
upsAdvBatteryReplaceIndicator => 'Battery replacement indicator. '.
'1: All OK 2: Battery needs replacing',
upsCommStatus => "The status of agent's communication ".
'with UPS. 1: OK 2: Failed',
upsAdvTestDiagnosticsResults => 'The results of the last UPS '.
'diagnostics test performed. 1: OK, 2: Failed, '.
'3: invalidTest, 4: testInProgress' },
time =>
{ upsAdvBatteryRunTimeRemaining => 'The UPS battery run time '.
'remaining before battery exhaustion.',
upsAdvConfigLowBatteryRunTime => 'The desired run time of the UPS, '.
'in minutes, once the low battery condition is reached. '.
'During this time the UPS will produce a constant warning '.
'tone which can not be disabled.' },
current =>
{ upsAdvOutputCurrent => "The current in Amperes drawn by the load on the UPS.",
upsAdvBatteryCurrent => "The battery current in Apmeres.",
upsAdvTotalDCCurrent => "The total DC current in Amperes.", },
);
# Extinfo is presented in conjunction with the time series information
# under the graph. Usually it supplies extra information specific to
# a fault, but it might also provide any information for any reason.
my %extinfo =
( status =>
{ upsAdvTestDiagnosticsResults => "Last diagnostic performed [OID:1.3.6.1.4.1.318.1.1.1.7.2.4.0]" } );
# ########################## Code here
sub collect_snmp {
# Mash together all the OIDs needed by the different graphs and
# make a (one) query to get them all. Returns a hash of the
# values keyed by OID.
#
# Occurrences of "noSuchInstance" is replaced by "U".
my ( $snmp ) = @_;
my @oids = ();
foreach my $graph ( keys %oidList ) {
foreach my $oid ( values %{ $oidList{$graph} } ) {
push(@oids, $oid);
}
}
my $values = $snmp->get_request( -varbindlist => \@oids );
if ( $snmp->error() ) {
die "$Munin::Plugin::me: SNMP error ".$snmp->error();
}
# Modify $values in place
map { $values->{$_} = 'U'
if $values->{$_} eq 'noSuchInstance'; } keys %$values;
return $values;
}
sub emit_a_fetch {
# Emit just one value line
my ( $text, $values, $key, $default ) = @_;
my $value = $values->{$key};
$value = $default if ! defined $value;
$value = 'U' if ! defined $value;
say "$text $value";
}
sub emit_fetch {
# Spew out
my ( $graph, $oids, $values ) = @_;
foreach my $label (keys %$oids) {
emit_a_fetch( "$label.value", $values, $oids->{$label}, 'U' );
}
}
sub emit_fetches {
# Emit all the fetches for all the multigraphs
my ( $snmp, $oids ) = @_;
my $values = collect_snmp( $snmp, $oids );
foreach my $graph (keys %label) {
say "multigraph $graph";
emit_fetch ( $graph, $oids->{$graph}, $values );
say '';
}
}
sub replace_oid {
my ( $str, $values ) = @_;
# If "str is [OID:1.3.6.1.2.1.1.5.0] then return the contents of sysName.0
my $oid = substr( $str, 5, -1 );
$str = $values->{$oid};
return $str;
}
sub process_oids {
my ( $str, $values ) = @_;
if ( ! defined $values ) {
croak("no values");
}
if ( $str =~ m/OID:/ ) {
$str =~ s/(\[OID:[^]]*])/&replace_oid($1, $values)/eg;
}
return $str;
}
sub emit_a_config {
# Emit a config line
# IF there is a default, always emit line.
# IF there is no default, only emit line if the hash lookup
# exists.
my ( $values, $text, $hash, $graph, $label, $default ) = @_;
if ( defined $default ) {
my $value = $hash->{$graph}->{$label};
$value = $default if ! defined $value;
$value = 'U' if ! defined $value;
say process_oids( "$text $value", $values );
return;
}
if ( exists $hash->{$graph}->{$label} ) {
say process_oids( "$text " . $hash->{$graph}->{$label}, $values );
}
}
sub emit_config {
# Emit a graph configuration
my ( $graph, $values ) = @_;
say "graph_title ".( $title{$graph} || "Untitled /$graph/");
say process_oids( "graph_vlabel " . $vlabel{$graph}, $values );
say "graph_category sensors";
say process_oids( "graph_info " . $info{$graph}, $values );
foreach my $label (keys %{ $label{$graph} } ) {
emit_a_config( $values, "$label.label", \%label, $graph, $label,
$label );
emit_a_config( $values, "$label.draw", \%tsdraw, $graph, $label,
'LINE1' );
emit_a_config( $values, "$label.type", \%tstype, $graph, $label,
$tstype );
emit_a_config( $values, "$label.min", \%tsmin, $graph, $label );
emit_a_config( $values, "$label.max", \%tsmax, $graph, $label );
emit_a_config( $values, "$label.cdef", \%cdef, $graph, $label );
emit_a_config( $values, "$label.info", \%subinfo,$graph, $label );
emit_a_config( $values, "$label.warning", \%tswarn, $graph, $label );
emit_a_config( $values, "$label.critical", \%tscrit, $graph, $label );
}
}
sub emit_configs {
my ( $snmp, $oids, $host, $results ) = @_;
my $values = collect_snmp( $snmp, $oids );
say "host_name $host";
say "";
foreach my $graph (keys %label) {
say "multigraph $graph";
emit_config( $graph, $values );
# If dirty config allowed:
emit_fetch ( $graph, $oids->{$graph}, $values );
say '';
}
}
sub main {
# need_multigraph();
if ($ARGV[0] and $ARGV[0] eq 'snmpconf') {
say "require 1.3.6.1.4.1.318.1.1.1.2.2.8.0 [0-9]";
exit 0;
}
my ( $host, undef ) = Munin::Plugin::SNMP::config_session();
# Ensure that we get times in ticks (hundredths of a second)
my $session =
Munin::Plugin::SNMP->session( -translate => [ -timeticks => 0x0 ] );
if ($ARGV[0] and $ARGV[0] eq 'config') {
emit_configs( $session, \%oidList, $host );
exit 0;
}
emit_fetches( $session, \%oidList );
exit 0;
}
main();

445
plugins/power/snmp__ipoman_ Executable file
View file

@ -0,0 +1,445 @@
#!/usr/bin/perl -w
#
# What is snmp__ipoman_
# ----------------------
# snmp__ipoman is a munin plugin written for the Ingrasys IpomanII 1202
# Power Distribution Unit. It should work on any PDU conforming to
# the IPOMANII-MIB.
#
# How do I use it
# ---------------
# You can use this plugin on a system with a working munin-node. Here's
# how:
#
# 1. Copy snmp__ipoman_ to the directory where all your munin plugins
# reside, for example /usr/share/munin/plugins.
#
# 2. Make the following symlinks to snmp__ipoman_ in that same directory
#
# snmp__ipoman_inletcurrent_
# snmp__ipoman_inletpower_
# snmp__ipoman_inletvoltage_
# snmp__ipoman_outletpower_
# snmp__ipoman_outletcurrent_
#
# (If you wonder why. I did not manage to make a plugin which has both
# the 'snmpconf' and the 'suggest' capabilities. So either I had to make
# separate plugins for all graph types, or I would have to make
# assumptions on the number of ports and the address of the ipoman in
# the script.)
#
# 3. Change to the directory where the links to munin plugins reside
# that are to be run by munin-node, for example /etc/munin/plugins/
#
# 4. Run munin-node-configure-snmp:
#
# $ munin-node-configure-snmp --snmpversion=1 <hostname> | sh -x
#
# where <hostname> is the hostname or ip address of your ipoman. This
# will create and print a bunch of symlinks to snmp__ipoman_ which will
# output current and power usage for all available outlets of the
# ipoman, and current, power usage and voltage/frequency on all inlets
# of the ipoman.
#
# 5. Restart munin-node
#
# 6. Make an entry in your munin server's munin.conf:
#
# [<hostname of ipoman as entered in 4.>]
# address <address of munin-node>
# use_node_name no
#
# 7. Done.
#
# Copyright (C) 2009 Rien Broekstra <rien@rename-it.nl>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; version 2 dated June,
# 1991.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
# Munin plugin to monitor power consumption and current of the sockets of an
# Ingrasys IpomanII 1202 Power Distribution Unit, or any power distribution
# unit that conforms to IPOMANII-MIB via SNMP.
#
# Parameters:
#
# config
# snmpconf
#
# Relevant OID's under .iso.org.dod.internet.private.enterprises.ingrasys.product.pduAgent.iPoManII
# .ipmObjects.ipmDevice.ipmDeviceOutlet.ipmDeviceOutletNumber.0
# .ipmObjects.ipmDevice.ipmDeviceOutlet.ipmDeviceOutletStatusTable.ipmDeviceOutletStatusEntry.outletStatusIndex.1
# .ipmObjects.ipmDevice.ipmDeviceOutlet.ipmDeviceOutletStatusTable.ipmDeviceOutletStatusEntry.outletStatusCurrent.1
# .ipmObjects.ipmDevice.ipmDeviceOutlet.ipmDeviceOutletStatusTable.ipmDeviceOutletStatusEntry.outletStatusKwatt.1
# .ipmObjects.ipmDevice.ipmDeviceOutlet.ipmDeviceOutletStatusTable.ipmDeviceOutletStatusEntry.outletStatusWH.1
#
# Version 0.1, Aug 4, 2009
#
#
#
#
#
#
#
#
#
#
# MAGIC MARKERS:
#
#%# family=snmpauto
#%# capabilities=snmpconf
use strict;
use Net::SNMP;
my $DEBUG = 0;
my $host = $ENV{host} || undef;
my $port = $ENV{port} || 161;
my $community = $ENV{community} || "public";
my $iface = $ENV{interface} || undef;
my $socketnumber;
my $response;
my $graphtype;
#
# Infer host, inlet/socketnumber and graphtype from the symlink name to this plugin.
#
if ($0 =~ /^(?:|.*\/)snmp_([^_]*)_ipoman_([^_]*)_(.*)$/)
{
$host = $1;
$graphtype = $2;
$socketnumber = $3;
if ($host =~ /^([^:]+):(\d+)$/) {
$host = $1;
$port = $2;
}
}
if (!defined($graphtype)) {
die "# Error: couldn't understand what quantity I'm supposed to monitor.";
}
#
# The relevant OID's on the IPOMAN
#
my $oid_inletnumber = ".1.3.6.1.4.1.2468.1.4.2.1.3.1.1.0";
my $oid_inletindextable = ".1.3.6.1.4.1.2468.1.4.2.1.3.1.2.1.1.";
my $oid_inletvoltage = ".1.3.6.1.4.1.2468.1.4.2.1.3.1.3.1.2.";
my $oid_inletcurrent = ".1.3.6.1.4.1.2468.1.4.2.1.3.1.3.1.3.";
my $oid_inletfrequency = ".1.3.6.1.4.1.2468.1.4.2.1.3.1.3.1.4.";
my $oid_inletenergy = ".1.3.6.1.4.1.2468.1.4.2.1.3.1.3.1.5.";
my $oid_outletnumber = ".1.3.6.1.4.1.2468.1.4.2.1.3.2.1.0";
my $oid_outletindextable = ".1.3.6.1.4.1.2468.1.4.2.1.3.2.3.1.1.";
my $oid_outletdescription = ".1.3.6.1.4.1.2468.1.4.2.1.3.2.2.1.2.";
my $oid_outletcurrent = ".1.3.6.1.4.1.2468.1.4.2.1.3.2.3.1.3.";
my $oid_outletenergy = ".1.3.6.1.4.1.2468.1.4.2.1.3.2.3.1.4.";
# FIXME: The voltage is not defined per outlet. For now we just assume that all sockets have the voltage on inlet 1.
my $oid_outletvoltage = ".1.3.6.1.4.1.2468.1.4.2.1.3.1.3.1.2.1";
#
# The snmpconf section prints out what oid's we need for the quantity we want to monitor, and where we find out how many ports the device has.
#
if (defined $ARGV[0] and $ARGV[0] eq "snmpconf") {
if ($graphtype eq "inletvoltage") {
print "number $oid_inletnumber\n";
print "index $oid_inletindextable\n";
print "require $oid_inletvoltage [0-9]+\n";
print "require $oid_inletfrequency [0-9]+\n";
}
elsif ($graphtype eq "inletcurrent") {
print "number $oid_inletnumber\n";
print "index $oid_inletindextable\n";
print "require $oid_inletcurrent [0-9]+\n";
}
elsif ($graphtype eq "inletpower") {
print "number $oid_inletnumber\n";
print "index $oid_inletindextable\n";
print "require $oid_inletvoltage [0-9]+\n";
print "require $oid_inletcurrent [0-9]+\n";
}
elsif ($graphtype eq "outletcurrent") {
print "number $oid_outletnumber\n";
print "index $oid_outletindextable\n";
print "require $oid_outletcurrent [0-9]+\n";
}
elsif ($graphtype eq "outletpower") {
print "number $oid_outletnumber\n";
print "index $oid_outletindextable\n";
print "require $oid_outletvoltage [0-9]+\n";
print "require $oid_outletcurrent [0-9]+\n";
}
else {
print "require dont.graph.anything [0-9]+\n"
}
exit 0;
}
#
# For all other options we need to connect to the host in our $0. if we cannot, bail out.
#
if (!defined($host))
{
print "# Debug: $0 -- $1 -- $2\n" if $DEBUG;
die "# Error: couldn't understand what I'm supposed to monitor.";
}
my ($session, $error) = Net::SNMP->session(
-hostname => $host,
-community => $community,
-port => $port
);
if (!defined ($session))
{
die "Croaking: $error";
}
#
# Output graph configuration depending on what quantity we want to plot
#
if (defined $ARGV[0] and $ARGV[0] eq "config") {
print "host_name $host\n";
if ($graphtype eq "inletvoltage") {
print "graph_title Inlet $socketnumber voltage/frequency\n";
print "graph_args --base 1000 -l 0\n";
print "graph_category sensors\n";
print "graph_info This graph shows the tension and frequency to inlet $socketnumber on the Power Distribution Unit\n";
print "voltage.label Tension (V)\n";
print "voltage.draw LINE2\n";
print "voltage.type GAUGE\n";
print "frequency.label Frequency (Hz)\n";
print "frequency.draw LINE2\n";
print "frequency.type GAUGE\n";
}
elsif ($graphtype eq "inletcurrent") {
print "graph_title Inlet $socketnumber current\n";
print "graph_args --base 1000 -l 0\n";
print "graph_category sensors\n";
print "graph_info This graph shows the delivered current to inlet $socketnumber on the Power Distribution Unit\n";
print "current.label Current (A)\n";
print "current.draw AREA\n";
print "current.type GAUGE\n";
}
elsif ($graphtype eq "inletpower") {
print "graph_title Inlet $socketnumber power\n";
print "graph_args --base 1000 -l 0\n";
print "graph_category sensors\n";
print "graph_info This graph shows the delivered apparent and real power to inlet $socketnumber of the Power Distribution Unit\n";
print "apparentpower.label Apparent power (kVA)\n";
print "apparentpower.draw LINE3\n";
print "apparentpower.type GAUGE\n";
print "realpower.label Real power (kW)\n";
print "realpower.draw AREA\n";
print "realpower.type COUNTER\n";
exit 0;
}
elsif ($graphtype eq "outletcurrent") {
print "graph_title Outlet $socketnumber current\n";
print "graph_args --base 1000 -l 0\n";
print "graph_category sensors\n";
print "graph_info This graph shows the delivered current to outlet $socketnumber of the Power Distribution Unit\n";
print "current.label Delivered current (A)\n";
print "current.draw AREA\n";
print "current.type GAUGE\n";
}
elsif ($graphtype eq "outletpower") {
print "graph_title Outlet $socketnumber power\n";
print "graph_args --base 1000 -l 0\n";
print "graph_category sensors\n";
print "graph_info This graph shows the delivered apparent and real power to outlet $socketnumber of the Power Distribution Unit\n";
print "apparentpower.label Apparent power (kVA)\n";
print "apparentpower.draw LINE3\n";
print "apparentpower.type GAUGE\n";
print "realpower.label Real power (kW)\n";
print "realpower.draw AREA\n";
print "realpower.type COUNTER\n";
exit 0;
}
exit 0;
}
if ($graphtype eq "inletvoltage") {
my ($voltage, $frequency);
if (defined ($response = $session->get_request($oid_inletvoltage.$socketnumber))) {
$voltage = $response->{$oid_inletvoltage.$socketnumber};
}
else {
$voltage = 'U';
}
if (defined ($response = $session->get_request($oid_inletfrequency.$socketnumber))) {
$frequency = $response->{$oid_inletfrequency.$socketnumber};
}
else {
$frequency = 'U';
}
# The IPOMAN returns tension in 0.1V units.
# Convert to V
if ($voltage ne 'U') {
$voltage = $voltage/10;
}
# The IPOMAN returns frequency in 0.1Hz units.
# Convert to Hz
if ($frequency ne 'U') {
$frequency = $frequency/10;
}
print "voltage.value ", $voltage, "\n";
print "frequency.value ", $frequency, "\n";
}
elsif ($graphtype eq "inletcurrent") {
my $current;
if (defined ($response = $session->get_request($oid_inletcurrent.$socketnumber))) {
$current = $response->{$oid_inletcurrent.$socketnumber};
}
else {
$current = 'U';
}
# The IPOMAN returns power in mA.
# Convert to A:
#
if ($current ne 'U') {
$current = $current/1000;
}
print "current.value ", $current, "\n";
}
elsif ($graphtype eq "inletpower") {
my ($current, $energy, $voltage, $apparentpower);
if (defined ($response = $session->get_request($oid_inletcurrent.$socketnumber))) {
$current = $response->{$oid_inletcurrent.$socketnumber};
}
else {
$current = 'U';
}
if (defined ($response = $session->get_request($oid_inletenergy.$socketnumber))) {
$energy = $response->{$oid_inletenergy.$socketnumber};
}
else {
$energy = 'U';
}
if (defined ($response = $session->get_request($oid_inletvoltage.$socketnumber))) {
$voltage = $response->{$oid_inletvoltage.$socketnumber};
}
else {
$voltage = 'U';
}
# Calculate results
# Apparent power (VA)= Voltage (V)* Current(A).
# IPOMAN delivers voltage in units of 0.1V. and current in units of mA:
if ($current ne 'U' && $voltage ne 'U') {
$apparentpower = ($current/1000)*($voltage/10);
}
#
# The IPOMAN returns consumed energy in Wh. We want it in J (= Ws), in order for munin to graph in W.
#
if ($energy ne 'U') {
$energy = $energy*3600;
}
print "realpower.value ", $energy, "\n";
print "apparentpower.value ", $apparentpower, "\n";
}
elsif ($graphtype eq "outletcurrent") {
my $current;
if (defined ($response = $session->get_request($oid_outletcurrent.$socketnumber))) {
$current = $response->{$oid_outletcurrent.$socketnumber};
}
else {
$current = 'U';
}
# The IPOMAN returns power in mA.
# Convert to A:
#
if ($current ne 'U') {
$current = $current/1000;
}
print "current.value ", $current, "\n";
}
elsif ($graphtype eq "outletpower") {
my ($current, $energy, $voltage, $apparentpower);
if (defined ($response = $session->get_request($oid_outletcurrent.$socketnumber))) {
$current = $response->{$oid_outletcurrent.$socketnumber};
}
else {
$current = 'U';
}
if (defined ($response = $session->get_request($oid_outletenergy.$socketnumber))) {
$energy = $response->{$oid_outletenergy.$socketnumber};
}
else {
$energy = 'U';
}
if (defined ($response = $session->get_request($oid_outletvoltage))) {
$voltage = $response->{$oid_outletvoltage};
}
else {
$voltage = 'U';
}
#
# Calculate results
# Apparent power (VA)= Voltage (V)* Current(A).
# IPOMAN delivers voltage in units of 0.1V. and current in units of mA:
if ($current ne 'U' && $voltage ne 'U') {
$apparentpower = ($current/1000)*($voltage/10);
}
#
# The IPOMAN returns consumed energy in Wh. We want it in J (= Ws), in order for munin to graph in W.
#
if ($energy ne 'U') {
$energy = $energy*3600;
}
print "realpower.value ", $energy, "\n";
print "apparentpower.value ", $apparentpower, "\n";
}
exit 0;

240
plugins/power/snmp__sentry Executable file
View file

@ -0,0 +1,240 @@
#!/usr/bin/perl -w
=head1 NAME
Munin plugin snmp__sentry is written to monitor the Sentry line of Power Distribution Units (PDU) offered by Server Technology.
This plugin currently assumes a 3-phase PDU.
=head1 AUTHOR
Danny Howard <dannyman@toldme.com>
This plugin was created on the behalf of Quantifind, Inc. http://www.quantifind.com
=head1 LICENSE
BSD
=head1 MAGIC MARKERS
#%# family=snmpauto
#%# capabilities=snmpconf
=head1 EXAMPLE MIB
$ wget ftp://ftp.servertech.com/pub/SNMP/sentry3/Sentry3.mib
$ snmpwalk -c public -v 2c -M +. -m +Sentry3-MIB 192.168.whatevs .1.3.6.1.4.1.1718.3.2.2
Sentry3-MIB::infeedID.1.1 = STRING: AA
Sentry3-MIB::infeedID.1.2 = STRING: AB
Sentry3-MIB::infeedID.1.3 = STRING: AC
Sentry3-MIB::infeedName.1.1 = STRING: Master_X
Sentry3-MIB::infeedName.1.2 = STRING: Master_Y
Sentry3-MIB::infeedName.1.3 = STRING: Master_Z
Sentry3-MIB::infeedCapabilities.1.1 = BITS: C6 00 onSense(0) loadSense(1) voltageSense(5) powerSense(6)
Sentry3-MIB::infeedCapabilities.1.2 = BITS: C6 00 onSense(0) loadSense(1) voltageSense(5) powerSense(6)
Sentry3-MIB::infeedCapabilities.1.3 = BITS: C6 00 onSense(0) loadSense(1) voltageSense(5) powerSense(6)
Sentry3-MIB::infeedStatus.1.1 = INTEGER: on(1)
Sentry3-MIB::infeedStatus.1.2 = INTEGER: on(1)
Sentry3-MIB::infeedStatus.1.3 = INTEGER: on(1)
Sentry3-MIB::infeedLoadStatus.1.1 = INTEGER: normal(0)
Sentry3-MIB::infeedLoadStatus.1.2 = INTEGER: normal(0)
Sentry3-MIB::infeedLoadStatus.1.3 = INTEGER: normal(0)
Sentry3-MIB::infeedLoadValue.1.1 = INTEGER: 717 hundredth Amps
Sentry3-MIB::infeedLoadValue.1.2 = INTEGER: 708 hundredth Amps
Sentry3-MIB::infeedLoadValue.1.3 = INTEGER: 787 hundredth Amps
Sentry3-MIB::infeedLoadHighThresh.1.1 = INTEGER: 16 Amps
Sentry3-MIB::infeedLoadHighThresh.1.2 = INTEGER: 16 Amps
Sentry3-MIB::infeedLoadHighThresh.1.3 = INTEGER: 16 Amps
Sentry3-MIB::infeedOutletCount.1.1 = INTEGER: 10
Sentry3-MIB::infeedOutletCount.1.2 = INTEGER: 10
Sentry3-MIB::infeedOutletCount.1.3 = INTEGER: 10
Sentry3-MIB::infeedCapacity.1.1 = INTEGER: 20 Amps
Sentry3-MIB::infeedCapacity.1.2 = INTEGER: 20 Amps
Sentry3-MIB::infeedCapacity.1.3 = INTEGER: 20 Amps
Sentry3-MIB::infeedVoltage.1.1 = INTEGER: 2055 tenth Volts
Sentry3-MIB::infeedVoltage.1.2 = INTEGER: 2034 tenth Volts
Sentry3-MIB::infeedVoltage.1.3 = INTEGER: 2052 tenth Volts
Sentry3-MIB::infeedPower.1.1 = INTEGER: 726 Watts
Sentry3-MIB::infeedPower.1.2 = INTEGER: 809 Watts
Sentry3-MIB::infeedPower.1.3 = INTEGER: 874 Watts
Sentry3-MIB::infeedApparentPower.1.1 = INTEGER: 793 Volt-Amps
Sentry3-MIB::infeedApparentPower.1.2 = INTEGER: 876 Volt-Amps
Sentry3-MIB::infeedApparentPower.1.3 = INTEGER: 941 Volt-Amps
Sentry3-MIB::infeedPowerFactor.1.1 = INTEGER: 92 hundredths
Sentry3-MIB::infeedPowerFactor.1.2 = INTEGER: 92 hundredths
Sentry3-MIB::infeedPowerFactor.1.3 = INTEGER: 93 hundredths
Sentry3-MIB::infeedCrestFactor.1.1 = INTEGER: 18 tenths
Sentry3-MIB::infeedCrestFactor.1.2 = INTEGER: 17 tenths
Sentry3-MIB::infeedCrestFactor.1.3 = INTEGER: 17 tenths
Sentry3-MIB::infeedEnergy.1.1 = INTEGER: 762 tenth Kilowatt-Hours
Sentry3-MIB::infeedEnergy.1.2 = INTEGER: 913 tenth Kilowatt-Hours
Sentry3-MIB::infeedEnergy.1.3 = INTEGER: 928 tenth Kilowatt-Hours
Sentry3-MIB::infeedReactance.1.1 = INTEGER: capacitive(1)
Sentry3-MIB::infeedReactance.1.2 = INTEGER: capacitive(1)
Sentry3-MIB::infeedReactance.1.3 = INTEGER: capacitive(1)
Sentry3-MIB::infeedPhaseVoltage.1.1 = INTEGER: 2055 tenth Volts
Sentry3-MIB::infeedPhaseVoltage.1.2 = INTEGER: 2034 tenth Volts
Sentry3-MIB::infeedPhaseVoltage.1.3 = INTEGER: 2052 tenth Volts
Sentry3-MIB::infeedPhaseCurrent.1.1 = INTEGER: 386 hundredth Amps
Sentry3-MIB::infeedPhaseCurrent.1.2 = INTEGER: 431 hundredth Amps
Sentry3-MIB::infeedPhaseCurrent.1.3 = INTEGER: 459 hundredth Amps
Sentry3-MIB::infeedCapacityUsed.1.1 = INTEGER: 358 tenth percentage
Sentry3-MIB::infeedCapacityUsed.1.2 = INTEGER: 354 tenth percentage
Sentry3-MIB::infeedCapacityUsed.1.3 = INTEGER: 393 tenth percentage
Sentry3-MIB::infeedLineID.1.1 = STRING: A:X
Sentry3-MIB::infeedLineID.1.2 = STRING: A:Y
Sentry3-MIB::infeedLineID.1.3 = STRING: A:Z
Sentry3-MIB::infeedLineToLineID.1.1 = STRING: A:X-Y
Sentry3-MIB::infeedLineToLineID.1.2 = STRING: A:Y-Z
Sentry3-MIB::infeedLineToLineID.1.3 = STRING: A:Z-X
Sentry3-MIB::infeedPhaseID.1.1 = STRING: A:X-Y
Sentry3-MIB::infeedPhaseID.1.2 = STRING: A:Y-Z
Sentry3-MIB::infeedPhaseID.1.3 = STRING: A:Z-X
=cut
use strict;
use Munin::Plugin::SNMP;
if (defined $ARGV[0] and $ARGV[0] eq "snmpconf") {
print "require 1.3.6.1.4.1.1718.3.2.2.1\n";
exit 0;
}
my $session = Munin::Plugin::SNMP->session(-translate =>
[ -timeticks => 0x0 ]);
my $sentry_h = $session->get_hash (
-baseoid => ".1.3.6.1.4.1.1718.3.2.2.1",
-cols => {
# maxcols 16 I guess
# 2 => 'infeedID',
3 => 'infeedName',
# 4 => 'infeedCapabilities',
# 5 => 'infeedStatus',
# 6 => 'infeedLoadStatus',
7 => 'infeedLoadValue',
8 => 'infeedLoadHighThresh',
# 9 => 'infeedOutletCount',
10 => 'infeedCapacity',
# 11 => 'infeedVoltage',
# 12 => 'infeedPower',
# 13 => 'infeedApparentPower',
14 => 'infeedPowerFactor',
15 => 'infeedCrestFactor',
# 16 => 'infeedEnergy',
# 17 => 'infeedReactance',
# 18 => 'infeedPhaseVoltage',
# 19 => 'infeedPhaseCurrent',
# 20 => 'infeedCapacityUsed',
# 21 => 'infeedLineID',
# 22 => 'infeedLineToLineID',
# 23 => 'infeedPhaseID',
}
);
if (defined $ARGV[0] and $ARGV[0] eq "config") {
my ($host) = Munin::Plugin::SNMP->config_session();
print "host_name $host\n" unless $host eq 'localhost';
print "
multigraph power_amps_drawn
graph_title Power Draw in Amps
graph_args --lower-limit 0
graph_vlabel Amps
graph_category sensors
graph_scale no
graph_info This shows the amperage drawn on your PDU. Per NEC, a PDU should not sustain 80% of its maximum circuit capacity for more than three hours.
";
foreach my $k ( keys %{$sentry_h} ) {
my $infeedName = $sentry_h->{$k}->{'infeedName'};
my $critical = ($sentry_h->{$k}->{'infeedCapacity'})*.9; # 90% of capacity
my $warning = $sentry_h->{$k}->{'infeedLoadHighThresh'}; # 80% of capacity
print "$infeedName.critical $critical\n";
print "$infeedName.draw LINE1\n";
print "$infeedName.label $infeedName\n";
print "$infeedName.min 0\n";
print "$infeedName.type GAUGE\n";
print "$infeedName.warning $warning\n";
}
print "
multigraph power_power_factor
graph_title Power Factor
graph_args --lower-limit 0
graph_vlabel Power Factor
graph_category sensors
graph_scale no
graph_info Power factor represents the efficiency of the components connected to the circuit. Power factor declines as components age, increasing the overall load on the circuit.
";
foreach my $k ( keys %{$sentry_h} ) {
my $infeedName = $sentry_h->{$k}->{'infeedName'};
print "$infeedName.draw LINE1\n";
print "$infeedName.label $infeedName\n";
print "$infeedName.type GAUGE\n";
}
print "
multigraph power_crest_factor
graph_title Crest Factor
graph_args --lower-limit 0
graph_vlabel Crest Factor
graph_category sensors
graph_scale no
graph_info Crest factor relates the peak value of a signal to its root mean square value. For three-phase AC, a crest factor of 1.732 is expected. Low crest factor may indicate UPS overclipping and crest factors over 5 degrade monitoring accuracy.
";
foreach my $k ( keys %{$sentry_h} ) {
my $infeedName = $sentry_h->{$k}->{'infeedName'};
print "$infeedName.draw LINE1\n";
print "$infeedName.label $infeedName\n";
print "$infeedName.type GAUGE\n";
}
exit 0;
}
print "multigraph power_amps_drawn\n";
foreach my $k ( keys %{$sentry_h} ) {
my $infeedName = $sentry_h->{$k}->{'infeedName'};
my $amps = $sentry_h->{$k}->{'infeedLoadValue'};
if ( $amps ) {
$amps = $amps * .01;
} else {
$amps = 'U';
}
print "$infeedName.value $amps\n";
}
print "multigraph power_power_factor\n";
foreach my $k ( keys %{$sentry_h} ) {
my $infeedName = $sentry_h->{$k}->{'infeedName'};
my $pf = $sentry_h->{$k}->{'infeedPowerFactor'};
if ( $pf ) {
$pf = $pf * .01;
} else {
$pf = 'U';
}
print "$infeedName.value $pf\n";
}
print "multigraph power_crest_factor\n";
foreach my $k ( keys %{$sentry_h} ) {
my $infeedName = $sentry_h->{$k}->{'infeedName'};
my $crest = $sentry_h->{$k}->{'infeedCrestFactor'};
if ( $crest ) {
$crest = $crest * .1;
} else {
$crest = 'U';
}
print "$infeedName.value $crest\n";
}

217
plugins/power/snmp__ups_ Executable file
View file

@ -0,0 +1,217 @@
#!/usr/bin/perl -w
#
# This plugin is for querying UPSes that support the UPS-MIB from RFC 1628
# - NOT APC (apparently)
#
# current version by Michael Meier <michael.meier@fau.de>
# previous version by Jean-Samuel Reynaud <js.reynaud@free.fr>
# based on snmp__if_ from Jimmy Olsen, Dagfinn Ilmari Mannsaaker
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; version 2 dated June,
# 1991.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
#
# Usage:
# ln -s /usr/share/munin/node/plugins-auto/snmp__ups_ /etc/munin/node.d/snmp_ups.domain.tld_ups_mode
# available modes:
# batteryruntime, batteryremaining, batterypercent, batteryvoltage,
# batterycurrent, batterytemperature,
# inputfrequency, inputvoltage, inputcurrent, inputpower,
# outputvoltage, outputcurrent, outputpower, outputpercentload,
# inputlinebads
# Most UPSs only support a small subset of these modes.
#
#%# family=snmpauto
#%# capabilities=snmpconf
use strict;
use Net::SNMP;
my $DEBUG = 0;
my $host = $ENV{host} || undef;
my $port = $ENV{port} || 161;
my $community = $ENV{community} || "public";
my $mode = $ENV{mode} || undef;
my $response;
if (defined $ARGV[0] and $ARGV[0] eq "snmpconf")
{
print "require .1.3.6.1.2.1.33.1.2.7 [0-9]\n"; # Bat temp
exit 0;
}
if ($0 =~ /^(?:|.*\/)snmp_([^_]+)_ups_(.+)$/)
{
$host = $1;
$mode = $2;
if ($host =~ /^([^:]+):(\d+)$/) {
$host = $1;
$port = $2;
}
}
elsif (!defined($host))
{
print("# Debug: $0 -- $1 -- $2\n") if $DEBUG;
print("# Error: couldn't understand what I'm supposed to monitor.\n");
print("# You need to either name this plugin properly in the scheme\n");
print("# snmp_HOSTNAME_ups_MODE\n");
print("# or alternatively set the environment variables 'host' and 'mode'\n");
exit(1);
}
my $graphs = {
'batteryruntime' => { 'title' => 'Seconds running on battery',
'unit' => 'seconds',
'label' => 'onbatteryfor',
'value' => '.1.3.6.1.2.1.33.1.2.2' },
'batteryremaining' => { 'title' => 'Estimated remaining runtime on battery',
'unit' => 'minutes',
'label' => 'remaining',
'value' => '.1.3.6.1.2.1.33.1.2.3' },
'batterypercent' => { 'title' => 'Estimated remaining charge',
'unit' => '%',
'label' => 'remaining',
'value' => '.1.3.6.1.2.1.33.1.2.4' },
'batteryvoltage' => { 'title' => 'Battery Voltage',
'unit' => 'Volt',
'scale' => 0.1,
'value' => '.1.3.6.1.2.1.33.1.2.5' },
'batterycurrent' => { 'title' => 'Battery current',
'unit' => 'Ampere',
'scale' => 0.1,
'value' => '.1.3.6.1.2.1.33.1.2.6' },
'batterytemperature' => { 'title' => 'Battery Temperature',
'unit' => 'degC',
'label' => 'Temperature %u',
'value' => '.1.3.6.1.2.1.33.1.2.7' },
'inputfrequency' => { 'title' => 'Input Frequency',
'scale' => 0.1,
'unit' => 'Hz',
'list' => '.1.3.6.1.2.1.33.1.3.2',
'value' => '.1.3.6.1.2.1.33.1.3.3.1.2' },
'inputvoltage' => { 'title' => 'Input Voltage',
'unit' => 'Volt',
'list' => '.1.3.6.1.2.1.33.1.3.2',
'value' => '.1.3.6.1.2.1.33.1.3.3.1.3' },
'inputcurrent' => { 'title' => 'Input Current',
'unit' => 'Ampere',
'scale' => 0.1,
'list' => '.1.3.6.1.2.1.33.1.3.2',
'value' => '.1.3.6.1.2.1.33.1.3.3.1.4' },
'inputpower' => { 'title' => 'Input Power',
'unit' => 'Watt',
'list' => '.1.3.6.1.2.1.33.1.3.2',
'value' => '.1.3.6.1.2.1.33.1.3.3.1.5' },
'outputvoltage' => { 'title' => 'Output Voltage',
'list' => '.1.3.6.1.2.1.33.1.4.3',
'unit' => 'Volt',
'value' => '.1.3.6.1.2.1.33.1.4.4.1.2' },
'outputcurrent' => { 'title' => 'Output Current',
'unit' => 'Ampere',
'scale' => 0.1,
'list' => '.1.3.6.1.2.1.33.1.4.3',
'value' => '.1.3.6.1.2.1.33.1.4.4.1.3' },
'outputpower' => { 'title' => 'Output Power',
'unit' => 'Watt',
'list' => '.1.3.6.1.2.1.33.1.4.3',
'value' => '.1.3.6.1.2.1.33.1.4.4.1.4' },
'outputpercentload' => { 'title' => 'Output Load',
'unit' => '%',
'list' => '.1.3.6.1.2.1.33.1.4.3',
'value' => '.1.3.6.1.2.1.33.1.4.4.1.5' },
'inputlinebads' => { 'title' => 'Number of times input power went bad',
'unit' => 'n',
'value' => '.1.3.6.1.2.1.33.1.3.1' }
};
my ($session, $error) = Net::SNMP->session(
-hostname => $host,
-community => $community,
-port => $port,
-timeout => 1.0
);
if (!defined($session)) {
print("# Failed to open SNMP session: $error\n");
exit(1);
}
unless (defined($graphs->{$mode}->{'title'})) {
print("# Unknown mode '$mode'! Available modes are:\n");
foreach my $m (keys(%{$graphs})) {
if (defined($graphs->{$m}->{'title'})) {
printf("# %-18s %s\n", $m, $graphs->{$m}->{'title'});
}
}
exit(1);
}
my $count_data = 1;
if (defined $graphs->{$mode}->{'list'}) {
if (defined ($response = $session->get_request($graphs->{$mode}->{'list'} . ".0"))) {
$count_data = $response->{$graphs->{$mode}->{'list'} . ".0"};
} else { # Unfortunately, some UPSs do not properly implement RFC 1628:
# They fail to report the number of lines.
# We will default to 3 as that will work in most cases.
# The environment variable 'numlines' can be used to override the default.
$count_data = 3;
if (defined($ENV{'numlines'})) {
$count_data = int($ENV{'numlines'});
}
}
}
if ($ARGV[0] and $ARGV[0] eq "config") {
print("host_name $host\n");
printf("graph_title %s\n", $graphs->{$mode}->{'title'});
# print "graph_args --base 1000\n";
print("graph_category sensors\n");
printf("graph_vlabel %s\n", $graphs->{$mode}->{'unit'});
for (my $i=0; $i < $count_data; $i++) {
my $ip1 = $i + 1;
if (defined($graphs->{$mode}->{'label'})) {
printf("%s%u.label %s\n", $mode, $ip1, sprintf($graphs->{$mode}->{'label'}, $ip1));
} else {
printf("%s%u.label Line %u\n", $mode, $ip1, $ip1);
}
printf("%s%u.type GAUGE\n", $mode, $ip1);
#printf "line%u.info %s\n",$i+1,$graphs->{$mode}->{'unit'};
if (defined($ENV{"${mode}${ip1}.warning"})) { printf("%s%s.warning %s\n", $mode, $ip1, $ENV{"${mode}${ip1}.warning"}); }
if (defined($ENV{"${mode}${ip1}.critical"})) { printf("%s%s.critical %s\n", $mode, $ip1, $ENV{"${mode}${ip1}.critical"}); }
}
exit(0);
}
for (my $i = 0; $i < $count_data; $i++) {
my $l_current = $i+1;
if ($count_data == 1) {
$l_current = 0;
}
if (defined ($response = $session->get_request($graphs->{$mode}->{'value'} . sprintf(".%u",$l_current)))) {
my $v = $response->{$graphs->{$mode}->{'value'} . sprintf(".%u",$l_current)};
if (defined($graphs->{$mode}->{'scale'})) {
$v = $v * $graphs->{$mode}->{'scale'};
printf("%s%u.value %.1f\n", $mode, $i+1, $v);
} else {
printf("%s%u.value %u\n", $mode, $i+1, $v);
}
} else {
printf("%s%u.value U\n", $mode, $i+1);
}
}

222
plugins/power/upsmonpro_ Normal file
View file

@ -0,0 +1,222 @@
#!/usr/bin/perl
=head1 NAME
upsmonpro_ - Munin plugin to monitor Powercom UPS via UPSMON PRO program L<http://www.pcm.ru/support/soft/>
=head1 INSTALLATION
/etc/munin/plugins/upsmonpro_load -> /usr/share/munin/plugins/upsmonpro_
/etc/munin/plugins/upsmonpro_status -> /usr/share/munin/plugins/upsmonpro_
/etc/munin/plugins/upsmonpro_temp -> /usr/share/munin/plugins/upsmonpro_
/etc/munin/plugins/upsmonpro_voltage -> /usr/share/munin/plugins/upsmonpro_
=head1 CONFIGURATION
Environment variables:
host - UPSMON PRO server host, default localhost
port - UPSMON PRO port, default 2601
Example configuration (optional):
[upsmonpro_*]
env.host localhost
env.port 2601
=head1 MAGIC MARKERS
#%# family=auto
#%# capabilities=autoconf
#%# capabilities=suggest
=head1 AUTHOR
Copyright (C) 2017 pru.mike@gmail.com
=head1 LICENSE
GPLv2.
=cut
use strict;
use warnings;
use feature qw/say/;
use Munin::Plugin;
use IO::Socket::INET;
use Time::HiRes qw/usleep/;
use English qw/-no-math-vars/;
our $VERSION = '0.0.1';
$OUTPUT_AUTOFLUSH++;
our $DEFAULT_HOST = 'localhost';
our $DEFAULT_PORT = 2601;
our %TYPES = (
voltage => [qw/input output/],
load => [qw/battery_load battery_capacity/],
temp => [q/temp/],
status => [qw/power_failure low_battery voltage_status ups_status battery_test/]
);
our @TYPES = sort keys %TYPES;
my %DISPATCH_TABLE = ();
my $pkg = __PACKAGE__;
$DISPATCH_TABLE{"${pkg}::run_suggest"} = \&run_suggest;
$DISPATCH_TABLE{"${pkg}::run_autoconf"} = \&run_autoconf;
for my $t (@TYPES) {
$DISPATCH_TABLE{"${pkg}::run_config_$t"} = \&{"run_config_$t"};
$DISPATCH_TABLE{"${pkg}::run_autoconf_$t"} = \&run_autoconf;
$DISPATCH_TABLE{"${pkg}::run_default_$t"} = sub {
run_default(@{ $TYPES{$t} });
};
}
find_key($ARGV[0])->();
sub find_key {
my $argv = shift || '';
my $type_re = join '|', @TYPES;
my $key;
if ($argv =~ /(suggest|autoconf)/i) {
$key = 'run_' . lc($1);
} elsif ($Munin::Plugin::me =~ /upsmonpro_{1,}($type_re)$/) {
my $graph = $1;
$key = 'run_' . ((grep { $argv eq $_ } qw/autoconf config/) ? $argv : 'default') . "_$graph";
} else {
die "Could not determine script type [@TYPES] ? name=$Munin::Plugin::me\n";
}
return $DISPATCH_TABLE{"${pkg}::$key"};
}
sub run_config_voltage {
print <<'END';
graph_title UPS Input/Output Voltage
graph_vlabel volt
graph_scale no
graph_category sensors
input.label input
input.info Input Voltage
input.type GAUGE
output.label output
output.info Output Voltage
output.type GAUGE
END
exit(0);
}
sub run_config_temp {
print <<'END';
graph_title UPS Temperature
graph_vlabel celsius
graph_scale no
graph_category sensors
temp.label temperature
temp.type GAUGE
END
exit(0);
}
sub run_config_load {
print <<'END';
graph_title UPS Battery Load/Capacity
graph_vlabel precent%
graph_scale no
graph_category sensors
battery_load.label battery_load
battery_load.type GAUGE
battery_capacity.label battery_capacity
battery_capacity.type GAUGE
END
exit(0);
}
sub run_config_status {
print <<'END';
graph_title UPS Statuses
graph_vlabel status
graph_scale no
graph_category sensors
power_failure.label power_failure
power_failure.type GAUGE
low_battery.label low_battery
low_battery.type GAUGE
voltage_status.label voltage_status
voltage_status.info 0 normal, 1 boost, 2 buck
voltage_status.type GAUGE
ups_status.label ups_status
ups_status.type GAUGE
battery_test.label battery_test
battery_test.type GAUGE
END
exit(0);
}
sub run_default {
my $host = $ENV{host} || $DEFAULT_HOST;
my $port = $ENV{port} || $DEFAULT_PORT;
my @val_list = @_;
my $r = gather_data($host, $port);
for (@val_list) {
die "Wrong value: $_" if not exists $r->{$_};
say "${_}.value $r->{$_}";
}
}
sub run_suggest {
local $LIST_SEPARATOR = "\n";
say "@TYPES";
exit(0);
}
sub run_autoconf {
if (gather_data($DEFAULT_HOST, $DEFAULT_PORT)->{response} eq 'ok') {
say "yes";
} else {
say "no ($DEFAULT_HOST:$DEFAULT_PORT not response)";
}
exit(0);
}
sub gather_data {
my $host = shift;
my $port = shift;
my %data = map { ($_ => 'U') } map { @{ $TYPES{$_} } } @TYPES;
$data{response} = 'failed';
my $sock = IO::Socket::INET->new(
PeerAddr => $host,
Proto => 'udp',
PeerPort => $port,
Blocking => 0
) or die "Cannot create socket: $@";
my $pattern = pack 'AAAACAAA', split //, 'PCMG1END';
$sock->send($pattern) or die "send to $host: $!";
usleep(200);
my $data;
my $buf;
while ($sock->read($buf, 32)) {
$data .= $buf;
}
if (defined $data and $data =~ /^PCMR.*END$/) {
my @data = unpack('C*', $data);
%data = (
response => 'ok',
input => $data[6] + 256 * $data[5],
output => $data[8] + 256 * $data[7],
battery_load => $data[11],
battery_capacity => $data[12],
temp => $data[15],
power_failure => ($data[18] ? 1 : 0),
low_battery => ($data[19] ? 1 : 0),
#voltage_status: 0 = normal, 3 = buck, 2 = boost
voltage_status => ($data[17] == 0 ? 0 : ($data[17] == 3 ? 2 : 1)),
ups_status => ($data[21] ? 1 : 0),
battery_test => ($data[23] ? 1 : 0),
);
}
return \%data;
}