My garden features a set of "garden lamps" which I turn-on at night.
Arduino Astronomical Clock for Automatic Light Control
There are many ways to automatically control these lights. The gadget I was using (until I completed this project, that is) was a simple mechanical timer. This product allows you to set separate turn-on and turn-off times and those repeat every day. The disadvantage of this product is that, as the seasons change, you need to constantly adjust the turn-on and turn-off times. As illustrated in Figure 1, the variation over the year (in sunset time in this example) is very significant even at my Northern California latitude, with almost three hours difference between the earlier and latest sunset times!
Figure 1 - Sunset time variation at my location (note: time axis is "DST time" a.k.a "summer time")
Another approach to this problem, and one that you often find in many beginner elecronics projects, is to turn the lights ON/OFF based on some photo-sensitive device; a LDR or a photo-transistor for example. While this approach can be made to work reasonably well, it's not without its issues. It's hard to choose a threshold that won't either turn the lights ON too late or turn them OFF too early. In very cloudy days, you run the risk that the system will turn on unnecessarily. Furthermore, if a leave or some other object obstructs the light sensor, the device won't work properly. It's not a very robust approach.
My objective with this project was to build a system that, given my latitude and longitude coordinates and the current time/day of the year, automatically calculates the sunrise and sunset times, controlling the lights accordingly. There are of course commercial products that do this (see this one from Amazon for example), but it is so much more fun to build one:)
So here are the features/objectives for this project:
- Automatic sunrise and sunset relay control to turn lights (or some other AC load) on/off respectively
- 7-segment display continuously shows time, estimated sunrise and sunset time
- Simple Plus/Minus push buttons to adjust time manually (i.e, without a PC)
- Automatic Daylight Savings Time (DST) adjustments
- Battery backed time (restores correct time following a power-failure).
- USB port access for software debug and upgrade
I've been looking for an excuse to get myself into the "Arduino" world and this project seemed like a good candidate. In-fact, one can learn quite a bit about Arduino programming by implementing a system like this. And so was born the "Arduino Astronomical Clock for Automatic Light Control". Let's jump-in.
Theory of operation
As shown in Figure 1, the sunset (and sunrise) times follow an almost sinusoidal pattern over the year. The actual formula is a little more complicated than that, and for those curious about these things, there is an excellent resource at this website with more details:
The beauty of the Arduino open-source community is that you'll often find someone already implemented code to do something similar to what you are intending to do. This project is no exception (see "Credits" section at the end for more info), and fortunately for me, the good folks at swfltek.com produced the "Timelord" library:
The "Timelord" library does a great job of calculating sunrise and sunset times for a given latitude/longitude and present time. The library also includes a handy automatic DST time conversion method that I used as well in this project.
The code must also take care of determining current time, driving the 7-segment display, and handle the time adjustment buttons. For the time-keeping function, I decided to use an inexpensive DS1307 Real Time clock (RTC) from ebay. The great thing about this item is that it is battery backed, so once time is set for the first time, it remains (relatively) accurate even if there's a power failure. Some drift is expected over time with such a budget oscillator, but the time adjustment buttons should enable us to compensate that should it be needed. So far, it has proven quite accurate. There are also equivalent modules from Adafruit or Sparkfun that you could use.
The 4-digit seven segment display is driven in the common time-multiplexed way . For the manual (button driven) time adjustment, I chose a PLUS/MINUS three-speed button arrangement. This is my favorite (arguably most elegant) clock time adjustment method. My car uses it, and I liked it so much that I decided to replicate it in software. Basically the PLUS button increments the time whereas the MINUS decrements it. If you hold any of these buttons for longer than 4s, then it enters a second speed, and later on a third speed where the increment (decrement) is faster. It's intuitive, simple, and works quite well.
So without further ado, let's look at the implementation.
The Arduino is the "brains" of the project. The Arduino Uno board is considered the 'reference' platform in the Arduino family, and it's the one I used (also because I had one just laying around). I reckon you could also use an Arduino Nano for a smaller footprint. Most of the I/Os were used in this project, so I wouldn't recommend a limited I/O version. See Figure 2 for a block diagram.
Figure 2 - Block Diagram
The Uno's digital I/O #13 (configured as output) controls the LED on-board and also turns ON the external relay that controls AC power. I could have used a "relay shield", but my philosophy is to use first what I already have on the shop, so I built one around an Omron 5V relay and a 2N2222 transistor with 1KOhm base resistor (see Figure 3). A 1N4001 diode protects the transistor from over-voltage when the relay switches state. As an added convenience, the switch S allows the user to force the relay ON (manual override) or put it into normal "AUTO" mode, controlled by the Arduino. I recommend addin a fuse to the AC circuit for protection as shown in the figure. The AC adpater also connects 'downstream' from the fuse so it is also protected.
Figure 3 - Relay Board
Figure 4 - Relay Board Photo
In keeping with my re-use philosophy, I built my 7-segment display from individual segments I already owned (Figure 5). It's a lot of soldering work and you may save yourself some work by buying a pre-assembled module. These were common-anode type displays, so I used 2N3905 PNP transistors for the multiplexing and as a consequence the Arduino outputs are active Low. This can easily be changed in the code in case of common-cathode displays, NPN transistors and active High outputs. Google around for more info if you are not familiar with this driving arrangement. Series 150Ohm resistors (in this case resistor array) limits the I/O current through the ATmega pins. Notice that I don't drive the decimal points in the segments so only 7 segment connections are needed (plus 4 multiplexing enables). See Figure 5 and the circuit in Figure 6.
Figure 5 - Display Board
Figure 6 - Display Board Circuit
The time-adjustment push-buttons are connected to A0 and A1 inputs (configured as digital Inputs) and must include pull-up resistors. Figure 7 shows the simple circuit.
Figure 7 - Time-adjustment push-buttons
The RTC module connects through I2C to the A4 and A5 Arduino I/Os. Finally, the 5V power supply (Figure 8) is provided from a re-purposed cell-phone wall wart. This supply is rated at 5.2V 400 mA. Following some measurements, I figured it's an unregulated design, so with 100 mA load it actually outputs in the range of 7 to 8V. This is perfectly fine since the Arduino DC input includes a 5V regulator. The project consumes less than 100 mA in normal operation.
Figure 8- Power Supply
The following link takes you to a .zip file with the source code:
In addition to the code ("sketch" in Arduino parlance) you will also need to install the following libraries (links provided below):
Wire http://arduino.cc/en/reference/wire (Probably already installed by default)
To adapt this code to your needs, you should edit the TIMEZONE, LATITUDE and LONGITUDE constants to match your particular location. See Figure 9.
Figure 9 - Code Customization
The seven segment digits location and polarity are also defined in constants so you can set those as well. I found it easier to layout the wires to the board at will, and then just assign the mappings in software (changing the 'seg' constants).
Before you can use the RTC, you need to set its' time which can be done manually using the example provided under the DS1307RTC library (File -> Examples -> DS1307RTC -> SetTime). I recommend running that sketch first, editing the time parameters manually, so you have a good starting point. From that point on, the buttons can be used for small adjustments without a PC.
Putting it all together
For reference only, I'm including some photos of my build using a (relatively large) plastic enclosure. many other arrangements are of course possible. Notice that I used an old cell-phone charger supply for the project. This is a safer bet than building your AC/DC supply as all the safety issues should already be properly handled inside these devices. Nonetheless, I added an external fuse and a MOV for over-voltage protection. Please be very careful when handling AC circuits and never play with the circuit while it is plugged.
Figure 10 - Assembled Parts
Figure 11 - Insides
Figure 12 - Outsides
Figure 13 - Final panel in operation
Notice the "programming hole" feature in Figures 11 and 12. One of the great things about the Arduino boards is the ability to debug and upgrade code through a USB port, so this feature allows me to plug my PC in at any time to add features or correct some bug. I believe it's well worth keeping this port easily accessible.
Figure 14 - Programming Hole
Figures 15 show the display cycling through time (TTTT) -> sunset (SSSS) and sunrise (AAAA) indications:
Figure 15 - Cycling Through
There's always room for improvement in any project. I've been considering adding a temperature sensor to the project and display it in the screen every so often. The project could also be used to control Christmas lights and could have an option for turning them ON only a couple of hours after sunset. The default display is in 24hr format but could easily be chaged to 12hr mode. Other ideas/suggestions are welcomed.
The Arduino open-source platform leverages the work of many talented developers that contribute libraries and example code. I've used code from many sources in this project and would like to credit them here (my apologies in advance if I forgot anyone):
- The "Timelord" library http://www.swfltek.com/arduino/timelord.html was crucial for sunrise/sunset calculations
- Jack Christensen's excellent high-tech night light article was a source of many of the ideas in the code: http://adventuresinarduinoland.blogspot.com/2012/02/high-tech-night-light.html
- The fascinating Arduino chicken coup project: http://arduino-coop.blogspot.com/p/source-code.html
- This article on driving seven segment displays http://www.hobbytronics.co.uk/arduino-4digit-7segment
And everyone who contributes to the wonderful Arduino world. It was a fun first-project for me in Arduinoland. I think I'm hooked:)
Comments, questions, suggestions? You can reach me at: contact (at sign) paulorenato (dot) com