Water pump with relay and pwm

Hello.

I've been working on a sketch to activate a water pump when moisture percentage level is below 35, the problem is that when moisture level starts to increase, the whole system hangs and relay never turns off, any help will be greatly appreciated.

#include <GyverOLED.h>

// Sensor pins
const int sensorPinS1 = A0; // CMS connected to analog pin A0
const int sensorPinS2 = A1; // CMS connected to analog pin A1
const int humedadAireS1 = 700;
const int humedadAguaS1 = 470;
const int humedadAireS2 = 700;
const int humedadAguaS2 = 500;
long unsigned diffTime;


GyverOLED<SSH1106_128x64, OLED_BUFFER> oled;

void setup() {
  pinMode(4, OUTPUT); //Relay 1, pump 1
  pinMode(7, OUTPUT); //Relay 2, pump 2
  digitalWrite(4, HIGH); //Relay 1 Off
  digitalWrite(7, HIGH); //Relay 2 Off
  Serial.begin(9600);
  oled.init();
  oled.clear();
  oled.setCursor(0, 0);
  oled.setScale(3);
  oled.print("P1");
  oled.setCursor(0, 5);
  oled.setScale(3);
  oled.print("P2");
  oled.fastLineH(31, 0, 128);
  oled.update();
}

void waterPump1() {
  int porcentajeHumedadS1;
  do {
    int humedadS1 = analogRead(sensorPinS1);
    porcentajeHumedadS1 = map(humedadS1, humedadAireS1, humedadAguaS1, 0, 100);
    if (porcentajeHumedadS1 > 100) porcentajeHumedadS1 = 100;
    Serial.print("Lectura analógica Sensor P1: ");
    Serial.println(humedadS1);
    Serial.print("Porcentaje humedad P1: ");
    Serial.print(porcentajeHumedadS1);
    Serial.println("%");
    oled.setScale(1);
    oled.setCursor(40, 0);
    oled.print("Sensor: ");
    oled.print(humedadS1);
    oled.setCursor(40, 1);   //
    oled.print("Humedad: ");
    oled.print(porcentajeHumedadS1);
    oled.print("%");
    oled.setScale(1);
    oled.setCursor(40, 2);
    oled.print("Regando...");
    oled.setCursor(100, 2);
    oled.print(porcentajeHumedadS1);
    oled.update();
    digitalWrite(4, LOW);
  } while (porcentajeHumedadS1 <= 80);
  digitalWrite(4, HIGH);
  Serial.println("Fin regado P1");
  oled.setCursor(40, 2);
  oled.print("Fin de regado");
  oled.update();
  return;
}


void waterPump2() {
  int porcentajeHumedadS2;
  do {
    int humedadS2 = analogRead(sensorPinS2);
    porcentajeHumedadS2 = map(humedadS2, humedadAireS2, humedadAguaS2, 0, 100);
    if (porcentajeHumedadS2 > 100) porcentajeHumedadS2 = 100;
    Serial.print("Lectura analógica P2: ");
    Serial.println(humedadS2);
    Serial.print("Porcentaje humedad P2: ");
    Serial.print(porcentajeHumedadS2);
    Serial.println("%");
    oled.setScale(1);
    oled.setCursor(40, 5);   //
    oled.print("Sensor: ");
    oled.print(humedadS2);
    oled.setCursor(40, 6);   //
    oled.print("Humedad: ");
    oled.print(porcentajeHumedadS2);
    oled.print("%");
    oled.setScale(1);
    oled.setCursor(40, 7);
    oled.print("Regando...");
    oled.setCursor(100, 7);
    oled.print(porcentajeHumedadS2);
    oled.update();
    digitalWrite(7, LOW);
    delay(6000);
    Serial.println("Fin regado P2");
    oled.setCursor(40, 7);
    oled.print("Fin de regado");
    oled.update();
  } while (porcentajeHumedadS2 <= 80);
  digitalWrite(7, HIGH);
  Serial.println("Fin regado P2");
  oled.setCursor(40, 7);
  oled.print("Fin de regado");
  oled.update();
  return;
}

void loop() {
  int humedadS1 = analogRead(sensorPinS1);
  int porcentajeHumedadS1 = map(humedadS1, humedadAireS1, humedadAguaS1, 0, 100);
  if (porcentajeHumedadS1 > 100) porcentajeHumedadS1 = 100;
  Serial.print("loop Lectura analógica Sensor P1: ");
  Serial.println(humedadS1);
  Serial.print("loop Porcentaje humedad P1: ");
  Serial.print(porcentajeHumedadS1);
  Serial.println("%");
  oled.setCursor(0, 0);
  oled.setScale(3);
  oled.print("P1");
  oled.setScale(1);
  oled.setCursor(40, 0);   //
  oled.print("Sensor: ");
  oled.print(humedadS1);
  oled.setCursor(40, 1);   //
  oled.print("Humedad: ");
  oled.print(porcentajeHumedadS1);
  oled.print("%");
  oled.setCursor(40, 2);
  oled.print("OK");
  oled.update();
  
  if (porcentajeHumedadS1 < 35) {
  oled.setCursor(40, 2);
  oled.print("Water");
  oled.update();
    //waterPump1();
  }


  //End of sensor 1

  //Start sensor 2
  int humedadS2 = analogRead(sensorPinS2);
  int porcentajeHumedadS2 = map(humedadS2, humedadAireS2, humedadAguaS2, 0, 100);
  if (porcentajeHumedadS2 > 100) porcentajeHumedadS2 = 100;
  Serial.print("loop Lectura analógica Sensor P2: ");
  Serial.println(humedadS1);
  Serial.print("loop Porcentaje humedad P2: ");
  Serial.print(porcentajeHumedadS2);
  Serial.println("%");
  oled.setScale(1);
  oled.setCursor(40, 5);   //
  oled.print("Sensor: ");
  oled.print(humedadS2);
  oled.setCursor(40, 6);   //
  oled.print("Humedad: ");
  oled.print(porcentajeHumedadS2);
  oled.print("%");
  oled.setCursor(40, 7);
  oled.print("OK");
  oled.update();
  
  if (porcentajeHumedadS2 < 35) {
   oled.setCursor(40, 7);
  oled.print("Water");
  oled.update();
    //waterPump2();
  }
  
  Serial.println();
  delay(1500);
}

a lot of repetitive code

a basic regulator does something above one threshold and something else below another threshold.

    int humedadS1 = analogRead (sensorPinS1);
    int porcentajeHumedadS1 = map(humedadS1, humedadAireS1, humedadAguaS1, 0, 100);
    if (porcentajeHumedadS2 > ThreshUpper)
        turnPumpOff ();
    else if (porcentajeHumedadS2 < 35)
        turnPumpOn ();

try making that work for one input and without oled

Hi, @shagrath001
You would be better to write your code in stages.

I would forget your full code for the moment and write code that JUST controls your pump with some serial monitor serial.print statements to show you what is happening.

Can we please have a circuit diagram?
An image of a hand drawn schematic will be fine, include ALL power supplies, component names and pin labels.

We need to see how you have your hardaware connected.
What are you using for moisture sensors?
Can you please post a link to specs/data of the moisture sensors?

Thanks.. Tom... :smiley: :+1: :coffee: :australia:

1 Like

You are using blocking delays and while loops. These are sub optimal in most situations and can prevent your code being responsive. Look at millis timing but, as above, I would simplify things until you get the basics working and combine code once that is done

This is the diagram

Materials used:

as you suggested, I simplified the code like this. Haven't tried it yet as plants have enough water, do you think it could work as expected?

// Sensor pins
const int sensorPinS1 = A0; // CMS connected to analog pin A0
const int airOne = 700;
const int humOne = 470;

void setup() {
  pinMode(4, OUTPUT); //Relay 1, pump 1
  digitalWrite(4, HIGH); //Relay 1 Off
  Serial.begin(9600);
}

void waterPumpOne() {
  int hOne;
  do {
    int sOne = analogRead(sensorPinS1);
    hOne = map(sOne, airOne, humOne, 0, 100);
    if (hOne > 100) hOne = 100;
    Serial.print("Do Analog read Sensor 1: ");
    Serial.println(sOne);
    Serial.print("Do Humidity sensor 1: ");
    Serial.print(hOne);
    Serial.println("%");
    digitalWrite(4, LOW);
  } while (hOne <= 80);
  digitalWrite(4, HIGH);
  Serial.println("End Watering Sensor One");
  delay(5000);
}

void loop() {
  int sensorOne = analogRead(sensorPinS1);
  int humSensorOne = map(sensorOne, airOne, humOne, 0, 100);
  if (humSensorOne > 100) humSensorOne = 100;
  Serial.print("loop analog sensor 1: ");
  Serial.println(sensorOne);
  Serial.print("loop humidity sensor 1: ");
  Serial.print(humSensorOne);
  Serial.println("%");
  if (humSensorOne >= 20) {
    Serial.println("OK");
  } else if (humSensorOne < 20) {
    waterPumpOne();
  }
  //End of sensor 1
  Serial.println();
  delay(5000);
}

this isn't what i suggested. i suggested checking for an upper and lower threshold and simply turning the pump on/off when those thresholds are crossed

your logic is to call waterPumpOne() when the humidity is below a lower threshold is crossed and waterPumpOne() doesn't return until an upper threshold is crossed. it presumably shuts the pump off when it exits

there is no delay within waterPumpOne() until it exits which means it is very quickly repeatedly checking if the value exceeds the upper threshold.

the delay in loop() means it only checks the lower threshold every 5 sec.

consider

// plant water program
#undef MyHW
#ifdef MyHW
const int sensorPinS1 = A0;
const int pumpPin     = LED_BUILTIN;

const int airOne = 500;
const int humOne = 470;

#else
const int sensorPinS1 = A0; // CMS connected to analog pin A0
const int pumpPin     = 4;

const int airOne = 700;
const int humOne = 470;
#endif

const int threshLow = 20;
const int threshHi  = 80;

enum { Off = HIGH, On = LOW };

char s[80];

// -----------------------------------------------------------------------------
void
checkSensor (
    int  sensorPin,
    int  pumpPin )
{
    int sensorOne = analogRead(sensorPin);
    int humSensorOne = map(sensorOne, airOne, humOne, 0, 100);

    sprintf (s, " sensor [%d] %4d, humidity %3d%%",
        sensorPin, sensorOne, humSensorOne);
    Serial.println (s);

    if (humSensorOne < 20)  {
        sprintf (s, " pump [%d] On", pumpPin);
        Serial.println (s);
        digitalWrite(pumpPin, On);
    }
    else if (humSensorOne > 80)  {
        sprintf (s, " pump [%d] Off", pumpPin);
        Serial.println (s);
        digitalWrite(pumpPin, Off);
    }
}

// -----------------------------------------------------------------------------
void loop() {
    checkSensor (sensorPinS1, pumpPin);
    delay (1000);
}

// -----------------------------------------------------------------------------
void setup() {
    pinMode      (pumpPin, OUTPUT); //Relay 1, pump 1
    digitalWrite (pumpPin, Off); //Relay 1 Off
    Serial.begin(9600);
}

The OP may find that running the pump till the water is at a % may lead to over watering. It takes time for the water to travel through the dirt to the moisture sensor. What I do, instead is run the pump for X amount of time after low trigger point has been realized. Wait for 1 minute then test the moisture level, if too low run the pump for x amount of time and repeat till water is at or above the moisture level.

1 Like

make sense, turn the pump on periodically until satisfied, but seems the OP has a logic, rather than requirements issue

This will probably just muddy the water but this is how I do it,

void fDoMoistureDetector( 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 (;;)
  {
    //read AD values every 100mS.
    if ( (esp_timer_get_time() - TimeADreading) >= TimeForADreading )
    {
      xEventGroupSetBits( eg, evtADCreading );
      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 )
          {
            WaterPump0_on();
            log_i( "pump on " );
            pumpOn = !pumpOn;
            PumpOnTime = esp_timer_get_time();
          }
        }
        //xSemaphoreGive( sema_RemainingMoisture );
      } else {
        log_i( "water level bad " );
        WaterPump0_off();
        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 PumpRunTime seconds turn pump off
        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
    }
    xLastWakeTime = xTaskGetTickCount();
    vTaskDelayUntil( &xLastWakeTime, xFrequency );
  }
  vTaskDelete( NULL );
}// end fDoMoistureDetector()

Your Fritzing is unreadable. Please post something better.

Hi,
Can you please post a circuit diagram of your project, including power supplies, use a pen(cil) and paper and show an image of it would be fine.

A picture of your project would be great to, so we can see your component layout.

Thanks.. Tom... :smiley: :+1: :coffee: :australia:

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.