Last month I posted a Perl script for reading data from the Temper232. Once the problem of reading data is solved, the next step is to provide logging and alerting. I’m using rrdtool for logging and generating graphs. This might be the subject of a future blog post, but today I’m writing about alerting. For alert management, I turned to Jim Trocki’s Mon.
Mon has been around for a while. It’s not fancy, but as I’m planning to deploy on a Raspberry Pi, I need a light-weight solution. The fact that Mon is written in Perl helps quite a bit, as I’m already using Perl to extract data from the Temper232. This presentation gives a good overview of Mon and what it can do. debianhelp.co.uk has a nice set of instructions for configuring Mon with Debian.
I am using Debian GNU/Linux as a platform. There is a Mon package which can be installed with the following command line (as root):
apt-get install mon
Mon’s modular architecture makes it pretty easy to add new monitors. I went ahead and wrote a monitor for the Temper232, which is pasted below. On my Debian machine I saved this script as
/usr/lib/mon/mon.d/temper.monitor
Once the file is saved, we need modify its permission settings so that it is executable by the Mon daemon. To match the permission settings of other monitor scripts, I used the following command:
chmod a+x /usr/lib/mon/mon.d/temper.monitor
Here’s the source code of the monitor script:
#!/usr/bin/perl
use Device::SerialPort;
use Getopt::Std;
getopts("dt:l:h:");
# d debug mode
# t timeout period
# h high threshold
# l low threshold
my $timeout = $opt_t || 10;
my $minTemp = $opt_l || -99;
my $maxTemp = $opt_h || 99;
my @serialports = @ARGV;
my @failed;
my $detail;
print "testing @serialports\n" if $opt_d;
foreach my $portname (@serialports){
my $timer = $timeout;
$port = Device::SerialPort->new($portname)||die "Couldn't open port $!\n";
$port->user_msg(ON);
$port->baudrate(4800);
$port->databits(8);
$port->parity("none");
$port->stopbits(1);
$port->handshake("none");
$port->read_char_time(0);
$port->read_const_time(1000);
die "Couldn't open port $!\n" unless $port->write_settings;
my $code = "\x24\x10\x05\x01\x01\x00\x32\x01\x55";
my $count_out = $port->write($code);
while ($timer > 0){
# Read enough characters from port to guarantee a complete reading
my ($count,$saw) = $port->read(10);
if($count > 0){
if ($saw=~m/\x24\xfe\x02(\C\C)\x55/){
my $raw = unpack('n*',$1);
$raw -= 1<<16 if $raw & 1 << 15;
my $temp = ($raw * 0.007812);
if ($temp > $minTemp && $temp < $maxTemp){
print "temperature OK\n" if $opt_d;
$detail .= "$portname in range: $temp\n";
}else{
push @failed,$portname;
$detail .= "$portname out of range: $temp\n";
print "temperature bad\n" if $opt_d;
}
print "$temp\n" if $opt_d;
last;
}
}
else{
$timer--;
}
}
$code = "\x24\x11\x00\x55";
$port->write($code);
}
print join (" ", @failed), "\n";
print $detail;
@failed == 0 ? exit 0 : exit 1;
To use this monitor, I created a “temp” hostgroup in Mon pointing to the serial device corresponding to the Temper232. In most cases this will be /dev/ttyUSB0. Mon’s a networking tool, but since the “hostname” specified in the hostgroup is the parameter passed to the monitor script, we can use this functionality to get data from a local serial port. In /etc/mon/mon.cf, my “hostgroup” section looks like this:
# # Define groups of hosts to monitor # hostgroup localhost localhost hostgroup temp /dev/ttyUSB0
I set up the following monitoring specification for the hostgroup:
watch temp
service temperature
description Temp monitor
interval 1m
monitor temper.monitor -t 10 -l 10 -h 25
period
numalerts 10
alert mail.alert bob@aol.com
The entry is fairly self-explanatory except for the switches passed to the monitor.
- -t specifies a timeout value (in seconds) to wait for the serial port
- -l specifies the low temperature minimum for our range (in Celsius)
- - h specifies the high temperature maximum for our range
If the temperature reading falls outside of the acceptable range, Mon will dispatch an e-mail alert to the address specified.









