Help programing - Turn on/off based on input

I think you're going to need some extra logic to handle the sensor bad/out of water condition. Otherwise, when one of those things occurs, you're going to run the pump for 30 seconds every time you check the level sensor, possibly burning out the pump once it exhausts the reservoir.

Well 30 seconds is the cut off time, if pump still on (meaning no water in the reservoir) shut it off. Assuming it take 20 seconds to fill up the water, so it never have to reach the 30 seconds limit.

Does that make sense?

Not entirely. Now I think it's "if the sensor is confirmed high over a ten second period, run the pump until sensor is low and then for another 2 seconds. If that pumping is still happening after 30 seconds, stop the pump and use the infinite loop to stop all subsequent operations until reset"

Yes! that is pretty much what I wanted to do :slight_smile:

Requirement is defined (pretty much) so it's time to look at state machines - you'll find examples in the forums. Enumerate your states (I count five), figure out what you have to do in each state, what causes transitions between them and what to do when you transition. Loop() becomes a switch statement with the states as cases. Add in some variables to tell you when timed events started and you're most of the way there.

To use a timer instead of a delay, you use code like MarkT showed already.

If you're short on space, one way to manage is to use a variable for each item's timer, and use zero to represent an unused event (that is, not currently active).

For example, say you want a light on for 5 seconds, then turn off. Use a variable 'timerLight' to hold the milliseconds to stop in the future:

unsigned long timerLight=0;
void loop()
{
  unsigned long msec=millis();
  if ( ourNotYetWrittenHelperFunctionToDetectIfWeWantTheLightOn() )
  {
    timerLight=msec+5000; // when to stop in the future

// now turn on light

  }
  if ( timerLight && timerLight<msec ) // time to turn off?
  {
    timerLight=0;// turn off timer so we don't check again
        
// turn off light (somehow)
    
  }
}

Now the code loop will stay active without delays, yet still catch events.

You can also gang up the events - for example, after you turn off one light, you could turn on another:

unsigned long timerLight1=0, timerLight2=0;
void loop()
{
  unsigned long msec=millis();
  if ( ourNotYetWrittenHelperFunctionToDetectIfWeWantTheLightOn() )
  {
    timerLight1=msec+5000; // when to stop in the future

// now turn on light

  }
  if ( timerLight1 && timerLight1<msec ) // time to turn off 1st light?
  {
    timerLight1=0;// turn off timer so we don't check again
        
// turn off light1 (somehow)

    // now next light - turn it off in 10 seconds
    timerLight2=msec+10000; // when to stop #2 in the future

// turn ON light2 (somehow)

    
  }
  if ( timerLight2 && timerLight2<msec ) // time to turn off 2nd light?
  {
    timerLight2=0;// turn off timer so we don't check again
        
// turn off light2 (somehow)
    
  }
}

The result is a you can a number of events in whichever order you want - just remember to add on and off code in the appropriate sections.

Thanks for the feedback guys.

My computer currently not working, so will have to wait few days to test out the codes.

Ok! I got this codes to do what I wanted, but I need a timeout code within this codes. I want to say if "val" still read HIGH after 1 minute, write LOW to relayPin.

Can someone help me?

unsigned long relay_on_time;
unsigned long loopTime;

int relayPin = 13; // relay connected to digital pin 13
int inPin = 7; // sensor input source connected to digital pin 7
int val = 0; // variable to store the read value

void setup()
{
relay_on_time = millis();
loopTime = relay_on_time;

pinMode(relayPin, OUTPUT); // sets the digtial pin 13 as output
pinMode(inPin, INPUT); // sets the digital pin 7 as input
}

void loop()
{
relay_on_time = millis();

if (relay_on_time >= (loopTime + 10000))
{
val = digitalRead(inPin);

if (val == HIGH)
{
digitalWrite(relayPin, HIGH);
}

if (val == LOW)
{
digitalWrite (relayPin, LOW);
}
loopTime = relay_on_time;
}

}

Perhaps the (untested) sketch below will get you closer.
see the BlinkWithoutDelay example sketch if you need more on using millis to determine a timeout period

int relayPin = 13;   // relay connected to digital pin 13
int waterLowPin = 7; // pint goes high when water level is low
int val = 0;         // variable to store the read value

long relay_on_time;

void setup()
{
  pinMode(relayPin, OUTPUT);       // sets the digtial pin 13 as output
  pinMode(waterLowPin, INPUT);     // sets the digital pin 7 as input
}

void loop()
{ 
  if( digitalRead(waterLowPin))
  {
    // here if the water level is low
    delay(1000 * 10); // wait ten seconds
    if( digitalRead(waterLowPin))  // check again
    {
       // here if water level is still low   
       digitalWrite(relayPin, HIGH); // turn on relay       
       relay_on_time = millis();
       while( millis() - relay_on_time < (1000 * 30) )
       {   
         if( digitalRead(waterLowPin) == false)  // check if level is now high
         {
            delay(1000 * 2); // wait two seconds
            digitalWrite(relayPin, LOW); // turn off relay
            break; // exit the while loop
         }
       }
       // here if pump on for more than 30 seconds 
       digitalWrite(relayPin, LOW); // turn off relay
    }
  }
}

What your code is doing is checking the value every 10 seconds, and turning a relay high or low. What you want is to make sure it doesn't stay on for over 30 seconds. You can add a 'deadman switch' test:

unsigned long timeToTurnOff=0; // << change
void loop()
{
  relay_on_time = millis();
  if (relay_on_time >= (loopTime + 10000))
  { 
    val = digitalRead(inPin);
    if (val == HIGH)
    {
      digitalWrite(relayPin, HIGH);
      if (0==timeToTurnOff)  // << change: first time on since turned off?
        timeToTurnOff=relay_on_time+30000;  // << change: store max time on
    }
    if ( val == LOW || timeToTurnOff>=relay_on_time )  // << change: off or out of time? then turn off
    {
      digitalWrite (relayPin, LOW);
      timeToTurnOff=0; // << change: turn off our test
    }
    loopTime = relay_on_time;
  }
}

'timeToTurnOff' is used to make sure you shut down after a predetermined time.

David,

I tried your codes and nothing happen.

Xenia2:
David, I tried your codes and nothing happen.

Oops- I had the test backwards:

 if ( val == LOW || timeToTurnOff<=relay_on_time )  // << change: off or out of time? then turn off

I'm not sure how you are testing this - you'd need to force things on for over thirty seconds for this to kick in.

By the way, I was looking over your posts - at one point, you wanted it to be 60 seconds, not 30; at another, you wanted to go into an infinite loop until a manual reset. Am I misunderstanding the requirements?

That's correct, after 60 seconds write LOW to relayPin, but stay LOW until manual reset.

Your codes is now working, how do I modify the codes so its go into infinite loop until reset?

An infinite loop is easy.

while(1) {}

Add this wherever you want the Arduino to stop doing anything useful.

I'm glad the code worked!

Reworking the code for the new changes - I broke out just the section of code that would change:

...
        timeToTurnOff=relay_on_time+60000; 
    }
    if ( val == LOW ) 
    {
      digitalWrite (relayPin, LOW);
      timeToTurnOff=0; // << change: turn off our test
    }
    if ( timeToTurnOff>=relay_on_time )  
    {
      digitalWrite (relayPin, LOW); // turn off
      // lock up until reset
      while (1)
      {
// turn on led somehow
        delay(500);
// turn off led somehow
        delay(500);
      }
    }
    loopTime = relay_on_time;
  }
}
  • I changed the 30000 to 60000

  • Since you had a different direction to go with the deadman switch, I separated it from the original LOW test.

  • For the deadman, it will stay in that loop until your reset - I'd recommend turning on the Arduino's LED as a visual indicator you're all locked up, but it's whatever you wish.

Hope this solves it.

David, thanks for sticking with me :slight_smile:

Is this correct? I have the LED hookup to relayPin, and with the new "if statement", nothing happen to relayPin

....
void loop()
{
  relay_on_time = millis();
  
  if (relay_on_time >= (loopTime + 10000))
  { 
    val = digitalRead(inPin);
    
    if (val == HIGH)
    {
      digitalWrite(relayPin, HIGH);
      if ( 0 == TimeToTurnOff)
      {
        TimeToTurnOff = relay_on_time + 60000;
      }
    }
    
    if (val == LOW)
    {
      digitalWrite (relayPin, LOW);
      TimeToTurnOff = 0;
    }
    
    if (TimeToTurnOff >= relay_on_time)
    {
       digitalWrite(relayPin, LOW);
       while(1)
       {}
    }
    loopTime = relay_on_time;
  }
  
}

It looks right - but with nothing happening in the while(1) {} loop, you won't have an indication it's locked. You could always wire another led to another pin.

I was expecting the LED to come on after 10 seconds and after 60 seconds the LED go off and remain off until manual reset.

But the LED doesn't even come on after 10 seconds.

I don't think it's the code - take a moment (and a new sketch) to turn on/off a LED exactly how you want to, and then use that code back in this main sketch. Debugging two things at once is usually more complicated than doing each separately.

I am not sure if this relevant but if changed

...
    if (shutoff <= relay_on_time)  // changed relay_on_time >= shutoff relayPin go into HIGH but never get inside infinite loop to shutoff
    {
       digitalWrite(relayPin, LOW);
       while(1)
       {}
    }
    loopTime = relay_on_time;
  } 
}