Thursday, April 26, 2012

Interrupt-Driven Alarm on Hold - Polling Instead

BUG REPORTS :

Bug # 1 - Polling instead of Interruptions

After finding a bug in the interrupt-driven alarm mechanism, that has been put on hold while the project progresses. The bug is this - with the basic circuit design, if ANY input is open, opening another one will NOT trigger the interrupt.  In lieu of the interrupt-based concepts, I implemented a simpler design that people would have used defacto - polling. In this case, the loop() function sleeps for 50ms, then manually calls the interrupt function, and continues this way indefinitely. Power savings were merely 10 milliamp (very paltry considering the overall design), and simpler is always better. As a result, it's now a polling-based alarm mechanism, and functions well. Code is available at http://svn.silverhawk.net/files/polling_alarm.ino.

Bug # 2 - DD-WRT Router, Static Lease, and Arduino Static Config

This one isn't a bug with the Arduino, but a bug with the system.  In configuring the network, I used my current Asus device with DD-WRT installed, and configured a static lease.  On the Arduino side, I set the IP address statically (no DHCP).  The problem came about after realizing the Arduino could not talk to the outside world and running some iptables routing commands on the DD-WRT :

iptables -t mangle -A POSTROUTING -d 10.1.1.20 -j ROUTE --tee --gw 10.1.1.100
iptables -t mangle -A PREROUTING -s 10.1.1.20 -j ROUTE --tee --gw 10.1.1.100
The above two lines copied all network traffic to and from 10.1.1.20 to my workstation, 10.1.1.100, and then I slapped Wireshark on there.  I saw internal communication from the Arduino to the alarm server, but as soon as it tried to talk externally, nothing got out.  In fact, the Arduino threw "Who as 10.1.1.1?" ARP messages out to the gateway in order to communicate with it, but the gateway (the DD-WRT) simply ignored the Arduino.

Hmph!  I adjusted the static lease in the DD-WRT, and the thing was instantly communicating to the outside world.  It was live (open a door and my VPS server knew what happened).  Awesome!  So, let's run it with the PoE instead of USB power.....

Bug # 3 - Insufficient Power From PoE Device

After having successful communication to the outside world with everything in place (and the sensors installed in the doors), I tried running the Arduino over the PoE with long cables - and some sensors stopped working (they just reported back as "open").  When using the USB to power the device, it worked flawlessly.  Back to the PoE, and they stopped working again.

Conclusion : put the Arduino where it can be powered using a transformer, preferrably a 12v power source.

Next, I tried installing Linux motion after ZoneMinder failed to give me decent enough performance on the frame rate,  but that had poor performance, too, so I opted to hack some security flood lights that had LED indicators - might as well get dual purpose devices.  I start picking the theories for this apart in Motion Detection via Flood Light, and interfacing that to trigger camera recording, not just events.

Friday, April 13, 2012

tcpdump - when no other tools are available to filter a packet

I am fairly used to using tcpdump to capture network data.  However, I really gained the ability to review and understand the captures via Ethereal, later renamed to Wireshark (as it was spun off and the original trademark owner wanted to keep the trademark).  As a systems admin, I have to be familiar with reading the capture file from a network, but not always are the tools available.  As an example, I recently had to filter a packet capture for a partner as we did some troubleshooting, because policies require not exposing internal network structures, layouts, or organization.

So, I found myself one day sitting at my Linux box (without Wireshark installed) having the results of four tcpdumps from separate hosts in separate files.  I needed to combine the captures together and then filter out the partner-specific traffic.  Took me a while to remember the filtering options, so I thought I'd post the process here in the form of a journal - I can't even remember how old I am sometimes.

First, you have to combine the packet capture files together.  You cannot just cat the files together as you might have an incomplete packet from when you started.  The later versions of tcpdump actually have a tool to facilitate this :
mergecap -w silverhawk.cap host1.cap host2.cap host3.cap

After merging the captures together, you will want to remove the stuff not related to your current problem (to prevent the prying eyes from seeing inside of your network).  To do this, take the combined packet capture, and write another one, feeding it through a filter.  Your filters can be complex or simple.  I prefer the simple filters :

tcpdump -r silverhawk.cap -w silverhawk-filtered.cap -n "port 443"
The above would grab all of the TCP port 443 traffic, or the SSL-encrypted traffic (for HTTPS connections).  For most concerns, that alone would be enough (decrypting the SSL traffic would require the SSL certificate keys for the traffic streams you need to see).  However, if you have multiple connections to different port 443 traffic and you would prefer the partner doesn't see whom else you are connecting to, you can do it via IP address :

tcpdump -r silverhawk.cap -w silverhawk-filtered.cap -n "host 200.20.200.20"
Those are fairly simple filters, and should definitely assist in restricting who sees what.  I'd strongly suggest looking at those, and then adjusting as necessary (e.g. adding other, fancier filters by merging them together).

Tuesday, April 10, 2012

Apache, mod_perl, and an example output filter

Perhaps I should explain what an output filter really is.  Before apache serves any content to the web browser, it filters it, or allows different modules to alter it.  Here is an example situation :
You have been given a task where you have HTML pages that contain information for both the authenticated user and the user that hasn't authenticated.  You need to prevent the information intended for the user isn't served when a visitor hasn't authenticated.
How do you implement the above?  It's called an output filter.  For the above example, you will have to implement a simple module that checks a response page for a special tag, check for authentication, and if we are authenticated, allow the contents of the tag to be returned to the browser.  If not authenticated, remove the tag.  As an example, I'll use an HTML type tag :
<AuthenticatedOnly>
You are logged in!
</AuthenticatedOnly>
Please note, we aren't actually implementing the above.  It is merely a hypothetical situation.

There are two ways around creating an output filter.  You can create code that has to be compiled (my mod_template.so is a good example - it's written in C, and it wraps any HTML content in a template so that the whole site appears the same), or you can accomplish the same thing using mod_perl.  We'll take the latter one, as we won't need to install the compiler, just mod_perl.

To start out, we need to modify the Apache configuration to add it in.  Once you have it open, there are three things we need to do :

  1. Enable mod_perl, and insert an "internal" configuration to add our path.
  2. Create the filter module.
  3. Enable the configuration directive for the filter
To enable mod_perl :
LoadModule perl_module modules/mod_perl.so
PerlSwitches -Mlib=/opt/hacks/perl
With those two options in the Apache config, we also need to create our filter.  We'll create it in /opt/hacks/perl, obviously, since we told mod_perl to use that in the above example.


package MyOutputFilter;

use strict;
use warnings;

use base qw(Apache2::Filter);
use Apache2::RequestRec;
use APR::Brigade;
use Apache2::Const -compile => qw(OK);

sub handler : FilterRequestHandler {
  my $f = shift;
  my $bucketBrigade = shift;
  my $r = $f->r;
  my $uri = $r->uri();
  my $contentType = $r->headers_out->get("Content-Type");
  if ($contentType eq 'text/xml') {
    my $content = '';
    my $contentLength = $bucketBrigade->flatten($content);

    # modify $content here

    $f->r->headers_out->set('Content-Length', length $content);
    $f->print($content);
  }
  return Apache2::Const::OK;
}
This is a very simple filter - it does absolutely nothing, but should give you an idea of how a filter works. I'll break things down a little bit at a time. The first line is a good key - it's the name we use later when we enable our specific module. After the name, we have a few libraries we use, and then we must declare our handler function, since that is what mod_perl will call. Ours is the line :
sub handler : FilterRequestHandler {
The contents of that function define what we are doing.

Note that I have grabbed a "bucket brigade". A bucket brigade in apache is a pretty novel idea. Remember the stories about people putting out fires by passing buckets of water between each other? This is the same thing, but the "people" are apache modules, and the "buckets" aren't water, but response data.

In the above example, I call "flatten" on the bucket brigade - for another project, I needed to have ALL of the data at the same time, so it needed to be flattened into one "bucket".  If you work with large data, do NOT flatten them - you can cause Apache to use up free memory!  That assigned the contents of the response into the $content variable, which I can then modify.

After I am done with the data, I can pass it on to the next filter by calling $f->print($content);.  Note that I am also re-setting the Content-Length header - if your browser respects that, and you change the data but don't change the header, you might end up with blank pages (Google Chrome is a good example browser that does that).  Congrats!  You now have a simple filter that you can start to enhance to do some pretty amazing things!

Apache - proxiing to simple proxy to allow viewing of authenticated data

In Apache, we can enable the proxy module to allow our web server to send a request to another location, and we serve the result.  To do this quickly, simply enable the proxy modules you need :
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_connect_module modules/mod_proxy_connect.so
LoadModule proxy_ftp_module modules/mod_proxy_ftp.so
LoadModule proxy_http_module modules/mod_proxy_http.so
Once enabled, you can then create the proxy section. Please note that the following configuration is for an example - do NOT use it without hardening who has access to your proxy!  The config :
<Proxy *>
Order deny,allow
Allow from all
</Proxy>
ProxyPass / http://www.google.com/
Again, note that this will create an open proxy, and that is bad if you don't control who can access what, because you will be the one left holding the bag if they request illegal material. You have been warned!

This works great for most things, but let's presume for a minue that you wanted to serve a page from an HTTPS connection, no matter how it's requested from our web server. We need to enable SSLProxyEngine. If we are using self-signed certificates from that location, you might have to also add "SSLProxyCheckPeerCN off", e.g. :
SSLProxyEngine On
SSLProxyCheckPeerCN off
Let's toss in two more criteria. First, let's presume that you want one subsection of your site to be served from the local filesystem.  We can disable the proxy for a location by adding another proxy pass :
ProxyPass /local/ !
Now, for the second part, let's presume we have a chunk of the proxy that requires authentication.  In this case, we don't want to present the real user with the password pop-up, so, how do we do this?  Web browsers utilize a basic authentication using a series of headers, WWW-Authenticate, and Authorization.  The WWW-Authenticate is a response header that triggers the browser to authenticate the request.  The browser pops up the username/password dialog box, and then uses that information to generate an Authorization header.

Since we really don't need to worry about the WWW-Authenticate header, we can simple inject a permanent Authorization header into the system.  It's done with the RequestHeader directive, similar to :
<Location /svn/trunk/>
RequestHeader set Authorization "Basic dXNlcm5hbWU6cGFzc3dvcmQ="
</Location>
Now, here is a problem. How do we know what to put with the Authorization header?  Looking at the value that follows Basic, it looks like a MIME Base64 encoding.  Feeding it through a simple perl command, we can decode it and find out that it is indeed a Base64 encoding in the format of "username:pass".  We can figure out what we need by installing the MIME::Base64 perl module and running :
[username@hostname ~]$ perl -MMIME::Base64 -e "print encode_base64('username:password');"
dXNlcm5hbWU6cGFzc3dvcmQ=
[username@hostname ~]$
This will inject an authorization header into the proxied request.  Hopefully, this little cheat sheet will be of assistance to someone.

Thursday, April 5, 2012

Arduino - Assembly and Testing

Okay, we have the basics down for how the interface should behave.  Before I continue, I've been asked why not just expose the current states in a web server on the device, so I'd like to take a moment to explain that.  First, there are some things that would be perfect to expose via web service.  Those kinds of states would be temperature or other environmental variables.  The problem with exposing the door sensor via web server is that it would then depend on how often you are probing the actual device via the web.

For example, if you check the device once every minute, you will find that you might not even see the doors "open".  (In the case of an intruder, I doubt they will leave the door open to attract attention while they are in the structure.  Perhaps when they leave, but by then, it could be too late to trigger camera captures or notifications - your valuables could be long-gone.)

Arduino Assembly

The Ethernet shield (W5100) couples with the Arduino Mega 2560 just perfectly.  I suggest that you put them together to run through a test run before soldering on the PoE module.  The shield fits on perfectly by just connecting them :



Once those are connected, go ahead and upload your code to the Arduino.  The next phase for testing is to create the diode board.  I grabbed a cheap prototype board from Radioshack, and just slapped things on there quickly (it might explain the "poor design" in the following photo) :


(Obviously, the diodes are on the other side of the board).  Note that I have soldered ethernet lines up as the switches.  To simplify the other ends of the switches, I use the twisted pairs on a switch basis, e.g. the white-green and green are for the front door, etc.  Those are then tied to a computer header connector (they are cheap, and you can get a male-male header pretty cheap, too - and they work great together!), and also via the diodes to an extra line for the interrupt pin.  Once all of that is soldered together, we connect things up :


We tie our little protoboard to the 5v and ground, and then the individual pins that we want to use as inputs and the interrupt pin.  I then crafted a cheap case (and later found out there are better cases for approximately the same costs, cases that were designed for the Arduino), cut some holes, and slapped it together to check the fit.


Once it's been put together, we take the covers back off, start preparing the configuration for the SD card.  If you are using the code from a previous post, you will create an INI file in the root of the SD card called "ALARM.CFG".  This file has three sections :
[global]

[doors]

[garage]

[network]

[notifications]
The "[global]" section might eventually contain more settings (and did at one point before the code was simplified), but as of now, the only "global" setting is that of the interrupt pin.  For example :

[global]
interruptpin=18
The "[doors]" contains a list of the door switches.  The format for this is a priority:pin - you'll understand the priority when we get to the "[notifications]" section, and the pin is the input on the Arduino that it will be tied to.  These are "open" or "closed" types of switches, so if you were adding window sensors, they'd go right here.  Examples :
[doors]
frontdoor=1:38
backdoor=1:36
gate=1:37
The "[garage]" section contains the garage door switches.  It has the format of priority:pin1,pin2 - again, priority will be discussed later on, but as the garage has four states ("open", "closing", "closed", "opening"), we needed to have two pins (the logic was discussed in the Code Design post).  An example of this :
[garage]
maingarage=1:40,41
The "[network]" contains our configuration for the W5100 card - the IP address we want to assign, gateway, mask, and the MAC address.  For example :
[network]
ipaddr=10.1.0.61
gateway=10.1.0.1
dns=10.1.0.1
mask=255.255.0.0
macaddr=41:4C:41:52:4D:01
The "[notifications]" section contains the places we send state changes for the doors - this happens via a simple network connection (I'll slap some code in here for the server-side, using C for you Linux gurus). The format for these entries in the configuration are priority:IP_address:[EncryptionKey:[port]]
[notifications]
internal network=1:10.1.0.2:11223344556677889900AABBCCDDEEFF
offsite network=1:209.59.216.248:FFEEDDCCBBAA00998877665544332211
Now, to talk about the priority. As an event happens, it has an associated priority with it - e.g. "1" in the above examples. As an event happens associated with a priority, only those notification destinations associated with that priority will be called. It makes it easy to break out various switches to different locations (you can, for example, define the same notification location twice by giving it a different name but the same components, and have two priorities going to the same location). If you don't specify a port, the default port is 3612. If you don't specify an encryption key, you will have a non-encrypted communication. To specify a port without encryption, simply place an entry of the format "Priority:IPaddress::Port" (e.g. no encryption key). The encryption is to prevent a snooper from easily grabbing and spoofing requests to the server. It is a simple encryption, because too much work might cause us to miss other events as they happen if the Arduino is working too hard. The process is a shared key on both ends, and an XOR between them.
void enc(char *src,char *key,int msg_len,int key_len) {
  int   current_pos_key,current_pos_msg;
  current_pos_msg = 0;
  while (current_pos_msg < msg_len) {
    current_pos_key = 0;
    while ((current_pos_key < key_len)
          && (current_pos_msg < msg_len)
          && (src[current_pos_msg + current_pos_key] != '\0')) {
      src[current_pos_msg + current_pos_key] ^= key[current_pos_key];
      current_pos_key++;
    }
    current_pos_msg += key_len;
  }
};
The above is the actual encryption function out of the Arduino code, and gives good idea of how to implement the function.  Call the function again with the same key on the data, and you will have the original message.  For the server-side, the encryption function is identical - we just need the same key configured somewhere with the server.

The entire simple server code is available via http://www.silverhawk.net/files/interrupt_alarm-server-side.c. The tests indeed show that good keys have encrypted communication and that things look great! (I actually tied in the notification server to Google Voice using a fork(), but that code is not available as I'm not sure how far I can go - I was getting door open notifications via SMS!)  Whahooo!  Next up - a bug!

Tuesday, April 3, 2012

Arduino - Design, Code, and Assembly

When I started this component, I went through three different designs :

  1. Learning Curve : With the ultimate objective in mind (and no idea of how to use an Arduino at this point), this project became my Arduino learning curve. In this first "learning" state, it used pull-up or pull-down resistors on a separate circuit board, and the device was actively polling the switches for state changes.
  2. Sleep Mode : As I started to wonder about power consumption, I found that the Arduino utilized interrupts, and (as a result), could be put to sleep. That lead to a redesign using both pull up resistors AND diodes to trigger a separate interrupt pin.  This option was later scrapped due to time constraints and the fact that power consumption dropped to 3mA rather than the original 15mA.  That is NOT a lot of power, and the polling was easier.
  3. Simpler Design : As I progressed in completing the sleep mode, I found that the Arduino INCLUDES on-board pull-up resistors - making them pointless in my initial design. A subsequent test with using the on-board pull-up resistors gave me a fully functional design that required half of the parts I thought I'd end up with.

I toyed with the following schematic, only to find it buggy :


The PROBLEM :

The problem with the above design is that, if any door is closed, the interrupt pin will be grounded out, meaning someone could open any single door, leaving another one closed, and the Arduino would never wake up to find out.  Still, it can be done, I just don't have the time to implement it (using some NEG gates and an OR gate across all switches).  Because it can be done, I'll discuss what was intended with the above.

The THEORY :

All switches (I'm using magnetic reed switches) have one end tied to the ground pin on the arduino. As a switch is closed, it pulls the corresponding digital pin that it is tied to DOWN. (It's high because when we start, we pretend it's an OUTPUT pin and set it to HIGH.) The diode is to prevent switch one from also pulling switch 2 low because we are tying the switches together into an extra pin that is specific for the INT (interrupt). That is required, since we start the Arduino up, initialize everything, then put it to sleep.

Here's how it was supposed to work. When a door is in it's closed state, the switch for that corresponding door is closed, causing the digital pin for that to be pulled low. As a door opens, the switch opens, and the pull-up resistor for that pulls that input to HIGH. It also causes the state to change on the INT. That INT signals the controller to launch a subroutine that scans all of the pins it's configured to looking for a state change, and then launches the appropriate subroutine (e.g. the "closed()" or "closing()" functions).  The interrupt-based code is still available at :

http://svn.silverhawk.net/files/interrupt_alarm.pde


The REAL-LIFE answer : back to "polling"

The solution to the INT problem is to switch back to a "polling" mode.  This means that the Arduino doesn't sleep, but the power savings are negligible. It also means that we call the handleInterrupt() function manually.  The time I delay is 50ms - which is nearly instantaneous to the human mind due to reactions, etc.  It should catch pretty much everything, plus, it allows us to throw in a server (to not just sent notices out, but to be passive in the states, too!), and gives us a little more elbow room.

Onward and Upward :

So, with no interrupts enabled, and with the above description of how it was "supposed" to work, we can surmise that everything pretty much stays the same, but without the INT functionality.  Above, we mentioned "closed", "closing", "opened", and "opening".  You might be asking what the difference is on closed/closing and opened/opening functions. That comes into play with the garage door code. Using a single magnet embedded into the garage door, and two "switches" connected to the endpoints of the door, when the door is closed, one switch will be closed and the other open, and when it opens, those reverse. It also gave the ability to see when both are open, and the last state was "closed", we must logically have started opening the door. The same is also true if both switches are open and the last state is "open" - we are now "closing" the door. That means that the configuration MUST be able to know the difference between a normal switch, and the stateful garage door "switches". For a garage door, the code would look like :
int previous_state;
int state1 = digitalRead(pin1);
int state2 = digitalRead(pin2);
if ((state1 == LOW) && (state2 == LOW)) {
  previous_state = -1;
  eventUnknown("Garage Door Sensors both low! Error");
} else if ((previous_state == 0) && (state1 == HIGH) && (state2 == HIGH)) {
  eventDoorOpening();
} else if ((previous_state == 2) && (state1 == HIGH) && (tstate2 == HIGH)) {
  eventDoorClosing();
} else if (state1 == LOW) {
  eventDoorClosed();
} else if (state2 == LOW) {
  eventDoorOpened();
}
To implement it, you'd need to define a structure that could include this, since the INT specifications mean that the contents are volatile.

For a regular door, it simple checks the previous state, and if the state has changed, call the corresponding "open()" or "close()" function. Also, by passing a structure to a configuration for what sensor we are looking at, we can suddenly reuse the function (memory is limited on an Arduino).

I wanted this device to be configurable, so I had to read from the SD card on an Ethernet shield (W5100). This was done in the setup function. Since I needed a configuration that was easily modifiable without re-uploading the code to the device, I re-invented the INI wheel. The setup function includes the code :
char config_code[10];
char currentChar;
char config_section[80];
char config_line[356];
char *config_key;
char *config_val;
void setup() {
  pinMode(SD_OUTPUT_PIN, OUTPUT);
  if (!SD.begin(SD_PIN)) {
    return;
  }
  // open the configuration file. To write, add FILE_WRITE param
  myFile = SD.open(config_file_name);
  // if the file opened okay, read it. We use an INI-type format
  if (myFile) {
    Serial.print("Reading from ");
    Serial.print(config_file_name);
    Serial.print("...");
    config_line[0] = '\0';
    while (myFile.available()) {
      String cl = myFile.read();
      cl.toCharArray(config_code,10);
      currentChar = atoi(config_code);
      config_line[strlen(config_line)+1] = '\0';
      if (currentChar == '\n') {
        handle_config_line(config_line);
        config_line[0] = '\0';
      }
      config_line[strlen(config_line)+1] = '\0';
      if ((currentChar != '\n') && (currentChar != '\r')) {
        config_line[strlen(config_line)] = currentChar;
      }
    }
    // close the file:
    myFile.close();
    Serial.println("done.");
  } else {
    // if the file didn't open, print an error:
    Serial.print("error opening config file ");
    Serial.print(config_file_name);
    Serial.println("...");
    return;
  }
}
Note that this requires some extra functions (otherwise, setup would have become extremely ugly).
void handle_setting(char *section,char *key,char *val) {
  // put the code in there that would handle your config settings from the INI
};
void handle_config_line(char *line) {
  int  tmp_remove_comment;
  config_val = 0;
  while ((line[strlen(line)-1] == '\n') ||
         (line[strlen(line)-1] == '\r') ||
         (line[strlen(line)-1] == ' ') ||
         (line[strlen(line)-1] == '\t')) {
    line[strlen(line)-1] = '\0';
  }
  tmp_remove_comment = 0;
  while (tmp_remove_comment < strlen(line)) {
    if (line[tmp_remove_comment] == ';') line[tmp_remove_comment] = 0;
    tmp_remove_comment++;
  }
  if (strlen(line) > 0) {
    if (line[0] == '[') {
      strcpy(config_section,line + 1);
      while (config_section[strlen(config_section)-1] == ']') {
        config_section[strlen(config_section)-1] = '\0';
      }
    } else {
      config_key = line;
      config_val = line;
      while ((config_val[0] != '\0') && (config_val[0] != '=')) {
        config_val++;
      }
      if (config_val[0] != '\0') {
        config_val[0] = '\0';
        config_val++;
        handle_setting(config_section,config_key,config_val);
      }
    }
  }
}
Polling doesn't require the following chunk of code! If we get a good interrupt design and need to implement, then, while we are in the setup function, we need to set up the interrupt pins. We do this by enabling the pull-up resistor on the interrupt pin, and then attaching the interrupt function (handleEvent) to that pin :
// set pull-up resistor
digitalWrite(interruptPin,HIGH);
// attach the interrupt
switch (interruptPin) {
  case 2 :
    attachInterrupt(0,handleEvent,CHANGE);
    break;
  case 3 :
    attachInterrupt(1,handleEvent,CHANGE);
    break;
  case 18 :
     attachInterrupt(5,handleEvent,CHANGE);
    break;
  case 19 :
    attachInterrupt(4,handleEvent,CHANGE);
    break;
  case 20 :
    attachInterrupt(3,handleEvent,CHANGE);
    break;
  case 21 :
    attachInterrupt(2,handleEvent,CHANGE);
    break;
};
For each switch, we also need to enable the pull-up resistors :
digitalWrite(pin1,HIGH);
pinMode(pin1,INPUT);
If we were doing the interrupt driven, we'd have to put the thing to sleep. This makes the main loop() function VERY small and short. In fact, the loop() function is ONLY powering the device down :
void loop() {
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
  sleep_enable();
  sleep_mode();
  sleep_disable();
}
Since we are not using interrupts (we're polling, remember?), our loop function will call our "handleEvent()" function manually by doing the following :
void loop() {
  delay(50ms);
  handleEvent();
}
The interrupt function (used in both interrupt and polling code sets) is fairly simple :
void handleEvent() {
};
At that point, it's merely a matter of making the handleEvent function check all of the pins it needs to. To see the full code, check out http://svn.silverhawk.net/files/polling_alarm.ino. Next, we put it all together to test in Arduino - Assembly and Testing.

Introducing Project Homebrew Security System

The Arduino home security system has led into a new project.  A year ago, I had acquired some outdoor cameras from Harbor Freight for relatively cheap costs ($40 for a color camera).  At the time, I had a PVR device (home built DVR system to record on two channels), and enabled the "motion" application on Linux to work with them.  For a simple and cheap "security" system, it sufficed, but it was isolated to a single room, and it wasn't very "secure", and was fairly limited (the requirements list, points one and two).

After purchasing a home, I realized that I needed something a little better.  I then purchased a 4 channel recorder from a maker.  That device filled the need (almost).  The device kept freezing every few months, without so much of a notification (point 3).  It did show when someone broke into the car, but didn't provide enough clarity (point 4 in the requirements).  The device primarily was for a video stream, and the search mechanism was pretty poor when looking for video files (leading to requirement 5).  Though the device handled input for "GPIO's" (general input pins), there were no instructions on how to use them.

I picked up an Arduino (my first Arduino project), and thought about using it as a "sensor" for doors being opened.  I realized that there were some added requirements.  Those requirements culminated into the following list :

The things learned so far (e.g. the requirements of the system) :
  1. An external alert mechanism
  2. Handle more than two video streams
  3. Stability
  4. Clarity on video streams, both night and day
  5. Good interface
  6. Able to handle external notifications (e.g. a door, gate, motion, heat, or seismic sensor)
  7. Logs for events, from cameras to sensors
  8. Able to send notifications to an off-site location
  9. Nothing "wireless" - wireless is easily spoofed and jammed, and is easily eavesdropped on
  10. Expandable (e.g. connecting in to phone systems via Asterisk)
  11. System monitoring
The above list of requirements gave me solid ground to start working from.  First, since I wanted a system that was stable, I needed a piece of hardware that would not have to worry about doing the device capturing - so I knew I needed IP cameras (or "network cameras").  Because I didn't want to run power lines for each camera, that meant these IP cameras needed to have PoE (power-over-ethernet), and I wanted an effective 40 feet range at night (to cover automobiles, fences, etc).  I finally did find the cameras I wanted : TRENDnet TV-IP322P cameras.  I already have lines run for the smaller cameras, so I will use those to "fish" the CAT cables through the walls.

I was able to design a cheap piece of hardware to cover point 6 in the above.  That was the Interrupt-Driven Arduino Alarm.  I've since expanded that project into the above requirements list, and will document the design and implementation of the system through a few different blog posts.  Additionally, due to time constraints and a bug found in that interrupt-driven code for the Arduino, it is no longer interrupt-driven, but a polling mechanism.  Reasons will be identified in the design post.  However, the parts list so far :
  1. TRENDnet TV-IP322P cameras, IP-based, PoE, night vision to 20m, good resolution (1280x1024), cost : $420 each
  2. TRENDnet TPE-S44 8-port, 100Mbps, PoE switch [enough ports for all cameras, arduino, LAN link, and local device to handle video capture] ($50.00)
  3. Arduino Mega 2560 ($48.00)
  4. Arduino Ethernet Shield W5100 ($40.00)
  5. Arduino Ethernet Shield PoE module Ag9120-S ($21.00 from Amazon) (I moved the Arduino, and found I didn't need to use the switch for the Arduino, so save yourself $20 and buy yourself a new movie and put the Arduino in place with a power supply).
  6. SD card to hold the Arduino configuration ($4.00) (I ended up adding code to the Arduino that, if the SD card fails, will fall back to a coded configuration - and you can actually accomplish all of this without the SD card).
  7. Case for Arduino ($15-30, depending on what you want)
  8. Linux Server (this can range - I had one that had been decomissioned a while back)
  9. Ethernet cable, connectors, and jacks
We'll document the project in the following order :
  1. Arduino - Design and Code - should act as the interrupt-driven sensor interface with PoE so that it will report in when events happen in real-time
  2. Arduino Assembly and Testing - putting the active sensor together
  3. !!Bugs!! - found some gotchas, might help you to see these.
  4. Installing the Arduino and doing preliminary testing of at least two doors. This is pretty self explanatory - find a spot and a box, install the arduino to this, and run cables with the door sensors - examples of the installation can be found here).
  5. Configure the TrendNet TV-IP322P camera in a motion detection package. After failing with first ZoneMinder and then Linux Motion due to unacceptable frame rate recordings, I found I could use a  flood light connected to the alarm server documented in Arduino Assemly and Testing, but didn't want flood lights by every camera.  After testing and retesting, I found that the highest quality of uploaded video, the fastest to get set up, the easiest to tweak and reduce false positives was the camera's own motion detection and upload functionality.  Incidentally, it turns out that when the arduino was down, this still provided a layer of security as I could configure the CGI events to still alert me.
  6. Changing from a prototyping perf board to an actual PCB for a cleaner installation. The board looked great, connections and components fit (the relays were a little snug, but not too bad).  I did run into some issues with the early board (I deleted the old board and uploaded a new one to fix those problems), but things are looking up.  If you need a board professionally done and an initial small count for testing, BatchPCB is the way to go.  Testing the board was successful.
  7. Setting up a portal that includes current camera views, event logs (from sensors and camera recordings), and the ability to view live camera feeds.
  8. Full testing and results
Questions and comments are welcome.