1 round of activation only

Simple question. Got 2 reed switches that activate a pump when both have magnets on them. How do i make the pump do only one round of delay (10 sec)? Now the pump goes indefinitely if the magnets are present. I want the pump to do only one 10 sec activation that reset only when you reapply magnets; so take magnets off and put them close again.

void setup() {
  //start serial connection
  Serial.begin(9600);
  //configure pin2 as an input and enable the internal pull-up resistor
  pinMode(5, INPUT_PULLUP);
  pinMode(7, INPUT_PULLUP);
  pinMode(2, OUTPUT);

}

void loop() {
  //read the pushbutton value into a variable
  int sensorVal1 = digitalRead(5);
  int sensorVal2 = digitalRead(7);
  //print out the value of the pushbutton
  Serial.println("Var 1:\t Var 2\t");
  Serial.print("\t");
  Serial.print(sensorVal1);
  Serial.print("\t");
  Serial.print(sensorVal2);
  Serial.println();

  // Keep in mind the pullup means the pushbutton's
  // logic is inverted. It goes HIGH when it's open,
  // and LOW when it's pressed. Turn on pin 13 when the
  // button's pressed, and off when it's not:
 if ((sensorVal1 == HIGH && sensorVal2 == HIGH))
{ 
    digitalWrite(2, LOW);
    delay(10000);
    
  } else {
    digitalWrite(2, HIGH);
  }
}

This needs state machine.

Your machine has the following states:

Idle: no magnets or 1 magnets applied and the pump is not running Running: 2 magnets applied, counting down from 10s to 0s.

So you first need to make sure you assign the idle state to your state machine. Then under idle state, you wait for both switches to close. Once that happens, assign Running state to your state machine and set count down to 10 second. Turn on the pump. Once in running state, you look at the time stamp to determine whether 10s has expired. If not, stay in this state. If yes, turn off pump and assign idle state to your state machine.

The easiest state machine can be constructed with a switch-case structure. Read about it in C/C++. It's not too hard to use.

It is harmless, but I do not know why this

 if ((sensorVal1 == HIGH && sensorVal2 == HIGH))

has two sets of parentheses.

Maybe it is intentional, but this

    delay(10000);

will keep the Arduino (whatever Arduino it is) from doing anything useful for 10 seconds, an eternity in Arduino time.

vaj4088: will keep the Arduino (whatever Arduino it is) from doing anything useful for 10 seconds, an eternity in Arduino time.

Guess they are redundant, the delay makes the pump go for 10 seconds. Might not be the proper way to do it, me being new with this.

liudr: This needs state machine.

Your machine has the following states:

Idle: no magnets or 1 magnets applied and the pump is not running Running: 2 magnets applied, counting down from 10s to 0s.

So you first need to make sure you assign the idle state to your state machine. Then under idle state, you wait for both switches to close. Once that happens, assign Running state to your state machine and set count down to 10 second. Turn on the pump. Once in running state, you look at the time stamp to determine whether 10s has expired. If not, stay in this state. If yes, turn off pump and assign idle state to your state machine.

The easiest state machine can be constructed with a switch-case structure. Read about it in C/C++. It's not too hard to use.

This is my go at it. Haven't tested it yet.

void setup()
{
  pinMode(5, INPUT_PULLUP);
  pinMode(7, INPUT_PULLUP);
  pinMode(2,OUTPUT);
}

void loop()
{
  static int state = 1; // initial state is 1, the "idle" state.
  static unsigned long ts;  // To store the "current" time in for delays.
  int sensorVal1 = digitalRead(5);
  int sensorVal2 = digitalRead(7);
  //print out the value of the pushbutton
  Serial.println("Var 1:\t Var 2\t");
  Serial.print("\t");
  Serial.print(sensorVal1);
  Serial.print("\t");
  Serial.print(sensorVal2);
  Serial.println();

  switch(state)
  {
    case 1:
      // We don't need to do anything here, waiting for a forced state change.
      break;
    case 2:
      if ((sensorVal1 == HIGH && sensorVal2 == HIGH))
      ts = millis();  // Remember the current time
      digitalWrite(2, LOW);
      state = 3;  // Move to the next state
      if(millis() > ts + 10000)
      {
        state = 1;
      }
      break;
    default:
      state = 1;
      break;
  }
}
    case 1:
      // We don't need to do anything here, waiting for a forced state change.
      break;
You do need to keep checking digital pins 5 and 7 in case 1 so when they are both high, you turn on pump, set state to 2 and jump out of it.

Instead of 1 and 2, make them more memorable:

const int state_idle=1;
const int state_running=2;
...
case state_idle:

... (when both pins are high)
state=state_running;
pump_on();
break;
case state_running:
...
break;

Thanks for the instructions, despite them I'm unable to do this properly. What am I doing wrong now?

void setup()
{
  Serial.begin(9600);
  pinMode(5, INPUT_PULLUP);
  pinMode(7, INPUT_PULLUP);
  pinMode(2, OUTPUT);
}

void loop()
{
  static int state = 1; // initial state is 1, the "idle" state.
  const int state_idle=1;
  const int state_running=2;
  static unsigned long ts;  // To store the "current" time in for delays.
  int sensorVal1 = digitalRead(5);
  int sensorVal2 = digitalRead(7);
  //print out the value of the pushbutton
  Serial.println("Var 1:\t Var 2\t");
  Serial.print("\t");
  Serial.print(sensorVal1);
  Serial.print("\t");
  Serial.print(sensorVal2);
  Serial.println();

  switch(state)
  {
    case state_idle:
     sensorVal1 = digitalRead(5);
     sensorVal2 = digitalRead(7);
     if (sensorVal1 == HIGH && sensorVal2 == HIGH)
      ts = millis();  // Remember the current time
      
      state = state_running;
           
      break;
    case state_running:
      digitalWrite(2, HIGH);
      if(millis() > ts + 10000)
     
      state = state_idle;
     
      break;
    default:
     
      state = state_idle;
     
      break;
  }
}
  switch(state)
  {
    case state_idle:
     sensorVal1 = digitalRead(5);
     sensorVal2 = digitalRead(7);

Why do you need to read the states again?

What do your Serial.print()s tell you is happening? Why not?

You are missing {} in state 1

if (sensorVal1 == HIGH && sensorVal2 == HIGH) 
{
      ts = millis();  // Remember the current time
      
      state = state_running;
}

(And you don't want to read again the values and you want to start the pump)

In case 2 (running)

You want to check for timeout or removing the magnet in which case you stop running

PaulS:  switch(state)  {    case state_idle:     sensorVal1 = digitalRead(5);     sensorVal2 = digitalRead(7);

Why do you need to read the states again?

What do your Serial.print()s tell you is happening? Why not?

Serial print works fine, it reads both switches. I'm kinda just following other peoples examples when structuring this. The repeat read might be redundant. Currently pump is not being activated when both switches are high.

Currently pump is not being activated when both switches are high.

See my comment above

That's because you forgot to do it....

ALSO AND IMPORTANT - DON'T FORGET THE PULL-UP AND THUS INVERTED LOGIC - YOU WANT TO CHECK FRO LOWs

J-M-L: See my comment above

That's because you forgot to do it....

Kind of thought that this did. Guess I'm wrong.

Chole:    case state_running:      digitalWrite(2, HIGH);

Post full code - we don't know what you did or not...

If setting pin 2 high is not starting the pump, what should I being doing instead. Setting it to be low actually makes the pump work indefinately with no switches activated.

void setup()
{
  Serial.begin(9600);
  pinMode(5, INPUT_PULLUP);
  pinMode(7, INPUT_PULLUP);
  pinMode(2, OUTPUT);
}

void loop()
{
  static int state = 1; // initial state is 1, the "idle" state.
  const int state_idle=1;
  const int state_running=2;
  static unsigned long ts;  // To store the "current" time in for delays.
  int sensorVal1 = digitalRead(5);
  int sensorVal2 = digitalRead(7);
  //print out the value of the pushbutton
  Serial.println("Var 1:\t Var 2\t");
  Serial.print("\t");
  Serial.print(sensorVal1);
  Serial.print("\t");
  Serial.print(sensorVal2);
  Serial.println();

  switch(state)
  {
    case state_idle:
      if (sensorVal1 == HIGH && sensorVal2 == HIGH)
      {
      ts = millis();  // Remember the current time
     
      state = state_running;
      }
      break;
    case state_running:
      digitalWrite(2, LOW);
      if(millis() > ts + 10000)
     
      state = state_idle;
     
      break;
    default:
     
      state = state_idle;
     
      break;
  }
}

Try to read this and see if that makes sense

I cleaned up a bit the variables names and pins to make this readable

const int state_idle = 1;
const int state_running = 2;

#define MAGNET1_PIN 5
#define MAGNET2_PIN 7
#define PUMP_PIN 2
#define PUMP_RUN_DURATION 10000L  // time in ms

int state = state_idle; // initial state is 1, the "idle" state.

void setup()
{
 Serial.begin(9600);
 pinMode(MAGNET1_PIN, INPUT_PULLUP); // Careful, inverted logic. pin HIGH when button not pressed
 pinMode(MAGNET2_PIN, INPUT_PULLUP);
 pinMode(PUMP_PIN, OUTPUT);
digitalWrite(PUMP_PIN, LOW); // stop the pump
}

void loop()
{
 static unsigned long startPumpTime;  // To store the "current" time in for delays.

 int magnet1 = digitalRead(MAGNET1_PIN);
 int magnet2 = digitalRead(MAGNET2_PIN);

 //print out the value of the pushbutton
 Serial.println("Var 1:\t Var 2\t");
 Serial.print("\t");
 Serial.print(magnet1);
 Serial.print("\t");
 Serial.print(magnet2);
 Serial.println();

 switch (state) {

   case state_idle:
     // we are idle, check if we need to start the pump.
     if ((magnet1 == LOW) && (magnet2 == LOW)) { // inverted logic, LOW means magnet are there
       startPumpTime = millis();  // Remember the current time
       digitalWrite(2, HIGH); // launch the pump
       state = state_running; // remember the pump is running
     }
     break;

   case state_running:
     // check if it's time to  switch off the pump: timeout or a magnet missing
     // note that it could be worth debouncing - depending on quality of the sensors. assuming no bouncing.
     if ((magnet1 == HIGH) || (magnet2 == HIGH) || (millis() - startPumpTime >= PUMP_RUN_DURATION )) { // do timeout this way, not addition which overflow
       // we need to stop the pump.
       digitalWrite(PUMP_PIN, LOW); // stop the pump
       state = state_idle;
     }
     break;

   default:
     // this should never happen, to be safe ensure pump is not running
     digitalWrite(PUMP_PIN, LOW); // stop the pump
     state = state_idle;
     break;
 } // end case
} // end loop

J-M-L:
Try to read this and see if that makes sense

I cleaned up a bit the variables names and pins to make this readable

const int state_idle = 1;

const int state_running = 2;

#define MAGNET1_PIN 5
#define MAGNET2_PIN 7
#define PUMP_PIN 2
#define PUMP_RUN_DURATION 10000L  // time in ms

int state = state_idle; // initial state is 1, the “idle” state.

void setup()
{
Serial.begin(9600);
pinMode(MAGNET1_PIN, INPUT_PULLUP); // Careful, inverted logic. pin HIGH when button not pressed
pinMode(MAGNET2_PIN, INPUT_PULLUP);
pinMode(PUMP_PIN, OUTPUT);
digitalWrite(PUMP_PIN, LOW); // stop the pump
}

void loop()
{
static unsigned long startPumpTime;  // To store the “current” time in for delays.

int magnet1 = digitalRead(MAGNET1_PIN);
int magnet2 = digitalRead(MAGNET2_PIN);

//print out the value of the pushbutton
Serial.println(“Var 1:\t Var 2\t”);
Serial.print("\t");
Serial.print(magnet1);
Serial.print("\t");
Serial.print(magnet2);
Serial.println();

switch (state) {

case state_idle:
    // we are idle, check if we need to start the pump.
    if ((magnet1 == LOW) && (magnet2 == LOW)) { // inverted logic, LOW means magnet are there
      startPumpTime = millis();  // Remember the current time
      digitalWrite(2, HIGH); // launch the pump
      state = state_running; // remember the pump is running
    }
    break;

case state_running:
    // check if it’s time to  switch off the pump: timeout or a magnet missing
    // note that it could be worth debouncing - depending on quality of the sensors. assuming no bouncing.
    if ((magnet1 == HIGH) || (magnet2 == HIGH) || (millis() - startPumpTime >= PUMP_RUN_DURATION )) { // do timeout this way, not addition which overflow
      // we need to stop the pump.
      digitalWrite(PUMP_PIN, LOW); // stop the pump
      state = state_idle;
    }
    break;

default:
    // this should never happen, to be safe ensure pump is not running
    digitalWrite(PUMP_PIN, LOW); // stop the pump
    state = state_idle;
    break;
} // end case
} // end loop

Thank you, I really appreciate the effort. Your code starts the pump when both magnets are present and stops it when they are not; but if you see the first post the reason we tried with state is because I need the magnet to trip one ten second activation time and then stay off even when the magnet has not lost contact. Only reapply both magnets will trip the pump. Also the relay for the pump now goes on and off for a fraction of a second every 10 seconds.

The state change detection example would be a good place to start. Each switch will change to "pressed" only once when the magnet is applied.

Turn the pump on only when both switches have changed to "pressed". Do nothing when either switch becomes released, and do nothing when either switch becomes pressed. Only do something when both switches have become pressed.

You are right this adds a stage where you need to capture that once activated at least one magnet needs to be gone before we restart the pump.

Try this

const int state_idle = 1;
const int state_running = 2;

#define MAGNET1_PIN 5
#define MAGNET2_PIN 7
#define PUMP_PIN 2
#define PUMP_RUN_DURATION 10000L  // time in ms

int state = state_idle; // initial state is 1, the "idle" state
boolean magnetRemoved;

void setup()
{
 Serial.begin(9600);
 pinMode(MAGNET1_PIN, INPUT_PULLUP); // Careful, inverted logic. pin HIGH when button not pressed
 pinMode(MAGNET2_PIN, INPUT_PULLUP);
 pinMode(PUMP_PIN, OUTPUT);
 digitalWrite(PUMP_PIN, LOW); // stop the pump
 magnetRemoved = true;
}

void loop()
{
 static unsigned long startPumpTime;  // To store the "current" time in for delays.

 int magnet1 = digitalRead(MAGNET1_PIN);
 int magnet2 = digitalRead(MAGNET2_PIN);

 //print out the value of the pushbutton
 Serial.println("Var 1:\t Var 2\t");
 Serial.print("\t");
 Serial.print(magnet1);
 Serial.print("\t");
 Serial.print(magnet2);
 Serial.println();

 switch (state) {

   case state_idle:
     // we are idle, check if we need to start the pump.
     if ((magnet1 == LOW) && (magnet2 == LOW) && magnetRemoved) { // inverted logic, LOW means magnet are there
       startPumpTime = millis();  // Remember the current time
       digitalWrite(PUMP_PIN,HIGH); // launch the pump
       state = state_running; // remember the pump is running
       magnetRemoved = false;
     } else if ((magnet1 == HIGH) || (magnet2 == HIGH)) magnetRemoved = true;
     break;

   case state_running:
     // check if it's time to  switch off the pump: timeout or a magnet missing
     // note that it could be worth debouncing - depending on quality of the sensors. assuming no bouncing.
     if ((magnet1 == HIGH) || (magnet2 == HIGH) || (millis() - startPumpTime >= PUMP_RUN_DURATION )) { // do timeout this way, not addition which overflows
       // we need to stop the pump.
       digitalWrite(PUMP_PIN, LOW); // stop the pump
       state = state_idle;
     }
     if ((magnet1 == HIGH) || (magnet2 == HIGH)) magnetRemoved = true;
     break;

   default:
     // this should never happen, to be safe ensure pump is not running
     digitalWrite(PUMP_PIN, LOW); // stop the pump
     state = state_idle;
     break;
 } // end case
} // end loop

J-M-L: You are right this adds a stage where you need to capture that once activated at least one magnet needs to be gone before we restart the pump.

Try this

const int state_idle = 1;
const int state_running = 2;

define MAGNET1_PIN 5

define MAGNET2_PIN 7

define PUMP_PIN 2

define PUMP_RUN_DURATION 10000L  // time in ms

int state = state_idle; // initial state is 1, the "idle" state boolean magnetRemoved;

void setup() { Serial.begin(9600); pinMode(MAGNET1_PIN, INPUT_PULLUP); // Careful, inverted logic. pin HIGH when button not pressed pinMode(MAGNET2_PIN, INPUT_PULLUP); pinMode(PUMP_PIN, OUTPUT); digitalWrite(PUMP_PIN, LOW); // stop the pump magnetRemoved = true; }

void loop() { static unsigned long startPumpTime;  // To store the "current" time in for delays.

int magnet1 = digitalRead(MAGNET1_PIN); int magnet2 = digitalRead(MAGNET2_PIN);

//print out the value of the pushbutton Serial.println("Var 1:\t Var 2\t"); Serial.print("\t"); Serial.print(magnet1); Serial.print("\t"); Serial.print(magnet2); Serial.println();

switch (state) {

  case state_idle:     // we are idle, check if we need to start the pump.     if ((magnet1 == LOW) && (magnet2 == LOW) && magnetRemoved) { // inverted logic, LOW means magnet are there       startPumpTime = millis();  // Remember the current time       digitalWrite(PUMP_PIN,HIGH); // launch the pump       state = state_running; // remember the pump is running       magnetRemoved = false;     } else if ((magnet1 == HIGH) || (magnet2 == HIGH)) magnetRemoved = true;     break;

  case state_running:     // check if it's time to  switch off the pump: timeout or a magnet missing     // note that it could be worth debouncing - depending on quality of the sensors. assuming no bouncing.     if ((magnet1 == HIGH) || (magnet2 == HIGH) || (millis() - startPumpTime >= PUMP_RUN_DURATION )) { // do timeout this way, not addition which overflows       // we need to stop the pump.       digitalWrite(PUMP_PIN, LOW); // stop the pump       state = state_idle;     }     if ((magnet1 == HIGH) || (magnet2 == HIGH)) magnetRemoved = true;     break;

  default:     // this should never happen, to be safe ensure pump is not running     digitalWrite(PUMP_PIN, LOW); // stop the pump     state = state_idle;     break; } // end case } // end loop

When I try this version after uploading the code the pump starts after 10s countdown and goes on indefinitely. Putting the magnet on either of the switches resets the relay and the pump and goes on indefinitely.

Please confirm if magnets HIGH means magnet present or absent and if you turn the pump on with a HIGH or a LOW...

Have you analyzed to code? If I had left a bug could you suggest a fix? How much work did you put into understanding the structure?

I suppose low as is in the code, right? First the pump starts after 10 seconds regardless of what I do and I can only reset the the pump to start again by putting a magnet on any or both of the reed switches. There is no 10 second countdown after the pump starts in any of the combinations and pump never stops. My knowledge is quite limited to be able to pinpoint the bug. I really appreciate your effort.