Garden H2O Timer

Triple Zone Water Timer for your Garden

Geoff Cohen

Issue 31, February 2020

This article includes additional downloadable resources.
Please log in to access.

Log in

Keep your garden watered with this fully automatic, Arduino based garden timer with touchscreen control and easy operation (no manual required).


As we continue to get less rain and more hot days every year, I’m reducing my impact on our planet by minimising water usage, without killing our garden. The best way I’ve found is a fully automatic watering system, using drippers or low volume micro sprays for all our plants (grass has to fend for itself).

However, setting up/programming and using these timers is difficult, tedious and usually quite arcane, and just about impossible without the manual (which has usually burrowed under stuff and hidden itself).

My DIYODE H2O Timer project shows this is unnecessary - it doesn’t need a manual, uses readily available parts and is easy to set up and Run. If you can use an iPad or iPhone or an Android, you can use this Timer.


The DIYODE H2O Timer is made up of several readily available and inexpensive modules – an Arduino compatible Mega, a plugin Prototype Shield, WiFI and RTC, plus a plugin 2.8” TFT colour Touchscreen for display and control, with a fully 3D printed case. The only other parts needed are three MOSFETs, a regulator, and a few resistors and capacitors.



The H2O Timer runs from any regulated 12V power adaptor (2A or higher). The 12V is reduced to approximately 7.2V by diodes D1 to D6 to power the Arduino and backlight control. The voltage is reduced to keep the Arduino’s 5V regulator reasonably cool, otherwise, at the 12V input, it gets extremely hot (nearly 50°C), which is definitely not recommended for maximum life.


The three solenoids are powered directly from the 12V input and controlled by MOSFETs Q1 to Q3. Their gate inputs are driven directly from the Arduino digital output pins, via 100Ω resistors R1, R2, R3, with back EMF (spike) protection provided by diodes D7, D8, and D9. These solenoids are designed for 24VAC, but all the ones I have used run reliably on 12VDC, drawing around 1A to 2A each.


As you would expect with a timer, knowing the exact time is crucial and a tiny RTC (Real Time Clock) I2C module provides accurate time. It uses a DS1307 RTC chip and communicates with the Arduino via the I2C protocol.

I found two problems with this inexpensive module. Firstly, the module I purchased from Jaycar included a standard, non-rechargeable 3V CR2032, however, this module is designed for a rechargeable (4V) LIR2032. This mismatch results in the 3V battery being charged to 4.5V, which is definitely not recommended. Fortunately, the high internal resistance of the CR2032 prevents any overheating. The solution is simple; replace the CR2032 with the correct rechargeable LIR2032 or unsolder R5, D1, R4, and R6 then replace R6 with a jumper wire. The second option is only recommended if you can desolder SMD components.

Note: If you remove these components you also need to change variable LIR2032 rechargeable in DIYODE-H2O-Timer.ino from true to false to get an accurate voltage reading, due to the R4/R6 voltage divider being removed – it is near line 50.

Secondly, the DS1307/xtal combination used in this RTC module drifts a few seconds per day, which will lead to significant errors over a long period of time, plus I find setting the RTC time a total waste of my time and also totally unnecessary, as we now have the InterWeb available. Adding an ESP2866 powered ESP-01 WiFi module corrects both of these problems. With Internet access available, all that’s needed to get the exact time is access to a NTP (Network Time Protocol) server, which retrieves the exact time from an Atomic Clock – the exact accuracy depends on the latency (delay) of your Internet connection, but will normally be within a second - and unlike our $6 RTC module, it doesn’t suffer from long term drift. The RTC is updated from the NTP server once per day, so the RTC (and Arduino) time and date should always be accurate to within a few seconds.


To reduce power, run cooler and maximise the touchscreen’s life, I like a dimmable backlight on TFT screens, as backlight LEDs can get quite hot, lowering their lifespan and wasting power.

Unfortunately, the Jaycar 240x320 LCD touchscreen used doesn’t have backlight dimming available, however, after thinking about it for several days, I worked out how to control the backlight on the Jaycar screen. It’s possible because the backlight LEDs are powered directly from the 5V rail (via inaccessible series resistors hidden under the LCD), so lowering this voltage will also lower the LED current and backlight brightness. Fortuitously, the touchscreen digital electronics keeps working, as the internal touchscreen 3V regulator works down to (approximately) 3.5V.

The simplest way to implement this was to cut the 5V line on the protoshield that goes to the screen connector, and make the screen power switchable between bright (5V) and dim (3.5V). This only needed a handful of extra components - an adjustable voltage regulator, three resistors, two capacitors and one diode. U1, a LM317 adjustable regulator, is used to control the voltage using Arduino digital output pin D44. When D44 is LOW, resistor R6 (via isolation diode D10) lowers the screen 5V rail to approximately 3.5V, when D44 is HIGH resistors R4 & R5 provide 5V for full brightness.

For this touchscreen, the full brightness current of 300mA is reduced to 180mA in low brightness (or Dim) mode. This happens automatically when the screen is not touched for 90 seconds – current measured with all solenoids off, of course.

The Build:

Parts Required:Jaycar
1 x Arduino Mega or Compatible BoardXC4420
1 x Prototyping Shield to suit Arduino Mega BoardXC4416
1 x Pack of Stackable HeadersHM3208
1 x 40 Pin Female Header Strip (cut off 4 & 7 pin strips from each)HM3230
1 x 40 Pin male Header Strip (cut off 4 & 7 pin strips from each)HM3212
1 x WiFi Module (ESP-01)-
1 x RTC (DS1307)XC4450
1 x Screw Terminal Strip +HM3196
3 x N-channel MOSFETs (STP16NF06, FQP30N06L or equivalent)ZT2277
1 x Spool of Thin Jumper Wire - Red^WW4344
1 x Spool of Thin Jumper Wire - Blue^WW4346
1 x Spool of Thin Jumper Wire - Black^WW4345
2 x 12mm Screws (Either M3 or self tapping)*HP0140
3 x 10mm Screws (Either M3 or self tapping)*HP0403
3 x 3mm Insulating Washers (See text for a 3D printed option)HP0148
1 x 12V DC Power Socket #PS0526
3 x 100Ω 1/4W Resistors *RR0548
1 x 220Ω 1/4W Resistor *RR0556
2 x 680Ω 1/4W Resistors *RR0568
1 x 1KΩ 1/4W Resistor *RR0572
1 x 2KΩ 1/4W Resistor *RR0579
1 x 1MΩ 1/4W Resistor *RR0644
1 × 1N419 or 1N4148 DiodeZR1100
9 × 1N4004 Diodes *ZR1004
1 × 1000μF 25V Electrolytic CapacitorRE6220
3 x 1µF 25V/35V Tantalum CapacitorsRZ6627
1 × LM317T Voltage RegulatorZV1615

* Quantity required, may only be sold in packs. General purpose hook-up wire is also required for the solenoids and power socket wiring.

# This is the standard size Arduino socket – but may be different for your Power Supply connection

+ Screw terminal strips also available from hardware and electrical wholesale stores

^ We recommend using multiple colours to help troubleshooting, but one colour is also fine. For the 12V input and Solenoid leads any wire with the correct current rating will do - I personally use Silicone insulated superflex type wire (100 to 150 strands of .08mm wire), but it's by no means an essential requirement - just much nicer to use.

Note: for the RTC, it should be possible to use the Core-Electronics ADA3296 RTC as it also uses I2C and the DS1037 IC, with some rearranging of the proto board, but the battery voltage monitor display would need to be disabled as there is no BAT out terminal.

Top view for wiring and solder tracks.
Bottom view for wiring and solder tracks
Top view with component placement


Unzip the file that is available to download from our website. Copy to your usual Arduino folder (all files should be placed in a sub Folder named DIYODE-H2O-Timer). If not already installed, you will need to install these libraries:



RTClib (DS1307):


Wire and EEPROM are standard libraries and should be included with the Arduino IDE

Now you can finally test your Arduino Mega. Start by uploading the DIYODE-H2O-Timer software to your Arduino.

The best starting options are with DEBUG true, displayWiFi and displayRTC both false (all these variables are near line 40 in DIYODE-H2O-Timer.ino ). This allows testing the Mega, prototyping shield and touchscreen before any extra parts are added (or if the WiFi/RTC modules are not plugged in at any stage). You should get a reply from the Serial Monitor (set to 250000 baud) that includes the phrase “No Touchscreen”.

After turning off the power (usually, just unplug the USB lead), carefully insert the prototype shield into the Arduino Mega. It is really important to make sure there are no bent pins and that all pins are inserted correctly.

I found it easiest to line up the 2x18 way digital Mega socket first, then one side’s pins and insert at a slight angle. By the way, with this number and size of pins, it can be difficult to insert, so I always (lightly) spray all pins and sockets with CRC 808. It’s also the best way of lowering contact resistance I have ever found, plus it’s a reasonable lubricant.

Now plug the four stackable header extenders into the touchscreen and insert the header/Screen assembly into the prototyping shield. Again, make sure no pins are bent.

Turn the Mega ON and, after a few seconds, you will see the touchscreen calibration screen. Once this is all working, unplug the prototyping shield and start soldering.


The photos, schematic and wiring diagrams make assembly relatively easy.

See our website to view the wiring diagram close-up.

A close-up view of the wiring diagrams can be seen on our website, and we will also include the working OpenSCAD files on our website if you need them.

The wiring diagrams have a Ruler for accurate positioning of parts, with 1/10 inch markings to match the prototyping shield - as well as most non-SMD through-hole electronic components.

When soldering in the components, if the leads are long enough, I usually bend them over to make the solder tracks.

However, this can make removal more difficult if you make a mistake, so it’s best not to make any errors. The safer alternative is to solder in each component after cutting their leads flush, then use some scrap tinned copper wire to make the solder tracks. (Either method is a cheap way to emulate a PCB for one-off projects that don’t justify the time and expense of a full blown PCB design).

When all of the components for each section are soldered in place, solder the thin (wire-wrap) jumper wires in place, I always use several colours, as this makes correct assembly easier and bug detection simpler.


There are two wiring diagrams on page 56 that give a detailed view of the solder tracks and jumper leads. These diagrams don't show the components to make the wiring diagram clearer to follow.

Note that the orange solder tracks are only added on the bottom of the prototyping shield. They are only displayed on the top views to make positioning parts easier.

WiFi & RTC

Insert the 2 x 4way WiFi socket into the Prototyping board & solder in place.

Break 4 & 7 way strips off the 40 pin male header terminal strip and push into the tiny RTC PCB. Note that only 4 of the 5 pin side are used (ignore DS) – the 5 pin end is only used for mechanical support of the RTC PCB, and the prototyping shield didn’t have quite enough room for all 5 pins.

Cut off 4 & 7 way strips from the 40 pin female header strip (I found it easiest to use side cutters at the next pin and file/Dremel away the unused plastic).

Push the 4 & 7 way pins into the RTC.

Push the 4 & 7 way sockets into these pins.

Insert the complete RTC/Socket/Pin assembly into the prototyping board and solder both pins and sockets. Doing it this way should avoid any pins or sockets being soldered at an angle.

You can either add all components now, or, as I did, only complete in one section at a time, and test that section is working before proceeding to the next section.

I installed the WiFi components next, soldering in R7, R8, R10, and R11 plus the WiFi Data and Power wiring. When this is completed, you can finally plug in the ESP WiFi module.

To test, change displayWiFi to true and add your network WiFi name and password (near line 86 - “WiFiname” and “WiFipass”). Plug the Arduino/prototyping board and screen together and upload DIYODE-H2O-Timer.ino. The serial port will show the WiFi connection progress and when connected, the display will show you the WiFi strength as 1-5 bars.

Solder in the RTC parts, R8, C4, and C5, and associated RTC wiring. Change displayRTC to true and upload again. The correct time and battery voltage is displayed onscreen and the Serial Monitor will show WiFi and RTC connection details, similar to:

WiFi connect #1
[WiFiEsp] Initializing ESP module
[WiFiEsp] Initilization successful - 2.0.0
WiFi - Connecting to Kitchen
[WiFiEsp] Connected to Kitchen
RTC.begin() OK
48 byte NTP packet received
time sync to NTP atomic clock Successful
DST time 1 hour added
NTP time=2020:1:7--19:52:11
RTC time=2020:1:7--19:52:11
NTP-RTC time Diff (secs)=0
Screen Size=320x240
rechargable Battery Voltage=4.5

Power Supply

Up to this stage, everything is powered from the Arduino USB socket. Now add diodes D1 to D6 (to reduce VIN down to (approximately 7.2V) and add a jumper wire between V6/U1 and VIN. Also add the two 12V power input leads, with a socket that matches your 12V power supply, of course. I always check the schematic and wiring diagram before soldering to try and avoid (or at least minimise) errors.


Add MOSFET’s Q1, Q2, Q3, resistors R1, R2, R3 capacitor C1 and diodes D7, D8, D9. I recommend soldering the (heavier) solenoid screw connector strip leads to each diode as they are mechanically strong, and won’t lift off unlike PCB thru holes, as you can see in the picture.

Backlight Control

The backlight control is optional - if you decide use it, fit U1, C2, C3, R4, R5, R6 and D10 and CUT the 5V PCB track on the Prototyping Shield (shown here), then make the solder tracks and then add the jumper wires. Otherwise just skip this section.

Note, once you cut the 5V PCB track, the display will be blank unless the timer is powered from 12V.


While the circuitry may be simple, there are nearly 4000 lines of Arduino source code. I have tried to make the Arduino code easy to understand, with meaningful variable and function names, plus lots and lots of comments.

The touchscreen calibration values are stored in non-volatile EEPROM memory space, so they aren’t lost when your H2O Timer is turned off.

Arduino Warnings

Be careful when modifying Arduino code. It’s normal to define variables before they are used, but I’ve found having to define Functions before they are used can break a lot of code that worked perfectly with earlier versions of the Arduino IDE. This timer code did exactly that - it just stopped working when I upgraded the IDE. It took many hours to fix, which is why maths.ino is now called maths.h, and explicitly called in line 455 of DIYODE-H2O-Timer.ino (with the #include “maths.h” statement). The problem is the Arduino IDE loads all .ino files in a folder/directory (probably alphabetically), which never appeared to be a problem with earlier versions. With this new method of having to define Functions before use breaks the code in my experience.


The algorithm isItDST() [in time.ino] calculates whether it is DST (Daylight Saving Time). The start and end of DST are selected by variables DSTstartMonth and DSTendMonth, and the time difference (in seconds) between standard to DST time is stored DSTvalue. All are defined in DIYODE-H2O-Timer.ino (around line 110). If you want to ignore DST, just make the variable “DSTvalue” equal to zero.

The rest of the code is, like nearly all Arduino code. A simple loop, checking many times per second for a touchscreen press, and then running the appropriate code to switch screens between Main, Set Time/Day and Calibration. Also, every minute, the code checks to see if a solenoid needs to be turned on or off.

Once per day, the time is updated from a NTP server. The servers I used “” is for Australia. You can check at to find the best server for your location (this info is also available in DIYODE-H2O-Timer.ino near line 70). The source code file names make it obvious where everything is. For example, all time functions are in time.ino, WiFi functions are in WiFi.ino, etc.


While building/testing, I recommend initially leaving the Etch-a-Sketch set to true. This displays a blue dot underneath your finger/stylus and, if you use the supplied stylus, this is a really good check for calibration; the blue dot will be exactly underneath the stylus, if your calibration is done correctly (and the screen is perfectly linear). If not, it should still be a reasonably close match.

//#define DEBUG                 
//uncomment for NO Serial.print 
bool displayWiFi      = true  ; 
//NO WiFi & quick Startup mode
bool displayRTC       = true  ; 
//NO RTC mode 
bool etchAsketch      = trueX  ; 
//calibration test- work like an Etch-a-Sketch     
bool testBacklight    = trueX  ; 
//backlight test-flashes BRIGHT 
//then DIM forever
//Touchscreen is inoperative for this test


Calibration is quick and easy, and takes only a few seconds. I recommend using the stylus that comes with your touchscreen display, as this gives the most accurate calibration.

After programming the Arduino, your timer starts with the calibration screen. Calibration is easy - just press each green crosshair until it turns red, then move to the next green crosshair and press it until it also turns red. Repeat until all eight crosshairs have changed from grey to green and then red.

Note: If you somehow managed to mess up your calibration, and your touchscreen doesn’t respond correctly, you can force a new calibration on the next bootup. Just change the variable EEPROMreferenceNo from its default 24242 to, say, 24243. Its sole purpose is to verify the screen has been calibrated (it’s near line 60 in DIYODE-H2O-Timer.ino).


The case is quite easy to print and assemble. For the top part, I have used both PETG and PLA. I’ve tried ABS, but it tends to crack (common for such a large ABS part). For the base and the six clips, ABS/PLA or PETG are all fine, although PLA may not stand up to the heat. It will depend on where you mount the H2O Timer case.

The 12V power input leads should just fit into the baseplate strain relief through the slot, as will all FDM (Fused Deposition Modeling) 3D prints. Drill/file/Dremel to fit, if it doesn’t.

The baseplate has six slots for the clips. These should be a reasonably tight fit and can usually be tapped into place with a small hammer. A dab of glue will prevent any future movement. If they don’t go in perfectly straight, just heat them and adjust until the case top part is held securely in place and doesn’t come off easily.

I originally printed the baseplate and clips as one part, but the clips were very prone to breaking. Printing separately with the strongest orientation (on a FDM printer) makes it (nearly) impossible to break them when inserted in the baseplate slots. The top part has recesses that mate with these clips, and it won’t fall off accidentally, but can be easily removed using a spudger/spatula or thin screwdriver.

The holes in the 3D printed base are made for a 3mm screw to easily self-tap into. You can use a 3mm tap if they are very hard to screw in. Also, if you ever strip a thread, just add a bit of glue or use a 3D pen to partially fill the hole and convert it from too large to just right.


After it’s all been built and the Arduino code uploaded, it’s finally time to actually use your DIYODE H2O Timer.

Note that all timing updates, Manual or Auto, only occur when the clock clicks over to a new minute.

Programming your timer is really simple with only two screens that are regularly used (plus the Calibration screen). The main screen displays the time, WiFi status and battery voltage, as well as the on/off and run times for each zone.


Manual - pressing the RED/GREEN ON/OFF Touchscreen Area manually toggles a Solenoid On or OFF, If the timer is running in Auto mode, pressing the button once will turn it off. If you press it again that Zone turns On and Auto mode restarts.


Press anywhere on a Zone window (except the Manual area) and the set times window pops up, to change the On/Off/Run times, just swipe your finger up or down. To change the On days, just tap a day to toggle between On/Off.

If needed, you can also recalibrate from this screen, but I’ve never needed to.



If DEBUG is made true, Serial.print debug lines are sent to the Serial port (250,000 baud) for testing. I have commented out many I used in developing this software after testing each part of the code, apart from the automatic pin configuration changes made at startup.


DEBUG: For adding Serial.print debugging options. Undefining #DEBUG means you don’t have to comment out every last Serial.print for the final version

displayWiFi: For testing without WiFi module, or for a very quick startup without the 10 second WiFi connection time

displayWiFi: For testing without the RTC module

etchAsketch: Displays the cursor where the touchscreen is pressed to test Calibration (makes the Screen work like an Etch-a-Sketch)

testBacklight - backlight test - flashes bright then dim continuously every few seconds (the touchscreen is inoperative for this test)


USE WITH CAUTION! When using Arduino touchscreens, I don’t recommend using the analogReference() command to change the reference voltage from 5V, as these touchscreens rely on analogReference being set to default (or 5V). If you use any of the lower voltage options (internal 1.1V or 2.56V) it totally kills the touchscreen calibration, with touch only working on half the screen (for 2.56V). I wasted many hours tracking down this bug.

As always, it was glaringly obvious in hindsight, as the resistive touch must use the Arduino A/D to work So, changing the reference voltage to half its value will obviously do really odd things to the touchscreen behaviour.

You could, of course, switch between 2.56V and 5V references, but then you need to add settling delays, but I think it’s best to avoid the extra complexity unless it’s absolutely necessary for maximum resolution in your application.


By default, UART0 will output some printed information when the device is powered on and is booting up. The baud rate of the printed information is closely related to the frequency of the external crystal oscillator. If the frequency of the crystal oscillator is 40MHz, then the baud rate for printing is 115200; if the frequency of the crystal oscillator is 26MHz, then the baud rate for printing is 74880.


I don’t use true & false, I use true & trueX. It’s much faster to change from true to false, just add/remove an X to change - to implement just add #define trueX false at the top of your source code.

Use a red coloured marker to mark the + side of polarised capacitors. The tiny polarity mark is often just about impossible to see when it’s soldered in place, especially for tag tantalum caps.

Arduino Editor

I find the Arduino IDE editor too basic, so I recommend a multipane, (programmers) external text editor. A 3K/4K hi-res monitor helps a lot too.

Sometimes the stackable headers of prototyping shield sockets don’t make a good connection. This is easy to fix. If soldered in, gently lift the plastic off the pins. if not, pull the pin out the bottom of the plastic. Then gently press the connectors to tighten them and reinsert.

If you don’t have a multi-function tester, your DMM should have a diode test, which will usually light up an LED enough for polarity testing.

If you overtighten a screw and strip the thread in a 3D print, a dab of glue inside the stripped hole will fix the problem.


If you are a programmer, you can modify the Arduino source code to make the H2O Timer work exactly the way you like (a common hazard of being a programmer).