// =======================================================
// Automatic reserve gasoline generator start controller
// © OBO email: [email protected]
// ver. 0.0
// =======================================================
//
// Program to be used for automatic reserve gasoline generator start, where control of chock needed.
//
// Autostart is designed to be used together with an UPC to be started only when the upc battery charge is low. City power is controlled on the CityVPin, the UPC battery charge level on the BetteryVPin.
// During the generator run the fuel level (FuelPin) in tank, the oil preasure (OilPin) in the engine, the temperature of the alternator are controlled.
// While idling the fuel level and the ambient temperature are controled. If the temperature is out of the normal operation range or fuel is low - generator will not start.
// Three LEDs and a LCD screen are used for informing about status of generator.
// Green LED constant light - generator is runnig OK. Green LED blink - generator is paused after max permitted work time.
// Yellow LED constant light - generator is idle and ready to start. Yellow LED blink - low fuel level, but generator still be started/running.
// Red LED constant light - generator has been stopped due to an error (oil, tempetare, fuel, power cut). Press Button to reset. Red LED blink - the ambient temperature is out of the normal operation range.
// One button is used for manual start/stop the generator and reset on errors.
// External time relay on the SchedulePin could be used for maintenance scheduled start of the generator. Run time is preset.
// Total amount of time that generator was in operation is calculated, showed on the LCD and stored in the EEPROM.
// The maximum operation time is preset. If the generator is running longer than this time it will be stopped and then started again after preset pause time.
// Additional cooling fan could be connected throw the fan relay.
//program version
const byte verMajor = 0;
const byte verMinor = 0;
#include <EEPROM.h> //save variables in eeprom external library
#include <OneWire.h> //onewire protocol external library
#include <DallasTemperature.h> //dallas temperature sensor external library
#include <LiquidCrystal_I2C.h> //lcd external library
OneWire oneWire(3); //temperature sensor pin
DallasTemperature sensor(&oneWire); //temperature sensor init
LiquidCrystal_I2C lcd(0x27, 16, 2); //lcd screen init
#define GreenLed 11 //running successfully led indicator
#define RedLed 12 //error indicator
#define YellowLed 13 //standby indication
#define BatteryPin A7 //UPS battery level probe
#define FuelPin A6 //gasoline level probe
#define OilPin A3 //oil pressure probe
#define CityVPin A2 //city energy probe
#define GenVPin A1 //generator energy probe
#define GenRunPin A0 //generator runner probe (for example 12V outlet)
#define ChockOnPin 10 //chocke close actuator relay
#define ChockOffPin 9 //chocke open actuator relay
#define IgnitionPin 8 //generator ignition
#define StarterPin 7 //generator starter relay
#define SwitchPin 6 //genarator load switch relay
#define ButtonPin 5 //button - start/stop, reset
#define SchedulePin 4 //external time relay to periodic service run
#define FanPin 2 //generator external cooling fan relay
const int ambLowTemp = -15; //lowest ambient temperature for genarator start
const int ambHighTemp = 50; //highest ambient temperature for genarator start
const int genOwerTemp = 95; //temperature of genarator owerheat
const int genLowTemp = 40; //temperature of cooling fan OFF
const int genHighTemp = 70; //temperature of coolong fan ON
const unsigned int chockDelay = 1000; //time to generator run with chock full closed, milliseconds
const unsigned int startOnTime = 500; //time of starter activation, milliseconds
const unsigned int startPause = 500; //pause between attempts to start, milliseconds
const unsigned long warmCoolTime = 1000; //cooling time - time to run genarator withou load, milliseconds
const unsigned long workTimePermit = 50000; //maximum permitted time for generator to work, milliseconds
const unsigned long idleTime = 50000; //idle pause, milliseconds
const unsigned long workTimeSchedule = 5000; //time to run by schedule (genirator will work this amount of time + cooling time), milliseconds
unsigned int fuelLevel = 0;
unsigned int batteryLevel = 0; //charging level of UPC battery
unsigned long runTime = 0; //generator runned time
unsigned long totalRunTime = 0; // generator total runned time
unsigned long startTime = 0; // time, when generator was started
unsigned long stopTime = 0; // time, when generator was stopped
unsigned long previousMillis = 0; //varible for using with millis delay code
bool timerStop = false;
bool scheduleStop = false;
bool genError = false;
bool genIsRunning = false;
bool genPower = false;
bool runBySchedule = false;
bool runByButton = false;
bool stopByButton = false;
bool tempError = false;
bool gasError = false;
byte ignitionState = LOW;
byte ledState = LOW;
void setup() {
sensor.begin(); //startup temperature sensor library
lcd.begin(16, 2); //startup lcd library
lcd.init();
lcd.backlight();
pinMode(GenRunPin, INPUT_PULLUP); //generator run probe
pinMode(CityVPin, INPUT_PULLUP); //city power probe
pinMode(GenVPin, INPUT_PULLUP); //generator power probe
pinMode(ButtonPin, INPUT_PULLUP); //button
pinMode(OilPin, INPUT_PULLUP); //oil sensor
pinMode(FuelPin, INPUT); //gasoline tank level probe
pinMode(BatteryPin, INPUT); //UPC battery charge level
pinMode(ChockOnPin, OUTPUT); //chock close
pinMode(ChockOffPin, OUTPUT); //chock open
pinMode(IgnitionPin, OUTPUT); //ignition switch
pinMode(StarterPin, OUTPUT); //starter switch
pinMode(SwitchPin, OUTPUT); //generator load switch
pinMode(FanPin, OUTPUT); //cooling fan relay
pinMode(GreenLed, OUTPUT);
pinMode(YellowLed, OUTPUT);
pinMode(RedLed, OUTPUT);
//inital set relays OFF
digitalWrite(ChockOnPin, LOW);
digitalWrite(ChockOffPin, LOW);
digitalWrite(IgnitionPin, LOW);
digitalWrite(StarterPin, LOW);
digitalWrite(SwitchPin, LOW);
digitalWrite(FanPin, LOW);
//write initial 0 value of total work time to EEPROM
if (EEPROM.read(0) == 255 && EEPROM.read(1) == 255) {
writeUnsignedIntIntoEEPROM(0, totalRunTime);
}
verlcdprint(verMajor, verMinor);
}
void loop() {
//generator error processing
while (genError == true) {
//stop on error
if (genError == true) {
digitalWrite(SwitchPin, LOW); //load OFF
ignitionState = LOW;
digitalWrite(IgnitionPin, ignitionState); //ignition OFF
digitalWrite(RedLed, HIGH); //error indicator ON
digitalWrite(GreenLed, LOW); //run indicator OFF
digitalWrite(YellowLed, LOW); //standby indicator OFF
stopTime = millis();
genIsRunning = false;
genPower = false;
}
//reset errors by button
if (digitalRead(ButtonPin) == LOW) {
digitalWrite(RedLed, LOW); //error indicator OFF
digitalWrite(YellowLed, HIGH); //standby indicator ON
totalRunTime = readUnsignedIntFromEEPROM(0);
totalRunTime = totalRunTime + (stopTime - startTime); //total generator work time calculation
writeUnsignedIntIntoEEPROM(0, totalRunTime);
genError = false; //reset error
runByButton = false; //prevent restart if was started by button
runBySchedule = false; //prevent restart if was started by schedule
}
} //generator error processing end
//generator normal work routine
while (genError == false) {
//check if generator is running
if (digitalRead(GenRunPin) == HIGH) {
genIsRunning = false;
} else {
genIsRunning = true;
}
//idle generator temperature control
sensor.requestTemperatures();
if (sensor.getTempCByIndex(0) >= ambHighTemp || sensor.getTempCByIndex(0) <= ambLowTemp) { //temperature is out of range
if (millis() - previousMillis >= 500) { //error indicator blinking procedure
previousMillis = millis();
ledState = (ledState == HIGH) ? LOW: HIGH;
digitalWrite(RedLed, ledState);
}
tempError = true;
warninglcdprint("T out of range! "); //lcd error message print
} else {
previousMillis = 0;
tempError = false;
}
//cooling fan OFF while generator is idle
if (sensor.getTempCByIndex(0) <= genLowTemp) {
digitalWrite(FanPin, LOW);
}
//gasoline level controlling
fuelLevel = analogRead(FuelPin); //read data from fuel probe; if doesnt exist - set constant value
if (fuelLevel >= 1000) {
if (millis() - previousMillis >= 500) {
previousMillis = millis();
ledState = (ledState == HIGH) ? LOW: HIGH;
digitalWrite(YellowLed, ledState);
}
gasError = true;
warninglcdprint("Fuel tank empty!");
} else {
previousMillis = 0;
gasError = false;
}
//generator idle indication
if (genIsRunning == false && tempError == false && gasError == false && timerStop == false) {
digitalWrite(GreenLed, LOW); //run indicator OFF
digitalWrite(YellowLed, HIGH); //idle indicator ON
digitalWrite(RedLed, LOW); //error indicator OFF
readylcdprint(totalRunTime, fuelLevel); //lcd ready message
}
//generator pause indication
if (genIsRunning == false && tempError == false && gasError == false && timerStop == true) {
if (millis() - previousMillis >= 500) { //run indicator blinking
previousMillis = millis();
ledState = (ledState == HIGH) ? LOW: HIGH;
digitalWrite(GreenLed, ledState);
}
digitalWrite(YellowLed, LOW); //idle indicator OFF
digitalWrite(RedLed, LOW); // error indicator OFF
pauselcdprint(totalRunTime, stopTime, fuelLevel); //lcd pause massage
}
while (genIsRunning == true) {
//run indication
runTime = (millis() - startTime); //running time calculation
digitalWrite(GreenLed, HIGH); //run indicator ON
digitalWrite(YellowLed, LOW); //idle indicator OFF
runlcdprint(runTime, fuelLevel);
//generator stop routine
batteryLevel = analogRead(BatteryPin); //read UPC battery charge level; if does not exist - set constant value
if (((digitalRead(CityVPin) == LOW || batteryLevel <= 10) && runBySchedule == false && runByButton == false) || timerStop == true || gasError == true || scheduleStop == true || stopByButton == true) { //check if city power is ON or button pressed
digitalWrite(SwitchPin, LOW); //switch load OFF
lcd.clear();
lcd.print("Stopping...");
delay (warmCoolTime); //run without load for alternator cooling
ignitionState = LOW;
digitalWrite(IgnitionPin, ignitionState); //ignition OFF
stopTime = millis();
genIsRunning = false;
genPower = false;
runBySchedule = false;
scheduleStop = false;
runByButton = false;
stopByButton = false;
totalRunTime = readUnsignedIntFromEEPROM(0);
totalRunTime = totalRunTime + (stopTime - startTime);
writeUnsignedIntIntoEEPROM(0, totalRunTime);
}
//oil level sensor error
if (digitalRead(OilPin) == HIGH) {
genIsRunning = false;
genError = true;
warninglcdprint("Check oil! ");
}
//engine stall
if (ignitionState == HIGH && digitalRead(GenRunPin) == HIGH) {
digitalWrite(GreenLed, LOW); //run indicator OFF
genIsRunning = false;
genPower = false;
//genError = true; //if comment - try to start normally after stall
}
//generator power cut while it is still running
if (genPower == true && digitalRead(GenVPin) == HIGH && digitalRead (GenRunPin) == LOW && runBySchedule == false) {
digitalWrite(GreenLed, LOW); //run indicator OFF
genIsRunning = false;
genError = true;
warninglcdprint("Check switch! ");
}
//stop by timer
if (millis() - startTime >= workTimePermit) {
timerStop = true;
}
if (runBySchedule == true && (millis() - startTime >= workTimeSchedule)) {
scheduleStop = true;
}
//stop by button when started by button
if (digitalRead(ButtonPin) == LOW && runByButton == true) {
stopByButton = true;
}
//emergency stop by button
if (digitalRead(ButtonPin) == LOW && runByButton == false) {
genIsRunning = false;
genError = true;
warninglcdprint("Stopped manualy!");
}
//running generator temperature control
sensor.requestTemperatures();
//cooling fan ON
if (sensor.getTempCByIndex(0) >= genHighTemp) {
digitalWrite(FanPin, HIGH);
}
//cooling fan OFF
if (sensor.getTempCByIndex(0) <= genLowTemp) {
digitalWrite(FanPin, LOW);
}
//stop by temperature
if (sensor.getTempCByIndex(0) >= genOwerTemp) {
genIsRunning = false;
genError = true;
warninglcdprint("Owerheat! ");
}
//gasoline level controling
fuelLevel = analogRead(FuelPin); //read data from fuel probe; if does not exist - set constant value
if (fuelLevel >= 800) {
if (millis() - previousMillis >= 500) {
previousMillis = millis();
ledState = (ledState == HIGH) ? LOW: HIGH;
digitalWrite(YellowLed, ledState);
}
}
if (fuelLevel >= 1000) {
gasError = true;
warninglcdprint("Fuel tank empty!");
}
} //generator is running end
//reset stop timer
if (millis() - stopTime >= idleTime) {
timerStop = false;
}
//button idle time override
if (digitalRead(ButtonPin) == LOW && timerStop == true) {
timerStop = false;
}
//run by external schedule relay
if (digitalRead(SchedulePin) == HIGH) {
runBySchedule = true;
}
//generator start routine
batteryLevel = analogRead(BatteryPin); //read UPC battery garge level; if does not exist - set constant value
if (digitalRead(ButtonPin) == LOW) {
runByButton = true;
}
if (((digitalRead(CityVPin) == HIGH && batteryLevel >= 800) || runByButton == true || runBySchedule == true) && digitalRead(GenRunPin) == HIGH && timerStop == false && tempError == false && gasError == false) {
while (genError == false && genIsRunning == false) { //generator is not running and ready to start
lcd.clear();
lcd.print("Starting...");
ignitionState = HIGH;
digitalWrite(IgnitionPin, ignitionState); //ignition ON
digitalWrite(ChockOnPin, HIGH); //close chock
delay(500); //chock actuator runnig time
digitalWrite(ChockOnPin, LOW);
delay(500); //timeout before start attempt
//try to start generator for i times, each time 5 sec longer starter run and 5 sec longer pause between attempts
for (int i = 3; i > 0; i = i - 1) {
delay (startPause+(3-i)*500); //pause between attempts to start generator
digitalWrite(StarterPin, HIGH); //starter run
delay(startOnTime+(3-i)*500); //starter running time
digitalWrite(StarterPin, LOW);
delay(500); //timeout before check if generator is started successfully
if (digitalRead(GenRunPin) == LOW) { //check if generator is running
delay(chockDelay); //run with chock full closed
digitalWrite(ChockOffPin, HIGH); //open chock
delay(500);
digitalWrite(ChockOffPin, LOW);
lcd.clear();
lcd.print("Started");
lcd.setCursor(0, 1);
lcd.print("successfully");
i = 0; //stop trying to start genarator
startTime = millis();
genIsRunning = true;
}
if (digitalRead(GenRunPin) == HIGH && i == 1) { //error if generator doesnt start after all attempts
stopTime = millis();
genError = true;
warninglcdprint("Start failed! ");
}
}
}
// switch load ON
if (digitalRead(GenRunPin) == LOW && digitalRead(CityVPin) == HIGH) { //check if generator is runnig ok with open chock & city power still off
delay(warmCoolTime); //run without load
digitalWrite(SwitchPin, HIGH); //swich load ON
delay (500);
if (digitalRead(GenVPin) == HIGH) { //no power from generator
stopTime = millis();
genError = true;
genPower = false;
warninglcdprint("SwitchON failed!");
} else {
genPower = true;
lcd.clear();
lcd.print("Load is ON");
}
}
} //generator start procedure end
} //generator normal work routine end
} //end of main loop
//print inital screen
void verlcdprint (byte major, byte minor) {
lcd.setCursor(0, 0);
lcd.print("<Gen Auto Start>");
char buffer[16];
sprintf(buffer, "version %02d.%02d ", major, minor);
lcd.setCursor(0, 1);
lcd.print(buffer);
delay(10);
}
//print "run" message
void runlcdprint (unsigned long msecTime, unsigned int gasLevel) { //running time in millisec
lcd.setCursor(0, 0);
lcd.print("Running... ");
unsigned int runTimeHH = msecTime/3600; //hours
unsigned int runTimeMM = (msecTime%3600)/60; //minutes
char buffer[5];
sprintf(buffer, "%02d:%02d", runTimeHH, runTimeMM); //format for lcd
lcd.setCursor(0, 1);
lcd.print(buffer);
unsigned int fuelTank = (1023 - gasLevel)*0.09775; //fuel remaining %
char bufferF[11];
sprintf(bufferF, " Fuel: %2d%%", fuelTank);
lcd.setCursor(5, 1);
lcd.print(bufferF);
}
//print "pause" message
void pauselcdprint(unsigned long totalTime, unsigned long msecStop, unsigned int gasLevel) { //total running time and stoped time in milliseconds
lcd.setCursor(0, 0);
lcd.print(" PAUSED ");
unsigned int totalTimeH = totalTime/3600; //convert milliseconds to hours
char buffer[5];
sprintf(buffer, "%05d", totalTimeH);
lcd.setCursor(0, 1);
lcd.print(buffer);
unsigned int fuelTank = (1023 - gasLevel)*0.09775; //fuel remaining %
char bufferF[6];
sprintf(bufferF, " F%d%% ", fuelTank);
lcd.setCursor(5, 1);
lcd.print(bufferF);
unsigned long remTime = idleTime - (millis() - msecStop); //remaining pause
unsigned int remTimeHH = remTime/3600; //hours
unsigned int remTimeMM = (remTime%3600)/60; //minutes
char bufferR[5];
sprintf(bufferR, "%02d:%02d", remTimeHH, remTimeMM); //format for lcd
lcd.setCursor(11, 1);
lcd.print(bufferR);
}
//print "ready" message
void readylcdprint(unsigned long totalTime, unsigned int gasLevel) {
lcd.setCursor(0, 0);
lcd.print(" READY ");
unsigned int totalTimeH = totalTime/3600; //convert milliseconds to hours
char buffer[5];
sprintf(buffer, "%05d", totalTimeH);
lcd.setCursor(0, 1);
lcd.print(buffer);
int fuelTank = (1023 - gasLevel)*0.09775; //fuel remaining %
char bufferF[11];
sprintf(bufferF, " Fuel: %2d%%", fuelTank);
lcd.setCursor(5, 1);
lcd.print(bufferF);
}
//print "warning" message
void warninglcdprint (String warningMessage) {
lcd.setCursor(0, 0);
lcd.print(" WARNING! ");
lcd.setCursor(0, 1);
lcd.print(warningMessage);
}
//store valiue in eeprom
void writeUnsignedIntIntoEEPROM(int address, unsigned int number) {
EEPROM.write(address, number >> 8);
EEPROM.write(address + 1, number & 0xFF);
}
unsigned int readUnsignedIntFromEEPROM(int address)
{
return (EEPROM.read(address) << 8) + EEPROM.read(address + 1);
}