I wanted to be able to monitor our Ademco Vista 20P alarm system control panel messages via an Arduino-based web server. The Vista 20P installation in our house has 2 keypads. The main controller in the alarm panel sends 30-character ASCII strings preceded by to the keypads via a serial interface to let the user know what the alarm system and sensor status is. The serial interface is RS-232-like at 4800, 8, E, 2.
I found the work of Martyn Woerner, Alessandro Calzavara, and Alberto Capponi at Arduino Playground - WebServer very helpful. I also borrowed from the works of Surfer Tim, Michael Margolis, Tom Igoe, and Nick Gammon, and perhaps others whom I don't recall.
The hardware I used is (1) an Arduino Uno, (2) an Ethernet Shield, and (3) an RS-232 shield (see, e.g., the DEV-11958 from SparkFun) that interfaces to the 12V serial port levels coming from the Vista 20 panel. I had to add an extra set of stackable headers (SparkFun PRT-11417 or equivalent) between the Ethernet Shield and the RS-232 Shield to keep the RS-232 Shield's DB9 connector pins from shorting out against the top of the metal can surrounding the RJ-45 connector on the Ethernet Shield.
This little web server has 7 pages:
- A login page*[/li]
- A general display page that displays the time and the alarm panel message*[/li]
- A page for entering email addresses for event messages*[/li]
- A logout page*[/li]
- A page to tell you you're logged in[/li]
- A page to tell you the server is busy, i.e. the max number of clients are logged in[/li]
- A 404 - Page Not Found page[/li]
- The first 4 pages listed above are associated with menu options on the tops of the pages. The others are essentially status messages.
The "semi-secure" login uses session cookies. The server generates a random cookie when the client logs in and sends a "Set-Cookie: SID=XXXXXXXX" line in the HTTP header to the client when it acknowledges the login. ("XXXXXXXX" is an ASCII-HEX 32-bit number, e.g. "05AF2CE1".) The client sends the cookie back in its HTTP header in a "Cookie: SID=XXXXXXXX" line. See IETF RFC 6265. When the server gets a page request from a client, it checks to see if it received a cookie it issued. If not, it sends the client the login page. If so, it sends the client the requested page, or a status page if appropriate. Right now, it's set up to allow at most 2 clients, and to automatically log clients off after 5 minutes. The latter is to prevent something unexpected from filling up the cookie jar and preventing me from logging in.
To torture myself (I'm a bureaucrat by profession, not a software engineer), I wrote a small libary ("Cookies") that I use to create the random cookies, put them in a "jar," test to see if the jar is full, if a particular cookie is in the jar, if the jar is full, and where a cookie is in the jar. The cookies are just 8-character pseudo-random hex numbers ASCII-coded as 2 characters per byte. (They could be longer, but I'm not sure there's much point.) To ensure the torture was sufficiently painful, I made the jar a dynamically-allocated array of strings.
You can enter up to 3 email addresses to send event messages to. The server sends a test email message when you change the addresses, and sends messages to the addresses when it detects a fault message from the alarm panel.
The server sets an internal clock using Udp NTP code upon startup and once per day thereafter.
The server sends a refresh "GET" message to the Kiso Labs dynamic DNS server every 10 minutes. I need this because my ISP doesn't give me a permanent IP address, and I want to be able to log into the server when I'm away from home for a week or two.
It compiles to 26,012 bytes on the Uno with debug = 0 and 28,816 bytes with debug = 1 under the 1.0.5 development environment.
The code consists of the following files:
The Cookies library includes the following files:
Because I can only attach 4 files per post, I've concatenated Cookies.h and Cookies.cpp into one file, which I've called "Cookies.lib".
Sadly, I don't have the time or energy to answer questions about this stuff, so I'm pretty much just throwing it over the wall for you to figure it out as I did. I hope someone finds it useful.
See attached files.
P.S.: After I posted this, I added a feature to measure the temperature in the room in which the server is located using a Maxim DS18B20 and the OneWire library. It'll send an email if the temperature goes out of normal house limits (50F to 85F for us). Compiles to 29,604 bytes on the Uno under 1.0.5 with debug = 0. I had to bifurcate the debug stuff to squeeze it into 31,998 bytes when debug = 1. (I separated out free memory reports.) The temperature monitoring enhancement is not reflected in the attached code.
P.P.S.: A final modification was to replace the refreshing of the Kiso Labs dynamic DNS with a more "polite" updating of my IP address with another dynamic DNS provider. By "more polite," I mean I periodically check my IP address, and only send an update to the provider if it changes.
AlarmServerV1_5_Share.ino (45.4 KB)
AlarmServer.h (1.46 KB)
HTML.h (6.14 KB)
Cookies.lib (4.77 KB)