I very much enjoy gardening and have produced a fair amount of fruit and vegetables over the past few years. When I am away it sometimes does not get enough water. A timer is good, but it doesn’t deliver accurate amounts of water when it’s needed.

I would like to build an automatic watering system that measures the moisture level in a garden bed and waters through a simple drip irrigation system, using a solenoid valve or pump from a tank. The microcontroller I plan to use has a few available pins I will also grab air and soil temp, air humidity and light reading and graph them so I can get a bit of feedback.

1. Design Document

The first step is sourcing components. I generally work from an Arduino or similar microcontroller, so my voltages are always 3.3 V, 5 V and 12 V, from there I source the appropriate microcontrollers. I also look at the available C+ libraries for the device, this will help to simplify code down the track. Having 12V as the highest voltage makes a 4S appropriate battery voltage with step-down converters. Generally ESP8266 or ESP32 are the goto microcontroller options.

Tasks to Solve

  • Soil moisture level detection switches a solenoid valve or runs a pump when moisture is low.
  • Air and soil temperature and humidity readings.
  • Battery operated and solar charging.
  • Wireless device that sends information to a website.
  • Waterproof electronic case.
  • Even and consistent watering system for each garden bed.

Identify Constraints

  • Soil moisture readings will take from one section of the garden at a specific height so the bed size is limited to even water distribution. Multiple moisture readings are needed for large plots or uneven groundwater distribution.

Identify Hardware

  • ESP8266 Wifi Micro Controller
  • DHT11 Temperature and Humidity Sensor
  • TZT LDR Sensor
  • DS18B20 Soil Temp Sensor
  • Capacitive Soil Moisture Sensor v2.0
  • Relay for switching 12V
  • 2 x LM2596 Voltage Step Down
  • 12V Solenoid or Pump
  • Wire and Fuses
  • 3D Printed Case
  • 4S 3.7 18650 Batteries (14.8V)
  • 4S Li-ion 18650 Lithium Battery BMS
  • CN3722 Variable MPPT Solar Controller (up to 24V)
  • 18V 20W Solar Panel
  • Water Tank (bucket), Hose and fittings with drip irrigation system (holes in a pipe).

Identify Software

  • C+ using bootloader for ESP8266
  • Web Stack (Apache, PHP, MySQL)
  • WordPress Site (HTML, CSS, GUI)

Decision Flowchart

This is relatively simple and will not require a flowchart, just a description.

30 Second Reads

The ESP8266 takes readings from the moisture sensor every 30 seconds which will print to the serial monitor when connected. A relay will switch the pump on and off using the moisture sensor readings.

I have set a moisture value of 35 – 65% which can be changed to suit different situations. If the moisture level is < 35% Then switch on the relay. If moisture level > 65% then switch off the relay.

This means the pump minimum on time is 30 seconds.

Hourly Reads for Database

The total number of 30-second blocks when the relay (pump) is on is divided by two to get the total minutes of pump operation in an hour. This will take moisture readings and water pump ‘on-time’ readings. The light reading follows the same approach as the relay, it adds up all the 30-second blocks when shade was sensed and gives the database an hourly total of minutes of shade in the hour.

All other readings (temps and humidity) are taken on the hour and sent to the database. I found them to be accurate and I can prolong the battery life with only the required readings.

2. Build

Breadboard build with most components connected.

The following is a description of each component of the physical build. It explains the characteristics and specifications of each component and explains any component-specific processes.

ESP8266 Wifi Micro Controller

The ESP8266 DM-101 ES-07 is on a PCB which gives it the following built-in manufacturer-listed functionality;

  • Working Current – 240 mAh (max)
  • Working Voltage – 4.5 – 5.5 VDC (3.3 V Regulator onboard)
  • Interface Logic Voltage – 3.3 V / 5 V Compatible
  • Chips ESP8266 is ES-07
  • The SOC has an Integrated TCP/IP protocol stack.
  • It is TTL serial communication interface and its parameters can be set by AT command.
  • TCP/IP protocol. stack – Serial Baud Rate 115200(can be modified)
  • Serial communication format: 8N1 – 802.11 b/g/n 2.4 gHz – Support WPA/WPA2 Security
  • Wireless Network Mode: station / softAP / SoftAP + station
  • Parameters via AT command
  • Onboard Switch for UART or firmware update mode.
  • Onboard Reset Button
  • 250 Max Re-Soldering Temp

Pinout

The pin-out of the ESP 8266 is as follows:

Bypass Arduino Bootloader to connect and Flash ESP8266

I found I could flash using an Arduino mega in bootloader mode. This method bypasses the Arduino chip to communicate directly with the device. Which makes the Arduino a UART Converter to USB, which I don’t have.

This schematic explains how it is wired:

Arduino as a Bootloader (UART) for ESP8266.
Arduino as UART. Bypass Arduino Bootloader.

DHT11 Temperature and Humidity Sensor

Working Voltage: 3.3 – 5.5V
Recommended Voltage: 5V

Relative humidity Resolution: 16Bit
Repeatability: ±1% RH
Accuracy: At 25°C ±5% RH
Interchangeability: fully interchangeable
Response time: 1 / e (63%) of 25°C 6s 1m / s air 6s
Hysteresis: <± 0.3% RH
Long-term stability: <± 0.5% RH / yr in
Temperature Resolution: 16Bit
Repeatability: ±0.2°C Range: At 25°C ±2°C
Response time: 1 / e (63%) 10S
Electrical Characteristics
Power supply: DC 3.5~5.5V
Supply Current: measurement 0.3mA standby 60μ A
Supply Measuring 2.5mA
Average 1mA
Standby 150uA
Sampling period Second 1

Sampling period: more than 2 seconds

Pin Description
1, the VDD power supply 3.5~5.5V DC
2 DATA serial data, a single bus
3, NC, empty pin
4, GND ground, the negative power

TZT LDR Sensor

This works better connected to an analogue pin with a ranging value, connected to a digital pin it only offers a 0 or 1 value for dark or light. A potentiometer allows the sensitivity of this value to be adjusted.

The ESP8266 only has one analogue pin. I attempted to use two components on one pin. and a diode to switch but the components offered invalid readings with voltage seep. I could use a different microprocessor like an ESP32 with 8 analogue pins. but there is no need. I only wish to know when plants are in the sun or the shade, this device will suit the task.

DS18B20 Soil Temp Sensor

Information is sent to/from the DS18B20 over a 1-Wire interface, only one wire and ground need to be connected from a central microprocessor. Power for reading, writing, and performing temperature conversions can be derived from the data line itself with no need for an external power source (an internal capacitor is used to store power for reads).

The Voltage pin is not required for this device as long as timing and voltage requirements are met by the ESP8266 and Capacitor. There is no harm in keeping the voltage pin connected as it will provide power if needed and accurate measurements require power.

Capacitive Soil Moisture Sensor v2.0

Capacitive Soil Moisture Sensor Corrosion Resistant for Arduino Moisture Detection Garden Watering DIY

Specifications:

  • Analog output
  • Interface: PH2.0-3P
  • Size: 99mmx16mm
  • Output Voltage: DC 0-3.0V
  • Operating Voltage: DC 3.3-5.5V
  • Supports 3-Pin Gravity Sensor interface.

Applications:

  • Garden plants
  • Moisture detection
  • Intelligent agriculture

V1 (Cannot find V2 Current Usage)
Operating Voltage: 3.3 ~ 5.5 VDC
Output Voltage: 0 ~ 3.0VDC
Operating Current: 5mA
Interface: PH2.0-3P
Dimensions: 3.86 x 0.905 inches (L x W)
Weight: 15g

Relay

Connect to the ESP8266 3.3 Volt. Why this works, I am not sure, but the 5-volt does not work.

2 x LM2596 Voltage Step Down

Set to 12V & 5V.

Solenoid or Pump

(both 12V) for water flow

Wire and Fuses

I will use 25 Gauge wire for battery Serial and Parallel wiring in the cases and component connections. I will use 22 Gauge wire for the battery to solar. The Solar is pre-wired with 22 Gauge.

I will use Fuses in the following areas based on values;

  • Between the solar charge controller and battery bank – 10 A (Charge Controller Max 7 A). I will use a 20 A fuse for now as I have one.
  • Between the charge controller and solar panels – 5 A (Solar Max 1.1 A)
  • Between the Battery and step-down converters – 20 A (BMS Max 15 A)

3D Printed Case

A screenshot from Blender 3D of all case model parts.
A screenshot from Blender 3D of all case model parts.

The different parts of the case are listed below. All components were designed in Blender 3D and then the case was designed with their size and position in mind. Future designs will be more compact.

Printed Base

The lip of the case has tape over it to snugly fit the lid. It has standoffs and a hole on the bottom that feeds the external components. I use two filaments to print the base and had issues with the first so have added glue and tape to protect those fragile areas.

If water was to get into the case it would likely cause malfunctions. I used hot glue around the base hole where the cables exit to the garden. All of the wires that are connected with pins could wiggle loose, so they were hot glued to prevent them from unplugging.

I could have hot glued many more connections and components, but I have kept it this way as I imagine some maintenance may be required when the device is in the field. I have also kept the RX, TX and additional positive and negative leads available for this scenario.

I used M3 bolts as the 5V positive and negative connections with ring connectors on each wire, again for easy maintenance of this prototype.

I will use a desiccant in the case to prevent moisture buildup. I will write an article describing how I make these.

Solar Panel Lid

The Solar Panel acts as the lid with a 3D printed cap glued with a waterproof adhesive to the bottom. This fits snug over the main case and is tapered to prevent water from running around the edge and possibly into the case through the lid seal.

Solar Panel Lid Cap ready to glue down.
Solar Panel Lid Cap ready to glue down.

18650 Battery Holder

The model I used is from here.

4S2P 3.7 18650 Batteries

My selection of 18650's for projects was collected from old laptop battery packs.
My selection of 18650’s for projects was collected from old laptop battery packs.

I have many of these batteries left over that I would like to cycle through devices till they are no good. I will need to retest mAh and voltage to make sure they are ok and get a rough mAh estimate. In 4S they come to 14.8 Nom, 16.8V max. Using 2P will double the mAh, and the battery life to at least 2600 mAh for new batteries. The old batteries are around ~1200.

Battery Estimate Consumption

Total battery usage in mAh will help me size the solar panels and battery required mAh. I will probably switch pins off or on to reduce standby to the minimum required before a read. This will drastically reduce battery consumption. All devices run at 5V except the solenoid and the pump run at 12V.

The battery is 14.8 V with ~1200 mAh.

  • ESP8266240 mA max, sometimes much less.
  • DHT11 – 2.5 mA, 1 read per hour. Standby is 0.1 mA. 2.6 mA.
  • TZT LRD – Doc states ‘Driving ability is strong over 15 mA.’ 15 mA.
  • DS18B20 – 1.5 mA, 1 read an hour. Standby is .001 mAh. 1.5 mA.
  • CSMSV2 – Operating Current 5 mA
  • Relay – Max working current 3.8 mA.

5 V current ~270 mA.

  • Pump – Max 8 minutes per hour. Max Rated Current 1000 mA. 1000 / 60 * 8 = 134 mA for 8 mins in the hour.

12 V current ~140 mA

These mA values need to be converted from their 5 and 12 Volts to 14.4 Volts nominal for 4S 18650 batteries to get the estimated consumption mAh draw from 14.4 Volts (nominal). I could go further and take into account the mA lost from the step-down converters but this is an estimate and I have already overcompensated with higher mA values than will be the actual draw.

W = A x V, so 0.270 x 5 = 1.35 Watts, and 0.140 x 12 = 1.68 Watts. Total Power = 3.03 Watts.

3.03 / 14.8 = 0.205 A @ 14.8 Volts.

The battery will last at least 10 hours on new batteries (or 5 hrs on old batteries) without sun.

4S Li-ion Lithium Battery 18650 BMS

4S (16.8V) Li-ion Lithium Battery 18650 Charger will protect the batteries. The working current is 10 A using natural cooling. Add heat sink for 15 A. The maximum instantaneous current is 30 A. 10 Amps will suit.

It appears to have a protection condition for automatic recovery that should be active. It also offers Short circuit protection, Overcharge protection, Over-discharge protection and Overcurrent protection.

  • Module: 4S Li-ion Lithium Battery Protection Board
  • overcharge detection voltage: 4.25 ± 0.025 V
  • overcharge Lift the voltage: 4.15 ± 0.05 V
  • over-discharge detection voltage :2.50 ± 0.08 V
  • over-discharge Lift the voltage:3.00 ± 0.1 V
  • over-current current: 20 – 30 A
  • operating temperature: -40 – 85

BMS and Battery Wiring

I should note that using a 4S BMS connected to 2 batteries in parallel will mean I should check each battery and match them based on their mAh combined.

I have completed the Parallel Wiring so there are now 4 cells for the eight batteries.

The BMS will be wired so the batteries are balanced from the solar side.

Each cell represents two 18650 batteries. The P + and P- are for the Solar Controller (Photovoltaic).

CN3722 MPPT Solar Controller

CN3722 MPPT Solar Controller 2A Charging management system for the following applications:

  • 3.7V lithium battery – 1S 4.2V / 2S 8.4V / 3S 12.6V / 4S16.8V
  • 3.2V lithium iron phosphate battery – 1S 3.6V / 2S 7.2V / 3S 10.8V / 4S14.4V
  • 6V lead-acid battery – 6.8V
  • 12V lead-acid battery – 13.6V

The variable Solar Controller has a max of 24V and the battery pack is 16.8V at full.

This is an MPPT controller (maximum power point tracking). According to the manufacturer, the output current is greater than the solar panel current, for true ultra-high efficiency MPPT.

  • Support 7 V – 24 V, 90 W or less solar panels
  • Can be adjusted output voltage, CC-CV automatic control (to support single or multi-cell lithium-ion battery or lithium iron phosphate or lead-acid batteries)
  • PWM switching frequency: 300KHz
  • Constant current charging current is set by external resistor Default 2A (3A / 4A / 5A)
  • Trickle charge for deeply discharged batteries
  • Charge status and charge end status double indication (when charging, red light is on / full green light is on / the red light is flashing green on to indicate that the battery is not connected)
  • soft-start function
  • battery terminal over-voltage protection
  • integrated into the model copper inductance, 7A saturation current, more stable work more current output

Configuring the Solar Controller

My charging current from the panel is 1.1 A. If the charging current is greater than 2 A, it is recommended to attach the heat sink to a good aluminium or heat sink.

Note, please do not adjust the MPPT voltage to less than 7 V or less than the output voltage, otherwise is no charging output. The MPPT voltage is 1.04 V.

  • red light – Charging or No-load, also no current output.
  • blue light – charging the end or no battery.
  • red flashing – voltage setting error.

The potentiometer is extremely precise, be patient and refer to the following information carefully.

First: The input voltage must be higher than the set MPPT voltage.

Second: Set the output voltage must be lower than the input voltage. Factory default: MPPT voltage is about 18V, and the output voltage is about 4.2V.

  1. Connect the solar cell, not connected to the rechargeable battery, if there is the output voltage, then go to Step 2. If there is no output, slowly turn MPPT counterclockwise until there is the output voltage.
  2. Turn down the output voltage counterclockwise until the red/green light flashes, and then coarsely adjust the output voltage to full voltage. 16.8 V
  3. Connect an under-charged battery and monitor the charging current at the output ammeter. Trim the MPPT potentiometer until the charging current is maximum. Or use a multi-meter to measure the solar cell voltage close to the nominal optimum working voltage.
  4. Continuously observe the battery with a multi-meter to determine whether the battery charge cut-off voltage is correct, or adjust the output adjustable resistance until the output voltage is the battery charge voltage constant voltage.

Solar Controller and Battery Wiring

The solar controller is wired to the battery providing its charging capability.

18 Volt 20 Watt Solar Panel

I have calculated the solar panel size required to be 18 V 20 Watt. The Panel sourced also has the following feature list:

  • Monocrystalline solar cell A-level chips.
  • Using advanced polyethylene coating technology, the battery surface is sealed with epoxy resin.
  • Durable, lightweight and stable. Anti-scratch, non-foaming, easy to clean.
  • High conversion rate and high output.
  • High conversion efficiency, good output efficiency,
  • Strong resistance, resistance to different environments, good waterproof performance.
  • All battery positive and negative electrodes are made of high-quality silver paste with high welding strength and low series resistance.
  • Semi-flexible, and can be bent appropriately to use a wider range of applications.

Specifications:

  • Power: 20W
  • Voltage: 5V/18V
  • Current: 1.1 A
  • Output interface: single USB plus DC

Calculating the Solar Panel Size

18 Volt will be a good voltage to charge a 14.8 (max 16.8 Volt) battery. Based on battery consumption, a solar panel that keeps the battery full towards the end of the day will go into the night with a full battery, so the solar should charge the batteries at least 1 amp.

V = W x A, so the Cell is 18V at 20W, 20 / 18 = 1.11 A. With the batteries 14.8 this should deliver 20 / 14.8 = 1.35 Amps.

It will take around 2 hours to charge the batteries with full sun. This will be ~0.4 Amps per 18650, keeping within 1C and prolonging the life of batteries. Also keeping within 2 Amp ability of charge controller.

LM2596 Voltage Step Down

For this prototype, I have used an LM2596 and a larger voltage step-down that I had handy. This made the first case design quite a bit larger than future designs. (Set to 12V & 5V)

Schematic

A schematic of the completed wiring shows all of the connections.

[SCHEMATIC]

3. Code

There are two snippets of code along with a WordPress plugin I used to display the graphs. You could use any method to pull the SQL data to a graph.

I also tried a few Python methods, but prefer the data on my site. The GitHub Project is below.

ESP8266 C+ Code

The first piece of code is for the ESP8266. I use Visual Studio and PIO to upload to ESP8266 (via Bootloader as explained before).

#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <WiFiClient.h>
#include <Adafruit_Sensor.h>
#include <DHT.h>
#include <OneWire.h>
#include <DallasTemperature.h>

const char* ssid     = "SSID-HERE";
const char* password = "SSID-PASS";
const char* serverName = "http://domain/sensor-file.php"; //Your Domain name with URL path or IP address with path
String apiKeyValue = "APP-VALUE-HERE"; // If you change the apiKeyValue value, the PHP file also needs to have the same key

// VARIABLES
int valueCount = 120;      // How many values to collect. Should be every hour
int valueTime = 29500;     // Time between value counts. currently 29.5 seconds
int moistureChange = 1015; // The value dry to wet that the relay swithces at
const int dry = 1024;      // When Capacitive Soil Moisture Sensor is Dry
const int wet = 940;       // Will need to recalibrate in soil

#define DHT11PIN 13         // Digital pin connected to the DHT sensor 
#define DHTTYPE DHT11       // DHT 11
DHT dht(DHT11PIN, DHTTYPE); // Initialize DHT sensor.
float DHT11tval;
float DHT11hval;

int TZTpin = 5;     // Variable for Light Detector
int TZTval = 0;     // Set initial value (Maybe not needed)
int TZTshd = 0;     // Number of shade reads
int TZTfin = 0;     // Final minutes in shade (number of reads times 2)

int CSMSV2pin = 0;
int CSMSV2rel = 0;    // variable for relay on/off check
int CSMSV2pct = 0;    // Moisture as Percentage
int CSMSV2sum = 0;    // Sum of all the reads
int CSMSV2fin = 0;    // Final minutes relay on (Number of reads divided by total reads)

const int RELAY01pin = 14;
int RELAY01val = 0;
int RELAY01num = 0; // Total number of relay on's.
int RELAY01tim = 0; // Total Operation time of Relay, hence water running time.

const int DS18B20pin = 12;
float DS18B20val = 0;
#define ONE_WIRE_BUS 12
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature SoilTempSensor(&oneWire);
DeviceAddress insideThermometer, outsideThermometer;
// function to print a device address
void printAddress(DeviceAddress deviceAddress)
{
  for (uint8_t i = 0; i < 8; i++)
  {
    if (deviceAddress[i] < 16) Serial.print("0");
    Serial.print(deviceAddress[i], HEX);
  }
}

int sensorCount = 0; // The current count of sensor reads

void setup() {

  Serial.begin(115200);

  pinMode(TZTpin,INPUT);
  pinMode(DS18B20pin, INPUT);
  pinMode(RELAY01pin, OUTPUT);

  // DS18B20 Setup
  Serial.println(F("DS18B20 Soil Temp Sensor"));
  SoilTempSensor.begin();
  Serial.print(SoilTempSensor.getDeviceCount(), DEC);
  Serial.println(" devices.");
  if (!SoilTempSensor.getAddress(insideThermometer, 0)) Serial.println("Unable to find address for Device 0");
  Serial.print("Device 0 Address: ");
  printAddress(insideThermometer);
  SoilTempSensor.setResolution(insideThermometer, 9);
  Serial.print("Device 0 Resolution: ");
  Serial.print(SoilTempSensor.getResolution(insideThermometer), DEC); 
  Serial.println(F("------------------------------------"));

  WiFi.begin(ssid, password);
  Serial.println("Connecting");
  while(WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.print("Connected to WiFi network with IP Address: ");
  Serial.println(WiFi.localIP());

  dht.begin();
}

void printTemperature(DeviceAddress deviceAddress)
{
  DS18B20val = SoilTempSensor.getTempC(deviceAddress);
  if(DS18B20val == DEVICE_DISCONNECTED_C) 
  {
    Serial.println("Error: Could not read temperature data");
    return;
  }
  Serial.print("Soil Temp: ");
  Serial.print(DS18B20val);
  Serial.println("°C");

}

void loop() { 
  
  int CSMSV2array[119]; // 120 Elements in array.
  byte CSMSV2index = 0;

  // Send Serial prints over local network to PC...

  // MySQL has a hard limit of 4096 lines per table.
  // This will keep the solinoid from being on for too long.
  // Might need to look into timer if 4 hours is not accurate.

  while (sensorCount < valueCount) { // Loop everything 6 times to get an average of 6 values
    delay(valueTime);   // Wait ~29.5 seconds between measurements.

    //TZT
    TZTval = analogRead(TZTpin); 
    Serial.print(TZTval, DEC); // light intensity
    if (TZTval > 1000) {
      TZTshd++;
      Serial.println(" - Shade");
      } else { 
        Serial.println(" - Sunny"); }
    Serial.print("TZT Shade Count: ");// Calculate this to get minute of shade...
    Serial.println(TZTshd);
  
    // CSMSV2  
    Serial.print("CSMSV2 Value: ");
    Serial.println(analogRead(CSMSV2pin));
    CSMSV2array[CSMSV2index] = analogRead(CSMSV2pin);    //put a value in entry 0
    CSMSV2rel = analogRead(CSMSV2pin); // A variable to work the relay

    // RELAY01
    if (CSMSV2rel > moistureChange) {
      digitalWrite(RELAY01pin,LOW);
      RELAY01val = 1;
      Serial.println("Min Moisture - Pump Running");
      } else {
        digitalWrite(RELAY01pin,HIGH);
        RELAY01val = 0;
        Serial.println("Max Moisture - Pump Stopped");
      }
    if (RELAY01val == 1) { RELAY01num++; } // Add one relay time increase
    Serial.print("Relay Switch Count: ");
    Serial.println(RELAY01num);

    Serial.println(F("------------------"));
    CSMSV2index++;
    sensorCount++;
  }

    // DS18B20 Hourly Reading
    SoilTempSensor.requestTemperatures(); // Send the command to get temperatures
    printTemperature(insideThermometer); // Use a simple function to print out the data

    // DHT11 Hourly Reading
    float DHT11tval = dht.readHumidity();       // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
    float DHT11hval = dht.readTemperature();    // Reading temperature or humidity takes about 250 milliseconds!
    if (isnan(DHT11tval) || isnan(DHT11hval)) {
      Serial.println(F("Failed to read from DHT sensor!"));
      return; }
    Serial.print(F("Humidity: "));
    Serial.print(DHT11tval);
    Serial.print(F("%  Temperature: "));
    Serial.print(DHT11hval);
    Serial.println(F("°C "));

    // CSMSV2 Array to average results to percent for hour
    for ( int i = 0; i < 120; i++ ) {
      CSMSV2sum += CSMSV2array[i]; }
    Serial.print("Sum of total elements of an array: ");
    Serial.println(CSMSV2sum);
    CSMSV2fin = CSMSV2sum / 120;
    Serial.print("Average of array: ");
    Serial.println(CSMSV2fin);
    CSMSV2pct = map(CSMSV2fin, wet, dry, 100, 0);
    Serial.print(" - Soil Moisture: ");
    Serial.print(CSMSV2pct);
    Serial.println("%");
    CSMSV2sum = 0;
    CSMSV2fin = 0;

    //Relay minutes of operation per hour
    RELAY01tim = RELAY01num / 2; // Divide by 2 to get minutes from 30 seconds.
    Serial.print("Total relay minutes:");
    Serial.println(RELAY01tim);
    RELAY01num = 0;

    //TZT minutes of shade per hour
    TZTfin = TZTshd / 2; // Divide by 2 to get minutes from 30 seconds.
    Serial.print("Total minutes of shade:");
    Serial.println(TZTfin);
    TZTshd = 0;

    if(WiFi.status()== WL_CONNECTED){ //Check WiFi connection status
      WiFiClient client;
      HTTPClient http;
      http.begin(client, serverName);
      http.addHeader("Content-Type", "application/x-www-form-urlencoded"); // Specify content-type header
      String httpRequestData = "api_key=" + apiKeyValue // Prepare your HTTP POST request data
      + "&valueDHT11t=" + String(dht.readTemperature())
      + "&valueDHT11h=" + String(dht.readHumidity())
      + "&valueTZT=" + String(TZTfin)
      + "&valueCSMSV2=" + String(CSMSV2pct)
      + "&valueDS18B20=" + String(DS18B20val)
      + "&valueRELAY01=" + String(RELAY01tim)
      + "";
      Serial.print("httpRequestData: ");
      Serial.println(httpRequestData); 
      int httpResponseCode = http.POST(httpRequestData); // Send HTTP POST request

      if (httpResponseCode>0) {
        Serial.print("HTTP Response code: ");
        Serial.println(httpResponseCode);
        Serial.println(F("------------------"));
      }
      else {
        Serial.print("Error code: ");
        Serial.println(httpResponseCode);
        Serial.println(F("------------------"));
      }
      // Free resources
      http.end();

      RELAY01tim = 0;
      TZTfin = 0;

    }
    else {
      Serial.println("WiFi Disconnected");
    }
  sensorCount = 0;
}

Server PHP File

The second script is a file to place on your server. Change the database details and file name, and server details to match.

<?php

$servername = "localhost";

// REPLACE with your Database name
$dbname = "database";
// REPLACE with Database user
$username = "user";
// REPLACE with Database user password
$password = "pass";

// Keep this API Key value to be compatible with the ESP32 code provided in the project page. If you change this value, the ESP32 sketch needs to match
$api_key_value = "APIKey";

$api_key = $valueDHT11t = $valueDHT11h = $valueTZT  = $valueCSMSV2 = $valueDS18B20 = $valueRELAY01 = "";

if ($_SERVER["REQUEST_METHOD"] == "POST") {
    $api_key = test_input($_POST["api_key"]);
    if($api_key == $api_key_value) {
        $valueDHT11t = test_input($_POST["valueDHT11t"]);
        $valueDHT11h = test_input($_POST["valueDHT11h"]);
        $valueTZT = test_input($_POST["valueTZT"]);
        $valueCSMSV2 = test_input($_POST["valueCSMSV2"]);
        $valueDS18B20 = test_input($_POST["valueDS18B20"]);
        $valueRELAY01 = test_input($_POST["valueRELAY01"]);


        // Create connection
        $conn = new mysqli($servername, $username, $password, $dbname);
        // Check connection
        if ($conn->connect_error) {
            die("Connection failed: " . $conn->connect_error);
        } 
        
        $sql = "INSERT INTO Sensor (valueDHT11t, valueDHT11h, valueTZT, valueCSMSV2, valueDS18B20, valueRELAY01)
        VALUES ('" . $valueDHT11t . "', '" . $valueDHT11h . "', '" . $valueTZT . "', '" . $valueCSMSV2 . "', '" . $valueDS18B20 . "', '" . $valueRELAY01 . "')";
        
        if ($conn->query($sql) === TRUE) {
            echo "New record created successfully";
        } 
        else {
            echo "Error: " . $sql . "<br>" . $conn->error;
        }
    
        $conn->close();
    }
    else {
        echo "Wrong API Key provided.";
    }

}
else {
    echo "No data posted with HTTP POST.";
}

function test_input($data) {
    $data = trim($data);
    $data = stripslashes($data);
    $data = htmlspecialchars($data);
    return $data;
}

Create your SQL Database

The Third could also be a file, it’s just a way of displaying the data. I chose to integrate into my website and use a SQL database graphing plugin.

First, This query will create the correct database for the sensor readings (I could probable adjust the char length for them all):

CREATE TABLE Sensor (
    id INT(6) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    valueDHT11t VARCHAR(10),
    valueDHT11h VARCHAR(10),
    valueTZT VARCHAR(10),
    valueCSMSV2 VARCHAR(10),
    valueDS18B20 VARCHAR(10),
    valueRELAY01 VARCHAR(10),
    reading_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
)

Using a WordPress Plugin to Graph the Data

A WordPress plugin allows me to write SQL queries to get data for charts. This query will grab the previous 24hours of the air and soil temp:

SELECT * FROM `Sensor` WHERE 1

The Graphs can be seen below.

4. Overview

All of the equipment is listed in this article and the code is on GitHub so you can source components and build this yourself.

The Graphs

Here I have all the useful chart data from the various sensors. You can easily see the correlations between sensors. This data is updated every hour with additional readings as you can see by the last date and time, being around the time now.

Air Temperature

Air Humidity

Soil Temperature

Soil Moisture Level

Pump Running Time Per Hour

Minutes of Shade Per Hour

I do have plans for a second version with the following improvements;

  • Analogue Light Sensor – Need additional analogue output (using ESP32).
  • More accurate sensor timing – Get the time from a server rather than using the crystal hertz and code.
  • ESP 32 Upgrade – Offering more pins and a faster microprocessor.
  • Access Point / Web Server – Ability to enter SSID and connect to your network via a browser for quick setup.
  • Battery Packs – Pre-designed packs of 14.8 V that can easily plug into the system.
  • New Design – Redesign case using PETG or ABS with rails for positive and negative and other features missing from this design.
  • PCB – Design a PCB for this. If it is foreseeable to get around 10,000 orders it will be a viable option. Else buying components specific to tasks is cheaper on a small scale.
  • Camera Monitoring and AI Implementation – If I can monitor the garden with a camera the data can be sent to a faster system to monitor different plants and life cycles and with other sensor data, prompt the gardener on sowing and harvesting times. I have a project underway for a ‘Garden Planner’ that would use this functionality.