Help please adding code to Smart Plant Watering system

2nd topic. Following on from the very helpful assistance from @xfpd and @time_document_3108 to get my Elecrow Automatic Smart Plant Watering project working, I am now seeking help in adding some code to improve the system. The project is based around an Arduino Leonardo (UNO also mentioned in manual) 'Crowtail Smart Pump Shield'. Details on this wiki: Elecrow wiki

At present the system works by sensing moisture levels and triggering the pump on <30% and off >55%. This is fine if the water is pumped directly onto or very close to the sensor. If however the water is pumped away from the sensor it takes time for the water to migrate through the soil to the sensor. Thus the pump will be running continuously for this time and the plant will be massively over-watered.

What I would like to do is introduce a pump duration and delay element into the code. When triggered by the moisture sensor the pump should run for a specified time and then wait for a specified time before reading the sensor again. This loop would then cater for all placements of the sensor. In my case, I'm looking at installing this system in a greenhouse to water an irrigation tray. Water should be added remotely from the sensor to allow the capillary matting to absorb water uniformly.

I'm aware that delay code stops the entire program, so need a different way of timing the pump rest period as the system needs to loop round the 4 independent sensor/pump combos. I've read up on the 'blink without delay' workaround, but will need help implementing something like this.

There appears to be redundant code in the project at present, with references to days of the week and RTC timing, but with no way of controlling these that I have discovered. There is also redundant code from when the developers used resistive sensors rather than capacitive.

Any help writing this code or pointing me towards useful help would be much appreciated. I did offer feedback and request assistance from Elecrow customer services and, while they were very grateful for my ideas (don't zip inside zip inside zip...!), they were unable to offer assistance with development of the code. It should be clear from what I've written that I don't really know what I'm talking about! I'm brand new to Arduino and code, though understand MS Excel programming. Please be gentle and give simple instructions! Thank you!

As we discovered in my earlier topic, the code is well hidden inside multiple zip files, so here is the fully unpacked and working code, once Arduino library versions of U8glib and RTC are installed:

#include <U8glib.h>
U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_NONE);    // I2C
#include "RTClib.h"
RTC_DS1307 RTC;


// set all moisture sensors PIN ID
int moisture1 = A0;
int moisture2 = A1;
int moisture3 = A2;
int moisture4 = A3;


// declare moisture values
int moisture1_value = 0 ;
int moisture2_value = 0;
int moisture3_value = 0;
int moisture4_value = 0;


// set water relays
int relay1 = 6;
int relay2 = 8;
int relay3 = 9;
int relay4 = 10;


// set water pump
int pump = 4;


// set button
int button = 12;


//pump state    1:open   0:close
int pump_state_flag = 0;


//relay1 state    1:open   0:close
int relay1_state_flag = 0;


//relay2 state   1:open   0:close
int relay2_state_flag = 0;


//relay3 state  1:open   0:close
int relay3_state_flag = 0;


//relay4 state   1:open   0:close
int relay4_state_flag = 0;


static unsigned long currentMillis_send = 0;
static unsigned long  Lasttime_send = 0;


char daysOfTheWeek[7][12] = {"Sun", "Mon", "Tues", "Wed", "Thur", "Fri", "Sat",};
unsigned long nowtime;
unsigned long endtime;
unsigned long nowtimeNext;
unsigned long nowtime1;
unsigned long endtime1;
unsigned long nowtimeNext1;
unsigned long nowtime2;
unsigned long endtime2;
unsigned long nowtimeNext2;
unsigned long nowtime3;
unsigned long endtime3;
unsigned long nowtimeNext3;




// good flower
unsigned char bitmap_good[] U8G_PROGMEM = {


  0x00, 0x42, 0x4C, 0x00, 0x00, 0xE6, 0x6E, 0x00, 0x00, 0xAE, 0x7B, 0x00, 0x00, 0x3A, 0x51, 0x00,
  0x00, 0x12, 0x40, 0x00, 0x00, 0x02, 0x40, 0x00, 0x00, 0x06, 0x40, 0x00, 0x00, 0x06, 0x40, 0x00,
  0x00, 0x04, 0x60, 0x00, 0x00, 0x0C, 0x20, 0x00, 0x00, 0x08, 0x30, 0x00, 0x00, 0x18, 0x18, 0x00,
  0x00, 0xE0, 0x0F, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00,
  0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0xC1, 0x00, 0x00, 0x0E, 0x61, 0x00,
  0x00, 0x1C, 0x79, 0x00, 0x00, 0x34, 0x29, 0x00, 0x00, 0x28, 0x35, 0x00, 0x00, 0x48, 0x17, 0x00,
  0x00, 0xD8, 0x1B, 0x00, 0x00, 0x90, 0x1B, 0x00, 0x00, 0xB0, 0x09, 0x00, 0x00, 0xA0, 0x05, 0x00,
  0x00, 0xE0, 0x07, 0x00, 0x00, 0xC0, 0x03, 0x00
};


// bad flower
unsigned char bitmap_bad[] U8G_PROGMEM = {
  0x00, 0x80, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xE0, 0x0D, 0x00, 0x00, 0xA0, 0x0F, 0x00,
  0x00, 0x20, 0x69, 0x00, 0x00, 0x10, 0x78, 0x02, 0x00, 0x10, 0xC0, 0x03, 0x00, 0x10, 0xC0, 0x03,
  0x00, 0x10, 0x00, 0x01, 0x00, 0x10, 0x80, 0x00, 0x00, 0x10, 0xC0, 0x00, 0x00, 0x30, 0x60, 0x00,
  0x00, 0x60, 0x30, 0x00, 0x00, 0xC0, 0x1F, 0x00, 0x00, 0x60, 0x07, 0x00, 0x00, 0x60, 0x00, 0x00,
  0x00, 0x60, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
  0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xC7, 0x1C, 0x00,
  0x80, 0x68, 0x66, 0x00, 0xC0, 0x33, 0x7B, 0x00, 0x40, 0xB6, 0x4D, 0x00, 0x00, 0xE8, 0x06, 0x00,
  0x00, 0xF0, 0x03, 0x00, 0x00, 0xE0, 0x00, 0x00
};


// Elecrow Logo
  static unsigned char bitmap_logo[] U8G_PROGMEM ={
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0xE0,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x04,0xF8,0xFF,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x08,0xFE,0xFF,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x10,0x1F,0xE0,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0xB0,0x07,0x80,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0xE0,0x03,0x00,0x3F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0xC0,0x00,0x00,0x3E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x80,0x01,0x00,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x60,0x23,0x00,0x7C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x70,0xC7,0x00,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x70,0x9E,0x0F,0x7F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x70,0x3C,0xFE,0x7F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x70,0x78,0xF8,0x7F,0xF0,0x9F,0x07,0xFE,0x83,0x0F,0xFF,0x00,0x77,0x3C,0x18,0x1C,
  0x70,0xF0,0xE1,0x3F,0xF1,0x9F,0x07,0xFE,0xE1,0x1F,0xFF,0xC3,0xF7,0x3C,0x38,0x0C,
  0x70,0xE0,0x87,0x8F,0xF1,0xC0,0x07,0x1E,0x70,0x3C,0xCF,0xE3,0xE1,0x7D,0x3C,0x0E,
  0x70,0xD0,0x1F,0xC0,0xF1,0xC0,0x03,0x1F,0x78,0x3C,0xCF,0xE3,0xE1,0x7D,0x3C,0x06,
  0xF0,0xB0,0xFF,0xF1,0xF0,0xC0,0x03,0x0F,0x78,0x3C,0xCF,0xF3,0xE0,0x7B,0x3E,0x06,
  0xF0,0x60,0xFF,0xFF,0xF0,0xC6,0x03,0xEF,0x3C,0x80,0xEF,0xF1,0xE0,0x7B,0x3E,0x03,
  0xF0,0xE1,0xFC,0xFF,0xF8,0xCF,0x03,0xFF,0x3C,0x80,0xFF,0xF0,0xE0,0x7B,0x7B,0x01,
  0xE0,0xC3,0xF9,0x7F,0x78,0xC0,0x03,0x0F,0x3C,0x80,0xF7,0xF1,0xE0,0xF9,0xF9,0x01,
  0xE0,0x83,0xE3,0x7F,0x78,0xE0,0x03,0x0F,0x3C,0xBC,0xE7,0xF1,0xE0,0xF9,0xF9,0x00,
  0xC0,0x0F,0x8F,0x3F,0x78,0xE0,0x81,0x0F,0x3C,0x9E,0xE7,0xF1,0xE0,0xF1,0xF8,0x00,
  0x80,0x3F,0x1E,0x00,0x78,0xE0,0x81,0x07,0x38,0x9E,0xE7,0xF1,0xF0,0xF0,0x78,0x00,
  0x80,0xFF,0xFF,0x00,0xF8,0xEF,0xBF,0xFF,0xF8,0xCF,0xE7,0xE1,0x7F,0x70,0x70,0x00,
  0x00,0xFF,0xFF,0x0F,0xF8,0xEF,0xBF,0xFF,0xE0,0xC3,0xE3,0x81,0x1F,0x70,0x30,0x00,
  0x00,0xFC,0xFF,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0xF8,0xFF,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0xE0,0x7F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
  };




static unsigned char bitmap_T[] U8G_PROGMEM = {
  0xF7, 0x01, 0x1D, 0x03, 0x0B, 0x02, 0x0C, 0x02, 0x0C, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x08, 0x02,
  0x18, 0x03, 0xF0, 0x01
};


static unsigned char bitmap_H[] U8G_PROGMEM = {
  0x00, 0x00, 0x80, 0x01, 0xC0, 0x03, 0xE0, 0x07, 0xF0, 0x0F, 0xF8, 0x1F, 0xF8, 0x1F, 0xFC, 0x3F,
  0xFC, 0x3F, 0xFE, 0x7F, 0xEE, 0x7F, 0xB3, 0xF7, 0xBB, 0xFB, 0xBB, 0xFD, 0xBB, 0xFD, 0xC7, 0xFE,
  0x7F, 0xC3, 0x3F, 0xDD, 0xBF, 0xFD, 0xDF, 0xDD, 0xEE, 0x5B, 0xFE, 0x7F, 0xFC, 0x3F, 0xF8, 0x1F,
  0xE0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};




void setup()
{
  draw_elecrow();
 delay(2000);
  Wire.begin();
  RTC.begin();
  Serial.begin(9600);
  // declare relay as output
  pinMode(relay1, OUTPUT);
  pinMode(relay2, OUTPUT);
  pinMode(relay3, OUTPUT);
  pinMode(relay4, OUTPUT);
  // declare pump as output
  pinMode(pump, OUTPUT);
  // declare switch as input
  pinMode(button, INPUT);
  //pinMode(ROTARY_ANGLE_SENSOR, INPUT);
  // water_flower();
}


void loop()
{
  // read the value from the moisture sensors:
  read_value();
  water_flower();
  int button_state = digitalRead(button);
  if (button_state == 1)
  {
    read_value();
    u8g.firstPage();
    do
    {
      drawTH();
      drawflower();
     
    } while ( u8g.nextPage() );
  }
  else
  {
    u8g.firstPage();
    do
    {
      drawtime();
      u8g.drawStr(8, 55 , "www.elecrow.com");
    } while (u8g.nextPage());
  }
}


//Set moisture value
void read_value()
{
/**************These is for resistor moisture sensor***********
 float value1 = analogRead(A0);
  moisture1_value = (value1 * 120) / 1023; delay(20);
  float value2 = analogRead(A1);
  moisture2_value = (value2 * 120) / 1023; delay(20);
  float value3 = analogRead(A2);
  moisture3_value = (value3 * 120) / 1023; delay(20);
  float value4 = analogRead(A3);
  moisture4_value = (value4 * 120) / 1023; delay(20);
 **********************************************************/
/************These is for capacity moisture sensor*********/
 float value1 = analogRead(A0);
  moisture1_value =map(value1,590,360,0,100); delay(20);
  if(moisture1_value<0){
    moisture1_value=0;
  }
  float value2 = analogRead(A1);
  moisture2_value =map(value2,600,360,0,100); delay(20);
  if(moisture2_value<0) {
    moisture2_value=0;
  }
  float value3 = analogRead(A2);
  moisture3_value =map(value3,600,360,0,100); delay(20);
  if(moisture3_value<0){
    moisture3_value=0;
  }
  float value4 = analogRead(A3);
  moisture4_value =map(value4,600,360,0,100); delay(20);
  if(moisture4_value<0) {
    moisture4_value=0;
  }
}


void water_flower()
{
  if (moisture1_value < 30)
  {
    digitalWrite(relay1, HIGH);
    relay1_state_flag = 1;
    delay(50);
    if (pump_state_flag == 0)
    {
      digitalWrite(pump, HIGH);
      pump_state_flag = 1;
      delay(50);
    }
  }
  else if (moisture1_value > 55)
  {
    digitalWrite(relay1, LOW);
    relay1_state_flag = 0;
    delay(50);
    if ((relay1_state_flag == 0) && (relay2_state_flag == 0) && (relay3_state_flag == 0) && (relay4_state_flag == 0))
    {
      digitalWrite(pump, LOW);
      pump_state_flag = 0;
      delay(50);
    }
  }


  if (moisture2_value < 30)
  {
    digitalWrite(relay2, HIGH);
    relay2_state_flag = 1;
    delay(50);
    if (pump_state_flag == 0)
    {
      digitalWrite(pump, HIGH);
      pump_state_flag = 1;
      delay(50);
    }
  }
  else if (moisture2_value > 55)
  {
    digitalWrite(relay2, LOW);
    relay2_state_flag = 0;
    delay(50);
    if ((relay1_state_flag == 0) && (relay2_state_flag == 0) && (relay3_state_flag == 0) && (relay4_state_flag == 0))
    {
      digitalWrite(pump, LOW);
      pump_state_flag = 0;
      delay(50);
    }
  }


  if (moisture3_value < 30)
  {
    digitalWrite(relay3, HIGH);
    relay3_state_flag = 1;
    delay(50);
    if (pump_state_flag == 0)
    {
      digitalWrite(pump, HIGH);
      pump_state_flag = 1;
      delay(50);
    }
  }
  else if (moisture3_value > 55)
  {
    digitalWrite(relay3, LOW);
    relay3_state_flag = 0;
    delay(50);
    if ((relay1_state_flag == 0) && (relay2_state_flag == 0) && (relay3_state_flag == 0) && (relay4_state_flag == 0))
    {
      digitalWrite(pump, LOW);
      pump_state_flag = 0;
      delay(50);
    }
  }


  if (moisture4_value < 30)
  {
    digitalWrite(relay4, HIGH);
    relay4_state_flag = 1;
    delay(50);
    if (pump_state_flag == 0)
    {
      digitalWrite(pump, HIGH);
      pump_state_flag = 1;
      delay(50);
    }
  }
  else if (moisture4_value > 55)
  {
    digitalWrite(relay4, LOW);
    relay4_state_flag = 0;
    delay(50);
    if ((relay1_state_flag == 0) && (relay2_state_flag == 0) && (relay3_state_flag == 0) && (relay4_state_flag == 0))
    {
      digitalWrite(pump, LOW);
      pump_state_flag = 0;
      delay(50);
    }
  }


}






  void draw_elecrow(void){


  u8g.setFont(u8g_font_gdr9r);
  u8g.drawStr(8,55 , "www.elecrow.com");
  u8g.drawXBMP(0, 5,128,32, bitmap_logo);
  }




void drawtime(void)
{
  int x = 5;
  float i = 25.00;
  float j = 54;
  DateTime now = RTC.now();
  //Serial.print(now.year(), DEC);
  if (! RTC.isrunning())
  {
    u8g.setFont(u8g_font_6x10);
    u8g.setPrintPos(5, 20);
    u8g.print("RTC is NOT running!");
    RTC.adjust(DateTime(__DATE__, __TIME__));
  }
  else
  {
    u8g.setFont(u8g_font_7x13);
    u8g.setPrintPos(x, 11);
    u8g.print(now.year(), DEC);
    u8g.setPrintPos(x + 80, 11);
    u8g.print(daysOfTheWeek[now.dayOfTheWeek()]);
    u8g.setPrintPos(x + 28, 11);
    u8g.print("/");
    u8g.setPrintPos(x + 33, 11);
    u8g.print(now.month(), DEC);
    if (now.month() < 10)
      x -= 7;
    u8g.setPrintPos(x + 47, 11);
    u8g.print("/");
    u8g.setPrintPos(x + 53, 11);
    u8g.print(now.day(), DEC);
    u8g.setFont(u8g_font_8x13);
    int x = 35;
    u8g.setPrintPos(x, 33);
    u8g.print(now.hour(), DEC);
    if (now.hour() < 10)
      x -= 7;
    u8g.setPrintPos(x + 15, 33);
    u8g.print(":");
    u8g.setPrintPos(x + 21, 33);
    u8g.print(now.minute(), DEC);
    if (now.minute() < 10)
      x -= 7;
    u8g.setPrintPos(x + 36, 33);
    u8g.print(":");
    u8g.setPrintPos(x + 42, 33);
    u8g.print(now.second(), DEC);
  }
}


void drawLogo(uint8_t d)
{
  u8g.setFont(u8g_font_gdr25r);
  u8g.drawStr(8 + d, 30 + d, "E");
  u8g.setFont(u8g_font_gdr25r);
  u8g.drawStr(30 + d, 30 + d, "l");
  u8g.setFont(u8g_font_gdr25r);
  u8g.drawStr(40 + d, 30 + d, "e");
  u8g.setFont(u8g_font_gdr25r);
  u8g.drawStr(55 + d, 30 + d, "c");
  u8g.setFont(u8g_font_gdr25r);
  u8g.drawStr(70 + d, 30 + d, "r");
  u8g.setFont(u8g_font_gdr25r);
  u8g.drawStr(85 + d, 30 + d, "o");
  u8g.setFont(u8g_font_gdr25r);
  u8g.drawStr(100 + d, 30 + d, "w");
}




//Style the flowers     bitmap_bad: bad flowers     bitmap_good:good  flowers
void drawflower(void)
{
  if (moisture1_value < 30)
  {
    u8g.drawXBMP(0, 0, 32, 30, bitmap_bad);
  }
  else
  {
    u8g.drawXBMP(0, 0, 32, 30, bitmap_good);
  }
  if (moisture2_value < 30)
  {
    u8g.drawXBMP(32, 0, 32, 30, bitmap_bad);
  }
  else
  {
    u8g.drawXBMP(32, 0, 32, 30, bitmap_good);
  }
  if (moisture3_value < 30)
  {
    u8g.drawXBMP(64, 0, 32, 30, bitmap_bad);
  }
  else
  {
    u8g.drawXBMP(64, 0, 32, 30, bitmap_good);
  }
  if (moisture4_value < 30)
  {
    u8g.drawXBMP(96, 0, 32, 30, bitmap_bad);
  }
  else
  {
    u8g.drawXBMP(96, 0, 32, 30, bitmap_good);
  }


}




void drawTH(void)
{
  int A = 0;
  int B = 0;
  int C = 64;
  int D = 96;
  char moisture1_value_temp[5] = {0};
  char moisture2_value_temp[5] = {0};
  char moisture3_value_temp[5] = {0};
  char moisture4_value_temp[5] = {0};
  read_value();
  itoa(moisture1_value, moisture1_value_temp, 10);
  itoa(moisture2_value, moisture2_value_temp, 10);
  itoa(moisture3_value, moisture3_value_temp, 10);
  itoa(moisture4_value, moisture4_value_temp, 10);
  u8g.setFont(u8g_font_7x14);
  u8g.setPrintPos(9, 60);
  u8g.print("A0");
  if (moisture1_value < 10)
  {
    //u8g.setPrintPos(A + 14, 45 );
    u8g.drawStr(A + 14, 45, moisture1_value_temp);
    delay(20);
    u8g.drawStr(A + 14, 45, moisture1_value_temp);
   
  }
  else if (moisture1_value < 100)
  {
    //u8g.setPrintPos(A + 7, 45);
    u8g.drawStr(A + 7, 45, moisture1_value_temp);
    delay(20);
    u8g.drawStr(A + 7, 45, moisture1_value_temp);
   
  }
  else
  {
    //u8g.setPrintPos(A + 2, 45 );
    moisture1_value = 100;
    itoa(moisture1_value, moisture1_value_temp, 10);
    u8g.drawStr(A + 2, 45, moisture1_value_temp);
  }
  //u8g.print(moisture1_value);
  u8g.setPrintPos(A + 23, 45 );
  u8g.print("%");
  u8g.setPrintPos(41, 60 );
  u8g.print("A1");
  if (moisture2_value < 10)
  {
    //u8g.setPrintPos(B + 46, 45 );
    u8g.drawStr(B + 46, 45, moisture2_value_temp);
    delay(20);
    u8g.drawStr(B + 46, 45, moisture2_value_temp);
  }
  else if (moisture2_value < 100)
  {
    //u8g.setPrintPos(B + 39, 45);
    u8g.drawStr(B + 39, 45, moisture2_value_temp);
    delay(20);
    u8g.drawStr(B + 39, 45, moisture2_value_temp);
  }
  else
  {
    //u8g.setPrintPos(B + 32, 45);
    moisture2_value = 100;
    itoa(moisture2_value, moisture2_value_temp, 10);
    u8g.drawStr(B + 32, 45, moisture2_value_temp);
  }
  // u8g.print(moisture2_value);
  u8g.setPrintPos(B + 54, 45);
  u8g.print("%");
  u8g.setPrintPos(73, 60);
  u8g.print("A2");
  if (moisture3_value < 10)
  {
    //u8g.setPrintPos(C + 14, 45 );
    u8g.drawStr(C + 14, 45, moisture3_value_temp);
    delay(20);
    u8g.drawStr(C + 14, 45, moisture3_value_temp);
   
  }
  else if (moisture3_value < 100)
  {
    // u8g.setPrintPos(C + 7, 45);
   u8g.drawStr(C + 7, 45, moisture3_value_temp);
    delay(20);
    u8g.drawStr(C + 7, 45, moisture3_value_temp);
   
  }
  else
  {
    // u8g.setPrintPos(C + 2, 45);
    moisture3_value = 100;
    itoa(moisture3_value, moisture3_value_temp, 10);
    u8g.drawStr(C + 2, 45, moisture3_value_temp);
  }
  //u8g.print(moisture3_value);
  u8g.setPrintPos(C + 23, 45);
  u8g.print("%");
  u8g.setPrintPos(105, 60);
  u8g.print("A3");
  if (moisture4_value < 10)
  {
    //u8g.setPrintPos(D + 14, 45 );
    u8g.drawStr(D + 14, 45, moisture4_value_temp);
    delay(20);
    u8g.drawStr(D + 14, 45, moisture4_value_temp);
   
  }
  else if (moisture4_value < 100)
  {
    // u8g.setPrintPos(D + 7, 45);
    u8g.drawStr(D + 7, 45, moisture4_value_temp);
    delay(20);
    u8g.drawStr(D + 7, 45, moisture4_value_temp);
 
  }
  else
  {
    //u8g.setPrintPos(D + 2, 45);
    moisture4_value = 100;
    itoa(moisture4_value, moisture4_value_temp, 10);
    u8g.drawStr(D + 2, 45, moisture4_value_temp);
  }
  //u8g.print(moisture4_value);
  u8g.setPrintPos(D + 23, 45);
  u8g.print("%");
}




As a first step I would recommend improving the code you have now. Large parts of it are 4 times longer than they need to be because code is copied & pasted 4 times over for the 4 sensors/relays. Using arrays, you can significantly reduce the length of the code AND make it easier to change the timing as you want.

I have previously posted this video. The author demonstrates a project with two LEDs blinking simultaneously at different rates to show how two or more tasks can be made to run apparently at the same time without blocking delays using the millis() function. Its a step by step demonstration of the 'blink without delay' concept that you have already read about. What he does with the LED control functions can also be applied to the pump control functions to run them at intervals.

There is, of course, a lot more involved in reorganizing this project code but maybe this little demonstration will provide food for thought.

You haven't posted a schematic for your circuit, so we are left to read the code and use that to try to imagine what your circuit consists of. But you also mentioned there is much redundant code, so we might imagine your circuit is more complex than reality. Please help us so we can better help you.

Your code mentions 4 sensors and 4 relays and a pump. The pump appears to be controlled separately from the relays. But what are the relays for? Do they control solenoid valves? Do you even have them in your circuit? Do you plan to add them later? You mention only one sensor and the pump in your rather vague description.

instead of monitoring levels, maybe monitor the change in level.

consider shutting off the water when moisture senser begins increasing and is above some level lower than your target of 55

a PID-like algorithm that considers the delay and rate of increase may also be applicable

Apologies @PaulRB, I thought I had that covered by the link to the Elecrow wiki. What exactly do you mean by a 'schematic'? The wiki shows a photo of the components connected together which I found helpful when learning about this kit.

That's a brilliant video! Many thanks for sharing. It perfectly describes the issue I'm trying to solve and is really nicely explained for a new user like me.

Thanks @gcjr. That's an interesting idea and would certainly prevent the flood that waiting for the full 55% results in. However, it still relies on water getting to the sensor, which could take quite some time along a large irrigation tray. I'm not looking at something that needs an immediate response as the delay I have in mind could be days between waterings to allow hydration levels to stabilise. I'm hoping that my idea of a timed pump run followed by a timed wait would be simple to design and implement and would work in all user scenarios.

Break it down into manageable sections. Maybe use functions to make it easier to understand.

Yes, you are right about the watering taking time to uniformly dampen the growing compost, but ideally, you don't let that happen to the extent you have very dry and very wet areas.

The advice generally given with watering, is little and often, don't allow compost to dry out or get to the point of being so wet that water runs out, removing nutrients at the same time. Over-watering pretty rapidly leads to die-off with rot etc

These are all things that can be tweaked.

Temperature and humidity are going to be factors in how much watering you do.

of course.

the a priori solution is you just need to turn the pump on for a specific amount of time for a particular sensor. But wouldn't that timing being different for each sensor, wouldn't a there be a different amount of soil that needs to be replenished? (certainly a possibly solution)

just cycling the pump on/off has 2 factors: the delay and the rate of increase, and the worry is that it's been cycled too many times resulting in over watering.

maybe you need multiple sensors between the plant and water source to evaluate soil replenishmment

I'm only showing code snippets.

You have the RTC so why not use it.

int lastHour = -1;

void loop()
{
  DateTime now = RTC.now();
  // Check once an hour to see if we need water
  if ((now.minute() == 0) && (now.hour() != lastHour))
  {
    read_value();
    water_flower();
    lastHour = now.hour();
  }

Only water for one second if needed

void water_flower()
{
  if (moisture1_value < 30)
    flower1_needs_water = true;
  else if (moisture1_value > 55)
    flower1_needs_water = false;

  if (flower1_needs_water)
  {
    // Water for only 1 second
    digitalWrite(relay1, HIGH);
    digitalWrite(pump, HIGH);
    delay(1000);  // 1 second
    digitalWrite(pump, LOW);
    digitalWrite(relay1, LOW);
  }

So it will water the plants for one second once an hour until the sensor goes above 55 then it will stop. It won't start watering again until the sensor drops below 30

Good question! I am completely new to all this, so learning from you all as I go. But I did see that RTC was included and I installed it, but couldn't see it being used anywhere that showed up on the display.

Your ideas look great! I'll try to work through it and see how it could be incorporated into the existing code. I know, I should probably have started with a nice simple project and learned the coding progressively, but this is fun too, if probably frustrating for you!

If you have not yet set the time on the RTC, this explains how:

Unless you remove the battery, you only need to set he time once.

I agree. Turn the pump ON on Mondays at noon for one second, then turn it off.

So you are using all 4 sensors and relays/solenoid valves?

I would suggest a design that avoids opening more than one valve at a time. Opening 2, 3 or 4 valves together will probably reduce the flow to each plant watered because the more valves that are open, the lower the flow to each plant will be. That will make it difficult to estimate how much volume of water reach plant receives, and the flow probably won't be equal between them.

Instead, perhaps every 15 minutes, check one sensor and, if necessary, operate one valve. At the next 15 minute interval, check the next sensor in turn. That way, each sensor gets checked and each plant gets watered over the course of an hour, and only one valve is open at any time.

These two bitmaps are declared, but never used. They represent (T)emperature and (H)umidity. The first bitmap is only 20 bytes, so it is probably the "degree" symbol ( ° ), the second bitmap is only 56 bytes, so probably the percent symbol (%) or a teardrop. The code lines can be commented-out if you want to keep the bitmaps for later or deleted/replaced if you want to make your own bitmap.

// static unsigned char bitmap_T[] U8G_PROGMEM = { // 16 x 10 degreeC
//   0xF7, 0x01, 0x1D, 0x03, 0x0B, 0x02, 0x0C, 0x02, 0x0C, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x08, 0x02,
//   0x18, 0x03, 0xF0, 0x01
// };

// static unsigned char bitmap_H[] U8G_PROGMEM = { // 16 x 28 - tear shaped % sign
//   0x00, 0x00, 0x80, 0x01, 0xC0, 0x03, 0xE0, 0x07, 0xF0, 0x0F, 0xF8, 0x1F, 0xF8, 0x1F, 0xFC, 0x3F,
//   0xFC, 0x3F, 0xFE, 0x7F, 0xEE, 0x7F, 0xB3, 0xF7, 0xBB, 0xFB, 0xBB, 0xFD, 0xBB, 0xFD, 0xC7, 0xFE,
//   0x7F, 0xC3, 0x3F, 0xDD, 0xBF, 0xFD, 0xDF, 0xDD, 0xEE, 0x5B, 0xFE, 0x7F, 0xFC, 0x3F, 0xF8, 0x1F,
//   0xE0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
// };

Make your own XBM here: U8g2 Bitmap Converter and XBM Array Generator | Microcontroller Tutorials

Logo:
image
Bad flower:
bitmap-32x30
Good flower:
bitmap-32x30(1)
degreeC
degreeC16x10
percent
percent16x28

That's exactly what happened when I tested the system and withdrew all 4 sensors from their glasses of water; the system immediately spotted the reduction in moisture, fired up all 5 relays and opened all 4 solenoids - water trickled from each pipe. Your idea makes a lot of sense.

This is one of the many things I don't understand about the code; lots of bits of code that don't appear to be used. All I get on the screen are the moisture percentages and pictures of happy or sad plants. I've found, but trial and error, that pressing one of the buttons on the side of the module produces the date and approximate time above the Elecrow web address. Maybe there is the potential, if they don't currently exist, to fit temperature and humidity sensors that would bring that code to life?

That's what I would like to do, with each sensor and pump getting their go in succession, then waiting a day or so before doing it again. I just need to puzzle or how to incorporate that idea and the code already suggested into the existing code.

Hopefully you have now got the message that "dry-->pump on; wet-->pump off" doesn't work well and results in flooding. A better technique is to turn pump on for a short time (like 30s or a minute) when dry, then don't even read the sensor again for a long time (like an hour) before repeating the process.