|All News -> Projects|
|Written by Nicholas McClanahan|
|Tuesday, 07 September 2010 12:08|
Make an embedded webserver for Home Automation projects
The Instructable documents how to build it and includes links to the code and schematic, but I thought it would be useful to share my experiences developing it.
The Web Clicker is built on a Propeller Platform USB and an E-Net module. A few additional components were added (an IR LED and receiver), but that circuit is very simple. I built it on a ProtoPlus, but it will fit on any Protoboard.
D1 is an IR LED (mouser part 638-IR333-A), and U1 is an IR receiver (mouser part 782-TSOP4838). 95% of devices use 38kHz modulation, but the IR receiver can be swapped out with another receiver sensitive to a different modulation easily.
Overall, the hardware is very straightforward. No tricks in reading the IR signal or re-transmitting were necessary.
Firmware: IR Transmit / Receive
I started by grabbing a few objects from the Propeller Object Exchange that were created for IR receive / transmit. I quickly ran into a problem: my downstairs TV is a JVC, and my upstairs TV is a Sharp. Neither used the RC5 remote control format or the SIRCS format. After extended google-ing, I found some documentation on JVC's format.
This looked easy enough, although you need to invert it because the IR receiver goes low when it senses an IR signal. I implemented a basic signal recorder in SPIN: It would wait until the signal went low, then test each 'cell', recording the bit value. I ran into some problems with this approach — I'm pretty sure SPIN is too slow to catch all the transitions (I would put it in a loop, wait for a transition, then do a few tests on the transition length & how many transitions had been received), and playing back the code wouldn't activate the TV. Another problem was the repeat portion of the code. It would broadcast the whole code once, then wait 30-40ms and re-broadcast a portion of the code.
I knew it was time to switch to assembly, but on reflection, I decided to implement something more generic. I wanted to be able to control multiple devices without understanding their (possibly undocumented) signal format. I built a generic capture object in Propeller Assembly.
Click on the link above to see the full code with documentation. It is built to wait until the IR pin goes low, start a timer and note every transition time into a series of longs (32-bit values). I've uploaded the object to the Object Exchange for others to use. Development took a while, but using ViewPort helped a lot. It also was useful using my camera to see when the IR LED was firing. Because the playback loop only requires a few instructions, that was done in SPIN and should be fast enough for nearly all IR codes.
This worked to record IR commands and play them back. Now the webserver.
I started with PropTCP by Harrison Pham. His code is easy to use. I started with his AJAX server demo and modified it until I could get an LED to blink. Once I figured out how to get any arbitrary command running from a CGI request, I was ready to go. I implemented a few methods;
For ease of coding, I designed it so when the browser requests exec.cgi, it will execute the IR command in the URL string. /exec.cgi?1- would execute the first stored command, the - (minus) served as the end of line character. This also makes it easy to script IR commands on a PC. Just request exec.cgi?x- and that command will run. Requesting stor.cgi started the storecommand method. And showcodes ran when the browser requested stor.cgi. That HTML is updated asynchronously (ajax).
One note on using PropTCP: You'll need to set your TCP/IP settings in the program first,
For my setup, it was pretty easy — just set the gateway and dns to your router, the subnet to 255.255.255.0 and pick an IP address that isn't being used.
Also, PropTCP takes about 16kB, leaving you with 16kB left for your program. This is a pretty large memory requirement, but you can get around that (somewhat) by using the SD card to store codes, files, etc.
On the Propeller, characters are stored in bytes — each byte stores 1 character. Text strings are zero-terminated, that's why you see a 'byte 0' at the end of each set of lines. To use a set of lines, you refer to the address where the text is stored. sock.str(@ajax) will return the text stored starting at label 'ajax' all they way until it reaches a zero byte.
Each of those functions makes a page request, and the webserver watches for the page request, executing a command based on it.
I had a lot of fun with this project and I learned a few things;