Microcontroller projects

last updated: 2022-07-08

Garden watering

Quick links

Activate valves per MQTT over WiFi using an ESP8266

garden watering

In the last summers we had months with no rain. Even my 10m³ rainwater tank did not suffice to provide water.

But the vegetable garden must be regularly supplied with water. To save water, I use drip hoses, and to simplify my life, I have automated the control of the irrigation.


It began with a command of a box with 5 magnetic valves from Hunter. When the box arrived I was startled by the size. Ok this will be hard work to dig the hole and ditches.

The box contained 5 valves Hunter PGV 101 MMB (3/4", 25 mm). The valves need 24 VAC, so we need a transformer. As the valves are never open at the same time a current of 1 A should suffice. As a recycled transformer was defective I had to buy a new one (40 VA, IP44).

After some days I remarked that the transformer heated a lot (high housing temperature), and after some measurements I saw that the efficiency was very bad and it occurred to me that it was not clever to use an oversized transformer. So this time the transformer was replaced with an 10 VA type. This gives us 420 mA. The valves need shortly 350 mA and than 190 mA.

There are cheap relay shields out there with Optocoupler, so I also bought such a board.

An ESP8266 (Lolin/Wemos D1 mini pro V2 connects us with the network over WiFi and MQTT is used to give commands and get data. The ESP8266 board is also powered by the transformer (don't use V<2 because a diode makes it difficult to power the board; look here). This is done with a LM2596 DC/DC buck converter breakout board.

As the whole thing will be contained in a IP65 waterproof enclosure, I wanted to monitor temperature and humidity in the box and added a BMP280 sensor. A piece of PLA from my 3D printer created with FreeCAD (files on git) helped to connect everything together.


garden watering circuit


The software communicates per MQTT over WiFi. It uses my ESPToolbox library for WiFi and logging functions and to get the time. To avoid version problems the lib is included in the sketch folder. Programming is done over OTA.

We get two topics:

    String MQTT_TOPIC_OUT = "weigu/garden/watering/data";
    String MQTT_TOPIC_IN = "weigu/garden/watering/command";

Commands are in JSON and have the following JSON format (I eliminated the square brackets in the new version 1.1 because openHAB had problems with those when transforming):

    {"Event_(nr_relay_start_duration)":"3 3 2021 5"}   

mqtt publish

The following is seen on the data channel:

mqtt subscribe

In the new version (1.1) all relevant data you must or can change are in a config (config.h) file, also contained in the main folder. You can also place this file in the sketchbook/library folder named Secrets and rename it to your needs (e.g. secrets.h).

In the main file (.ino) you can activate or deactivate features by commenting or uncommenting some lines. Here you must activate USE_SECRETS:

    /*?????? Comment or uncomment the following lines suiting your needs ??????*/

    /* The file "secrets.h" (here secrets_garden.h) has to be placed in the sketchbook libraries folder
      in a folder named "Secrets" and must contain the same things than the file config.h*/
    #define USE_SECRETS
    #define OTA               // if Over The Air update needed (security risk!)
    //#define MQTTPASSWORD    // if you want an MQTT connection with password (recommended!!)
    #define STATIC            // if static IP needed (no DHCP)
    #define BME280_I2C       

In the config.h file, you must change the WiFi parameter and the MQTT server address. In the automated watering array we define the start times and duration of watering events.

Other things we perhaps want to change are the publishing interval PUBLISH_TIME or the MQTT topics.

Here is the content of the config.h file:

    /*!!!!!! Things you must change: !!!!!!*/

    /****** WiFi SSID and PASSWORD ******/
    const char *MY_WIFI_SSID = "your_ssid";
    const char *MY_WIFI_PASSWORD = "your_password";

    /****** MQTT settings ******/
    const char *MQTT_SERVER = "";

    /*+++++++ Things you can change: +++++++*/

    /******* Automated watering array *******/
    bool auto_flag = 1;
    struct we {
      const byte relay_nr;
      const unsigned int start_time;
      const unsigned int duration;

    // A triple of data per watering event:
    // relay number, time (hr*100+min), minutes to water
    // never use 2 relays at the same time

    we watering_events[] = {
      {0,1800,10}, // relay number, time (hr*100+min), minutes to water

    /****** Publishes every in milliseconds ******/
    const long PUBLISH_TIME = 10000;

    /******* Relays *******/
    const byte NR_OF_RELAYS = 5;
    const byte PIN_RELAYS[NR_OF_RELAYS] = {16, 14, 12, 13, 0};
    bool relay_start_flags[NR_OF_RELAYS] = {false,false,false,false,false};
    bool relay_stop_flags[NR_OF_RELAYS] = {true,true,true,true,true};
    unsigned long relay_times_ms[NR_OF_RELAYS] = {10000,20000,30000,40000,50000};
    unsigned long relay_prev_millis[NR_OF_RELAYS] = {0,0,0,0,0};

    /****** MQTT settings ******/
    const char *MQTT_CLIENT_ID = "garden_watering"; // this must be unique!!!
    String MQTT_TOPIC_OUT = "weigu/garden/watering/data";
    String MQTT_TOPIC_IN = "weigu/garden/watering/command";
    const short MY_MQTT_PORT = 1883; // or 8883
    // only if you use MQTTPASSWORD (uncomment //#define MQTTPASSWORD in ino file)
    const char *MY_MQTT_USER = "me";
    const char *MY_MQTT_PASS = "meagain";

    /****** WiFi and network settings ******/
    const char *NET_MDNSNAME = "watering";      // optional (access with SmartyReaderLAM.local)
    const char *NET_HOSTNAME = "watering";      // optional
    const word UDP_LOG_PORT = 6666;             // UDP logging settings if enabled in setup()
    const byte UDP_LOG_PC_IP_BYTES[4] = {192, 168, 1, 50};
    const char *NTP_SERVER = "lu.pool.ntp.org"; // NTP settings
    // your time zone (https://remotemonitoringsystems.ca/time-zone-abbreviations.php)
    const char *TZ_INFO    = "CET-1CEST-2,M3.5.0/02:00:00,M10.5.0/03:00:00";

    // only if you use OTA (uncomment //#define OTA in ino file)
    const char *MY_OTA_NAME = "garden_watering"; // optional (access with garden_watering.local)
    const char *MY_OTA_PASS_HASH = "myHash";     // Hash for password

    // only if you use a static address (uncomment //#define STATIC in ino file)
    const byte NET_LOCAL_IP_BYTES[4] = {192, 168, 178, 155};
    const byte NET_GATEWAY_BYTES[4] = {192, 168, 178, 1};
    const byte NET_MASK_BYTES[4] = {255,255,255,0};  

The code is on Github:

Some more pictures

Here the new version:

housing  garden watering new

This is the older version. I changed the faulty transformer and the relay board with a 5 V version (I had mistakenly bought a 24 V version). So one DC/DC converter is no more needed. GPIO15 for relay 5 was exchanged with GPIO0 (because internal pull-down of GPIO15).

housing  pcb backrelay pcb  pla

The pipes:

pipes  pipespipes  pipes