Control Structure and Function question

I wrote a function to hold a Dpin high for a predetermined number of seconds (millis()), but I know I'm not using the correct structures. The function is called using the timer library which is defined as "offTime". The onTime is also defined and performs a millis test, however, because the function is only called so often, the Dpin is being held high thee entire time before the compiler can acknowledge that the onTime has already lapsed.

That being said, I know that using IF is not what I need, but am too novice a coder to know how to proceed and is why I'm asking for assistance. I suspect I may want to use DO WHILE structure, but don't know for sure. What I need accomplished though is for the function to run until the time definition has been lapsed without the compiler needing to revisit the function to measure in intertvals of offTime.


// Fill-in information from your Blynk Template here
#define BLYNK_TEMPLATE_ID           "TMPLWzp-xxxx"
#define BLYNK_DEVICE_NAME           "Relays"

#define BLYNK_FIRMWARE_VERSION        "0.1.0"

#define BLYNK_PRINT Serial
//#define BLYNK_DEBUG

#define APP_DEBUG

// Uncomment your board, or configure a custom board in Settings.h
//#define USE_SPARKFUN_BLYNK_BOARD
#define USE_NODE_MCU_BOARD
//#define USE_WITTY_CLOUD_BOARD
//#define USE_WEMOS_D1_MINI
#include "BlynkEdgent.h"

WidgetTerminal terminal(V10);
BlynkTimer timer;

#define TURN_ON LOW // TURN_ON and TURN_OFF are defined to account for Active LOW relays
#define TURN_OFF HIGH  // Used to switch relay states for on/off of 120VAC~ devices 

 
#define feedRelay 4           //Digitial Pin on ESP board
#define ROrelay 5             //Digitial Pin on ESP board
#define RelayPin3 13          //Digitial Pin on ESP board
#define RelayPin4 12          //Digitial Pin on ESP board

//----- Feed Pump time
boolean fertTime = true;
long totalTime;
long startFeed = 0; 
long MINUTE = 60000;
long HOUR = MINUTE * 60;
long onTime = MINUTE * .25;    //on for half a minute
long offTime = MINUTE / 4;      //off for 2 hours

//------ RO pump increment of quarts
boolean runningRO = false;
int msPerQuart = 9735;  //ms per Quart (39.6 secs per gal)
int ROstart;            //Start of count
int countQuarts;        //Total Quarts from Blynk times msPerQuart

  int button;       //V0
  int ROpumpOn;     //V1
  int totalQuarts;  //V2
  int feedPumps;    //V3
  
BLYNK_WRITE(V0) { //Test red LED on ESP8266
  button = param.asInt();  
}
BLYNK_WRITE(V1) { //triggers the RO countdown
  ROpumpOn = param.asInt();  // ROpump remote
}
BLYNK_WRITE(V2) { //number of quarts ordered from app
  totalQuarts = param.asInt();  // ROpump remote
  Serial.print("BLYNK_WRITE(V2) triggered, totalQuarts = ");
  Serial.println(totalQuarts);
}
BLYNK_WRITE(V3) { //button to activate all feed pumps
  feedPumps = param.asInt();
} 
BLYNK_CONNECTED()
{
  Blynk.virtualWrite(V0, 0);      //button
  Blynk.virtualWrite(V1, 0);      //ROpump
  Blynk.virtualWrite(V2, 0);      //Number of Quarts
}

void ROcheck()  //RO Pump = 34 seconds on time per gallon
{
  Serial.println("Entered ROcheck function");

  Serial.print("ROpumpOn = ");
  Serial.println(ROpumpOn);
  
  Serial.print("runningRO = ");
  Serial.println(runningRO);

  Serial.print("millis() - ROstart = ");
  Serial.println(millis() - ROstart);

  Serial.print("countQuarts = ");
  Serial.println(countQuarts);

  Serial.print("runningRO = ");
  Serial.println(runningRO);
  
  Serial.println();
 
  if (ROpumpOn == 1 && runningRO == false)           // Activates when Blynk button is toggled
  {
    Serial.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>First IF statement");
    digitalWrite(ROrelay, TURN_ON);
    runningRO = true;
    ROstart = millis();
    countQuarts = msPerQuart * totalQuarts;        // Calculates length of runtime for pump
    terminal.print("Pumping:");
    terminal.print(totalQuarts);
    terminal.println(" Quarts of RO");
  }
  
  if (millis() - ROstart > countQuarts && runningRO == true)  //Ends runtime
  {
    ROpumpOn = 0;
    runningRO = false;
    countQuarts = 0;
    ROstart = 0;
    digitalWrite(ROrelay, TURN_OFF);
    Blynk.virtualWrite(V1, 0);    
    Blynk.virtualWrite(V2, 0);  
    Serial.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>Second IF Statement");
    Serial.println("Finished Pumping");
    Serial.println();   
    terminal.print("Finished Pumping:");
    terminal.print(totalQuarts);
    terminal.println(" Quarts of RO");
  }
  terminal.flush();
}
void feedTime() 
{
  if (fertTime == true) 
  {
    startFeed = millis();
    digitalWrite(feedRelay, TURN_ON);
    terminal.println("Fertilizing Plants");
    fertTime = false;
  }
    
  if (millis() - startFeed > onTime && fertTime == false) 
  {
    digitalWrite(feedRelay, TURN_OFF);
    terminal.println("Done Fertilizing Plants");
    fertTime = true;
  }
  terminal.flush();
}

void setup()
{
  Serial.begin(115200);
  delay(100);
  BlynkEdgent.begin();
  
  pinMode(feedRelay, OUTPUT);
  pinMode(ROrelay, OUTPUT);
  pinMode(RelayPin3, OUTPUT);
  pinMode(RelayPin4, OUTPUT);
  
  digitalWrite(feedRelay, TURN_OFF);
  digitalWrite(ROrelay, TURN_OFF);
  digitalWrite(RelayPin3, TURN_OFF);
  digitalWrite(RelayPin4, TURN_OFF);
  timer.setInterval(1000L, ROcheck);
  timer.setInterval(offTime, feedTime);
}

void loop() {
  BlynkEdgent.run();
  timer.run();
}

What is preventing it from being called more frequently ?

Please post a complete sketch illustrating the problem so that it can be seen in context

consider


const byte LedPin = LED_BUILTIN;
const byte ButPin = A1;
byte butState;

enum { Off = HIGH, On = LOW };

const unsigned long Cycle = 2000;
unsigned long msecLst;

// -----------------------------------------------------------------------------
void loop ()
{
    unsigned long msec = millis ();

    if (On == digitalRead (LedPin) && (msec - msecLst) > Cycle)  {
        digitalWrite (LedPin, Off);
    }

    byte but = digitalRead (ButPin);
    if (butState != but)  {
        butState = but;
        delay (10);     // debounce

        if (LOW == but)  {
            digitalWrite (LedPin, On);
            msecLst = msec;
        }
    }
}

// -----------------------------------------------------------------------------
void setup ()
{
    Serial.begin (9600);

    pinMode      (LedPin, OUTPUT);
    digitalWrite (LedPin, Off);

    pinMode (ButPin,     INPUT_PULLUP);
    butState = digitalRead (ButPin);
}

I should have done that to begin with. I've edited my original post and pasted the whole sketch there. The function is called as per the offTime which ultimately will be 2 or more hours. onTime will be roughly 30 seconds and the result will be feed pumps off for 2+ hours and on for 30secs, but for the sake of working out the kinks, I shortened both to 15 seconds.

  timer.setInterval(1000L, ROcheck);
  timer.setInterval(offTime, feedTime);

This looks odd. Which values do you want the timer to use ?

the ROcheck() function is called every second. The feedTime() function is called in accordance with long offTime defined above. I need help with just the feeedTime function.

I am not familiar with the library, but when the timer action is triggered how does the program know which function to call ?

Hello myggle
Post a timing diagram to show what shall happens by which conditions.
I guess a modified BWOD sketch and a small FSM will help to find a smart and proper solution.
Have a nice day and enjoy coding in C++.

p.s. Do you have to use the libary?

SimpleTimer and BlynkTimer both use millis to call functions.


  timer.setInterval(1000L, ROcheck);
  timer.setInterval(offTime, feedTime);

1000L is 1000 ms. the other function is called/ran once every interval defined as offTime which in practice will be hours, but now trying to figure out where I went wrong, I'll keep that short. But for the sketch to succeed, the ROcheck function needs to always be on alert and called every second which may later be shortened to 5 times per second if I need to. The other function however, I only need it to pull the Dpin high for a few seconds once every few hours, so my thought process was to use the offTime as the timer.interval and the onTime to be what's inside the block of code once the function is initiated. I'm certain I got the logic screwed up somehow, I just can't figure out how and my skills are too basic to figure it out at this time.

I pasted the whole sketch in the first post above. I'm using Blynk, and that library has an updated version of the Simple Timer library where the ST library allows for 12 setInterval function calls, and Blynk allows for 16. I'm only using 2 though. I have a 4 channel relay wired to an ESP8266, and am only intending to use 2 of the relays, and each of the 2 relays accounts for each of the 2 functions. The ROcheck function monitors the Blynk cloud for commands sent from my android Blynk app and does math to hold a Dpin high for the desired length of time.

The feedTime function is what I'm struggling with. It will be ran in accordance with "offTime", and once ran, it must hold the Dpin high for the length of "onTime". Both onTime and offTime are defined with the rest of definitions and variables. Both need to be independently sized to achieve the desired end goal of choosing the length of LOW and HIGH on the respective Dpin.

shouldn't "feedTime()" be the action to take when the "timer" interval expires? why does feedTime() check if millis() has exceeded "onTime", isn't that what timer.run() does?

sound like you're stating the obvious. that a timed pin activity will either turn on or off a pin after a timed period expires and the pin remains in some state during the entire period

but it looks like you may want to repeatedly toggle the pin ON after every "offTIme" and OFF after every "onTime". wouldn't you need two timed events that trigger one another in addition to toggling the pin?

I'm not entirely sure what I need b/c I'm too novice and lack knowledge/experience. I'm still learning what's all included in the Blynk/Simple Timer library, but all I know now is that the timer can be used to call the functions which has a Blink W/O Delay effect.

more or less. I want the pin held in the OFF state for the duration of offTime and on for onTime. Right now, those values are greatly shortened for debugging, but ultimately will be off for 2-3 hours and on for 30-60 seconds, but also I want that cycle repeated endlessly. As to the logic I'm using, it's just my best effort at mirroring the logic in the other function ROcheck. It's just a nowMillis minus thenMillis is less than onTime, which sounds basic enough, yet it still has me stumped. My approach is to only call the function once every offTime, but if it would be better to call the function every second and figure out the onTime/offTime difference in the code, that would be fine, I just can't imagine how that should look.

sounds like you want to develop a feed system that does several different things several times a day.

a real time clock would be a more accurate approach, but millis() could be used to learn.

but wouldn't it make more sense to have scheduled feed times through at the day, such as morning and evening rather that every "2-3" hrs?

if that's the case, i would create a table with each entry specifying a time and some action (e.g. turning some pin on/off). the entries in the table could be just a few seconds apart (e.g. on then off).

is this what you're trying to do?

Somebody on the Arduino Facebook group helped me out. This is exactly what I was fishing for. You're right, I needed feed times, but you're wrong in thinking I wanted varying times. RTC would be practical on an Arduino Mega, but I'm using an ESP, and with other types of growing styles, but my particular style uses perlite which dries out pretty quick, so needs to be re-watered frequently throughout the day which would be best suited for measured off periods followed by brief watering periods.

//----- Feed Pump time
boolean fertTime = true;
long startFeed; 
long oldTime;
long MINUTE = 60000;
long HOUR = MINUTE * 60;
long onTime = MINUTE / 2;    //on for half a minute
long offTime = HOUR * 2;      //off for 2 hours


void feedTime()
{
  if (fertTime == true && millis() - oldTime >= offTime)
    {
      startFeed = millis();
      digitalWrite(feedRelay, TURN_ON);
      fertTime = false;
    }
  if (millis() - startFeed >= onTime && fertTime == false)
    {
      digitalWrite(feedRelay, TURN_OFF);
      fertTime = true;
      oldTime = millis();
    }
}

The timer library can now call this function every quarter second and stay accurate to my presets. Thank you for your time and consideration though.

consider


const byte LedPin = LED_BUILTIN;
const byte ButPin = A1;
byte butState;

enum { Off = HIGH, On = LOW };

const unsigned long OnPeriod  = 1000;
const unsigned long OffPeriod = 3000;
unsigned long       period    = OffPeriod;
unsigned long msecLst;

// -----------------------------------------------------------------------------
void loop ()
{
    unsigned long msec = millis ();

    if ((msec - msecLst) >= period)  {
        msecLst = msec;

        if (On == digitalRead (LedPin))  {
            digitalWrite (LedPin, Off);
            period = OffPeriod;
        }
        else {
            digitalWrite (LedPin, On);
            period = OnPeriod;
        }
    }
}

// -----------------------------------------------------------------------------
void setup ()
{
    Serial.begin (9600);

    pinMode      (LedPin, OUTPUT);
    digitalWrite (LedPin, Off);
}

I already have a functional function. This matter is resolved.

i guess you described your needs better on the facebook page

Perhaps, but I did post the solution code before your proposed solution, so it's not like you thoroughly read what I wrote anyways.

i believe i did read your posts. but you never responded to my post #13 where i asked for clarification

my understanding of what your needs are was derived from the code you posted and i posted code which i had previously considered as an alternative which i think is worth considering since you said you are a novice