Why is it that every spring there is something broken on my sprinkler system? This year my, supposedly waterproof, commercial-grade sprinkler controller ended up being non-responsive; leaving my whole sprinkler system as a useless, mindless, zombie moaning for brains.
What does a software/hardware engineer do when he runs into a problem like this? Can't rely on other people's designs, that's for sure! So I pulled one of our early prototype, ethernet-connected, relay boards and wired it for use as a sprinkler controller.
The wiring process is very very simple (24VAC to relay common, valve solenoid to relay normally open) so I won't detail it here, and it is made even easier with the common bussing feature on our hardware. I only have 4 zones, but this board would be able to handle up to 10 discrete valves.
Now that the easy part was done I needed something to operate the zones at the proper times. I have a Linux server/gateway in the basement that is always on, and what tool does a Linux admin use to do things at regular intervals? CRON!
Relay Board Control
I guess I should start with a quick primer on how to remotely control our boards. The firmware on our board uses an intentionally simple UTF-8 (haha, ASCII really), line-oriented protocol. Simply connect to its IP address on port 10001 and start sending commands terminated with a carriage return, line feed, or both.
The command structure is simple, first you specify the port (relay) then the operation, then the desired state. For example, to turn relay 1 to the ON state you would send
(port 1, operate relay, 1 = on state, carriage return terminated), then to turn it off send
1R0\r; for Relay 2
Another command type that the board supports, timed commands, are also useful for this project, they're the same as the relay commands but have an additional delay time parameter appended. To turn relay 1 off in 5 seconds send
1T050\r (port 1, timed command, 0 = off state, tenth-second delay: 50 = 5 seconds, carriage return terminated).
|1||T||0||50||All commands terminated with \r, \n or both|
I must mention a very important ordering requirement of these commands, first sending a timed command to turn the relay off after the required runtime, THEN send the command to activate the zone. This will ensure that the zone turns off even if something goes wrong while sending the commands.
Just ask my anonymous friend, who wrote his own sprinkler control system years ago, how important this is. Using relay boards that didn't support timed commands, his software sent the activation command to the board and then because of a forgotten assert, broke into the debugger, freezing execution. He woke to a thoroughly flooded basement; this has honestly been a bit of a deterrent to me as I've thought of doing this exact thing many times over the years.
So we want to use CRON to control the IP connected board. What's the easiest way to send arbitrary data to a host from the shell? NetCat! Here's the initial crontab that I set up to run my sprinkler zones, I wanted two start-times with relatively short watering times. Using a piece of graph paper I plotted the zone start and end times to derive the cron rules from.
# Sprinkler Schedule #Schedule A #Zone 1 1:00 - 15 minutes 0 1 * 4-10 * echo -ne "1T09000\r1R1\r" | netcat 192.168.0.225 > /dev/null 2>&1 #Zone 2 1:15 - 15 minutes 15 1 * 4-10 * echo -ne "2T09000\r2R1\r" | netcat 192.168.0.225 > /dev/null 2>&1 #Zone 3 1:30 - 20 minutes 30 1 * 4-10 * echo -ne "3T012000\r3R1\r" | netcat 192.168.0.225 > /dev/null 2>&1 #Zone 4 1:50 - 20 minutes 50 1 * 4-10 * echo -ne "4T012000\r4R1\r" | netcat 192.168.0.225 > /dev/null 2>&1 #Schedule B #Zone 1 2:15 - 15 minutes 15 2 * 4-10 * echo -ne "1T09000\r1R1\r" | netcat 192.168.0.225 > /dev/null 2>&1 #Zone 2 2:30 - 15 minutes 30 2 * 4-10 * echo -ne "2T012000\r2R1\r" | netcat 192.168.0.225 > /dev/null 2>&1 #Zone 3 2:45 - 20 minutes 45 2 * 4-10 * echo -ne "3T012000\r3R1\r" | netcat 192.168.0.225 > /dev/null 2>&1 #Zone 4 3:05 - 20 minutes 5 3 * 4-10 * echo -ne "4T012000\r4R1\r" | netcat 192.168.0.225 > /dev/null 2>&1
Echo by default appends a linefeed and does not process escaped sequences, the
-ne command-line parameters resolve these issues for us.
Sweet! 30 minutes after I started this project and my lawn is getting watered. Goal 1 accomplished, now my lawn won't die while we have some real fun!
The title of this post is Node.js Sprinkler Controller, right? So where's the node? One of the only reasons I decided to do this project was because I have been wanting to learn some of the new web technologies with a real project. For this one I've decided to learn Node.js on the server side; Knockout.js on the client; and Socket.IO, and Coffeescript on both. For this project I'll be taking advantage of the express web framework running on Node.js.
So the node... This introductory article is too long! Jump to Part 2 to where we'll get node set up and get it talking to the relay board.