Looking for Ideas for multiple conditions / Best way to proceed.

Hi all!

Ill start by saying, I have been playing around with arduino for a little while (when i get a chance; father of two girls...). I do have a background in Electrical Engineering. However I never got too in depth with C code. I have done some small amounts of plc programming ie RSLogix500 & 5000 as well as a few others but that was in the past. I am now more concentrated in schematics and wiring of controls.

To my main issue:

Background: I purchased a house on the edge of a city. I am just below the sewer level so they had installed a "holding tank" in my front yard that has a grinder pump to pump up into the sewers. The previous owners had issues with this system because it was not meant for the harsh Canadian winters. So needless to say the system is shot.. all of it...

Now: I have sorted out wiring and the correct control equipment so that it is both safe and within code. I will have a High level switch in the tank, a motor contactor with overload, and my arduino controlling it all.

Description of THE PLAN

I want to: 1) watch the input of the level switch ( if low Green LED is on) 2)when level switch goes high, A) Turn on an output for the motor (For a specified amount of time like 10 minutes) B) turn off Green LED 3)after time has passed, turn off motor 4) Check Level switch again, if Still high A) Sound an alarm B) Do not allow Pump to turn back on until Alarm is acknowledged(See other ideas) C) Turn on Red LED

Thats about it

This is what I have done so far. Its Virtually nothing as I started with an if statement then realized it was not going to work properly.

const int AckbuttonPin =5;    // stops buzzer when alarm is sounded
const int AlarmPin = 4;     //will sound an alarm if switch is high after motor pin has been on
const int OverloadPin = 6    //Motor overload has tripped
const int LevelokPin = 3;    //Green LED to show Tank Level is ok
const int LevelSwitchPin = 2;     // Level Switch in the tank
const int MotorPin =  13;      // pin for starting pump

// variables will change:
int LevelSwitchState = 0;         // variable for reading the pushbutton status

void setup() {
  // initialize the LED pin as an output:
  pinMode(MotorPin, OUTPUT);
  pinMode(AlarmPin, OUTPUT);
  pinMode(LevelokPin, OUTPUT); 
  pinMode(LevelSwitchPin, INPUT);
  pinMode(OverloadPin, INPUT);
  pinMode(AckbuttonPin, INPUT);  
}

void loop(){
  // read the state of the pushbutton value:
  LevelSwitchState = digitalRead(LevelSwitchPin);

  // check if the pushbutton is pressed.
  // if it is, the buttonState is HIGH:
  if (LevelSwitchState == HIGH) {     
    // turn LED on:    
    digitalWrite(MotorPin, HIGH);
  delay(1000);
  } 
  else if{
    // turn LED off:
    digitalWrite(MotorPin, LOW); 
  }
}

I am looking for my best route, as I am doing alot of reading trying to figure it out ...

Thanks !!!

Looks like you will want to implement a Finite State Machine. There are lots of websites with instructions and examples.

Here is an example from my own writing:

Note the use of ‘enum’ (enumeration) variables to track the state. There are actually two FSM’s in this code. That is why there are separate states.

Note the use of select/case statements to steer to the code that handles the current state. In each state, check for inputs that would cause a switch to a different state. If no such events have occurred, just sit in the current state until something happens to move the state to a new state.

/*
Description of problem:

Set heater1 to match HeatIn1.
 
 If HeatIn1 is low and reverse is high:
 delay 5sec 
 write heater1R high 
 delay 10sec 
 write heater1R low 
 delay 10sec
 Wait for HeatIn1 to come on
 
 Set heater2 to match HeatIn2.
 
 If HeatIn2 is low and reverse is high:
 delay 5sec 
 write heater2R high 
 delay 10sec 
 write heater2R low 
 delay 10sec
 Wait for HeatIn1 to come on
 
 if HeatIn1 or HeatIn2 are high:
 write valve high (Open valve)
 delay 15sec
 write pump high (Start pump)
 
 if HeatIn1 and HeatIn2 have been low for a full 30 minutes:
 write valve low (Close valve)
 write pump low (Stop pump)
 */

//          *** OUTPUT'S  ***
const int valve     =  2;    // valve in pooler room
const int pump      =  3;    //  pump in pooler room
const int heater1   =  4;    // heater 1 output forward
const int heater1R  =  5;    // heater 1 output reverse
const int heater2   =  6;    // heater 2 output forward
const int heater2R  =  7;    // heater 2 output reverse
const int ledinput  =  8;    // input led from PC

//         ***  INPUT'S  ***
const int HeatIn1   =  9;    // input from PC 1, Active Low
const int HeatIn2   =  10;    // input from PC 2, Active Low
const int reverse   =  11;   // reverse swich for heat's


void setup()
{
  //        ***  OUTPUT'S  ***
  pinMode(valve   ,    OUTPUT);
  pinMode(pump    ,    OUTPUT);
  pinMode(heater1 ,    OUTPUT);
  pinMode(heater1R,    OUTPUT);
  pinMode(heater2 ,    OUTPUT);
  pinMode(heater2R,    OUTPUT);
  pinMode(ledinput,    OUTPUT);

  //        ***  INPUT'S  ***
  pinMode(HeatIn1,     INPUT);
  pinMode(HeatIn2,     INPUT);
  pinMode(reverse,     INPUT);

}
enum LoopOneStates {
  Heating, NotHeating, ReverseMode, ReverseModeOn,  ReverseModeOff, WaitingToHeat};

enum LoopTwoStates {
  EitherHot, OpenValve, StartPump, NeitherHot,  CloseValveStopPump};

void loop() {
  unsigned long currentTime = millis();

  //  LoopOne for Heater 1
  static enum LoopOneStates state1 = Heating;
  static unsigned long state1EntryTime = 0;
  switch (state1) {
  case Heating:
    digitalWrite(heater1, HIGH);
    if (digitalRead(HeatIn1))
      state1 = NotHeating;
    break;

  case NotHeating: 
    digitalWrite(heater1, LOW);
    if (digitalRead(reverse)) {
      state1 = ReverseMode;
      state1EntryTime = currentTime;
    }
    if (!digitalRead(HeatIn1))
      state1 = Heating;
    break;

  case ReverseMode:
    if (currentTime - state1EntryTime > 5000) {
      digitalWrite(heater1R, HIGH);
      state1 = ReverseModeOn;
      state1EntryTime = currentTime;
    }
    break;

  case ReverseModeOn:
    if (currentTime - state1EntryTime > 10000) {
      digitalWrite(heater1R, LOW);
      state1 = ReverseModeOff;
      state1EntryTime = currentTime;
    }
    break;

  case ReverseModeOff:
    if (currentTime - state1EntryTime > 10000) {
      state1 = WaitingToHeat;
    }
    break;

  case WaitingToHeat:
    if (!digitalRead(HeatIn1)) {
      state1 = Heating;
    }
    break;
  }




  //  LoopOne for Heater 2
  static enum LoopOneStates state2 = Heating;
  static unsigned long state2EntryTime = 0;
  switch (state2) {
  case Heating:
    digitalWrite(heater2, HIGH);
    if (digitalRead(HeatIn2))
      state2 = NotHeating;
    break;

  case NotHeating: 
    digitalWrite(heater2, LOW);
    if (digitalRead(reverse)) {
      state2 = ReverseMode;
      state2EntryTime = currentTime;
    }
    if (!digitalRead(HeatIn2))
      state2 = Heating;
    break;

  case ReverseMode:
    if (currentTime - state2EntryTime > 5000) {
      digitalWrite(heater2R, HIGH);
      state2 = ReverseModeOn;
      state2EntryTime = currentTime;
    }
    break;

  case ReverseModeOn:
    if (currentTime - state2EntryTime > 10000) {
      digitalWrite(heater2R, LOW);
      state2 = ReverseModeOff;
      state2EntryTime = currentTime;
    }
    break;

  case ReverseModeOff:
    if (currentTime - state2EntryTime > 10000) {
      state2 = WaitingToHeat;
    }
    break;

  case WaitingToHeat:
    if (!digitalRead(HeatIn2)) {
      state2 = Heating;
    }
    break;

  }

  //                                                        **loop two**


  //  LoopTwo for Heater 1
  static enum LoopTwoStates state3 = EitherHot;
  static unsigned long state3EntryTime = 0;
  switch (state3) {
  case EitherHot:
    if (!digitalRead(HeatIn1) || !digitalRead(HeatIn2)) {
      state3 = OpenValve;
      state3EntryTime = currentTime;
    }
    break;

  case OpenValve:
    digitalWrite(valve, HIGH);
    // Fifteen seconds later, starty the pump
    if (currentTime - state3EntryTime > 15000) {
      state3 = StartPump;
      state3EntryTime = currentTime;
    }
    break;

  case StartPump:
    digitalWrite(pump, HIGH);
    state3 = NeitherHot;
    state3EntryTime = currentTime;
    break;

  case NeitherHot:
    // Wait for a full 30 minutes with neither heat indicators on
    if (!digitalRead(HeatIn1) || !digitalRead(HeatIn2)) {
      // Reset the timer if either heater is on
      state3EntryTime = currentTime;
    }
    if (currentTime - state3EntryTime > 1000UL*60UL*30UL) {
      state3 = CloseValveStopPump;
    }
    break;

  case CloseValveStopPump:
    digitalWrite(valve,       LOW);
    digitalWrite(pump,        LOW);
    state3 = EitherHot;
    break;
  }
}

you can start here…

it is untested but you can attach some LEDs to your arduino and play with this:

const int resetPin =5;        //button pin resets buzzer when alarm is sounding
const int buzzerPin = 4;      //will sound an alarm if switch is high after motor pin has been on
//const int OverloadPin = 6;  //Motor overload has tripped  ???
const int greenLed = 3;       //Green LED to show Tank Level is ok
const int redLed = 4;         //Red led indicates alarm state
const int levelSwitchPin = 2; // Level Switch in the tank
const int pumpPin =  13;      // pin for starting pump

int lastSwitchState = 0; 
int pumpState;
unsigned long pumpStartTime;
unsigned long tenMinutes = 600000UL;//10 mins
int buzzerState;
unsigned long buzzerStartTime;
unsigned long buzzTime = 10000UL;//10 seconds

void setup() 
{
  Serial.begin(115200);
  pinMode(pumpPin, OUTPUT);
  pinMode(buzzerPin, OUTPUT);
  pinMode(greenLed, OUTPUT); 
  pinMode(redLed, OUTPUT);
  pinMode(levelSwitchPin, INPUT);
  //pinMode(OverloadPin, INPUT);
  pinMode(resetPin, INPUT_PULLUP);  
}
//
void loop()
{
  int resetState = digitalRead(resetPin);
  if (resetState == LOW)
  {
    buzzerState = 0;
  }
  int levelSwitchState = digitalRead(levelSwitchPin);
  if (levelSwitchState == HIGH) 
  {
    if (lastSwitchState == LOW)
    {
      digitalWrite(greenLed, LOW);
      pumpStartTime = millis();
      pumpState = 1;
      Serial.println(F("Pump On"));
    }
  } 
  else
  {
    digitalWrite(greenLed, HIGH); // All Good
  }
  lastSwitchState = levelSwitchState;
  if (pumpState)
  {
    runPump();
  }
  if (buzzerState)
  {
    buzz();
  }
} 
//
void runPump()
{
  if (millis() - pumpStartTime < tenMinutes)
  {
    digitalWrite(pumpPin, HIGH);
  }
  else
  {
    digitalWrite(pumpPin, LOW);
    pumpState = 0;
    Serial.println(F("Pump OFF"));
    buzzerState = (digitalRead(levelSwitchPin) == HIGH ? 1 : 0);
    if (buzzerState) 
    {
      buzzerStartTime = millis();
      Serial.println(F("Buzzer On"));
    }
    else
    {
      Serial.println(F("Buzzer OFF"));
    }
  }
}
//
void buzz()
{
  if (millis() - buzzerStartTime >= buzzTime)
  {
    digitalWrite(buzzerPin, !digitalRead(buzzerPin));// alternate buzz and red leds each 10 seconds
    digitalWrite(redLed, !digitalRead(buzzerPin));
    buzzerStartTime += buzzTime;
  }
}

fastiva: I want to: 1) watch the input of the level switch ( if low Green LED is on) 2)when level switch goes high, A) Turn on an output for the motor (For a specified amount of time like 10 minutes) B) turn off Green LED 3)after time has passed, turn off motor 4) Check Level switch again, if Still high A) Sound an alarm B) Do not allow Pump to turn back on until Alarm is acknowledged(See other ideas) C) Turn on Red LED

Thats about it.

You've virtually written your program there. Look up State Machine and the Switch-Case construct in the Learning pages of this site. I'd define your states as: 1) if level switch indicates low, green LED on, else change to state 2. 2)Start timer and turn on motor, turn off green LED change to state 3 (you may want to turn on a different LED to indicate the motor is on) 3)If time is up turn off motor ( and motor indicator LED) change to state 4 4)If level switch indicates low, change to state 1, else sound alarm and turn on red LED, change to state 5 5)if alarm is acknowledged, silence alarm...What then?

As far as the electronics are concerned, I would definitely add a backup system/alarm that is not connected in any way to that of the Arduino. Including the power supply!

Henry_Best:

fastiva:
I want to:

  1. watch the input of the level switch ( if low Green LED is on)
    2)when level switch goes high, A) Turn on an output for the motor (For a specified amount of time like 10 minutes)
    B) turn off Green LED
    3)after time has passed, turn off motor
  2. Check Level switch again, if Still high A) Sound an alarm
    B) Do not allow Pump to turn back on until Alarm is acknowledged(See other ideas)
    C) Turn on Red LED

Thats about it.

You’ve virtually written your program there.

This Thread planning and implementing an Arduino program illustrates how to turn this sort of list into a program.

…R

Thanks guys!!

The support in the Arduino community is amazing. I appreciate all the help! I will try to test this concept out this weekend!