Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Merge pull request #594 from rrzefox/new_allnet_plugin

new plugin for monitoring allnet ip sensoric devices (e.g. ALL4500)
commit 4a6b17b7bd4e1933ecb56292a9297d83b379458d 2 parents feef1d0 + 23f3138
@ssm ssm authored
Showing with 247 additions and 0 deletions.
  1. +247 −0 plugins/sensors/allnet__
View
247 plugins/sensors/allnet__
@@ -0,0 +1,247 @@
+#!/usr/bin/perl
+
+# This script is used to feed sensor information from Allnet-Devices like e.g.
+# Allnet 4000 or 4500 into munin. It uses the XML-Interface of the devices to
+# fetch data.
+#
+# written by Michael Meier <michael.meier@fau.de>, License GPLv2
+#
+# Usage:
+# Put this script onto some server, either on your munin-server or onto some
+# other server that can reach the actual device. Then symlink to it from the
+# munin-node plugin dir (usually /etc/munin/plugins). The naming of the symlink
+# is a critical part of the configuration, it needs to be:
+# SOMETHING_HOSTNAME_TYPE, e.g. allnet_monitordevice42.yourdomain.com_temp
+# SOMETHING really is just a random name containing no special chars, use
+# whatever you like.
+# HOSTNAME is the hostname of the Allnet-Device. This is also the hostname
+# under which the sensors will show up in munin.
+# TYPE is the type of sensors you're interested in, valid values are:
+# temp, hum, amps
+# If you want to monitor more than one type of sensor, create more than one
+# symlink.
+# The plugin will automatically feed all sensors of the selected type to munin,
+# under the names that you set in the allnets config. Take care with special
+# characters, in particular Umlauts and the such - munin will probably not like
+# those in names.
+#
+# Note that the format of the XML output these devices deliver varies vastly
+# between different firmware versions. This script currently understands 3
+# completely different outputs, but there is no guarantee that's all the
+# variations that exist. If the script doesn't understand the output of your
+# device, set the beextratolerant parameter. You might also want to try a
+# different firmware version.
+#
+# The behaviour of the script can be influenced by environment variables. The
+# variables are (note this is case sensitive!):
+# username Username for basic HTTP auth (if your device is password protected)
+# password Password for basic HTTP auth (if your device is password protected)
+# beextratolerant This needs to be set to 1 for some extremely old/stripped
+# down devices. Note that this relaxes sanity checks and
+# will lead to nonsense-sensors showing up on devices that
+# do not require this.
+# DUMP set to 1 to enable some debug output (only outside of munin!)
+# internalsensorname.warning The warning-threshold for the sensor reported
+# to munin. You need to replace
+# "internalsensorname" with the munin-internal
+# name of the sensor, usually sensor+somenumber.
+# Can be seen in the webinterface.
+# internalsensorname.critical Same as above, but for the critical-threshold.
+#
+# As an example, you could put the following file into /etc/munin/plugin-conf.d:
+# [allnet_monitordevice42.yourdomain.com_*]
+# env.username horst
+# env.password topsecret
+# env.sensor14.warning 10.0
+# env.sensor14.critical 15.0
+
+# One tuneable:
+# Timeout for requests.
+my $timeout = 3; # the LWP default of 180 secs would be way too long
+
+# -----------------------------------------------------------------------------
+
+# No need to change those, can be overriden from commandline.
+my $hostname = 'localhost';
+my $valtype = 'temp'; # or humidity or amps
+# These are tried one after another.
+my @xmlpaths = ('/xml/sensordata.xml', '/xml');
+
+use LWP::UserAgent;
+use XML::Simple;
+
+# AuthAgent is simply LWP::UserAgent with a reimplemented version of the
+# method basic auth. Theoretically/according to the documentation, the base
+# implementation should be able to do everything that is needed as well, but
+# it seems to broken and "the internet" suggests it has been for a long time.
+{
+ package AuthAgent;
+ use base 'LWP::UserAgent';
+
+ sub get_basic_credentials {
+ if (defined($ENV{'username'}) && defined($ENV{'password'})) {
+ return $ENV{'username'}, $ENV{'password'};
+ } else {
+ return 'admin', 'password';
+ }
+ }
+}
+
+# Par. 0: URL
+# Returns: The contents of the website
+sub geturl($) {
+ my $url = shift();
+
+ my $ua = AuthAgent->new();
+ $ua->agent($0);
+ $ua->timeout($timeout);
+ # Create a request
+ my $req = HTTP::Request->new(GET => $url);
+ # Pass request to the user agent and get a response back
+ my $res = $ua->request($req);
+ # Check the outcome of the response
+ unless ($res->is_success()) {
+ #print("ERROR getting data from $url\n");
+ return undef;
+ }
+ return $res->content();
+}
+
+if ((@ARGV > 0) && ($ARGV[0] eq "autoconf")) {
+ print("No\n");
+ exit(0);
+}
+my $progname = $0;
+if ($progname =~ m/[-_]temp$/) {
+ $valtype = 'temp';
+} elsif ($progname =~ m/[-_]temperature$/) {
+ $valtype = 'temp';
+} elsif ($progname =~ m/[-_]hum$/) {
+ $valtype = 'humidity';
+} elsif ($progname =~ m/[-_]humidity$/) {
+ $valtype = 'humidity';
+} elsif ($progname =~ m/[-_]amps$/) {
+ $valtype = 'amps';
+} elsif ($progname =~ m/[-_]ampere$/) {
+ $valtype = 'amps';
+}
+if ($progname =~ m/.+_(.+?)_.+/) {
+ $hostname = $1;
+}
+my $sensorxml;
+foreach $xp (@xmlpaths) {
+ $sensorxml = geturl('http://' . $hostname . $xp);
+ if (defined($sensorxml)) { last; }
+}
+unless (defined($sensorxml)) {
+ print("# Sorry, Failed to fetch data.");
+ exit(1);
+}
+# VERY old firmware versions have HTML crap around the actual XML.
+$sensorxml =~ s!.*<xml>(.*)</xml>.*!$1!sg;
+if (defined($ENV{'DUMP'}) && ($ENV{'DUMP'} eq '1')) {
+ print($sensorxml . "\n");
+}
+if ((@ARGV > 0) && ($ARGV[0] eq "config")) {
+ if ($valtype eq 'humidity') {
+ print("graph_title Humidity sensors\n");
+ print("graph_args --lower-limit 0 --upper-limit 100.0\n");
+ print("graph_vlabel percent\n");
+ } elsif ($valtype eq 'temp') {
+ print("graph_title Temperature sensors\n");
+ print("graph_vlabel degC\n");
+ } elsif ($valtype eq 'amps') {
+ print("graph_title Electric current sensors\n");
+ print("graph_args --lower-limit 0\n");
+ print("graph_vlabel Ampere\n");
+ }
+ print("graph_category envsensors\n");
+ print("host_name $hostname\n");
+}
+my $sensordata = XMLin($sensorxml, KeyAttr => { }, ForceArray => [ 'data' ] );
+my $beextratolerant = 0;
+if (defined($ENV{'beextratolerant'})) {
+ if (($ENV{'beextratolerant'} =~ m/^y/) || ($ENV{'beextratolerant'} eq '1')) {
+ $beextratolerant = 1;
+ }
+}
+#print($sensordata->[0]);
+foreach $k (keys($sensordata)) {
+ if ($k =~ m/^n(\d+)$/) { # Special handling: Could be output from the OLD XML interface.
+ my $nr = $1;
+ if (defined($sensordata->{'s'.$nr})
+ && defined($sensordata->{'t'.$nr})
+ && defined($sensordata->{'min'.$nr})
+ && defined($sensordata->{'max'.$nr})) {
+ # OK, all values available, really is from the old XML interface.
+ if ($sensordata->{'s'.$nr} eq '0') { next; } # 0 means no sensor.
+ # OK, lets map the sensortype.
+ my $st = 'temp';
+ if ($sensordata->{'s'.$nr} eq '65') { $st = 'humidity'; }
+ if ($sensordata->{'s'.$nr} eq '101') {
+ # potential FIXME: 101 is actually "water/contact sensor", but since it
+ # returns 0.0 and 100.0 as values, we can treat it just like humidity
+ # for simplicity.
+ $st = 'humidity';
+ }
+ if ($valtype ne $st) { next; } # these aren't the droids you're looking for
+ if ((@ARGV > 0) && ($ARGV[0] eq "config")) {
+ print("sensor${nr}.label " . $sensordata->{'n'.$nr} . "\n");
+ print("sensor${nr}.type GAUGE\n");
+ if (defined($ENV{"sensor${nr}.warning"})) { printf("sensor%s.warning %s\n", $nr, $ENV{"sensor${nr}.warning"}); }
+ if (defined($ENV{"sensor${nr}.critical"})) { printf("sensor%s.critical %s\n", $nr, $ENV{"sensor${nr}.critical"}); }
+ } else {
+ print("sensor${nr}.value " . $sensordata->{'t'.$nr}. "\n");
+ }
+ }
+ # Fall through - probably wasn't the old XML anyways.
+ }
+ my $onesens = $sensordata->{$k};
+ unless (defined($onesens->{'value_float'})
+ && defined($onesens->{'name'})
+ && defined($onesens->{'min_abs_float'})
+ && defined($onesens->{'max_abs_float'})
+ && defined($onesens->{'unit'})) {
+ # Not all values available -> no sane sensor data (or the "system" block in the XML)
+ unless ($beextratolerant) { next; }
+ # Maybe yet another firmware version that does not deliver all of these values,
+ # so lets check for the absolute MINIMUM set.
+ unless (defined($onesens->{'value_float'}) && defined($onesens->{'name'})) {
+ next; # Minimum set not available either.
+ }
+ if ($onesens->{'value_float'} < -20000.0) { next; } # Invalid value
+ # OK, so fill in the blanks
+ unless (defined($onesens->{'unit'})) { $onesens->{'unit'} = 'C'; }
+ unless (defined($onesens->{'min_abs_float'})) {
+ $onesens->{'min_abs_float'} = $onesens->{'value_float'} - 0.01;
+ }
+ unless (defined($onesens->{'max_abs_float'})) {
+ $onesens->{'max_abs_float'} = $onesens->{'value_float'} + 0.01;
+ }
+ }
+ if (($onesens->{'min_abs_float'} == 0.0)
+ && ($onesens->{'max_abs_float'} == 0.0)
+ && ($onesens->{'value_float'} == 0.0)) {
+ next; # If the sensor never showed anything but 0.0, we do not care about it.
+ }
+ if ($onesens->{'unit'} eq 'A AC') { $onesens->{'unit'} = 'A'; }
+ if ($onesens->{'unit'} =~ m/C$/) {
+ $onesens->{'unit'} = 'C'; # Remove WTF8-Fuckup
+ }
+ if (($valtype eq 'temp') && ($onesens->{'unit'} ne 'C')) { next; }
+ if (($valtype eq 'humidity') && ($onesens->{'unit'} ne '%')) { next; }
+ if (($valtype eq 'amps') && ($onesens->{'unit'} ne 'A')) { next; }
+ if ((@ARGV > 0) && ($ARGV[0] eq "config")) {
+ print("${k}.label " . $onesens->{'name'} . "\n");
+ #print("${k}.info " . $onesens->{'name'} . "\n");
+ print("${k}.type GAUGE\n");
+ if (defined($ENV{"${k}.warning"})) { printf("%s.warning %s\n", $k, $ENV{"${k}.warning"}); }
+ if (defined($ENV{"${k}.critical"})) { printf("%s.critical %s\n", $k, $ENV{"${k}.critical"}); }
+ } else {
+ if ($onesens->{'value_float'} < -20000.0) { # Invalid readings return -20480.0
+ print("${k}.value U\n");
+ } else {
+ print("${k}.value " . $onesens->{'value_float'} . "\n");
+ }
+ }
+}
Please sign in to comment.
Something went wrong with that request. Please try again.