Yard Lights / Sprinklers

Share it!

Yard Lights

There are many options to set up yard lights, and I have tried most of them over the years. For example there are new solar panel charged yard lights you stick into the yard and pretty much forget about them, but they don’t work too well in the winter. There are some with timers where you set on / off times but sun rises and sets at different times throughout the year. Some yard lights have light sensors but how do you turn them off at a designated time.

I use an old computer in the garage running linux primarily as a firewall, but the same computer controls also the yard lights as well as the sprinklers and helps me brew beer. X10 modules are not too reliable but for yard lights and sprinklers they work fine. However, something as critical as beer we have to use the parallel port. We talk about the first two functions in this post. Brewing beer will have to go to another post.

X10 Firecracker modules allow one to turn power on or off from the computer’s RS232 serial COM port wirelessly and also from the remote unit. Each module is encoded with a single letter / number combination. The letters go from A to P, the numbers go from 1 to 16.

The C program to control X10 modules is called flipit. You can get it from http://code.google.com/p/flipit/. There are no dependencies that I know of, it should compile without any problems.

Let us assume that the transmitter is connected to the first COM port and also
assume that the lights are connected to the module M 1, you could turn the lights on/off with the following commands:

/usr/local/bin/flipit -t /dev/ttyS0 flip m1 on
/usr/local/bin/flipit -t /dev/ttyS0 flip m1 off

The next step is to figure out what time the sun will set. This is not a trivial problem since the geography of the location and the structures around it will possibly change the sun set time. I used a lookup table for my location, you would have to find a similar table for your location. The URL to get your lookup table is at the top of the perl script below. The perl script shown at the end of this post takes one argument -d and the number of minutes delay and calculate the sun set plus delay time in military time HH:MM and print the result on stdout.

Turning off the lights at a certain time from the cron job is fairly easy. Here is a sample cron entry to turn the lights off at 11:30pm daily.

30 23 * * * /usr/local/bin/flipit -t /dev/ttyS0 flip p10 off

But, how do we turn the lights on for example 20 minutes after sun set daily. at command allows us to schedule a program to run at a later time. The best part of this program is that even if the operating system is rebooted, it will remember to run our scheduled program at the designated time after reboot.

Here is a cron entry to run at 1:15am daily to schedule our program to run 20 minutes after sun set. Make sure that cron daemon crond is running by typing service crond status. If not running, start it by typing service crond start.

15 01 * * * echo /usr/local/bin/flipit -t /dev/ttyS0 flip p10 on | at `/usr/local/bin/sunset -d 20`

This setup has been working great so far. The lights come on in the dusk and the python script shown at the end of this post accounts for the Daylight Savings Time.


The best time to water the lawn is early in the morning. I have two separate circuits, one in the front which takes a lot of sun, and the one in the back with hardly any sun. We make two entries into cron file, one for each circuit. The python script sprinkler takes two arguments: the first is for the X10 module ID, the second for the number of minutes to water.

# front yard sprinkler, module n3, 25 minutes to water
05 05 * * * /usr/local/bin/sprinkler.py p9 25
# backyard sprinkler, module n4, 30 minutes to water
10 06 * * * /usr/local/bin/sprinkler.py p10 30

But since we have a computer with access to the internet, we can make the process of watering the lawn lot more efficient. Our script requests today’s weather report. If the high temperature of the day is greater than 80F, it will water daily. If less then that, it will water every other day. But only if rain or precipitation is not expected. The weather report is logged into the /tmp/sprinkler.log file. Don’t forget to update your latitude and longitude at the top of the script. You can also tweak the script to fit your needs and parse the weather report with new and unexpected terminology.

import re,string, sys, os, time 
import urllib
from HTMLParser import HTMLParser
#urlq = "http://www.wrh.noaa.gov/total_forecast/text_only.php?wfo=pqr&zone=orz006&county=orc067"
urlq = "http://forecast.weather.gov/MapClick.php?lat=45.52&lon=-122.68&TextType=1"
#print urlq
f = urllib.urlopen(urlq)
lines = f.readlines()
#print lines
for line in lines:
    if (string.find(line, "ay:") > -1):
        start = string.find(line, "ay:") + 11
        line2 = line[start:]
        end = string.find(line2, ".<br>")
        forecast = line2[:end]
    elif (string.find(line, "Tonight") > -1):
        start = string.find(line, "Tonight") + 12
        line2 = line[start:]
        end = string.find(line2, ".<br>")
        forecast = line2[:end]
(YY, MM, DD, j, j, j, j, j, j) = time.localtime()
rain = 0
if (re.match('.*showers.*', forecast, re.IGNORECASE) or
    re.match('.*thunderstorms.*', forecast, re.IGNORECASE) or
    re.match('.*precipitation.*', forecast, re.IGNORECASE) or
    re.match('.*rain.*', forecast, re.IGNORECASE)):
    rain = 1
temp = 0
result = re.match('.*Highs around (\d+).*', forecast, re.IGNORECASE)
if (result):
    temp = int(result.group(1))
result = re.match('.*high near (\d+).*', forecast, re.IGNORECASE)
if (result):
    temp = int(result.group(1))
result = re.match('.*Highs (\d+) to (\d+).*', forecast, re.IGNORECASE)
if (result):
    temp = int(result.group(2))
# even or odd day
even = ((DD % 2) == 0)
# water only May through September
summertime = (MM >= 5) and (MM <= 9)
f = open("/tmp/sprinkler.log", "a")
for line in lines:
f.write("%d/%02d/%02d TEMP:%d  RAIN:%d \n" % (YY, MM, DD, temp, rain))
if (sys.argv[1] == 'n3'):
    # NOT raining AND (even days OR temp>80) AND (month < SEP)
    if (not rain and (even or (temp > 80)) and summertime):
        os.system("/usr/local/bin/flipit -t /dev/ttyS0 flip p11 on")
        time.sleep(60 * int(sys.argv[2]))
        os.system("/usr/local/bin/flipit -t /dev/ttyS0 flip p11 off")
if (sys.argv[1] == 'n4'):
    if (not rain and summertime):
        os.system("/usr/local/bin/flipit -t /dev/ttyS0 flip p12 on")
        time.sleep(60 * int(sys.argv[2]))
        os.system("/usr/local/bin/flipit -t /dev/ttyS0 flip p12 off")

sunset perl script to figure out the sun set plus the delay time in minutes.

# I got the sunrise/sunset table from the government website
# shown below for Portland, Oregon.  Replace the table for your
# own location.
$suntxt = qq(
             o  ,    o  ,                                  PORTLAND, OREGON                            Astronomical Applications Dept.
Location: W122 39, N45 31                          Rise and Set for the Sun for 2006                   U. S. Naval Observatory        
                                                                                                       Washington, DC  20392-5420     
                                                         Pacific Standard Time                                                        
       Jan.       Feb.       Mar.       Apr.       May        June       July       Aug.       Sept.      Oct.       Nov.       Dec.  
Day Rise  Set  Rise  Set  Rise  Set  Rise  Set  Rise  Set  Rise  Set  Rise  Set  Rise  Set  Rise  Set  Rise  Set  Rise  Set  Rise  Set
     h m  h m   h m  h m   h m  h m   h m  h m   h m  h m   h m  h m   h m  h m   h m  h m   h m  h m   h m  h m   h m  h m   h m  h m
01  0751 1638  0732 1717  0649 1758  0551 1839  0459 1918  0425 1952  0426 2003  0455 1939  0532 1848  0609 1751  0650 1658  0730 1629
02  0751 1639  0730 1719  0647 1759  0549 1840  0457 1919  0425 1953  0426 2003  0456 1937  0533 1846  0610 1749  0652 1656  0732 1628
03  0751 1640  0729 1720  0645 1800  0547 1841  0456 1920  0424 1954  0427 2003  0457 1936  0534 1844  0611 1747  0653 1655  0733 1628
------ deleted other lines ------
29  0735 1713  0651 1756  0556 1835  0502 1915  0427 1950  0425 2003  0451 1942  0528 1854  0606 1755  0646 1702  0728 1630  0751 1635
30  0734 1714             0555 1836  0500 1916  0426 1950  0425 2003  0452 1941  0530 1852  0608 1753  0647 1700  0729 1629  0751 1636
31  0733 1716             0553 1838             0426 1951             0453 1940  0531 1850             0649 1659             0751 1637
sub getSunSet() {
    $month = @_[0];
    $day = @_[1];
    $sunsetstr = substr($lines[10 + $day], ($month-1)*11 + 9, 4);
    $hr = substr($sunsetstr, 0, 2);
    $mn = substr($sunsetstr, 2, 2);
    return ($hr, $mn);
$delay = 0;
if (@ARGV != 0) {
    if ($ARGV[0] ne "-d") {
	die "usage: sunset option\n" .
	    "option:   -d minutes (where minutes < 60)\n";
    else {
	$delay = $ARGV[1];
	if ($delay >= 60) {
	    die "delay must be less then 60 minutes.";
@lines = split(/\n/, $suntxt);
($d, $m, $y, $dst) = (localtime)[3, 4, 5, 8];
$y = $y + 1900;
$m = $m + 1;
($hr, $mn) = &getSunSet($m, $d);
if ($dst) {
    $hr = $hr + 1;
$mn = $mn + $delay;
if ($mn > 59) {
    $mn = $mn - 60;
    $hr = $hr + 1;
printf "%02s:%02s\n", $hr, $mn;
Share it!
This entry was posted in Projects and tagged , , , . Bookmark the permalink.

Leave a Reply

Your email address will not be published.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="" highlight="">