1

Sorry if something similar has been answered before...

I am working on a garden timer project that runs on a ESP8266 based NodeMCU and is integrated with Blynk.

I have a waterNow function that activates when I press a button on the Blynk app, it sets pin D5 to HIGH and waits 3 seconds with a delay function, the problem is that with delay the code just halts all other functions until the delay is complete.

After doing some research I found out that the millis function could be used to have a time delay and have the program still run, but I can't get it to work.

How do use the millis function to add a delay?

Any help is appreciated.

Code:-

#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>
#include <NTPClient.h>
#include <WiFiUdp.h>
#include "DHT.h"
#include "LiquidCrystal_PCF8574.h"

#define BLYNK_PRINT Serial
#define DHT_PIN_DATA  12
// LCD definations
#define LCD_ADDRESS 0x27
#define LCD_ROWS 2
#define LCD_COLUMNS 16
#define SCROLL_DELAY 150
#define BACKLIGHT 25
#define DHTTYPE DHT22


char auth[] = "ymri204FL9_xZhf6WIRHtQ1qEWOt9zBy";


char ssid[] = "Aihertgtel-Hotspotgfdf-82DB";
char pass[] = "";
int autoSch;
int waterNow;
int morTime;
int afterTime;
int eveTime;
int schTime;
int x;

DHT dht(DHT_PIN_DATA, DHTTYPE);
LiquidCrystal_PCF8574 lcdI2C;
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "in.pool.ntp.org", 19800, 600000);
// This function will be called every time Slider Widget
// in Blynk app writes values to the Virtual Pin 1

BLYNK_CONNECTED() {
  Blynk.syncAll();
}

BLYNK_WRITE(V0)
{
  autoSch = param.asInt(); // assigning incoming value from pin V1 to a variable
}

BLYNK_WRITE(V1)
{
  morTime = param.asInt(); // assigning incoming value from pin V1 to a variable
}

BLYNK_WRITE(V2)
{
  afterTime = param.asInt(); // assigning incoming value from pin V1 to a variable
}

BLYNK_WRITE(V3)
{
  eveTime = param.asInt(); // assigning incoming value from pin V1 to a variable
}

BLYNK_WRITE(V10)
{
  waterNow = param.asInt(); // assigning incoming value from pin V1 to a variable
}

BLYNK_WRITE(V4)
{
  schTime = param.asInt(); // assigning incoming value from pin V1 to a variable
}

void time_run() {
  Blynk.virtualWrite(V11, int(timeClient.getHours()));
  Blynk.virtualWrite(V12, int(timeClient.getMinutes()));
  Blynk.virtualWrite(V13, float(dht.readTempC()));
  Blynk.virtualWrite(V14, float(dht.readHumidity()));
  Serial.println(dht.readTempC());
}


void auto_run1() {
  if (morTime == 1 && String(timeClient.getFormattedTime()) > "06:00:00" && String(timeClient.getFormattedTime()) < "06:20:00") {
    digitalWrite(14, HIGH);
    Blynk.virtualWrite(V5, 255);
    Blynk.syncAll();
  }
  else if (afterTime == 1 && String(timeClient.getFormattedTime()) > "12:00:00" && String(timeClient.getFormattedTime()) < "12:20:00") {
    digitalWrite(14, HIGH);
    Blynk.virtualWrite(V5, 255);
    Blynk.syncAll();
  }
  else if (eveTime == 1 && String(timeClient.getFormattedTime()) > "15:47:00" && String(timeClient.getFormattedTime()) < "13:48:00") {
   // digitalWrite(14, HIGH);
    for (x; x >  10; x++){
  digitalWrite(14, HIGH);
  delay(1000);
  }
    Blynk.virtualWrite(V5, 255);
    Blynk.syncAll();

  }
  else {
    digitalWrite(14, LOW);
    Blynk.virtualWrite(V5, 0);
    Blynk.syncAll();
  }
}

void sch_run2() {
  if (schTime == 1) {
    digitalWrite(14, HIGH);
    Blynk.virtualWrite(V5, 255);
    Blynk.syncAll();
  } else {
    digitalWrite(14, LOW);
    Blynk.virtualWrite(V5, 0);
  }

}

void waterNowrun() {
  if (waterNow == 1) {
    digitalWrite(14, HIGH);
    Blynk.virtualWrite(V5, 255);
    lcdI2C.selectLine(2);
    lcdI2C.print("Watering Now     ");
    delay(3000); // I want to remove this for millis
    Blynk.virtualWrite(V10, 0);
    Blynk.syncAll();
  } else {
    digitalWrite(14, LOW);
    Blynk.virtualWrite(V5, 0);
  }
}
void lcd() {
  delay(300);
  lcdI2C.clear();

  timeClient.update();
  lcdI2C.print(timeClient.getFormattedTime());

  if (autoSch == 0) {
    lcdI2C.setCursor(9, 0);
    lcdI2C.print("Auto");
  } else {
    lcdI2C.print(" Sch");
  }


  if (digitalRead(14) == 1) {
    lcdI2C.selectLine(2);
    lcdI2C.print("Watering Now");
  }
  else
  {

    if (int(timeClient.getHours()) < 6 && morTime == 1 && autoSch == 0) {
      Blynk.syncAll();

      lcdI2C.selectLine(2);
      lcdI2C.print("Auto Wtr at: 6");
    } else if (int(timeClient.getHours()) < 12 && afterTime == 1 && autoSch == 0) {
      Blynk.syncAll();

      lcdI2C.selectLine(2);
      lcdI2C.print("Auto Wtr at: 12");
    } else if (int(timeClient.getHours()) < 18 && eveTime == 1 && autoSch == 0) {
      Blynk.syncAll();
      lcdI2C.selectLine(2);

      lcdI2C.print("Auto Wtr at: 18");
    } else if (int(timeClient.getHours()) >= 18 && morTime == 1 && autoSch == 0) {
      Blynk.syncAll();
      lcdI2C.selectLine(2);


      lcdI2C.print("Auto Wtr at: 6");
    } else {
      Serial.println(timeClient.getHours());
    }

  }

}


void loop()
{
  Blynk.run();
  time_run();
  lcd();
  timeClient.update();

  if (waterNow == 1) {
    waterNowrun();
  }
  if (autoSch == 0) {
    auto_run1();

  } else {
    sch_run2();


  }




}
void setup()
{
  dht.begin();
  lcdI2C.begin(LCD_COLUMNS, LCD_ROWS, LCD_ADDRESS, BACKLIGHT);
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, HIGH);
  pinMode(14, OUTPUT);
  digitalWrite(14, LOW);
  pinMode(16, INPUT_PULLDOWN_16);

  Serial.begin(9600);
  //WiFi.begin(ssid, password);
  Blynk.begin(auth, ssid, pass);
  while ( WiFi.status() != WL_CONNECTED ) {
    delay ( 500 );
    Serial.print ( "." );
  }
  timeClient.begin();
}
6
  • This question comes up regularly. Look at the “Blink without delay” example included with the Arduino IDE to see how you can use millis() for non-blocking time delays and event scheduling.
    – StarCat
    Apr 29, 2021 at 7:31
  • I have already looked at that, can't make out anything... but will try again
    – Coder9390
    Apr 29, 2021 at 7:34
  • Short hint: You have to keep track of your state. So in the WaterNow function you have to store the millis() value to a variable when you start watering and then compare that value regularly with the current time to find out when the required amount has elapsed.
    – PMF
    Apr 29, 2021 at 7:51
  • Does this answer your question? How to use millis() in my code instead of delay()?
    – sa_leinad
    Apr 29, 2021 at 8:21

1 Answer 1

2

I am assuming after you start watering you want to set V10 to 0 after 3 seconds.

First, you will have to set waterNow to 0 after you start watring. Otherwise waterNowrun() will keep executing.

Second, you need to keep track of the 'watering' state so that you know that you have to start tracking the time.

Third, save the time when the watering started so that you can compare with the current time to see if your '3 seconds' has been passed.

Here is a simple example:

// Global variables
const long int MAX_TIME_THRESHOLD_MS = 3000;
bool WateringStarted = false;
long int WateringStartTime = 0;

... ... ...

void waterNowrun() 
{
  if (waterNow == 1) 
  {
    digitalWrite(14, HIGH);
    Blynk.virtualWrite(V5, 255);
    lcdI2C.selectLine(2);
    lcdI2C.print("Watering Now     ");
    
    waterNow = 0;
    WateringStarted = true;
    WateringStartTime = millis();

  } 
  else   // <------ Why do you even have else! You only call waterNowrun() when waterNow == 1
  {                   
    digitalWrite(14, LOW);
    Blynk.virtualWrite(V5, 0);
  }
}

... ... ...

void loop()
{
  ... ... ...
  
  if(WateringStarted && (millis() - WateringStartTime) > MAX_TIME_THRESHOLD_MS)
  {
    WateringStarted = false;
    Blynk.virtualWrite(V10, 0);
    Blynk.syncAll();
  }

  ... ... ...

}

I haven't run this code and don't have your setup to check it either. But it should give you some idea. Also, check the comments to your question for some more information about millis().

3
  • The setup is after the loop 😐
    – Coder9390
    Apr 29, 2021 at 9:58
  • Haha! I meant your actual hardware setup and Blynk app etc.
    – Fahad
    Apr 29, 2021 at 11:20
  • Oh ok..... I got it solved
    – Coder9390
    Apr 30, 2021 at 2:24

Not the answer you're looking for? Browse other questions tagged or ask your own question.