RMS Door Contact Alarm Monitor

The Remote Monitoring System V1 is a remote data acquisition and control device designed for use with Battery powered Wireless Internet repeater sites. We recently aquired one of these and plan on using it for a solar powered site in a remote location. More information about the board can be found at http://www.remotemonitoringsystems.ca/rms/rms.php .
We have used internet cameras such as the Dlink DCS-3220 at other sites for security purposes but they draw more power than we will have available. We decided to put a simple set of magnetic door contact switches on one of the IO ports on the RMS board and monitor it via SNMP from our web server and Cacti system.


The RMS board has 5 general purpose IO ports that can be hooked up to a set of contacts. The SNMP command list for the RMS is available at http://www.remotemonitoringsystems.ca/rms/snmp.php . The script is called from cron job on our server once every minute via the following entry in /etc/crontab.

# monitor the RMS unit alarm
*/1 * * * * root /root/bin/dooralarm.pl

The current state of the contacts is kept in /root/bin/doorstatus.txt

door closed
counter 0
event Thu Jan 21 10:47:28 2010

The list of email addresses to contact is kept in /root/bin/alarmcontact.txt

fred@mydomain.com
9992221111@msg.telus.com
barney@mydomain.com
1112229999@msg.telus.com

The way it works. Once a minute the script pulls the state of the door contact from the RMS board and reads the previous state of the door from the file. If the door makes the transition from closed to open an alert email is sent to each of the addresses, which include a couple of cell phone numbers that get a text message. If the door makes the transition from open to closed another alert is sent out. While the door is open a counter is incremented until it reaches a maximum and another alert is sent out indicating that the door is still open and the counter is reset (every 30 minutes in our case). While the door is open the file gets updated with the counter and a timestamp. The variables $debug and $verbose can be set to 1 for testing purposes. Enjoy!
}

#!/usr/bin/perl
# Monitors the door contacts on a Remote Monitoring System (RMS V1)
# see http://www.remotemonitoringsystems.ca/rms/rms.php
# the MIBS are at http://www.remotemonitoringsystems.ca/rms/snmp.php
# the one we want to monitor is the IO port that is wired to a simple NC magnetic door contact
# .1.3.6.1.4.1.21749.1.3.x where x is the io port
#
# GNU license applies
# (C) Alan Madill, amadill --at-- hwy16.com, Jan 2010
#
# requires Net::SNMP

use Net::SNMP;		#Simple network management protocol
use Net::SMTP;		#Simple mail transport protocol
use strict;
require 'ctime.pl';

# we could load these from the command line
my($target) = "10.1.1.1";	# the IP of the RMS board
my($ioport) = "1";		# the IO port the switch is connected to
my($debug) = 0;			# set to 1 for debugging
my($verbose) = 0;		# set to 1 for status messages

# the oid for the io ports on the RMS
my($baseoid) = ".1.3.6.1.4.1.21749.1.3.";
my($community) = "public";		# can't be changed on the RMS

# where we keep the current state of the door contact
my($statefile) = "/root/bin/doorstatus.txt";

# who do we call?
my($maillist) = "/root/bin/alarmcontact.txt";
my($mailhost) = "mail.mydomain.com";

# the counter gets incremented from 0 to max when the door is open and then rolls over to 0 again
# the alarm message is sent out when the counter is 0 and the door is open
# the counter gets reset to 0 when the door makes the transition from open to closed
my($max) = 30;		# every 30 minutes assuming the cron calls it once a minute
my(%state);

my($session) = Net::SNMP->session(-hostname => $target, -community => $community);

if (! defined($session)) {
   print "session creation error: ".$session->error."\n" if ($debug || $verbose);  
   exit;
}

my($oid) = ($baseoid.$ioport);

my($result) = $session->get_request($oid); 

if (! defined($result)) {
   print "no result returned: ".$session->error."\n" if ($verbose);
   $session->close;
   exit;
}

my($status) = $result->{$oid};

print "IO Status: $status\n" if ($verbose);

$session->close;

# open up the status file and read it
open(STATE, "<$statefile");
while (<STATE>) {
   chomp;
   my($a, $b) = split(/\s/, $_, 2);
   $state{$a} = $b;
   print "$a:\t$state{$a}\n" if ($debug);
}
close(STATE);

$status = 0 if ($debug);

exit if ($status &amp;&amp; ($state{door} eq 'closed'));		# door is still closed

if (! $status &amp;&amp; ($state{door} eq 'closed')) {	# someone just opened the door!
   # send the alarm
   # write the new state
   $state{door} = 'open';
   $state{counter} = 1;
   writestate();
   do_alarm("Door OPEN event at $target");
}

if (! $status &amp;&amp; ($state{door} eq 'open')) {  # the door is still open
   $state{counter}++;
   if ($state{counter} == $max) {
      do_alarm("Door STILL OPEN event after $state{counter} minutes at $target");
      $state{counter} = 0;
   }
   writestate();
}

if ($status &amp;&amp; ($state{door} eq 'open')) {  # the door just closed
   $state{counter} = 0;
   $state{door} = 'closed';
   do_alarm("Door CLOSED event at $target");
   writestate();
}

sub do_alarm {
   # send the alarm to the list of email addresses
   my($msg) = shift;
   print "Message: $msg\n" if ($verbose);

   my($now) = ctime(time);
   
   open(MAIL, "<$maillist") or die "unable to open $maillist\n";
   while (<MAIL>) {
      chomp;
      my($smtp) = Net::SMTP->new($mailhost) or die "unable to open SMTP\n";
      $smtp->mail('dooralarm@hwy16.com');
      $smtp->to("$_");
      $smtp->data();
      $smtp->datasend("To: $_\n");
      $smtp->datasend("Subject: $msg\n");
      $smtp->datasend("$msg\n");
      $smtp->datasend("door: $state{door}\n");
      $smtp->datasend("time: $now\n");
      $smtp->dataend();
      $smtp->quit;
   }
}

sub writestate {
   # write the current state to file
   my($now) = ctime(time);
 
   open(STATE, ">$statefile") or die "error opening $statefile\n";
   print STATE "door $state{door}\n";
   print STATE "counter $state{counter}\n";
   print STATE "event $now";

   close(STATE);
}

The file is available for download here