General questions related to networked alarm system

I have created a web controllable alarm system with an Arduino Uno and PoEthernet shield. I have a sketch (included at the end) which is working fine. It monitors several doors/windows, allows me to arm/disarm the system from a webpage, and triggers an LED if a door is opened while "Armed". I'm trying to get it to do a few more things, but have run into issues. I'm hoping someone can look at these things and advise me as to the feasibility/complexity of doing them.

To do list:

  1. I currently have an LED (and resistor) between pin 8 and ground. When the "siren" should go off, pin 8 is set high. This works fine. I want to replace the LED with a relay module I got. The relay module however expects a constant 5v and ground connection (to light some onboard LEDs) and to switch the relay, a pin on the module has to be connected to ground. I think I can connect pin 8 to this module and just switch the program to set the pin high normally and low when the siren should be on. My two concerns though are: 1, will pin 8 (when high) and the 5v pin be at exactly the same potential thereby avoiding any current flow between the two? 2, should I put a resistor between pin 8 and the relay module?

  2. I have seen some examples where an IP is not given to the Ethernet.begin() function and apparently this causes the device to get an IP via DHCP. Does this actually work, as it seems to fail with my sketch?

My code. Again, this is working as is. Still in the "alpha" stages, so there are definitively some formatting/efficiency issues.

/*
*
 * Alarm sketch
 * Ryan Adams
 * 2/4/2012
 * Version 0.3.0
 *
 * TO DO:
 * Password protect pages
 * Cleanup code
 * Power from ethernet headers  
 */


#include <SPI.h>
#include <Ethernet.h>
#include <EthernetUdp.h>

#define zone1Name "Front Door"
#define zone2Name "Patio Door"
#define zone3Name "Bedroom Window"
#define zone4Name "Office Window"
#define zone5Name "Zone 5 - Unused"
#define zone6Name "Zone 6 - Unused"

#define sirenPin 8
#define sirenLength 5000

#define localUdpPort 8888
#define syslogPort 514

// Configure other variables
int previousClosedZoneCount = 0;
int closedZoneCount = 0;
boolean breached = 0;
unsigned long sirenOnTimestamp = 0;
boolean sirenStatus = 0;
boolean armedState = 1;
char line1[100];
EthernetServer server(80);

int zoneStatusArray[6] = {
  0, 0, 0, 0, 0, 0};

byte mac[] = { 
  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress ip(192, 168, 10, 102);
IPAddress syslogServer(192, 168, 10, 101); 

// An EthernetUDP instance to let us send and receive packets over UDP
EthernetUDP Udp;



void setup()
{
  Ethernet.begin(mac,ip);
  Udp.begin(localUdpPort);
  sendSyslogMessage(6, "Syslog logging started");

  // Set pullup on zone input pins

  pinMode(A0, INPUT);
  digitalWrite(A0, HIGH);
  pinMode(A1, INPUT);
  digitalWrite(A1, HIGH);
  pinMode(A2, INPUT);
  digitalWrite(A2, HIGH);
  pinMode(A3, INPUT);
  digitalWrite(A3, HIGH);
  pinMode(A4, INPUT);
  digitalWrite(A4, HIGH);
  pinMode(A5, INPUT);
  digitalWrite(A5, HIGH);

  pinMode(sirenPin, OUTPUT);
  digitalWrite(sirenPin, LOW);



  // Start HTTP server
    server.begin();
   sendSyslogMessage(6, "HTTP server started"); 

  sendSyslogMessage(6, "Boot complete");

}

void loop()
{

  // Determine status of each zone. 1 = closed, 0 = open
  previousClosedZoneCount = closedZoneCount;
  closedZoneCount = 0;
  for (int i=0; i <= 5; i++){
    if (analogRead(i) < 100){
      zoneStatusArray[i] = 1;
      closedZoneCount++;
    } 
    else {
      zoneStatusArray[i] = 0;
    }  
  }


  if (closedZoneCount >= previousClosedZoneCount){
    breached = 0;
  } 
  else {
    breached = 1;
    sendSyslogMessage(6, "A zone has been breached");
  }

  if ((breached) && (armedState)) {
    sirenStatus = 1;
    sendSyslogMessage(1, "Siren activated");
    digitalWrite(sirenPin, HIGH); 
    sirenOnTimestamp = millis();
    delay(500);
  } 
  else if (((sirenOnTimestamp + sirenLength) > millis()) && (armedState)) {
    sirenStatus = 1;
  } 
  else if (sirenStatus) {
    sirenStatus = 0;
    sendSyslogMessage(2, "Siren deactivated");
    digitalWrite(sirenPin, LOW); 
    sirenOnTimestamp = 0;
  } 
  else {
    sirenStatus = 0;
    sirenOnTimestamp = 0;
  }



  // listen for incoming clients
  EthernetClient client = server.available();
  if (client) 
  {
    while (client.connected()) 
    {
      sendSyslogMessage(6, "HTTP client connected");
      readHeader(client);
      if (! pageNameIs("/"))
      {
        client.stop();  
        return;
      }
      if (valueOfParam('a') == 0){
        armedState = 0;
        sendSyslogMessage(6, "System disarmed");
      } 
      else if (valueOfParam('a') == 1){
        armedState = 1;
        sendSyslogMessage(6, "System armed");
      } 
      else {
        armedState = armedState;
      }
      client.println("HTTP/1.1 200 OK");
      client.println("Content-Type: text/html");
      client.println();

      // send the body
      client.println("<html>");
      client.println("<head>");
      client.println("<title>");
      client.println("Arduino Alarm Interface");
      client.println("</title>");
      client.println("</head>");
      client.println("<body>");
      client.print(zone1Name);
      client.print(" : ");
      client.print(zoneStatusArray[0]);
      client.println("
");
      client.print(zone2Name);
      client.print(" : ");
      client.print(zoneStatusArray[1]);
      client.println("
");
      client.print(zone3Name);
      client.print(" : ");
      client.print(zoneStatusArray[2]);
      client.print("
");
      client.print(zone4Name);
      client.print(" : ");
      client.print(zoneStatusArray[3]);
      client.println("
");
      client.print(zone5Name);
      client.print(" : ");
      client.print(zoneStatusArray[4]);
      client.println("
");
      client.print(zone6Name);
      client.print(" : ");
      client.print(zoneStatusArray[5]);          
      client.println("
");
      client.print("Siren status : "); 
      client.print(sirenStatus);          
      client.println("
");
      client.print("Armed state : "); 
      client.print(armedState);          
      client.println("
");
      client.println("<form method='GET'>");  
      client.print("Armed: ");
      client.print("<select name='");
      client.print("a");
      client.println("'>");
      client.print("<option value='0'");
      if (armedState == 0)
      {
        client.print(" selected");
      }
      client.println(">Off</option>");
      client.print("<option value='1'");
      if (armedState == 1)
      {
        client.print(" selected");
      }
      client.println(">On</option>");
      client.println("</select></p>");
      client.println("<input type='submit' value='Update'/>");
      client.println("</form>");
      client.println("</body></html>");

      client.stop();   
    }
  }
}


void readHeader(EthernetClient client)
{
  // read first line of header
  char ch;
  int i = 0;
  while (ch != '\n')
  {
    if (client.available())
    {
      ch = client.read();
      line1[i] = ch;
      i ++;
    }
  }
  line1[i] = '\0'; 
  Serial.println(line1);
}

boolean pageNameIs(char* name)
{
  // page name starts at char pos 4
  // ends with space
  int i = 4;
  char ch = line1[i];
  while (ch != ' ' && ch != '\n' && ch != '?')
  {
    if (name[i-4] != line1[i])
    {
      return false;
    }
    i++;
    ch = line1[i];
  }
  return true;
}

int valueOfParam(char param)
{
  for (int i = 0; i < strlen(line1); i++)
  {
    if (line1[i] == param && line1[i+1] == '=')
    {
      return (line1[i+2] - '0');
    }
  }
  return 2;
}

void sendSyslogMessage(int severity, String message)
{
  /*
0 Emergency: system is unusable 
   1 Alert: action must be taken immediately 
   2 Critical: critical conditions 
   3 Error: error conditions 
   4 Warning: warning conditions 
   5 Notice: normal but significant condition 
   6 Informational: informational messages 
   
   Only severity levels 0, 1, and 2 will trigger an email message
   */

  int pri = (32 + severity);
  String priString = String(pri, DEC);

  String buffer = "<" + priString + ">" + "AlarmSystem " + message;
  int bufferLength = buffer.length();
  char char1[bufferLength+1];
  for(int i=0; i<bufferLength; i++)
  {
    char1[i]=buffer.charAt(i);
  }
  char1[bufferLength] = '\0';
  Udp.beginPacket(syslogServer, syslogPort);
  Udp.write(char1);
  Udp.endPacket();  


}

Any progress on this since February.
More people should be using syslog,I plan to.

Surprised you didn't

#define emerg 0
#define alert 1
#define crit 2
#define err 3
#define warn 4
#define notice 5
#define info 6
#define debug 7

Regarding the relay, beware of relay coil damage due to the BACK EMF generated in the relay's inductive coil when the pin is turned OFF.
Not the best description but check into it and others

Thanks for the reminder! I ended up writing a "sendSyslogMessage" function which takes the message and severity values as parameters. At first, I wrote a pretty all inclusive syslog function that included the current timestamp in the message, calculated the facility/severity levels, etc. However, the syslog server I am sending these messages to a Synololgy DiskStation (DSM 4.0) which ignores the timestamp included with the message and the facility value will always be the same, so I removed those parts.

What I have now is an Arduino that monitors several inputs (magnetic reed switches and a motion detector). It has two armed modes, "home" and "away". The difference being whether the motion detector is monitored. It can be armed by the web interface or by a push button (which also lights up when the alarm is armed). When the alarm is tripped, it closes a relay (on a dedicated relay board so resistors and diodes are already included) which triggers an alarm. At the same time, it sends a syslog message to my Synology that is set to send me an email alert when such messages are received. So far, the system has been running for just over 20 days without a hitch. The only thing I have left to do is attach a larger siren to the relay as presently it's just a small buzzer (didn't want a 130dB alarm going off during the testing stages :slight_smile: ).

The web interface is not secured with anything other than a password, however, to actually get to the device you have to be VPN'ed in to my home network, so the weak password is not as much of a concern.

Again, this whole thing works as is and for my purposes is "done". Nevertheless, if you see something that could be a problem, please do let me know!

Code is attached, as it is too long to post inline.

Alarm_working.ino (11.6 KB)

Thanks for the reply and the code