Duty Standby code

Hi all,I would like a little bit of advice about a program i am writing.

the idea is that there are 2 pumps which sit in a pond and when a level set point is reached then one of the pumps runs till the lower set point is reached the next time thew set point is reached the other pump should run as to kind of balance the duty. if one pump is running then then trips then the second pump will run. so i know what i want to do but i cant seem to write the code. If someone would point me down the right road im sure i can figure it out.

Thanks…Ben

here is my code


//------------------Pump 1 inputs and outputs----------------------
int Pump1Auto = D0; //pump 1 selector switch
int Pump1Running = D1;
int Pump1Run = D5;
int Pump1Tripped = A1;
//-----------------------------------------------------------------

//----------------- Pump 2 Inputs and Outputs
int Pump2Auto =D2;
int Pump2Running =D3;
int Pump2Run = D6;
int Pump2Tripped = A2;

//-----------------------------------------------------------------

//----------------Alarm inputs and outputs-------------------------
int Alarm4 = A3; // high float will be connected to pin A3 on the unit
int highlevellight = D7; //this is the light that will give us info about the state of the alarm

//-----------------------------------------------------------------


// ---------------Varibles----------------------------------------
bool isArmed = true;       //true or false is the alarm set
int i;      // integer to count 1 time so multiple emails are not sent
int Duty;

//-----------------------Level Inputs-----------------------------
const int LevelReading = A0;

float Level; // to hold the reading from analog 0

float StartSetpoint; // Holds the setpoing for turning on the pump
float StopSetpoint;// Holds the setpoint for turning off the pump
 





void setup() 
{
 // Particle.function("rearmAlarm", rearm); 
  Serial.begin(9600); // begin serial for displaying reading
  pinMode(Alarm4, INPUT_PULLDOWN);
  pinMode(highlevellight, OUTPUT);// declare the highlevellight pin as an output
  pinMode(Pump1Auto, INPUT_PULLDOWN);
  pinMode(Pump1Tripped, INPUT_PULLDOWN);
  pinMode(Pump2Tripped, INPUT_PULLDOWN);
  pinMode(Pump1Run, OUTPUT);
  pinMode(Pump2Run, OUTPUT);
 // pinMode(Level, Input); // does not need this line of code
  i = 0;
  StartSetpoint = 5;
  Duty = Pump1Run;
 // Pump1Tripped = LOW;
 // Automode = LOW;
}

void loop() 
{
//Alarm system which is activated when input becomes LOW 
//if the alarm is activated and waiting for a low input then led d7 will flash on and off every second
//if a low input is detected then the led on d7 will flash one cycle at 0.5seconds then stay on
//

    if (isArmed == true && i<1)
    {
 SetAlarm();
    
        
    }
    
  bool state = !digitalRead(Alarm4);  // invert active LOW to more intuitive active HIGH /////// state is asigned the oposite of Alarm1 so if it is low state will be TRUE
  if (isArmed && state)    /////// if isArmed and state is true 
  {
   
  RunAlarm();
  }
  
  if (!isArmed && !state) //if thr alarm is not armed and the state is false the alarm is not activated (not LOW)
  {
      i = 0; //set i back to 0 so the alarm active email can be sent once
      isArmed = true; // set isArmed to true  so the alarm process can be run again
  }
//---------------------------------------------------------------------------------
//----------------Running the pump on level----------------------------------------
//Serial.println(StartSetpoint);
delay(250);
Serial.print("Level Is....");
Serial.print(Level);
//Serial.println(Level);
Serial.println(" Metres");
//Serial.write(“Level is”);

//delay(2000); // use this when serial printing the analog value
delay(250);
Level = analogRead(LevelReading);
//Level = constrain(Level, 0, 2000);
  Level = map(Level, 0, 4095, 0, 10); // re map the analog value to 0 - 10 

if ((digitalRead(Pump1Auto) == HIGH )&& (Level>=StartSetpoint)&& (digitalRead(Pump1Tripped) == LOW))//&& (digitalRead(Pump2Auto)== HIGH)&&(digitalRead(Pump2Tripped)== LOW))
//if (Level >= Setpoint)
{
    digitalWrite(Duty, HIGH);
    flasher();
    if ((digitalRead(Pump1Tripped) == HIGH)&& (digitalRead(Pump2Auto) == HIGH))
    {
        Duty = Pump2Run;
    }
   

}
  
else digitalWrite(Duty, LOW);
  
}

//-------------------------------Functions wrote below here--------------------------------------
//-----------------------------------------------------------------------------------------------
//---------------------------------test function flash light when flasher() is called in the loop
void flasher()
{
    digitalWrite(highlevellight, LOW);
        delay (90);
        digitalWrite(highlevellight, HIGH);
        delay(90);
        digitalWrite(highlevellight, LOW);
        delay (90);
       //  digitalWrite(highlevellight, HIGH);
       // delay(90);
       // digitalWrite(highlevellight, LOW);
       // delay (90);
}

void RunAlarm()
{
     isArmed = false;  // don't trigger till rearmed
    //----------blocked for testing  
    Particle.publish("EVENT_PREFIX", PRIVATE); // publish the event so an email can be sent
    //----------BLocked for Testing  
    Particle.publish("twilio", PRIVATE);
        
        /////////////Flash light to indicate an alarm state////////////////////////////////
        digitalWrite(highlevellight, LOW);
        delay (500);
        digitalWrite(highlevellight, HIGH);
        delay(500);
        digitalWrite(highlevellight, LOW);
        delay (500);
         digitalWrite(highlevellight, HIGH);
        delay(500);
        digitalWrite(highlevellight, LOW);
        delay (500);

}

void SetAlarm()

        {
       //-------------blocked for testing        Particle.publish("ALARM_SET", PRIVATE); // publish the event so alarm set email can be sent
       ////// flash the lights so we know alarm is armed--------------------------------------------
        digitalWrite(highlevellight, LOW);
        delay (1000);
        digitalWrite(highlevellight, HIGH);
        delay(1000);
        digitalWrite(highlevellight, LOW);
        delay (1000);
        digitalWrite(highlevellight, HIGH);
        delay(1000);
        digitalWrite(highlevellight, LOW);
        delay(1000);
        digitalWrite(highlevellight, HIGH);
        delay (1000);
        digitalWrite(highlevellight, LOW);
        i++; //add one to i so the code will not be run again
        
             
        }

Hello Ben,

Looks like an interesting project. I’m unsure I understand what you are trying to achieve with the two pump system and where are you getting blocked on the code. Are the two pumps suppose to run together or just one at a time? A little bit of elaboration will definitely help.

Thanks!

Thanks for the reply.
i just cant get my head round the code but i will try to explain a little better

so if autopump1 is on and pump1tripped not on
and autopump2 is on and pump2tripped not on
and level setpoint is reached then the program will run the output(pump) that did not run last however if any pump has tripped or auto is turned off then the other output(pump) will run unless it has itself tripped or auto is turned off.
im sorry if i am not being very clear.

once again thanks for the help.

It’s still not at all clear to me. It sounds like you basically want to alternate which pump runs when you reach a certain threshold, but it’s not clear to me what auto is supposed to do, or what the meaning of the pumpTripped variables are. Do they indicate whether the pumps are running or not (tripped = running?)?

Ben, it sounds like you want to simulate a pump scheme like what we used to use for our building sump.

We had two pumps #1 and #2 one was designated the Lead and the other the Lag.

The sump had two level switches Hi and Hi-Hi. One would be set for 1 foot the other 2 feet above the bottom of the sump.

We normally selected the lead pump with a selector switch (pump #1 was lead one month, pump #2 the next month).

The lead pump started when the hi level switch closed. If level continued to rise the lag pump started when the hi-hi level switch closed.

The hi-hi level switch also gave us an alarm and the operator would go see why both pumps were needed or if the selected lead pump had tripped.

If you want the Lead and Lag pumps to alternate automatically you could swap pumps every time the hi switch opened or every 5 times the lead started on hi level etc. to even out pump wear.

Is this something like what you want to do?

Chuck

Thanks for the reply.

Yes this sounds somewhere near what i am trying to do however, as long as both selector switches for the pumps are on and both pumps do not have a tripped input on the electron then the program will alternate the pumps each time they are run. if one of the pumps is tripped or turned off it will not run that pump and just run the other when required.

hope this is a bit clearer

Ben

There is a lot of ways to do this.

You can have one analog signal for level to control both pumps and an alarm (save on using extra IO pins).

One Digital input from a switch to control which pump is lead and which is lag. I would only swap once a week or let the Photon / Electron swap pumps based on day of the week or month.

That would keep you from having to leave the football game to swap the switch (or use a smart phone / web page to change the pump instead of a physical switch and an IO pin).

I would forget having a sensor or input for pump tripped, If wired correctly and sized properly it should not trip unless something is sucked into the impeller.

If you go with an analog level you can set an alarm just above the start setpoint to indicate that the pump isn’t maintaining level (either the pump is tripped or not keeping up with the level increase).

The programming can do about what ever you want. You will likely need to provide output isolation and capacity to control the current that your pumps will require (relay or solid state device).

The hardest part is deciding on what you want it to do, It will likely change as you start programming it.

Chuck

cheers again maybe in not being very clear. i dont want anyone to write the code for me i just want to know. if i have two variables how to i alternate between them so each time a pump is run the next time the other pump will run. but thinking about it i could maybe use the debionce code to swap between then?

You can have one variable that holds the number of the pump to use next (e.g. pump1 = 0 & pump2 = 1).
Each time you start that respective pump increment that variable. Once the variable is greater 1 assign 0 to it for the next go.

Thanks ScruffR

i now kind of have something working ish

when i HIGH and LOW D0 it alternates between D6 and D5 however sometimes either D5 or D6 will stick HIGH and will not go LOW if i keep messing with D0 it eventually turns off. i know it is getting the HIGH/LOW on D0 as i use flasher() to flash D7 when D0 is HIGH.

Here is my code…Thanks…Ben



//------------------Pump 1 inputs and outputs----------------------
int Pump1Auto = D0; //pump 1 selector switch
int Pump1Running = D1;
int Pump1Run = D5;
int Pump1Tripped = A1;
//-----------------------------------------------------------------

//----------------- Pump 2 Inputs and Outputs
int Pump2Auto =D2;
int Pump2Running =D3;
int Pump2Run = D6;
int Pump2Tripped = A2;
int LastRunPump = 2;

//-----------------------------------------------------------------

//----------------Alarm inputs and outputs-------------------------
int Alarm4 = A3; // high float will be connected to pin A3 on the unit
int highlevellight = D7; //this is the light that will give us info about the state of the alarm

//-----------------------------------------------------------------


// ---------------Varibles----------------------------------------
bool isArmed = true;       //true or false is the alarm set
int i;      // integer to count 1 time so multiple emails are not sent
int Duty;
bool Pump1Available;
bool Pump2Available;

//-----------------------Level Inputs-----------------------------
const int LevelReading = A0;

float Level; // to hold the reading from analog 0

float StartSetpoint; // Holds the setpoing for turning on the pump
float StopSetpoint;// Holds the setpoint for turning off the pump
 





void setup() 
{
 // Particle.function("rearmAlarm", rearm); 
  Serial.begin(9600); // begin serial for displaying reading
  pinMode(Alarm4, INPUT_PULLDOWN);
  pinMode(highlevellight, OUTPUT);// declare the highlevellight pin as an output
  pinMode(Pump1Auto, INPUT_PULLDOWN);
  pinMode(Pump1Tripped, INPUT_PULLDOWN);
  pinMode(Pump2Tripped, INPUT_PULLDOWN);
  pinMode(Pump1Run, OUTPUT);
  pinMode(Pump2Run, OUTPUT);
 // pinMode(Level, Input); // does not need this line of code
  i = 0;
  StartSetpoint = 8;
  StopSetpoint = 5;
  Duty = Pump1Run;
  Pump1Available = FALSE;
  Pump2Available = FALSE;
 // Pump1Tripped = LOW;
 // Automode = LOW;
}

void loop() 
{
//Alarm system which is activated when input becomes LOW 
//if the alarm is activated and waiting for a low input then led d7 will flash on and off every second
//if a low input is detected then the led on d7 will flash one cycle at 0.5seconds then stay on
//

    if (isArmed == true && i<1)
    {
 SetAlarm();
    
        
    }
    
  bool state = !digitalRead(Alarm4);  // invert active LOW to more intuitive active HIGH /////// state is asigned the oposite of Alarm1 so if it is low state will be TRUE
  if (isArmed && state)    /////// if isArmed and state is true 
  {
   
  RunAlarm();
  }
  
  if (!isArmed && !state) //if thr alarm is not armed and the state is false the alarm is not activated (not LOW)
  {
      i = 0; //set i back to 0 so the alarm active email can be sent once
      isArmed = true; // set isArmed to true  so the alarm process can be run again
  }
//---------------------------------------------------------------------------------
//----------------Running the pump on level----------------------------------------
//Serial.println(StartSetpoint);
delay(250);
Serial.print("Level Is....");
Serial.print(Level);
Serial.println(" Metres");
GetOverloadStatus();
delay(250);
Level = analogRead(LevelReading);
//Level = constrain(Level, 0, 2000);
Level = map(Level, 0, 4095, 0, 10); // re map the analog value to 0 - 10




//if ((Level>=StartSetpoint)&&(Level>=StopSetpoint)&&(digitalRead(Pump1Auto) == HIGH ))
//{
    if ((Level>StopSetpoint)&&(Pump2Available)&&(LastRunPump)== 1 &&(digitalRead(Pump1Auto) == HIGH ))
    {
    digitalWrite(Pump2Run, HIGH);
    flasher();
    Serial.println(" Pump2 Running");
    GetOverloadStatus();
        if ((Level<StopSetpoint)||(!Pump2Available)||(digitalRead(Pump1Auto) == LOW && (LastRunPump)== 1 ))
         {
    digitalWrite(Pump2Run, LOW);
    Serial.println(LastRunPump);
    Serial.println(" Pump2 Stopped");
    LastRunPump = 2;
    }
    
    }

   // if ((digitalRead(Pump1Auto) == HIGH )&& (Level>=StartSetpoint)&& (digitalRead(Pump1Tripped) == LOW))
    if ((Level>StopSetpoint)&&(Pump1Available)&& (LastRunPump)== 2 &&(digitalRead(Pump1Auto) == HIGH ))
    {
    digitalWrite(Pump1Run, HIGH);
    Serial.println(" Pump1 Running");
    GetOverloadStatus();
    flasher(); 
    if ((Level<StopSetpoint)||(!Pump1Available)||(digitalRead(Pump1Auto) == LOW && (LastRunPump)== 2 ))
    {
    digitalWrite(Pump1Run, LOW);
    Serial.println(LastRunPump);
    Serial.println(" Pump1 Stopped");
    LastRunPump = 1;
    }
    }
  
    
  
  

//}  
}
//-------------------------------Functions wrote below here--------------------------------------
//-----------------------------------------------------------------------------------------------
//--------------------------------------Get Pump overload status---------------------------------------------------
void GetOverloadStatus()
{

  if (digitalRead(Pump1Tripped) == LOW)
  {
      Pump1Available = TRUE;
      Serial.println("Pump 1 Healthy");
  }
  else 
  {
      Pump1Available = FALSE;
      Serial.println("Pump 1 Tripped");
  }
  if (digitalRead(Pump2Tripped) == LOW)
  {
      Pump2Available = TRUE;
      Serial.println("Pump 2 Healthy");
  }
  else 
  {
      Pump2Available = FALSE;
      Serial.println("Pump 2 Tripped");
  }
  
}
//-------------------------------------------------------------------------------------------------

//---------------------------------test function flash light when flasher() is called in the loop
void flasher()
{
    digitalWrite(highlevellight, LOW);
        delay (90);
        digitalWrite(highlevellight, HIGH);
        delay(90);
        digitalWrite(highlevellight, LOW);
        delay (90);
       //  digitalWrite(highlevellight, HIGH);
       // delay(90);
       // digitalWrite(highlevellight, LOW);
       // delay (90);
}

void RunAlarm()
{
     isArmed = false;  // don't trigger till rearmed
    //----------blocked for testing  
   // Particle.publish("EVENT_PREFIX", PRIVATE); // publish the event so an email can be sent
    //----------BLocked for Testing  
  //  Particle.publish("twilio", PRIVATE);
        
        /////////////Flash light to indicate an alarm state////////////////////////////////
        digitalWrite(highlevellight, LOW);
        delay (500);
        digitalWrite(highlevellight, HIGH);
        delay(500);
        digitalWrite(highlevellight, LOW);
        delay (500);
         digitalWrite(highlevellight, HIGH);
        delay(500);
        digitalWrite(highlevellight, LOW);
        delay (500);

}

void SetAlarm()

        {
       //-------------blocked for testing        Particle.publish("ALARM_SET", PRIVATE); // publish the event so alarm set email can be sent
       ////// flash the lights so we know alarm is armed--------------------------------------------
        digitalWrite(highlevellight, LOW);
        delay (1000);
        digitalWrite(highlevellight, HIGH);
        delay(1000);
        digitalWrite(highlevellight, LOW);
        delay (1000);
        digitalWrite(highlevellight, HIGH);
        delay(1000);
        digitalWrite(highlevellight, LOW);
        delay(1000);
        digitalWrite(highlevellight, HIGH);
        delay (1000);
        digitalWrite(highlevellight, LOW);
        i++; //add one to i so the code will not be run again
        
             
        }

I would recommend to forget about all your variables called xxxx1 and xxxx2 and just use arrays where your 1 and 2 are the index to the array and then you can also dump all these double code blocks and just have one block that either acts on the one or the other pump/sensor/switch/device.

Also getting used to zero-based indexes is something that makes things just that bit more professional (and easier :wink: )

e.g. to extend your code to n pumps would be a piece of cake with something like this (just typed, not tested)

struct Pump {
  int auto;
  int running;
  int run;
  int tripped;
};

Pump pumpPins[] = {
  {D0, D1, D5, A1},
  {D2, D3, D6, A2}
};
 
const pumpCount = sizeof(pumpPins) / sizeof(pumpPins[0]);

int actPump = 0;

void setup() {
  for (int i=0; i < pumpCount; i++)
  {
    pinMode(pumpPins[i].auto, INPUT_PULLDOWN);
    pinMode(pumpPins[i].tripped, INPUT_PULLDOWN);
    pinMode(pumpPins[i].run, OUTPUT);
  }
  ...
}

void loop()
{
  ...
  
  if (conditionToStartAssignedPump)
    runPump(actPump);
  
  if (activePumpFinishedRunning())
  {
    actPump++;             // assign next pump to start next time
    actPump %= pumpCount;  // wrap round after last pump
  }
}

To add a new pump to the system just alter this

Pump pumpPins[] = {
  {D0, D1, D5, A1},
  {D2, D3, D6, A2},
  {TX, A5, A6, A7}
};

and you have three pumps but the code will need no extra work.

thank you very much for that it makes sense. my code was getting very complicated. i will have a play and see where i end up.

thanks again

just one thing in my if codition how would i address ie the auto switch as the input would be different depending which actpump was being used

That’s the point of using arrays


// pumpPins[0].auto == D0
// pumpPins[1].auto == D2
// so depending on the this will either read D0 or D2
if(digitalRead(pumpPins[actPump].auto)) {
  ...
}

You just change the index (or loop through all elements, as done in setup() for pinMode()) and you got all the respective pins right there.

And if you want to have the next element (with wrap-round), you’d just use pumpPins((idx+1) % pumpCount)
The previous element (only required with more than two elements) is retrieved via pumpPins((idx+pumpCount-1) % pumpCount).
You can if()..else for that too, but I prefer the mathematical aproach.

Like this??

 digitalWrite(pumpPins[actPump].run, HIGH);
1 Like