Background
I wanted to have a LCD display on my desk showing the status of my monitor system. At the same time op5 created a competition with the coolest implementation of Raspberry PI and op5 Monitor. These things together made me getting started with my project.
The result can be seen in this video
Implementation
Overview
A Raspberry PI collects status from op5 Monitor or Nagios and present appropriate info on the LCD. The data is collected over the network by using MK Livestatus. LCDproc is used to show the data on the display and a homebrewn perl program is developed to collect the relevant information and sent to LCDProc.
Stuff needed
- op5 Monitor or Nagios with MK_Livestatus running.
- Raspberry PI
- HD44780 LCD Display
- Patience
- Soldering stuff
- Cables
- Appropriate trim pot
- Depending of LCD display a resistor
Connecting the LCD Display and get LCDProc started
As I am lazy I tried to find if someone else has done this and I was lucky. I just followed the guide on this page Pi & GPIO powered HD44780 LCD.
Allow remote connections to MK_Livestatus
To be able to connect remotly from your Raspberry PI to MK_Livestatus you must set it up. Follow the guide here.
The magic script
The perl progam that collect the data and send it to LCDProc is below.
I know I am using global variables and other dirty tricks. I am not a programmer and did not have the time to make it more "pure". Another drawback is that I probably do not use correct LCDproc commands as it sends errormessages to syslog. However the program seems stable and has been running for weeks.
#!/usr/bin/perl
# Written by Peter Andersson, peter@it-slav.net http://www.it-slav.net/blogs
# Collects data from op5 Monitor or Nagios using MK_Livestatus
# and sends it to LCDProc
#
#
# 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, either version 3 of the License, or
# (at your option) any later version.
#
# 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, see <http://www.gnu.org/licenses/>.
use IO::Socket;
use Data::Dumper;
$livestatusserver="vakttornet";
$livestatusport=6557;
$handle;
sub connect_livestatus {
# create a tcp connection to livestatus
print "Attempting to connect to livestatus server… \n";
if ($handle = IO::Socket::INET->new(Proto => "tcp",
PeerAddr => "$livestatusserver",
PeerPort => "$livestatusport"))
{
print "Successfully connected to livestatus server.\n";
}
else
{
die "Failed to connect to livestatus server ($!). Are you sure it's running ?\n";
#socket enema
$handle->autoflush(1);
}
}
sub send_get_services {
print $handle "GET services\n";
print $handle "Columns: host_name description plugin_output state state_type\n";
print $handle "Filter: state = $_[0]\n";
print $handle "Filter: acknowledged = 0\n";
print $handle "Filter: state_type = 1\n";
# print $handle "ColumnHeaders: on\n";
print $handle "\n";
}
sub send_get_hosts {
print $handle "GET hosts\n";
print $handle "Columns: name alias plugin_output state state_type\n";
print $handle "Filter: state = $_[0]\n";
print $handle "Filter: acknowledged = 0\n";
print $handle "Filter: state_type = 1\n";
# print $handle "ColumnHeaders: on\n";
print $handle "\n";
}
sub read_services {
$i=0;
while (defined($line = readline($handle))) {
#next if $!{EINTR};
#last if eof($handle); # socket was closed
#die "readline: $!";
#$line=shift;
#print $line;
@service= split(/;/,$line) ;
@servicearray[$i]= [ "Host:$service[0]", "Service:$service[1]", "$service[2]" ];
$i++;
}
$handle->autoflush(1);
$handle->close;
return $i;
}
sub read_hosts {
$i=0;
while (defined($line = readline($handle))) {
#next if $!{EINTR};
#last if eof($handle); # socket was closed
#die "readline: $!";
#$line=shift;
#print $line;
@host= split(/;/,$line) ;
@hostarray[$i]= [ "Host:$host[0]", "Alias:$host[1]", "$host[2]" ];
$i++;
}
$handle->autoflush(1);
$handle->close;
return $i;
}
sub connect_lcdproc {
print "Attempting to connect to lcdproc server… \n";
if ($lcdhandle = IO::Socket::INET->new(Proto => "tcp",
PeerAddr => "127.0.0.1",
PeerPort => "13666"))
{
print "Successfully connected to lcdproc server.\n";
print $lcdhandle "hello\n";
print $lcdhandle "client_set op5 Monitor\n";
}
else
{
die "Failed to connect to lcdproc server ($!). Are you sure it's running ?\n";
#socket enema
$lcdhandle->autoflush(1);
}
}
sub create_lcd_screens_service {
print $lcdhandle "screen_add service$n$_[0]\n";
print $lcdhandle "screen_set service$n$_[0]\n";
print $lcdhandle "widget_add service$n$_[0] title title\n";
print $lcdhandle "widget_set service$n$_[0] title {op5 Monitor – $_[0]}\n";
print $lcdhandle "widget_add service$n$_[0] host scroller\n";
print $lcdhandle "widget_add service$n$_[0] service scroller\n";
print $lcdhandle "widget_add service$n$_[0] output scroller\n";
print $lcdhandle "widget_set service$n$_[0] host 1 2 20 2 h 6 {$servicearray[$n]->[0]}\n" or die "Nope.";
print $lcdhandle "widget_set service$n$_[0] service 1 3 20 3 h 6 {$servicearray[$n]->[1]}\n" or die "Nope.";
print $lcdhandle "widget_set service$n$_[0] output 1 4 20 4 h 4 {$servicearray[$n]->[2]}\n" or die "Nope.";
$lcdhandle->autoflush(1);
}
sub create_lcd_screens_host {
print $lcdhandle "screen_add host$n$_[0]\n";
print $lcdhandle "screen_set host$n$_[0]\n";
print $lcdhandle "widget_add host$n$_[0] title title\n";
print $lcdhandle "widget_set host$n$_[0] title {op5 Monitor – $_[0]}\n";
print $lcdhandle "widget_add host$n$_[0] host scroller\n";
print $lcdhandle "widget_add host$n$_[0] service scroller\n";
print $lcdhandle "widget_add host$n$_[0] output scroller\n";
print $lcdhandle "widget_set host$n$_[0] host 1 2 20 2 h 6 {$hostarray[$n]->[0]}\n" or die "Nope.";
print $lcdhandle "widget_set host$n$_[0] service 1 3 20 3 h 6 {$hostarray[$n]->[1]}\n" or die "Nope.";
print $lcdhandle "widget_set host$n$_[0] output 1 4 20 4 h 4 {$hostarray[$n]->[2]}\n" or die "Nope.";
$lcdhandle->autoflush(1);
}
sub create_lcd_screens_summary {
print $lcdhandle "screen_add summary\n";
print $lcdhandle "screen_set summary -priority 65\n";
print $lcdhandle "widget_add summary title title\n";
print $lcdhandle "widget_set summary title {op5 Monitor – Summary}\n";
print $lcdhandle "widget_add summary host scroller\n";
print $lcdhandle "widget_add summary service scroller\n";
print $lcdhandle "widget_add summary ego scroller\n";
print $lcdhandle "widget_set summary host 1 2 20 2 h 6 {$_[0]}\n" or die "Nope.";
print $lcdhandle "widget_set summary service 1 3 20 3 h 6 {$_[1]}\n" or die "Nope.";
print $lcdhandle "widget_set summary ego 1 4 20 4 h 4 {Created by peter\@it-slav.net}\n" or die "Nope.";
$lcdhandle->autoflush(1);
}
while (1!=0) {
$summary_services=0;
$summary_hosts=0;
&connect_lcdproc;
for($state=0;$state<=3;$state++) {
if ($state==0) { $sstatetext="Ok"; $hstatetext="Up"; }
elsif ($state==1) { $sstatetext="Warning"; $hstatetext="Down"; }
elsif ($state==2) { $sstatetext="Critical"; $hstatetext="Down";}
else { $sstatetext="Unknown"; $hstatetext="Unreachable";}
print "\nChecking services in state $stat $sstatetext\n";
#Services in ok=0, warning=1, critical=2, unknown=3
&connect_livestatus;
&send_get_services($state);
$summary_service_array[$state]=&read_services;
if ($state!=0) { #Skip sending ok to LCD
for ($n=0;$n<$summary_service_array[$state];$n++) {
$summary_services++;
print "Create lcdoutputservice$n $servicearray[$n]->[0] $servicearray[$n]->[1] $servicearray[$n]->[2]\n";
&create_lcd_screens_service("$sstatetext");
}
}
print "Checking hosts in state $hstatetext\n";
#Hosts in up=0, down=1, down=2, unreachable=3
&connect_livestatus;
&send_get_hosts($state);
$summary_host_array[$state]=&read_hosts;
if (!($state==0 )) { #Skip sending ok to LCD
for ($n=0;$n<$summary_host_array[$state];$n++) {
$summary_hosts++;
print "Create lcdoutputhost$n $hostarray[$n]->[0] $hostarray[$n]->[1] $hostarray[$n]->[2]\n";
&create_lcd_screens_host("$hstatetext");
}
}
# sleep (10);
}
print "\nTotal services to show at LCD is $summary_services\n Ok=$summary_service_array[0] Warning=$summary_service_array[1] Critical=$summary_service_array[2] Unknown=$summary_service_array[3]\n";
print "Total hosts to show at LCD is $summary_hosts\n Up=$summary_host_array[0] Down=$summary_host_array[1] Down=$summary_host_array[2] Unreachable=$summary_host_array[3]\n";
# &create_lcd_screens_summary("H: U=$summary_host_array[0] D=$summary_host_array[1] D=$summary_host_array[2] U=$summary_host_array[3]","S: O=$summary_service_array[0] W=$summary_service_array[1] C=$summary_service_array[2] U=$summary_service_array[3]");
$down=$summary_host_array[1]+$summary_host_array[2];
&create_lcd_screens_summary("H: D=$down U=$summary_host_array[2] Up=$summary_host_array[0]","S: C=$summary_service_array[2] W=$summary_service_array[1] U=$summary_service_array[3] O=$summary_service_array[0]");
$sleeptime=2*($summary_services*5+$summary_hosts*5)+20; #Show 2 times
print "Will sleep for $sleeptime seconds\n";
sleep ($sleeptime);
$lcdhandle->close;
print "\n\n\n—New Iteration—\n";
#print Dumper \@servicearray;
}
print "Normal quit\n";
Wrapup
I did create a video before I did my extremly good looking box and run the system on a breadboard.
Links:
- op5 Monitor
- Nagios
- LCDProc
- Howto connect an LCD display to a Raspberry PI and use LCDproc.
- Livestatus
Leave a Reply
You must be logged in to post a comment.