If value is higher than for given time

Millis is killing me again and after 4 hours of trial and error i need to ask.

I have a current sensor and need on and off delay. If the sensor measures more then x ampere for 3 seconds then turn on the relay. If the sensor then measures less then x ampere, wait for 3 seconds and then turn off the relay.

I guess the problem is that "loadRecognisedTime" is updated all the time and not only when load is recognized?

unsigned long loadRecognisedTime = 0;  // Time when load was recognised
unsigned long turnOnDelay = 3000;        // Wait to turn on relay
unsigned long turnOffDelay = 3000;       // Turn off relay after this time
bool relayReady = false;                 // Flag for load recognised
bool relayState = false;                 // Relay is on or not.

void automatic() {

  double Irms = checkPower.calcIrms(1480);   // Calculate Irms only
  unsigned long currentMillis = millis();

  if(Irms >= 0.03) {                         // If RMS is higher then 0.03A
    loadRecognisedTime = currentMillis;
    relayReady = true;
  }

  if (relayReady) {
    if ((unsigned long)(currentMillis - loadRecognisedTime) >= turnOnDelay) {
      digitalWrite(RELAY, HIGH);         // turn relay on
    }
  }

}

To test if something is HIGH for a certain length of time you need to save the value of millis() every time you detect a LOW. Then if the difference between millis() and the saved value exceeds your interval you can be sure that t was HIGH throughout the interval. That may seem perverse, but it works. Something like this pseudo code …

if(Irms < 0.03) {
    lastLowTime = currentMillis;
}
if (millis() - lastLowTime >= interval) {
   // has been > 0,03 for interval so do stuff
}

…R

I guess the problem is that "loadRecognisedTime" is updated all the time and not only when load is recognized?

So change the program so that it only saves the millis() value when the load [u]becomes[/u] more than the threshold value rather than when it [u]is[/u] more than the threshold value. The StateChangeDetection example in the IDE will show you the principle.

This code now is half working. But if i remove the load the test LED (instead of relay) is blinking.
1 second off, 3 seconds on…

void automatic() {

  double Irms = checkPower.calcIrms(1480);   // Calculate Irms only
  unsigned long currentMillis = millis();

  if (loadState == false) { // There is no load

    if(Irms < 0.03) {
      noLoadTime = currentMillis;
    }

    if (millis() - noLoadTime >= turnOnDelay) {  // If RMS is higher then 0.03A longer then 3 seconds
      digitalWrite(RELAY, HIGH);                 // turn relay on
      loadState = true;
    }

  }

  if (loadState == true) { // There is load
  
    if(Irms > 0.03) {
      loadRemoved = currentMillis;
    }

    if ((millis() - loadRemoved) >= turnOffDelay) {
      digitalWrite(RELAY, LOW);
      loadState = false;
    }
    
  }

}

void loop() {
  
  uint8_t switchState_1 = digitalRead(3);  // Read the switch value (pin D3)
  uint8_t switchState_2 = digitalRead(4);  // Read the switch value (pin D4)
  
  if(switchState_1 == LOW) {           // If pin 3 is low
    digitalWrite(RELAY, HIGH);         // turn relay on
    loadState = false;                 // and reset load detection state
  } else if (switchState_2 == LOW) {   // If pin 4 is low
    loadState = false;                 // reset load detection state
    automatic();                       // and run the automatic loop
  } else {
    digitalWrite(RELAY, LOW);          // Turn relay off
    loadState = false;                 // and reset load detection state
  }

}

There is a 3 state switch connected to D3 and D4.
If D3 is low turn on relay.
If D4 is low go to detection mode.
If D3 and D4 are high do nothing.

UKHeliBob:
So change the program so that it only saves the millis() value when the load becomes more than the threshold value

That is what i try to figure out since hours.

You need to post your complete program.

I don't understand what you mean by "But if i remove the load the test LED (instead of relay) is blinking. 1 second off, 3 seconds on...". Please describe what happens in both situations

Put in some temporary Serial.print() statements to let you follow the progress of the program.

,,,R

Try this alternative approach. Obviously you need to write it properly and use your own variable and function names.

start of loop()
  currentLoad = readTheSensor()
  if not timing and currentLoad > threshold
    startTime = millis()
    timing = true
  end if
  else 
    timing = false
  end else

  if timing and currentTime - startTime >= period
    //the load has been above the threshold for longer than period.  Do something
  end if
end of loop()

Try this:

const float CurrentThreshold=0.03;
const unsigned long TimeThreshold=3000UL;
const byte RELAY=2;
unsigned long loadRecognisedTime = 0;  // Time when load (or lack of it) was recognised

void setup()
{
}

void loop()
{
}

void automatic()
{
double Irms = checkPower.calcIrms(1480);   // Calculate Irms only
static bool PrevLoadOn=false;
bool LoadOn = Irms > CurrentThreshold;
if(LoadOn != PrevLoadOn)
  {
  loadRecognisedTime=millis();
  LoadOn=PrevLoadOn;  
  }
if(millis()-loadRecognisedTime > TimeThreshold)
    digitalWrite(RELAY,LoadOn ? HIGH : LOW);
}

Compiled (without the calcIrms piece), not tested. Obviously you'll need to fit automatic & my constants into your own sketch.

Robin2:
I don’t understand what you mean by "But if i remove the load the test LED (instead of relay) is blinking.[/quote]
The load from the current sensor…

If there is load (ampere detected) the relay is on (instead of a relay i use a LED for testing).
If i remove the load the relay is not of - it goes on for 3 seconds and then off for 1 second constantly.

I did edit my last posting because there is also a switch.

EDIT
The one from Robin is the only one that is half working. Can’t get the others do anything.

#include <EmonLib.h>   // Get it here: github.com/openenergymonitor/EmonLib

/**************************************************************

  • MISC SETUP                                                  *
    **************************************************************/
    #define DEBUG 1                      // Set to 1 for serial port output
    const uint32_t SERIAL_BAUD = 9600;  // Set serial 0 speed
    EnergyMonitor checkPower;            // Create an instance

const uint8_t RELAY = 8;  // Relay circuit is connected to D8
const uint8_t SENSOR = A3; // ECS1030-L72 is connected to A3

// Define switch pins
const uint8_t pinS = {3, 4};                      // Array of used switch pins
uint8_t pinSCount = sizeof(pinS) / sizeof(pinS[0]); // Count used switch pins

// Define unused pins
const uint8_t pin = {2, 5, 6, 7, 9, 10, 11, 12, 13}; // Array of unused digital pins
const uint8_t pinA = {A0, A1, A2, A4, A5, A6, A7};  // Array of unused analog pins
uint8_t pinCount = sizeof(pin) / sizeof(pin[0]);      // Count unused digital pins
uint8_t pinACount = sizeof(pinA) / sizeof(pinA[0]);    // Count unused analog pins

/**************************************************************

  • SETUP                                                      *
    **************************************************************/
    void setup() {

#ifdef DEBUG
    Serial.begin(SERIAL_BAUD); // Initialize serial communications
    while (!Serial) {;}        // Wait for serial port to connect
  #endif // END DEBUG
 
  for (uint8_t i = 0; i < pinCount; i++) {
    pinMode(pin[i], OUTPUT);    // Set unused digital pins as output
    digitalWrite(pin[i], LOW);  // Set unused digital pins state to low
  }

for (uint8_t i = 0; i < pinACount; i++) {
    pinMode(pinA[i], OUTPUT);    // Set unused analog pins as output
    digitalWrite(pinA[i], LOW);  // Set unused analog pins state to low
  }

for (uint8_t i = 0; i < pinSCount; i++) {
    pinMode(pinS[i], INPUT_PULLUP);  // Set switch pins as input and enable internal pull-up resistor
  }

pinMode(RELAY, OUTPUT);    // Set Relay pin (D8) as output
  digitalWrite(RELAY, LOW);  // Set Relay to off

checkPower.current(SENSOR, 20);  // Sensor input pin (A3) and calibration

}

/**************************************************************

  • AUTOMATIC LOOP                                              *
    **************************************************************/
    unsigned long noLoadTime = 0;
    unsigned long loadRemoved = 0;
    unsigned long turnOnDelay = 3000;
    unsigned long turnOffDelay = 3000;
    bool loadState = false;

void automatic() {

double Irms = checkPower.calcIrms(1480);  // Calculate Irms only
  unsigned long currentMillis = millis();

if (loadState == false) { // There is no load
     
    if(Irms < 0.03) {
      noLoadTime = currentMillis;
    }

if (millis() - noLoadTime >= turnOnDelay) {  // If RMS is higher then 0.03A longer then 3 seconds
      digitalWrite(RELAY, HIGH);                // turn relay on
      loadState = true;
    }

}

if (loadState == true) { // There is load
 
    if(Irms > 0.03) {
      loadRemoved = currentMillis;
    }

if ((millis() - loadRemoved) >= turnOffDelay) {
      digitalWrite(RELAY, LOW);
      loadState = false;
    }
   
  }

#ifdef DEBUG
    Serial.print(Irms*230.0);  // Apparent power
    Serial.print(" ");
    Serial.println(Irms);      // Irms
  #endif // END DEBUG

}

/**************************************************************

  • MAIN LOOP                                                  *
    **************************************************************/
    void loop() {
     
      uint8_t switchState_1 = digitalRead(3);  // Read the switch value (pin D3)
      uint8_t switchState_2 = digitalRead(4);  // Read the switch value (pin D4)
     
      if(switchState_1 == LOW) {          // If pin 3 is low
        digitalWrite(RELAY, HIGH);        // turn relay on
        loadState = false;                // and reset load detection state
      } else if (switchState_2 == LOW) {  // If pin 4 is low
        loadState = false;                // reset load detection state
        automatic();                      // and run the automatic loop
      } else {
        digitalWrite(RELAY, LOW);          // Turn relay off
        loadState = false;                // and reset load detection state
      }

#ifdef DEBUG
    Serial.println(loadState);      // Irms
  #endif // END DEBUG

}



The two problems are:
1. The turn off delay is not working
2. If i switch the switch to other states and go back to automatic and there is load/current then the relay goes instantly on without the 3 seconds delay.

You say that half is working but I can't figure out which half.

In your Original Post you say that the relay should only go ON when the amps are high for over 3 seconds. Then you say that if it detects low amps it should turn the relay OFF after 3 seconds.

The latter sounds like it should be triggered by a low amps reading but you are checking for a high amps reading with

if(Irms > 0.03) {
      loadRemoved = currentMillis;

...R

The half that is working is the “on delay” with the exception that if i disconnect pin 4 from low and reconnect it to low the relay turns on instantly.

From printing currentMillis it seems like currentMillis is not starting from zero after stopping and starting the automatic loop again with pin 4? I guess that’s the problem with the relay turning on instantaneously?

The off delay:
If i change the off part to “Irms < 0.03” the on part also stops working.

MrGlasspoole:
From printing currentMillis it seems like currentMillis is not starting from zero after stopping and starting the automatic loop again with pin 4? I guess that’s the problem with the relay turning on instantaneously?

The off delay:
If i change the off part to “Irms < 0.03” the on part also stops working.

You have mentioned at least 2 changes to the program. Post the latest version so that I can relate your comments to it.

…R

I made no changes since the last one…

MrGlasspoole:
I made no changes since the last one…

That is not what your Reply #9 says

From printing currentMillis it seems like currentMillis is not starting from zero

If i change the off part to “Irms < 0.03” the on part also stops working

Why are you wasting our time?

…R

Maybe something like this simple on/off delay sketch, connect a pushbutton from GND to pin 4 and see if it works like you want:

unsigned long strtOnDly, strtOffDly;
const byte RELAY = 8, btn = 4; 
int on_off_Delay = 3000;
bool relayReady = false; 

void setup(){
  pinMode(btn, INPUT_PULLUP);
  pinMode(RELAY,OUTPUT);
}
void loop(){
  relayReady = !digitalRead(btn);  
  if(relayReady == true)
    strtOffDly = millis(); // reset Off Delay timer
  else strtOnDly = millis(); // reset On Delay timer
  if(relayReady && millis() - strtOnDly > on_off_Delay)
    digitalWrite(RELAY,HIGH);
  else if(millis() - strtOffDly > on_off_Delay)
    digitalWrite(RELAY,LOW);
}

Adding

Serial.println(currentMillis);

is a code change?

And no

Irms < 0.03

is not in the code because as i wrote it does not work.

MrGlasspoole: Adding

Serial.println(currentMillis);

is a code change?

Yes, it is. It probably won't make any difference - probably. Anyone who has spent much time answering questions here has seen the classic situation of the OP making an unmentioned change that they thought irrelevant which actually broke their program. It means that if you're making changes and not posting the revised sketch, the people who might have helped you will shrug & move on.

MrGlasspoole:
And no

Irms < 0.03

is not in the code because as i wrote it does not work.

If you believe it does not work then you must have had a version of the code that included it.

One of the important lessons about debugging is that the cases that don’t work are often very useful indicators of the problem - don’t discard them without carefully studying them. So post the code that includes that change.

Plus what @wildbill said.

…R

Ok, step by step (ooh baby :slight_smile: )

This one turns on the relay after 3 seconds if load is detected but does not turn off the relay after removing the load:

#include <EmonLib.h>   // Get it here: github.com/openenergymonitor/EmonLib

/**************************************************************
* MISC SETUP                                                  *
**************************************************************/
#define DEBUG 1                      // Set to 1 for serial port output
const uint32_t SERIAL_BAUD = 9600;   // Set serial 0 speed
EnergyMonitor checkPower;            // Create an instance

const uint8_t RELAY = 8;   // Relay circuit is connected to D8
const uint8_t SENSOR = A3; // ECS1030-L72 is connected to A3

// Define switch pins
const uint8_t pinS[] = {3, 4};                      // Array of used switch pins
uint8_t pinSCount = sizeof(pinS) / sizeof(pinS[0]); // Count used switch pins

// Define unused pins
const uint8_t pin[] = {2, 5, 6, 7, 9, 10, 11, 12, 13}; // Array of unused digital pins
const uint8_t pinA[] = {A0, A1, A2, A4, A5, A6, A7};   // Array of unused analog pins
uint8_t pinCount = sizeof(pin) / sizeof(pin[0]);       // Count unused digital pins
uint8_t pinACount = sizeof(pinA) / sizeof(pinA[0]);    // Count unused analog pins

/**************************************************************
* SETUP                                                       *
**************************************************************/
void setup() {

  #ifdef DEBUG
    Serial.begin(SERIAL_BAUD); // Initialize serial communications
    while (!Serial) {;}        // Wait for serial port to connect
  #endif // END DEBUG
  
  for (uint8_t i = 0; i < pinCount; i++) {
    pinMode(pin[i], OUTPUT);    // Set unused digital pins as output
    digitalWrite(pin[i], LOW);  // Set unused digital pins state to low 
  }

  for (uint8_t i = 0; i < pinACount; i++) {
    pinMode(pinA[i], OUTPUT);    // Set unused analog pins as output
    digitalWrite(pinA[i], LOW);  // Set unused analog pins state to low 
  }

  for (uint8_t i = 0; i < pinSCount; i++) {
    pinMode(pinS[i], INPUT_PULLUP);  // Set switch pins as input and enable internal pull-up resistor
  }

  pinMode(RELAY, OUTPUT);     // Set Relay pin (D8) as output
  digitalWrite(RELAY, LOW);   // Set Relay to off

  checkPower.current(SENSOR, 20);  // Sensor input pin (A3) and calibration

}

/**************************************************************
* AUTOMATIC LOOP                                              *
**************************************************************/
unsigned long noLoadTime = 0;
unsigned long loadRemoved = 0;
unsigned long turnOnDelay = 3000;
unsigned long turnOffDelay = 3000;
bool loadState = false;

void automatic() {

  double Irms = checkPower.calcIrms(1480);   // Calculate Irms only
  unsigned long currentMillis = millis();

  if (loadState == false) { // There is no load
       
    if(Irms < 0.03) {
      noLoadTime = currentMillis;
    }

    if (millis() - noLoadTime >= turnOnDelay) {  // If RMS is higher then 0.03A longer then 3 seconds
      digitalWrite(RELAY, HIGH);                 // turn relay on
      loadState = true;
    }

  }

  if (loadState == true) { // There is load
  
    if(Irms > 0.03) {
      loadRemoved = currentMillis;
    }

    if ((millis() - loadRemoved) >= turnOffDelay) {
      digitalWrite(RELAY, LOW);
      loadState = false;
    }
    
  }

  #ifdef DEBUG
    Serial.print(Irms*230.0);  // Apparent power
    Serial.print(" ");
    Serial.println(Irms);      // Irms
    Serial.println(currentMillis);
  #endif // END DEBUG

}

/**************************************************************
* MAIN LOOP                                                   *
**************************************************************/
void loop() {
  
  uint8_t switchState_1 = digitalRead(3);  // Read the switch value (pin D3)
  uint8_t switchState_2 = digitalRead(4);  // Read the switch value (pin D4)
  
  if(switchState_1 == LOW) {           // If pin 3 is low
    digitalWrite(RELAY, HIGH);         // turn relay on
    loadState = false;                 // and reset load detection state
  } else if (switchState_2 == LOW) {   // If pin 4 is low
    loadState = false;                 // reset load detection state
    automatic();                       // and run the automatic loop
  } else {
    digitalWrite(RELAY, LOW);          // Turn relay off
    loadState = false;                 // and reset load detection state
  }

  #ifdef DEBUG
    Serial.println(loadState);      // Irms
  #endif // END DEBUG

}

The next one. It was dark and now i did see that the LED (that i use instead of a relay for testing) did flicker weakly.

#include <EmonLib.h>   // Get it here: github.com/openenergymonitor/EmonLib

/**************************************************************
* MISC SETUP                                                  *
**************************************************************/
#define DEBUG 1                      // Set to 1 for serial port output
const uint32_t SERIAL_BAUD = 9600;   // Set serial 0 speed
EnergyMonitor checkPower;            // Create an instance

const uint8_t RELAY = 8;   // Relay circuit is connected to D8
const uint8_t SENSOR = A3; // ECS1030-L72 is connected to A3

// Define switch pins
const uint8_t pinS[] = {3, 4};                      // Array of used switch pins
uint8_t pinSCount = sizeof(pinS) / sizeof(pinS[0]); // Count used switch pins

// Define unused pins
const uint8_t pin[] = {2, 5, 6, 7, 9, 10, 11, 12, 13}; // Array of unused digital pins
const uint8_t pinA[] = {A0, A1, A2, A4, A5, A6, A7};   // Array of unused analog pins
uint8_t pinCount = sizeof(pin) / sizeof(pin[0]);       // Count unused digital pins
uint8_t pinACount = sizeof(pinA) / sizeof(pinA[0]);    // Count unused analog pins

/**************************************************************
* SETUP                                                       *
**************************************************************/
void setup() {

  #ifdef DEBUG
    Serial.begin(SERIAL_BAUD); // Initialize serial communications
    while (!Serial) {;}        // Wait for serial port to connect
  #endif // END DEBUG
  
  for (uint8_t i = 0; i < pinCount; i++) {
    pinMode(pin[i], OUTPUT);    // Set unused digital pins as output
    digitalWrite(pin[i], LOW);  // Set unused digital pins state to low 
  }

  for (uint8_t i = 0; i < pinACount; i++) {
    pinMode(pinA[i], OUTPUT);    // Set unused analog pins as output
    digitalWrite(pinA[i], LOW);  // Set unused analog pins state to low 
  }

  for (uint8_t i = 0; i < pinSCount; i++) {
    pinMode(pinS[i], INPUT_PULLUP);  // Set switch pins as input and enable internal pull-up resistor
  }

  pinMode(RELAY, OUTPUT);     // Set Relay pin (D8) as output
  digitalWrite(RELAY, LOW);   // Set Relay to off

  checkPower.current(SENSOR, 20);  // Sensor input pin (A3) and calibration

}

/**************************************************************
* AUTOMATIC LOOP                                              *
**************************************************************/
unsigned long noLoadTime = 0;
unsigned long loadRemoved = 0;
unsigned long turnOnDelay = 3000;
unsigned long turnOffDelay = 3000;
bool loadState = false;

void automatic() {

  double Irms = checkPower.calcIrms(1480);   // Calculate Irms only
  unsigned long currentMillis = millis();

  if (loadState == false) { // There is no load
       
    if(Irms < 0.03) {
      noLoadTime = currentMillis;
    }

    if (millis() - noLoadTime >= turnOnDelay) {  // If RMS is higher then 0.03A longer then 3 seconds
      digitalWrite(RELAY, HIGH);                 // turn relay on
      loadState = true;
    }

  }

  if (loadState == true) { // There is load
  
    if(Irms < 0.03) {
      loadRemoved = currentMillis;
    }

    if ((millis() - loadRemoved) >= turnOffDelay) {
      digitalWrite(RELAY, LOW);
      loadState = false;
    }
    
  }

  #ifdef DEBUG
    Serial.print(Irms*230.0);  // Apparent power
    Serial.print(" ");
    Serial.println(Irms);      // Irms
    Serial.println(currentMillis);
  #endif // END DEBUG

}

/**************************************************************
* MAIN LOOP                                                   *
**************************************************************/
void loop() {
  
  uint8_t switchState_1 = digitalRead(3);  // Read the switch value (pin D3)
  uint8_t switchState_2 = digitalRead(4);  // Read the switch value (pin D4)
  
  if(switchState_1 == LOW) {           // If pin 3 is low
    digitalWrite(RELAY, HIGH);         // turn relay on
    loadState = false;                 // and reset load detection state
  } else if (switchState_2 == LOW) {   // If pin 4 is low
    loadState = false;                 // reset load detection state
    automatic();                       // and run the automatic loop
  } else {
    digitalWrite(RELAY, LOW);          // Turn relay off
    loadState = false;                 // and reset load detection state
  }

  #ifdef DEBUG
    Serial.println(loadState);      // Irms
  #endif // END DEBUG

}

Only change is < instead of > in

  if (loadState == true) { // There is load
  
    if(Irms < 0.03) {

MrGlasspoole: Ok, step by step (ooh baby :) )

I'm sure I'm crap at lots of things but I reckon I am a little better than average at diagnosis. And there is no substitute for baby steps.

It was dark and now i did see that the LED (that i use instead of a relay for testing) did flicker weakly.

Are you saying that the LED goes on for 3 seconds and then goes off for a very brief interval before going on for another 3 seconds?

Remember I can't see your workbench so you need to provide all the fine detail.

...R