Hello, I am trying to start a generator if the power has been out for 30 minutes. If the power comes back on during the 30 minute countdown, I need to stop the timer. Also, If the generator is running and the power comes back on, the generator needs to turn off as soon as the main comes back. Here is what I've done so far:
The houses transfer switch will close a circuit when the power goes out. The generator will listen for that closed circuit. When the circuit closes, the generator starts. What I have done is, make the arduino listen for the closed circuit, when it happens, delay for 30 min, then close a relay(which simulates the transfer switch for the generator.) Now my problem is that my code uses the delay() function. So all's well and good till the power comes back on and the generator doesn't turn off for 30 min because the 30min delay is going in a loop. Here is my code:
const int breakerSwitch = A0; // pin that the breaker is attached to
const int relayPin = 12; // pin that the relay is attached to
const int threshold = 1020; // an arbitrary threshold level that's in the range of the analog input
const int redLED = 3; //red led that shows when the genertor will start.
const int timerLED = 5; //led that will light when 30 min timer is active
void setup() {
// initialize the relay pin as an output:
pinMode(relayPin, OUTPUT);
pinMode(redLED, OUTPUT);
pinMode(timerLED, OUTPUT);
pinMode(7, OUTPUT);
}
void loop() {
//power relay
digitalWrite(7, HIGH);
// check if the breaker switch circut is closed, since digitalread won't work for this:
int analogValue = analogRead(breakerSwitch);
// if the analog value is high enough, activae relay:
if (analogValue > threshold) {
digitalWrite(timerLED, HIGH);
//delay for 30 minutes:
delay(1800000);
//delay(10000);
// after 30 minutes close relay:
digitalWrite(relayPin, HIGH);
digitalWrite(redLED, HIGH);
} else {
digitalWrite(relayPin, LOW);
digitalWrite(redLED, LOW);
digitalWrite(timerLED, LOW);
}
}
I need a way to maybe use millis or something to, when circuit closes, delay 30 min, but if power comes back while counting down, cancel the timer. Also, if the power comes back after the generator has started and is running, then turn off the relay immediately.
Thank you for your replies! I have read those before, but I will read them again and try to understand whats going on. With millis from what I can tell you can start a timer (if) a condition is met, see if 30min has passed since the condition was met, (then). and how can I interrupt the timer while it is going? It's all very complicated!
You also need to speak to your power company about doing this too - there maybe problems for example in sharing the earth connection with that of the supplying authority and proving your system can’t run in parallel with theirs .
These issues can relate to a fault on your generator electrocuting the work men upstream that are fixing the fault
Notwithstanding the good advice you got above, you can still use delay for this if you prefer. Just add in a check after the 30 minute delay to see that the power is still off before starting the generator.
KM4OVZ:
and how can I interrupt the timer while it is going? It's all very complicated!
When using millis() for timing you don't so much 'interrupt' a timer as reset it - thereby preventing it from reaching its preset value. Resetting is done by making the timer equal to millis(), and therefore the *difference *between millis() - accValue is zero. To get the timer to accumulate elapsed time stop resetting it.
This illustration may help you to see what's going on.
KM4OVZ:
Hello, I am trying to start a generator if the power has been out for 30 minutes. If the power comes back on during the 30 minute countdown, I need to stop the timer.
Sorry, that specification is incomplete.
You need to specify what happens if the power comes on only temporarily, for a few seconds or a few minutes, If that happens after the 30 minutes, you need to determine how long the power must return for the generator to shut down - "immediately" is probably not appropriate.
I have done it! I am amazed, it took my 15 minutes and just worked! Here is the code, if anyone wants to know how it was done. Mostly I just copied the millis code from BlinkWithoutDelay. Yay!
//Code written by KM4OVZ. This works really well!
const int breakerSwitch = A0; // pin that the breaker is attached to
const int relayPin = 12; // pin that the relay is attached to
const int threshold = 1020; // an arbitrary threshold level that's in the range of the analog input
const int redLED = 3; //red led that shows when the genertor will start.
const int timerLED = 5; //led that will light when 30 min timer is active
int relayState = LOW;
unsigned long previousMillis = 0;
//for testing:
//const long interval = 5000;
const long interval = 1800000; //1800000 for 30 minutes of delay
void setup() {
// initialize the relay pin and other pins as an output:
pinMode(relayPin, OUTPUT);
pinMode(redLED, OUTPUT);
pinMode(timerLED, OUTPUT);
pinMode(7, OUTPUT);
}
void loop() {
digitalWrite(7, HIGH);
//see if breaker is closed(power is out?)Weird method because digitalRead gives false readings
int analogValue = analogRead(breakerSwitch);
if (analogValue > threshold) {
//make timer led come on
digitalWrite(timerLED, HIGH);
//start timer for the provided interval:
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) {
// save the last time you enabled the relay
previousMillis = currentMillis;
//if relay is off, turn it on
if (relayState == LOW) {
relayState = HIGH;
digitalWrite(redLED, HIGH); //shows the generator is active
} else {
relayState = LOW;
}
digitalWrite(relayPin, relayState);
}
}
else { //if the mains never went out, do nothing.
digitalWrite(relayPin, LOW);
digitalWrite(redLED, LOW);
digitalWrite(timerLED, LOW);
}
}
I need a way to maybe use millis or something to, when circuit closes, delay 30 min, but if power comes back while counting down, cancel the timer. Also, if the power comes back after the generator has started and is running, then turn off the relay immediately.
Your code is not correct for a delayed start. With previousMillis initialized at 0, the relay will activate immediately if the analog threshold is initially reached any time after the interval time is passed.
The timing period needs to start when the threshold is crossed. Its more clear if you use a variable called startTime instead of previousMillis, and use a boolean control variable so that the timing only starts with the transition.
See this modification of your code. Some hysteresis around the analogRead() threshold value maybe necessary.
const int breakerSwitch = A0; // pin that the breaker is attached to
const int relayPin = 12; // pin that the relay is attached to
const int threshold = 1020; // an arbitrary threshold level that's in the range of the analog input
const int redLED = 3; //red led that shows when the genertor will start.
const int timerLED = 5; //led that will light when 30 min timer is active
int relayState = LOW;
//unsigned long previousMillis = 0;
unsigned long startTime = 0;
boolean timing = false;
//for testing:
//const long interval = 5000;
const long interval = 1800000; //1800000 for 30 minutes of delay
void setup() {
// initialize the relay pin and other pins as an output:
pinMode(relayPin, OUTPUT);
pinMode(redLED, OUTPUT);
pinMode(timerLED, OUTPUT);
pinMode(7, OUTPUT);
}
void loop() {
digitalWrite(7, HIGH);
//see if breaker is closed(power is out?)Weird method because digitalRead gives false readings
int analogValue = analogRead(breakerSwitch);
if (analogValue > threshold && timing == false)
{
//make timer led come on
digitalWrite(timerLED, HIGH);
startTime = millis();
timing = true;
}
else if (analogValue < threshold)
{ //if the mains on or back on reset timing
digitalWrite(relayPin, LOW);
digitalWrite(redLED, LOW);
digitalWrite(timerLED, LOW);
timing = false;
}
//check timer for the delayed start interval:
unsigned long currentMillis = millis();
if (timing == true && currentMillis - startTime >= interval)
{
digitalWrite(redLED, HIGH); //shows the generator is active
digitalWrite(relayPin, HIGH);
digitalWrite(timerLED, LOW);
timing = false; //period is over
}
}
cattledog:
Your code is not correct for a delayed start. With previousMillis initialized at 0, the relay will activate immediately if the analog threshold is initially reached any time after the interval time is passed.
The timing period needs to start when the threshold is crossed. Its more clear if you use a variable called startTime instead of previousMillis, and use a boolean control variable so that the timing only starts with the transition.
See this modification of your code. Some hysteresis around the analogRead() threshold value maybe necessary.
const int breakerSwitch = A0; // pin that the breaker is attached to
const int relayPin = 12; // pin that the relay is attached to
const int threshold = 1020; // an arbitrary threshold level that's in the range of the analog input
const int redLED = 3; //red led that shows when the genertor will start.
const int timerLED = 5; //led that will light when 30 min timer is active
int relayState = LOW;
//unsigned long previousMillis = 0;
unsigned long startTime = 0;
boolean timing = false;
//for testing:
//const long interval = 5000;
const long interval = 1800000; //1800000 for 30 minutes of delay
void setup() {
// initialize the relay pin and other pins as an output:
pinMode(relayPin, OUTPUT);
pinMode(redLED, OUTPUT);
pinMode(timerLED, OUTPUT);
pinMode(7, OUTPUT);
}
void loop() {
digitalWrite(7, HIGH);
//see if breaker is closed(power is out?)Weird method because digitalRead gives false readings
int analogValue = analogRead(breakerSwitch);
if (analogValue > threshold && timing == false)
{
//make timer led come on
digitalWrite(timerLED, HIGH);
startTime = millis();
timing = true;
}
else if (analogValue < threshold)
{ //if the mains on or back on reset timing
digitalWrite(relayPin, LOW);
digitalWrite(redLED, LOW);
digitalWrite(timerLED, LOW);
timing = false;
}
//check timer for the delayed start interval:
unsigned long currentMillis = millis();
if (timing == true && currentMillis - startTime >= interval)
{
digitalWrite(redLED, HIGH); //shows the generator is active
digitalWrite(relayPin, HIGH);
digitalWrite(timerLED, LOW);
timing = false; //period is over
}
}
Thank you for putting time to find this problem! However, I did test it with a shortened delay and it seemed like it was working as expected. I am going to test it again.
I just tested it and it works correctly every time. I close the connection, timer starts. timer goes for 10 seconds(test only) then the relay activates(as it is supposed to). Once I open the connection(mains coming back) it disables the relay instantly. If I close the connection again,(power going out) It does it's 10 second wait then closes the relay as intended.
Okay- After further testing I found that the relay was clicking on and off every ten seconds(test time) You were right! Thank you so much! I used your modified code, and that fixed it. Thanks again, it would have been bad if I had let that go without knowing about it.
Decide how long power should be down before you take action. (I think you are doing this).. There are often short interruptions that are quickly restored. I used 10 seconds.
Decide how long power must be restored before you switch back to regular power and shut down generator. I used 8 minutes.
Unless the generator has it's own automatic startup and shutdown sequencing, you must decide how to control starter motor, choke, if used, how to monitor successful startup, how to monitor running / faults / Alarms. How long to wait for "warmup" before transferring load, and how long to run without load before engine shutdown. I had different timing for small Propane fueled sets VS large Diesels.
You MIGHT want to monitor fuel level, engine and generator temperatures.
I'm working right now with a friend in Nigeria who is designing a system for retrofit to typical small 5-20 KVA generators often used in homes and small businesses. The power system in NG is terrible; he is in Port Harcourt and the power is up and down 2 - 3 times a day, and on for less than 50% of the time. He is using millis() and a State Machine in his Arduino code. A servo to control choke..
I'll post something on that project when it's done...
(I loved it when a TTL signal would start a big diesel cranking)