IoT based Smart Irrigation System using Soil Moisture Sensor and ESP8266 NodeMCU

IoT based Smart Irrigation System using Soil Moisture Sensor and ESP8266 NodeMCUIoT based Smart Irrigation System using Soil Moisture Sensor and ESP8266 NodeMCU

Most of the farmers use large portions of farming land and it becomes very difficult to reach and track each corner of large lands. Sometime there is a possibility of uneven water sprinkles. This result in the bad quality crops which further leads to financial losses. In this scenario the Smart Irrigation System using Latest IoT technology is helpful and leads to ease of farming.

The Smart irrigation System has wide scope to automate the complete irrigation system. Here we are building a IoT based Irrigation System using ESP8266 NodeMCU Module and DHT11 Sensor. It will not only automatically irrigate the water based on the moisture level in the soil but also send the Data to ThingSpeak Server to keep track of the land condition. The System will consist a water pump which will be used to sprinkle water on the land depending upon the land environmental condition such as Moisture, Temperature and Humidity.

We previously build similar Automatic Plant Irrigation System which sends alerts on mobile but not on IoT cloud. Apart from this, Rain alarm and soil moisture detector circuit can also be helpful in building Smart Irrigation system.

Before starting, it is important to note that the different crops require different Soil Moisture, Temperature and Humidity Condition. So in this tutorial we are using such a crop which will require a soil moisture of about 50-55%. So when the soil loses its moisture to less than 50% then Motor pump will turn on automatically to sprinkle the water and it will continue to sprinkle the water until the moisture goes upto 55% and after that the pump will be turned off. The sensor data will be sent to ThingSpeak Server in defined interval of time so that it can be monitored from anywhere in the world.

Components Required

  • NodeMCU ESP8266
  • Soil Moisture Sensor Module
  • Water Pump Module
  • Relay Module
  • DHT11
  • Connecting Wires

You can buy all the components required for this project.

Circuit Diagram

Circuit diagram for this IoT Smart Irrigation System is given below:

Circuit Diagram for IoT based Smart Irrigation System using Soil Moisture Sensor and ESP8266 NodeMCU

Circuit Hardware for IoT based Smart Irrigation System using Soil Moisture Sensor and ESP8266 NodeMCU

Programming ESP8266 NodeMCU for Automatic Irrigation System

For programming the ESP8266 NodeMCU module, only the DHT11 sensor library is used as external library. The moisture sensor gives analog output which can be read through the ESP8266 NodeMCU analog pin A0. Since the NodeMCU cannot give output voltage greater than 3.3V from its GPIO so we are using a relay module to drive the 5V motor pump. Also the Moisture sensor and DHT11 sensor is powered from external 5V power supply.

Complete code with a working video is given at the end of this tutorial, here we are explaining the program to understand the working flow of the project.

Start with including necessary library.

#include <DHT.h>
#include <ESP8266WiFi.h>

Since we are using the ThingSpeak Server, the API Key is necessary in order to communicate with server. To know how we can get API Key from ThingSpeak you can visit previous article on Live Temperature and Humidity Monitoring on ThingSpeak.

String apiKey = "X5AQ445IKMBYW31H
const char* server = ""; 

The next Step is to write the Wi-Fi credentials such as SSID and Password.

const char *ssid =  "CircuitDigest";     
const char *pass =  "xxxxxxxxxxx"; 

Define the DHT Sensor Pin where the DHT is connected and Choose the DHT type.

#define DHTPIN D3          

The moisture sensor output is connected to Pin A0 of ESP8266 NodeMCU. And the motor pin is connected to D0 of NodeMCU.

const int moisturePin = A0;
const int motorPin = D0;

We will be using millis() function to send the data after every defined interval of time here it is 10 seconds. The delay() is avoided since it stops the program for a defined delay where microcontroller cannot do other tasks. Learn more about the difference between delay() and millis() here.

unsigned long interval = 10000;
unsigned long previousMillis = 0;

Set motor pin as output, and turn off the motor initially. Start the DHT11 sensor reading.

pinMode(motorPin, OUTPUT);
digitalWrite(motorPin, LOW); // keep motor off initally

Try to connect Wi-Fi with given SSID and Password and wait for the Wi-Fi to be connected and if connected then go to next steps.

WiFi.begin(ssid, pass);
  while (WiFi.status() != WL_CONNECTED)
  Serial.println("WiFi connected");

Define the current time of starting the program and save it in a variable to compare it with the elapsed time.

unsigned long currentMillis = millis();

Read temperature and humidity data and save them into variables.

float h = dht.readHumidity();
float t = dht.readTemperature();

If DHT is connected and the ESP8266 NodeMCU is able to read the readings then proceed to next step or return from here to check again.

if (isnan(h) || isnan(t))
    Serial.println("Failed to read from DHT sensor!");

Read the moisture reading from sensor and print the reading.

moisturePercentage = ( 100.00 - ( (analogRead(moisturePin) / 1023.00) * 100.00 ) );
  Serial.print("Soil Moisture is  = ");

If the moisture reading is in between the required soil moisture range then keep the pump off or if it goes beyond the required moisture then turn the pump ON.

if (moisturePercentage < 50) {
    digitalWrite(motorPin, HIGH);
   if (moisturePercentage > 50 && moisturePercentage < 55) {
    digitalWrite(motorPin, HIGH);
 if (moisturePercentage > 56) {
    digitalWrite(motorPin, LOW);

Now after every 10 seconds call the sendThingspeak() function to send the moisture, temperature and humidity data to ThingSpeak server.

  if ((unsigned long)(currentMillis - previousMillis) >= interval) {
    previousMillis = millis();

In the sendThingspeak() function we check if the system is connected to server and if yes then we prepare a string where moisture, temperature, humidity reading is written and this string will be sent to ThingSpeak server along with API key and server address.

if (client.connect(server, 80))
      String postStr = apiKey;
      postStr += "&field1=";
      postStr += String(moisturePercentage);
      postStr += "&field2=";
      postStr += String(t);
      postStr += "&field3=";
      postStr += String(h);      
      postStr += "\r\n\r\n";

Finally the data is sent to ThingSpeak server using client.print() function which contains API key, server address and the string which is prepared in previous step.

client.print("POST /update HTTP/1.1\n");
      client.print("Connection: close\n");
      client.print("X-THINGSPEAKAPIKEY: " + apiKey + "\n");
      client.print("Content-Type: application/x-www-form-urlencoded\n");
      client.print("Content-Length: ");

Finally this is how the data looks on ThingSpeak Dashboard

Getting Data on ThingSpeak for IoT based Smart Irrigation System

This last step finishes the complete tutorial on IoT based Smart Irrigation System. Note that it is important to switch off the motor when the soil moisture has reached the required level after water sprinkle. You can make a more smart system which can contain different control for different crops.

If you face any issues while doing this project then comment below or reach to our forums for more relevant questions and their answers.

Find the complete program and demonstration Video for this project below.


#include <DHT.h>
#include <ESP8266WiFi.h>
String apiKey = “X5AQ3EGIKMBYW31H”;     //  Enter your Write API key here
const char* server = “”;
const char *ssid =  “CircuitLoop”;     // Enter your WiFi Name
const char *pass =  “circuitdigest101”; // Enter your WiFi Password
#define DHTPIN D3          // GPIO Pin where the dht11 is connected
WiFiClient client;

const int moisturePin = A0;             // moisteure sensor pin
const int motorPin = D0;
unsigned long interval = 10000;
unsigned long previousMillis = 0;
unsigned long interval1 = 1000;
unsigned long previousMillis1 = 0;
float moisturePercentage;              //moisture reading
float h;                  // humidity reading
float t;                  //temperature reading

void setup()
pinMode(motorPin, OUTPUT);
digitalWrite(motorPin, LOW); // keep motor off initally
Serial.println(“Connecting to “);
WiFi.begin(ssid, pass);
while (WiFi.status() != WL_CONNECTED)
Serial.print(“.”);              // print … till not connected
Serial.println(“WiFi connected”);

void loop()
unsigned long currentMillis = millis(); // grab current time

h = dht.readHumidity();     // read humiduty
t = dht.readTemperature();     // read temperature

if (isnan(h) || isnan(t))
Serial.println(“Failed to read from DHT sensor!”);

moisturePercentage = ( 100.00 – ( (analogRead(moisturePin) / 1023.00) * 100.00 ) );

if ((unsigned long)(currentMillis – previousMillis1) >= interval1) {
Serial.print(“Soil Moisture is  = “);
previousMillis1 = millis();

if (moisturePercentage < 50) {
digitalWrite(motorPin, HIGH);         // tun on motor
if (moisturePercentage > 50 && moisturePercentage < 55) {
digitalWrite(motorPin, HIGH);        //turn on motor pump
if (moisturePercentage > 56) {
digitalWrite(motorPin, LOW);          // turn off mottor

if ((unsigned long)(currentMillis – previousMillis) >= interval) {

sendThingspeak();           //send data to thing speak
previousMillis = millis();


void sendThingspeak() {
if (client.connect(server, 80))
String postStr = apiKey;              // add api key in the postStr string
postStr += “&field1=”;
postStr += String(moisturePercentage);    // add mositure readin
postStr += “&field2=”;
postStr += String(t);                 // add tempr readin
postStr += “&field3=”;
postStr += String(h);                  // add humidity readin
postStr += “\r\n\r\n”;

client.print(“POST /update HTTP/1.1\n”);
client.print(“Connection: close\n”);
client.print(“X-THINGSPEAKAPIKEY: ” + apiKey + “\n”);
client.print(“Content-Type: application/x-www-form-urlencoded\n”);
client.print(“Content-Length: “);
client.print(postStr.length());           //send lenght of the string
client.print(postStr);                      // send complete string
Serial.print(“Moisture Percentage: “);
Serial.print(“%. Temperature: “);
Serial.print(” C, Humidity: “);
Serial.println(“%. Sent to Thingspeak.”);

ADS1115 analog-to-digital converter and ESP8266

The ADS1115 device is a precision, low-power, 16-bit, I2C-compatible, analog-to-digital converters (ADCs) offered in an ultra-small, leadless, X2QFN-10 package, and a VSSOP-10 package. The ADS1115 device incorporates a low-drift voltage reference and an oscillator. The ADS1115 also incorporate a programmable gain amplifier and a digital comparator. These features, along with a wide operating supply range, make the ADS1115 well suited for power- and space-constrained, sensor measurement applications.

The ADS1115 perform conversions at data rates up to 860 samples per second (SPS). The PGA offers input ranges from ±256 mV to ±6.144 V, allowing precise large- and small-signal measurements. The ADS1115 features an input multiplexer  that allows two differential or four single-ended input measurements. Use the digital comparator in the ADS1115 for under- and overvoltage detection.

The ADS1115 operates in either continuous-conversion mode or single-shot mode. The devices are automatically powered down after one conversion in single-shot mode; therefore, power consumption is significantly reduced during idle periods.


Wide Supply Range: 2.0 V to 5.5 V
Low Current Consumption: 150 µA
(Continuous-Conversion Mode)
Programmable Data Rate: 8 SPS to 860 SPS
Single-Cycle Settling
Internal Low-Drift Voltage Reference
Internal Oscillator
I2C Interface: Four Pin-Selectable Addresses
Four Single-Ended or Two Differential Inputs (ADS1115)
Programmable Comparator (ADS1114 and ADS1115)
Operating Temperature Range: –40°C to +125°C

Parts List

This module will cost less than $2

Amount Part Type
1 ADS1115
1 Wemos D1 mini V2




In the layout below we just show basic connection between Wemos Mini and ADS1115 – you can add a pot, connect an LDR to one of the A0 – A3 inputs of the ADS1115

esp8266 and ads1115
esp8266 and ads1115



Again we use a library and again its an adafruit one –

#include <Wire.h>
#include <Adafruit_ADS1015.h>
Adafruit_ADS1115 ads(0x48);
void setup(void)
Serial.println("Getting single-ended readings from AIN0..3");
Serial.println("ADC Range: +/- 6.144V (1 bit = 3mV/ADS1015, 0.1875mV/ADS1115)");
void loop(void)
int16_t adc0, adc1, adc2, adc3;
adc0 = ads.readADC_SingleEnded(0);
adc1 = ads.readADC_SingleEnded(1);
adc2 = ads.readADC_SingleEnded(2);
adc3 = ads.readADC_SingleEnded(3);
Serial.print("AIN0: ");
Serial.print("AIN1: ");
Serial.print("AIN2: ");
Serial.print("AIN3: ");
Serial.println(" ");



I2C ADS1115 16 Bit ADC 4 channel Module with Programmable Gain Amplifier 2.0V to 5.5V RPi