# 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 turnOnDelay = 3000;        // Wait to turn on relay
unsigned long turnOffDelay = 3000;       // Turn off relay after this time
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
}

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(Irms < 0.03) {
}

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

}

if(Irms > 0.03) {
}

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

}

}

void loop() {

if(switchState_1 == LOW) {           // If pin 3 is low
digitalWrite(RELAY, HIGH);         // turn relay on
} else if (switchState_2 == LOW) {   // If pin 4 is low
automatic();                       // and run the automatic loop
} else {
digitalWrite(RELAY, LOW);          // Turn relay off
}

}

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()
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
bool LoadOn = Irms > CurrentThreshold;
{
}
}

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 turnOnDelay = 3000;
unsigned long turnOffDelay = 3000;

void automatic() {

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

if(Irms < 0.03) {
}

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

}

if(Irms > 0.03) {
}

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

}

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

}

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

• MAIN LOOP                                                  *
**************************************************************/
void loop() {

if(switchState_1 == LOW) {          // If pin 3 is low
digitalWrite(RELAY, HIGH);        // turn relay on
} else if (switchState_2 == LOW) {  // If pin 4 is low
automatic();                      // and run the automatic loop
} else {
digitalWrite(RELAY, LOW);          // Turn relay off
}

#ifdef DEBUG
#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) {

...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…

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;

void setup(){
pinMode(btn, INPUT_PULLUP);
pinMode(RELAY,OUTPUT);
}
void loop(){
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);
}

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.

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 )

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 turnOnDelay = 3000;
unsigned long turnOffDelay = 3000;

void automatic() {

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

if(Irms < 0.03) {
}

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

}

if(Irms > 0.03) {
}

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

}

#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() {

if(switchState_1 == LOW) {           // If pin 3 is low
digitalWrite(RELAY, HIGH);         // turn relay on
} else if (switchState_2 == LOW) {   // If pin 4 is low
automatic();                       // and run the automatic loop
} else {
digitalWrite(RELAY, LOW);          // Turn relay off
}

#ifdef DEBUG
#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 turnOnDelay = 3000;
unsigned long turnOffDelay = 3000;

void automatic() {

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

if(Irms < 0.03) {
}

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

}

if(Irms < 0.03) {
}

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

}

#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() {

if(switchState_1 == LOW) {           // If pin 3 is low
digitalWrite(RELAY, HIGH);         // turn relay on
} else if (switchState_2 == LOW) {   // If pin 4 is low
automatic();                       // and run the automatic loop
} else {
digitalWrite(RELAY, LOW);          // Turn relay off
}

#ifdef DEBUG
#endif // END DEBUG

}

Only change is < instead of > in

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