Introduction: ESP8266 Irrigation Controller / Echo Alexa Integration

I currently use an Orbit controller to control my three zone home irrigation system. This is a capable unit that has a very detailed system that includes scheduling watering events to a calendar, time and duration per zone. This system has worked without error for years.

This system is also capable of doing 'manual' over rides such as stopping the scheduled event or manually starting process. Life events, such as the dog needing to go out for business or an extended dry period, requiring more water than usual. It seems a plethora of unexpected events can cause my wife to grab the flashlight and disappear into the night to manually turn on the sprinkler system.

I, of course, am capable of doing this for her. However, Its 2015 we should be able to do this from our smart phones or IPADs!

In a nutshell, I want to be able to turn the zones on/off individually over WIFI.

This will not over-ride the programmed Orbit controller. My system will not interface with the Orbit, in other words this should only be used when the Orbit is idle. If the Orbit turns the zone on, this system will not be able to turn it off. It will over-ride the Orbit to turn the zones on.

Step 1:

Step 2: The Current System and Plan.

As I mentioned earlier, I use an Orbit controller to control the existing system. This unit can control four zones. I only use three at this time. The system runs on 24vac from a brick transformer. This brick without a substantial load is delivering around ~28vac.

A jump wire from the 'hot' side to any of the control wires will activate the valve controlling the zone. Only one zone should be activated at a time.

My plan is to use a ESP8266-12 to control three relays. Each of the three zones will have a relay that will complete a circuit from the hot side of the 24vac power supply to the control wire of the valve.

Each of these three relays will be controlled directly from a GPIO pin on the ESP8266. Each zone will turn on then off serially for the time duration specified by the user.

The LAN in my home is wired and WIFI. I have a PC configured as a server running Apache 2.0 with PHP 5.x installed. This server will host the user interface.

The ESP8266 will be flashed with NodeMCU.

Step 3: Power Considerations and Management.

Although the system runs on 24vac the ESP8266 only uses 3.3vdc. The only power to the system is the 24vac, another wall wart is not an option.

I opted to use a Buck converter to convert to DC and step the voltage down to 5v. I purchased this on ebay "AC/DC to DC Buck Converter Step Down Module 1.5V-27V Output Power Supply".

5vdc will be used to connect to JD-VCC on the relays.

A LM117t3.3 (great, fast service from Tayda Electronics), provides 3.3vdc to the ESP8266.

Good to go.

Step 4: Putting Things Together.

Noted here, the Buck converter and LM117 deliver plenty of amperage to the controller, so 1Kohm resisters between GND and GPIO15 and Vcc and CH_PD were required to let the controller boot.

I connected one of the tactile buttons to the REST/GND and the other to GPIO0/GND to boot for firmware upgrade. TX/RX/GND are connected for the FTDI.

You may be wondering why the LM117t when the Buck Converter is capable of being to set to deliver 3.3vdc? The short answer is, I had a four channel mechanical relay sitting around not being used and I planed on putting it into service for this project. The triggers can be set via 3.3v from the controller, however the opto-isolators needed 5v to trigger. I wanted to use the opto-isolators since this project is controlling solenoids.

However, during testing I discovered that only one of the channels on the relay board actually worked, two were completely dead and the fourth was 'sticky'. No bueno. So, I ordered a 4 channel SSR. Works fine with just 3.3v and opto-isolators are not needed.

Rather than re-solder and remove the LM117t, I just left it.

I tested new relay before installing this time.

The connections to the ESP8266 are:

Fritzing diagram

Vcc <> 3.3v/LM117
GND <> GND/LM117
CH_PD <> 1K <> Vcc
GPIO15 <> 1K <> GND
GPIO4 <> IN1 on relay
GPIO14 <> IN2 on relay
GPIO12 <> IN3 on relay
GPIO0 <> NO switch <> GND
REST <> NO switch <> GND


IN1, IN2 and IN3 will get the control wires from the associated GPIOs. 3.3v and Gnd connected to the LM117.

Each relay will get a feed from the hot side of the 24vac. Although the is ac only one side will activate the valves the neutral is the ground. Separate wires will connect from the other terminal and spliced to the wire connected to the valves.

Step 5: Prepare the ESP8266-12

Any ESP8266 flavor with 3 GPIOs will work for this project. I just happen to have some -12s.

NodeMCU is my firmware of choice at this point. I think the file system it creates is capable. LUA is friendly and familiar to a longtime PHP programmer.

Flashing the ESP has been a frustrating learning experience. All ESP8266s are not created equal and its difficult to tell what is inside.

I now use ESP Flash Download Tool v1.2. This tool will detect which ESP is connected and most importantly, tell you how much memory your controller has.

I am using this version of NodeMCU:

Don't forget to Format!

I also use LuaLoader and ESPlorer. I find ESPlorer very handy!

Step 6: Programming the System

The index.php page on the server collects information from the user and sends it to a formhandler (sendcmd.php). This file formats the data, creates a connection to the ESP and sends the commands to the ESP. Zone and time duration are sent.

This information is sent to the ESP via GET. The ESP8266 parses this header for details and turns the GPIOs on or off based on this information.

Commands can be sent to the ESP via, TCP, UDP or MQTT. They all work well. I find the TCP server very reliable and preferable to the others.

An example header: 60 min each zone:
GET /?zone0=60&zone1=60&zone2=60 HTTP/1.1

Sending this stops all zones:
GET /?stop HTTP/1.1

For this project I will have four files resident on the ESP8266 to interact with server and control the GPIO pins.

  • init.lua
  • control.lua
  • servernode.lua
  • stop.lua

The servernode.lua file will collect this header and call the control.lua file if it finds zone and duration in excess of 0. It will call stop.lua if stop is found or ignore the header if zone or stop is not found.

The control.lua file will parse the header and turn each GPIO pin on the off in order and for the duration specified.

Files on the server are:

  • index.php
  • sendcmd.php
  • lastcmd.txt

The lastcmd.txt file contains the total time sent to the ESP. This is used to seed the countdown timer in the javascript in the index.php. The timer in the ESP and the countdown script are not synchronized, however, they are within a minute or two. Accurate enough for this app.

The above files are here: github - breagan/ESP8266-WaterController

It is important to note whether you relays are normally open (NO) or normally closed (NC). Some relays let you choose, some are active high or active low, whichever, it is important that the relays are open when controller boots and when the controller is not powered!

As an example, GPIO16 is pulled high when the controller boots. I can set it to LOW in the init.lua, however in a panic loop, the time between the boot sequence and setting it to LOW in the init.lua, over and over again will send enough voltage to trigger the solenoid and activate the zone.

I want to purposely close the 24vac circuit to activate the valves. I do not want any valves activated if the controller looses its power or goes into a death loop. The default value in every conceivable configuration, except when a command is sent is no power to the valves.

My relays are Normally open and triggered (closed) when voltage is applied from the GPIOs. The GPIOs used are all pulled low when power is applied and during the boot process. Setting them to LOW in the init.lua file is not necessary but I prefer the redundancy.

Step 7: Install and Finish.

Be sure to compile 'servernode.lua' and 'control.lua' when debugging is complete. Edit the Init.lua to dofile("") and in the servernode.lua file edit to dofile("").

I was able to find a marine junction box a Lowes. This is a solid pvc box and the cover has a nice rubber gasket. The board and relay fit nicely. I drilled a small hole in the bottom for wiring. The wires from the relay are routed through the orbit and connected to the valve wires just below the controller.

Caution: 24~28vac is enough to start a fire, fry your components and cause all sorts of mayhem.
Electricity is very unforgiving.
Please be careful and don't be afraid to ask experts.

Although this project is specific to my irrigation system, the basics of the work flow, programming and ESP deployment are generic to many IoT projects.

And, yes! It works great!

I hope you find this useful, interesting and a possible seed for your projects!

Step 8: Update: Add Voice Control to the System.

Since I had already built a web based interface, it was not to difficult to integrate voice control using my new Amazon Alexa Dot.

I'm utilizing the Dot's hard-codded ability to recognize "Belkin" wifi switches. This is accomplished by installing and running a python script on a machine connected to your local lan. The Dot uses upnp to find the details.

Great information and source code can be found at "Maker Musings". The python code can be found on their Github at:

The only editing required in is in the section called FAUXMOS:

I added information about my three zones, treating each zone as if it were a unique switch.

['backyard water', rest_api_handler('', '')],

['frontyard water', rest_api_handler('', '')],
['plants water', rest_api_handler('', '')],

Run the py code and ask Alexa to "Scan for devices".

These are binary switches, when you say "Alexa turn backyard water On" Alexa should access the first URL, when you say "Alexa turn backyard water Off" Alexa should access the second URL in the [backyard water] switch.
If Alexa is successful, she will respond with "ok". If not she may state that she can't find a device or she may say nothing at all. Formatting is very important. Lots of trial and error.

Once Alexa is responding correctly, a script is needed to interpret the GET requests sent from Alexa.

I put the following code in the alexa/ folder and named it index.php:


$cmd = $_GET['cmd']; // on or off
$tgt = $_GET['a']; // currently not used.
$IP = ""; // IP to the water controller ESP8266
$zone0="00"; // set all zone vars to 00

if ( $cmd=="on")


// send command to ESP this hard codes the time to 30 minuets.

switch ($tgt) {

case "backyard":



case "frontyard":



case "plant":







$request = "zone0=$zone0&zone1=$zone1&zone2=$zone2"; // creats the attributes for the get request sent to ESP zone0 is zone0 and $zone0 is the time for zone0

if ($cmd=="off")


$request = "stop";


$fp = fsockopen($IP, 80, $errno, $errstr, 5); // opens connection

if (!$fp)


echo "$t not found or offline! - $errstr ($errno) \n";




$out = "GET /?$request HTTP/1.1\r\n";

fwrite($fp, $out); // sends request to ESP8266