Repository
Munin (contrib)
Last change
2018-03-08
Graph Categories
Family
auto
Capabilities
Keywords
Language
Perl
License
GPL-2.0-only
Authors

squeezebox_multi

Name

squeezebox_ - plugin to monitor a Logitech Media Server and associated players.

Applicable Systems

Probably any system running Logitech Media Server. Change the host to enable remote monitoring.

Configuration

No configuration should be required if run on the same server as the Logitech Media Server. If the plugin is run from another unit or in a non-default configuration, please use the environment variables ‘squeezebox_host’ and ‘squeezebox_port’ to connect.

Sample content for plugin-conf.d/ follows:

[squeezebox]
 env.squeezecenter_host 192.168.100.10
 env.squeezecenter_port 9095

Interpretation

The “volume” graphs only graphs the player volume levels, not the amplifier or whatever the player may be connected to.

Magic Markers

#%# family=auto
#%# capabilities=autoconf suggest

Bugs

None known

Author

Bjørn Ruberg

License

GPLv2

#!/usr/bin/perl

=head1 NAME

squeezebox_ - plugin to monitor a Logitech Media Server and associated
players.

=head1 APPLICABLE SYSTEMS

Probably any system running Logitech Media Server. Change the host to
enable remote monitoring.

=head1 CONFIGURATION

No configuration should be required if run on the same server as
the Logitech Media Server. If the plugin is run from another unit or
in a non-default configuration, please use the environment variables
'squeezebox_host' and 'squeezebox_port' to connect.

Sample content for plugin-conf.d/ follows:

 [squeezebox]
  env.squeezecenter_host 192.168.100.10
  env.squeezecenter_port 9095

=head1 INTERPRETATION

The "volume" graphs only graphs the player volume levels, not the
amplifier or whatever the player may be connected to.

=head1 MAGIC MARKERS

 #%# family=auto
 #%# capabilities=autoconf suggest

=head1 BUGS

None known

=head1 AUTHOR

Bjørn Ruberg

=head1 LICENSE

GPLv2

=cut

#%# family=auto
#%# capabilities=autoconf suggest

use strict;

my $ret = undef;
if (! eval "require Net::Telnet;") {
  $ret = "Net::Telnet not found";
}
if (! eval "require URI::Escape;") {
  $ret = "URI::Escape not found";
}

use vars qw ($host $port $config);

# Define connection settings, from plugin environment file or use defaults
my $host = exists $ENV{'squeezecenter_host'} ? $ENV{'squeezecenter_host'} : "127.0.0.1";
my $port = exists $ENV{'squeezecenter_port'} ? $ENV{'squeezecenter_port'} : "9090";

# Argument handling: autoconf, suggest, update, config

if (@ARGV) {
  if ($ARGV[0] eq "autoconf") {
    # autoconf for magically self-configuring the plugin
    if ($ret) {
      print "no ($ret)";
      exit 0;
    }
    my $conn = new Net::Telnet (Telnetmode => 0);
    $conn->open (Host    => $host,
		 Port    => $port,
		 Errmode => "return");
    if ($conn->errmsg) {
      print "no (No connection on $host port $port)";
      exit 0;
    } else {
      my $version = "";
      my $line = "";
      $conn->print("version ?");
      $conn->print("exit");
      while (($line = $conn->getline) and ($line !~ /exit/)) {
	$version = $line if $line =~ /version/;
      }
      if ($version =~ /^version/) {
	print "yes";
	exit 0;
      } else {
	print "no (socket responded but the server didn't respond as expected)";
	exit 0;
      }
    }
  } elsif ($ARGV[0] eq "suggest") {
    print "I am a multigraph plugin, and suggest is not required\n";
    exit 0;
  } elsif ($ARGV[0] eq "update") {
    # For scheduled inventory rescan, add this plugin to a cron job
    # with the argument "update" Adjust the interval to your own tempo
    # for adding/deleting music. This equals a "Look for new and
    # changed media files" rescan from the webUI.
    #
    # example: 5 * * * * /usr/share/munin/plugins/squeezebox update

    my $conn = new Net::Telnet (Telnetmode => 0);
    $conn->open (Host    => $host,
                 Port    => $port,
                 Errmode => "return");
    if ($conn->errmsg) {
      print $conn->errmsg, "\n";;
      exit 1;
    } else {
      $conn->print("rescan");
      $conn->print("exit");
      exit 0;
    }
  } elsif ($ARGV[0] eq "config") {
    # Sets $config value for using in the main execution cycle
    $config = 1;
  }
}

# We're keeping the socket open for all checks
my $conn = new Net::Telnet (Telnetmode => 0);
$conn->open (Host => $host,
             Port => $port);

use URI::Escape;
# use Encode qw (from_to);
use Text::Iconv;
my $converter = Text::Iconv->new("UTF-8", "LATIN1");
# $converted = $converter->convert("Text to convert");

# First all the simple readings
foreach my $attr (qw(albums artists genres songs)) {
  $conn->print ("info total ${attr} ?");
  my $line = uri_unescape($conn->getline);
  if ($line =~ /^info total ${attr} (\d+)$/) {
    my $number = $1;
    print "multigraph squeezebox_${attr}\n";
    if ($config) {
      print "graph_title Number of ${attr}\n";
      print "graph_scale no\n";
      print "graph_category radio\n";
      print "${attr}.label ${attr}\n";
    } else {
      print "${attr}.value $number\n";
    }
  }
}

# years
$conn->print ("years");
if (uri_unescape($conn->getline) =~ /^years\s+count:(\d+)/) {
  my $no_of_years = $1;
  $conn->print ("years 0 $no_of_years");
  my @years = split (" ", uri_unescape($conn->getline));
  print "multigraph squeezebox_years\n";

  if ($config) {
    # config run
    print "graph_title Albums per year\n";
    print "graph_category radio\n";
    print "graph_args --base 1000 -l 0\n";
    foreach my $year (@years) {
      if ($year =~ /year\:(\d+)/) {
	print "y" . $1 . ".label $1\n";
	print "y" . $1 . ".draw AREASTACK\n";
      }
    }
  } else {
    # regular run
    foreach my $year (@years) {
      if ($year =~ /(year\:\d+)/) {
	$conn->print ("albums 0 0 $1");
	# albums 0 0 year:2007 count:13
	my $line = uri_unescape ($conn->getline);
	if ($line =~ /^.*year\:(\d+) count\:(\d+)$/) {
	  print "y${1}.value ${2}\n";
	}

      }
    }
  }
}

# mixer volume and signalstrength
foreach my $attr ("signalstrength",  "mixer volume") {
  # The plugin reports as squeezebox_volume while the command is
  # "mixer volume".
  (my $attr_print = $attr) =~ s/mixer //g;
  print "multigraph squeezebox_${attr_print}\n";
  if ($config) {
    print "graph_title " . ucfirst ($attr) . "\n";
    print "graph_category radio\n";
  }
  $conn->print ("player count ?");
  (my $no_of_players = uri_unescape ($conn->getline)) =~ s/player count\s+//;
  chomp $no_of_players;
  my $id;
  for ($id = 0; $id < $no_of_players; $id++) {
    $conn->print ("player id ${id} ?");
    (my $mac = uri_unescape ($conn->getline)) =~ s/player id \d+ //g;
    chomp ($mac);
    (my $mac_print = 'm' . $mac) =~ s/\://g;
    if ($config) {
      $conn->print ("player name ${mac} ?");
      (my $name = uri_unescape ($conn->getline)) =~ s/player name ${mac} //g;
      chomp $name;
      print "${mac_print}.label ", $converter->convert($name), "\n";
    } else {
      $conn->print ("${mac} ${attr} ?");
      (my $value = uri_unescape ($conn->getline)) =~ s/^.* //g;
      chomp $value;
      print "${mac_print}.value $value\n";
    }
  }
}