Smart irrigation system problem

I attempted to follow the instructions given in this video

but the pump seems to be operating in reverse. It activates when the sensor is submerged in water and deactivates when it is removed. I suspect that the issue lies with the 5v relay board, as the module I am using features (S+, -) instead of (VCC, GND, IN). Could you offer any assistance?

Relays used with Arduino commonly are NO or are NC:
Guide for Relay Module with Arduino | Random Nerd Tutorials

NO: normally open
NC: normally closed

Normally means idle, not energized.

1 Like

Just modify the code that tests the sensor and/or controls the motor. Rather than setting the output HIGH to turn on the motor, set it LOW. Opposite for turning it off.

Since you didn't post your code, only you know for sure.

1 Like

A resque pump for boats?

this is the code:

#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);
 
void setup() {
  Serial.begin(9600);
  lcd.init();
  lcd.backlight();
  lcd.clear();
  pinMode(2, OUTPUT);
  digitalWrite(2, HIGH);
  delay(1000);
  lcd.setCursor(0, 0);
  lcd.print("IRRIGATION");
  lcd.setCursor(0, 1);
  lcd.print("SYSTEM IS ON ");
    lcd.print("");
    delay(3000);
  lcd.clear();
}
 
void loop() {
  int value = analogRead(A0);
  Serial.println(value);
  if (value > 950) {
    digitalWrite(2, LOW);
    lcd.setCursor(0, 0);
    lcd.print("Water Pump is ON ");
  } else {
    digitalWrite(2, HIGH);
    lcd.setCursor(0, 0);
    lcd.print("Water Pump is OFF");
  }
 
  if (value < 300) {
    lcd.setCursor(0, 1);
    lcd.print("Moisture : HIGH");
  } else if (value > 300 && value < 950) {
    lcd.setCursor(0, 1);
    lcd.print("Moisture : MID ");
  } else if (value > 950) {
    lcd.setCursor(0, 1);
    lcd.print("Moisture : LOW ");
  }
}

no pump like the one demonstrated in the video

you can factor out a lot of that code. Not really necessary to continuously write the same text to your LCD.

Also, when testing different ranges with a series of if() statements, it makes the code cleaner and easier to change if you start at the highest value and work your way down. This eliminates having to test both the upper and lower bounds.

#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);

void setup() {
  Serial.begin(9600);
  lcd.init();
  lcd.backlight();
  lcd.clear();
  pinMode(2, OUTPUT);
  digitalWrite(2, HIGH);
  delay(1000);
  lcd.setCursor(0, 0);
  lcd.print("IRRIGATION");
  lcd.setCursor(0, 1);
  lcd.print("SYSTEM IS ON ");
  lcd.print("");
  delay(3000);
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Water Pump is ");
  lcd.setCursor(0, 1);
  lcd.print("Moisture : ");
}

void loop() {
  int value = analogRead(A0);
  Serial.println(value);
  // water pump update
  lcd.setCursor(14, 0);
  if (value > 950) {
    digitalWrite(2, LOW);
    lcd.print("ON ");
  }
  else {
    digitalWrite(2, HIGH);
    lcd.print("OFF");
  }

  // moisture update
  lcd.setCursor(11, 1);
  if (value > 950) {
    lcd.print("LOW ");
  }
  else if (value > 300) {
    lcd.print("MID ");
  }
  else {
    lcd.print("HIGH");
  }
}
1 Like

The code is not functioning properly for me.
Although I substituted

void loop() {
  int value = analogRead(A0);
  Serial.println(value);
  if (value > 950) {
    digitalWrite(2, LOW);
    lcd.setCursor(0, 0);
    lcd.print("Water Pump is ON ");
  } else {
    digitalWrite(2, HIGH);
    lcd.setCursor(0, 0);
    lcd.print("Water Pump is OFF");
  }

with

void loop() {
  int value = analogRead(A0);
  Serial.println(value);
  if (value > 950) {
    digitalWrite(2, HIGH);
    lcd.setCursor(0, 0);
    lcd.print("Water Pump is ON ");
  } else {
    digitalWrite(2, LOW);
    lcd.setCursor(0, 0);
    lcd.print("Water Pump is OFF");
  }

which made the pump operate correctly, the code appears to lack logical consistency.

what does that mean? What does the serial monitor show?

1 Like

after using this code,

#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);
 
void setup() {
  Serial.begin(9600);
  lcd.init();
  lcd.backlight();
  lcd.clear();
  pinMode(2, OUTPUT);
  digitalWrite(2, HIGH);
  delay(1000);
  lcd.setCursor(0, 0);
  lcd.print("IRRIGATION");
  lcd.setCursor(0, 1);
  lcd.print("SYSTEM IS ON ");
    lcd.print("");
    delay(3000);
  lcd.clear();
}
 
void loop() {
  int value = analogRead(A0);
  Serial.println(value);
  if (value > 950) {
    digitalWrite(2, HIGH);
    lcd.setCursor(0, 0);
    lcd.print("Water Pump is ON ");
  } else {
    digitalWrite(2, LOW);
    lcd.setCursor(0, 0);
    lcd.print("Water Pump is OFF");
  }
 
  if (value < 300) {
    lcd.setCursor(0, 1);
    lcd.print("Moisture : HIGH");
  } else if (value > 300 && value < 950) {
    lcd.setCursor(0, 1);
    lcd.print("Moisture : MID ");
  } else if (value > 950) {
    lcd.setCursor(0, 1);
    lcd.print("Moisture : LOW ");
  }
}

The pump and screen are functioning correctly as required, and all appears to be in order. However, the logic of the code seems flawed since the pump should be turned off when the value exceeds 950

Asimoha,
Can you tell us what values you get from your analogRead(A0) when the sensor is:
(a) dry, and
(b) wet

Maybe your sensor works in the opposite sense to the one in the video

1 Like

I'm new to this and I don't have the knowledge to retrieve these values. Could you please explain to me how to invert the sensor?

The lines above are where you are already reading the output of the sensor, and then sending it to the serial monitor.

All you need to do is turn the serial monitor on, and check that the baud rate is set to 9600.

1 Like

Let's find out whether in needs changing first.

1 Like

When the probe is held in the air and dried off what does the probe read? Record that reading and note it as 100% dry.

When the probe is held in water what does the probe read? Recode that reading and note that is 100% wet. Post the 2 readings and your latest code.

1 Like
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);
 
void setup() {
  Serial.begin(9600);
  lcd.init();
  lcd.backlight();
  lcd.clear();
  pinMode(2, OUTPUT);
  digitalWrite(2, HIGH);
  delay(1000);
  lcd.setCursor(0, 0);
  lcd.print("IRRIGATION");
  lcd.setCursor(0, 1);
  lcd.print("SYSTEM IS ON ");
    lcd.print("");
    delay(3000);
  lcd.clear();
}
 
void loop() {
  int value = analogRead(A0);
  Serial.println(value);
  if (value > 950) {
    digitalWrite(2, LOW);
    lcd.setCursor(0, 0);
    lcd.print("Water Pump is ON ");
  } else {
    digitalWrite(2, HIGH);
    lcd.setCursor(0, 0);
    lcd.print("Water Pump is OFF");
  }
 
  if (value < 300) {
    lcd.setCursor(0, 1);
    lcd.print("Moisture : HIGH");
  } else if (value > 300 && value < 950) {
    lcd.setCursor(0, 1);
    lcd.print("Moisture : MID ");
  } else if (value > 950) {
    lcd.setCursor(0, 1);
    lcd.print("Moisture : LOW ");
  }
}

-The sensor gives me a reading of 1016 when removed from water, but when submerged in water, the reading increases to 3247.
-Upon taking the sensor out of the water, the screen displays the message "the pump is ON," however, the pump remains inactive and the relay lamp fails to illuminate.
Conversely,
-When I dip the sensor into the water, the screen shows a message indicating that the pump is OFF, but in reality, the pump is working and the relay lamp is lit.

-The sensor gives me a reading of 1016 when removed from water, but when submerged in water, the reading increases to 3247.
-Upon taking the sensor out of the water, the screen displays the message "the pump is ON," however, the pump remains inactive and the relay lamp fails to illuminate.
Conversely,
-When I dip the sensor into the water, the screen shows a message indicating that the pump is OFF, but in reality, the pump is working and the relay lamp is lit.

The situation appears to be flipped or reversed.

So reverse your operations to match reality.

1 Like

I'm new to this, Can you please provide me with an explanation on how to accomplish that?

Now lets say you want the pump to energize when the sensor is completely dry and deenergize when the sensor is completely wet.

if (sensorvalue =< 1016 )
{
pump on
}
if ( sensor value => 3247 )
{
 pump off
}

You'll most likely want to energize the pump before the water has completely dried off or has completely wetted the soil but that value is to be determined by you.

What I do is run the pump for an amount of time, say 11 seconds, then I wait one minute to allow the water to seep into the nooks and crannies, then I read the sensor value to see if the soil needs more water, if so then run the pump for another 11 seconds.

You could also look to create a formula for a % of moisture. Consider that 1016 is 0% moisture and 3247 is 100% moisture. You could use the map function, map() - Arduino Reference, to determine a percentage of moisture remaining in the soil to energize the pump for x amount of seconds and then check for a threshold % of moisture to keep the pump off.

Anyways here is how I do the thing.

void fDoMoistureDetector1( void * parameter )
{
  //wait for a mqtt connection
  while ( !MQTTclient.connected() )
  {
    vTaskDelay( 250 );
  }
  int      TimeToPublish = 5000000; //5000000uS
  int      TimeForADreading = 100 * 1000; // 100mS
  uint64_t TimePastPublish = esp_timer_get_time(); // used by publish
  uint64_t TimeADreading   = esp_timer_get_time();
  TickType_t xLastWakeTime = xTaskGetTickCount();
  const TickType_t xFrequency = 10; //delay for 10mS
  float    RemainingMoisture = 100.0f; //prevents pump turn on during start up
  bool     pumpOn = false;
  uint64_t PumpOnTime = esp_timer_get_time();
  int      PumpRunTime = 11000000;
  uint64_t PumpOffWait = esp_timer_get_time();
  uint64_t PumpOffWaitFor = 60000000; //one minute
  float    lowMoisture = 23.0f;
  float    highMoisture = 40.0f;
  for (;;)
  {
    xSemaphoreTake( sema_WaterCactus, portMAX_DELAY );
    //read AD values every 100mS.
    if ( (esp_timer_get_time() - TimeADreading) >= TimeForADreading )
    {
      xEventGroupSetBits( eg, evtADCreading0 );
      TimeADreading = esp_timer_get_time();
    }
    xQueueReceive(xQ_RM, &RemainingMoisture, 0 ); //receive queue stuff no waiting
    //read gpio 0 is water level good. Yes: OK to run pump : no pump off.   remaining moisture good, denergize water pump otherwise energize water pump.
    if ( RemainingMoisture >= highMoisture )
    {
      WaterPump0_off();
    }
    if ( !pumpOn )
    {
      log_i( "not pump on ");
      if ( gpio_get_level( GPIO_NUM_0 ) )
      {
        if ( RemainingMoisture <= lowMoisture )
        {
          //has one minute passed since last pump energize, if so then allow motor to run
          if ( (esp_timer_get_time() - PumpOffWait) >= PumpOffWaitFor )
          {
            gpio_set_level( GPIO_NUM_5, HIGH); //open valve
            WaterPump0_on();
            log_i( "pump on " );
            pumpOn = !pumpOn;
            PumpOnTime = esp_timer_get_time();
          }
        }
        //xSemaphoreGive( sema_RemainingMoisture );
      } else {
        log_i( "water level bad " );
        WaterPump0_off();
        gpio_set_level( GPIO_NUM_5, LOW); //denergize/close valve
        PumpOffWait = esp_timer_get_time();
      }
    } else {
      /*
         pump goes on runs for X seconds then turn off, then wait PumpOffWaitTime before being allowed to energize again
      */
      if ( (esp_timer_get_time() - PumpOnTime) >= PumpRunTime )
      {
        log_i( "pump off " );
        WaterPump0_off(); // after 5 seconds turn pump off
        gpio_set_level( GPIO_NUM_5, LOW); //denergize/close valve
        pumpOn = !pumpOn;
        PumpOffWait = esp_timer_get_time();
      }
    }
    // publish to MQTT every 5000000uS
    if ( (esp_timer_get_time() - TimePastPublish) >= TimeToPublish )
    {
      xQueueOverwrite( xQ_RemainingMoistureMQTT, (void *) &RemainingMoisture );// data for mqtt publish
      TimePastPublish = esp_timer_get_time(); // get next publish time
    }
    xSemaphoreGive( sema_WaterCactus );
    xLastWakeTime = xTaskGetTickCount();
    vTaskDelayUntil( &xLastWakeTime, xFrequency );
  }
  vTaskDelete( NULL );
}// end fDoMoistureDetector1()