Water barrel controller - Issues with switches

Hey team,

I've put together a controller that will help me keep a 55 gallon barrel filled with RO water for my fish tanks. It consists of an Arduino Uno R3, an ebay 4 channel relay board, 4 12v solenoids and a couple of float switches.

I had the sketch tested and working prior to the physical installation but now it's given me nothing but trouble. The code is a modified version of what someone posted here a while ago.

The general idea operation is supposed to be:

Low water float: Triggers a flush sequence of the RO filter and then begins to fill the barrel
High water float: Closes all solenoids
Start button: Manually trigger the flush sequence and fill barrel
Stop button: Closes all solenoids

The 'low water float' and 'start button' operate properly. However, whenever the 'stop button' or 'high water float' are triggered, 95% of the time it will trigger the filling sequence repeatedly rather than stopping.

I can replicate this by simply jumping the input pins. I'm confident it has nothing to do with the floats. I'm wondering if it's a problem in my code (introduced too late at night) or if it's a hardware problem caused by some weird ground interference on my setup causing the pins to misfire.

For troubleshooting purposes, I removed some of the timing code (debounce, max run time, etc..).

#define RELAY_ON 0
#define RELAY_OFF 1

byte lowWaterPin = A0;    // Goes LOW when water below switch
byte highWaterPin = A5;   // Goes LOW when water above switch
byte wasteFlushPin = 10;        // Relay to control the waste flush
byte wasteMainPin = 11;
byte roDumpPin = 12;
byte roMainPin = 13;
byte startButton = 7;
byte stopButton = 6;

unsigned long maxRunTime = 3 * 60 * 60 * 1000L;   // pump on for max of 3hrs
unsigned long minOffTime = 4000;  // pump must be off for at least Y miliseconds
unsigned long switchDebounceTime = 3000;  // Switch must be activated for at least 3 seconds.

unsigned long lastPumpTime = 0;

unsigned long lastLowWaterDetectTime = 0;
boolean lastLowWaterState = HIGH;

boolean pumpRunning = true;


void setup(){

  pinMode(lowWaterPin, INPUT_PULLUP);
  pinMode(highWaterPin, INPUT_PULLUP);

  pinMode(startButton, INPUT_PULLUP);
  pinMode(stopButton, INPUT_PULLUP);
  
  pinMode(wasteFlushPin, OUTPUT);
  pinMode(wasteMainPin, OUTPUT);
  pinMode(roDumpPin, OUTPUT);
  pinMode(roMainPin, OUTPUT);
        
  digitalWrite(wasteFlushPin, RELAY_OFF);
  digitalWrite(wasteMainPin, RELAY_ON);
  digitalWrite(roDumpPin, RELAY_OFF);
  digitalWrite(roMainPin, RELAY_ON);   

}

void loop(){

  unsigned long currentMillis = millis();

  boolean lowWaterState = digitalRead(lowWaterPin);
  boolean highWaterState = digitalRead(highWaterPin);
  boolean startButtonState = digitalRead(startButton);
  boolean stopButtonState = digitalRead(stopButton);

  if(lowWaterState != lastLowWaterState){
    lastLowWaterDetectTime = currentMillis;
  }


  if (pumpRunning) {  // if the pump is on then let's see if we should turn it off yet

    if ((highWaterState == LOW) || (stopButtonState == LOW)){
      digitalWrite(wasteFlushPin, RELAY_OFF);
      digitalWrite(wasteMainPin, RELAY_OFF);
      digitalWrite(roDumpPin, RELAY_OFF);
      digitalWrite(roMainPin, RELAY_OFF);   
      pumpRunning = false;
      lastPumpTime = currentMillis;
    }
  }
  else {   // pump is not running, see if we need to turn it on

      if( (startButtonState == LOW) || ((lowWaterState == LOW) )){   // switch is low and has been for at least 3 seconds
        digitalWrite(wasteFlushPin, RELAY_ON);   // Flush membrane and begin TDS creep dump
        digitalWrite(wasteMainPin, RELAY_OFF);
        digitalWrite(roDumpPin, RELAY_ON);
        digitalWrite(roMainPin, RELAY_OFF);   
        delay(1000);
        digitalWrite(wasteFlushPin, RELAY_OFF);  // Normal waste to increase flow though membrane and continue to dump last of TDS creep
        digitalWrite(wasteMainPin, RELAY_ON);
        digitalWrite(roDumpPin, RELAY_ON);
        digitalWrite(roMainPin, RELAY_OFF);   
        delay(1000);
        digitalWrite(wasteFlushPin, RELAY_OFF); // Normal operation
        digitalWrite(wasteMainPin, RELAY_ON);
        digitalWrite(roDumpPin, RELAY_OFF);
        digitalWrite(roMainPin, RELAY_ON);   
        pumpRunning = true;
        lastPumpTime = currentMillis;
      }
  }



  lastLowWaterState = lowWaterState;

}

Thanks so much!

Does your reduced code behave like the full code?
If your answer is no, post the full code.

You have this

        lastPumpTime = currentMillis;

in two places but you don't have any test based on lastPumpTime

Likewise for

lastLowWaterDetectTime = currentMillis;

I suspect you need to post the complete program.

...R

The fault happens with or without the extra timing code. But who knows, there could be something else wrong as well :slight_smile:

#define RELAY_ON 0
#define RELAY_OFF 1

byte lowWaterPin = A0;    // Goes LOW when water below switch
byte highWaterPin = A5;   // Goes LOW when water above switch
byte wasteFlushPin = 10;        // Relay to control the waste flush
byte wasteMainPin = 11;
byte roDumpPin = 12;
byte roMainPin = 13;
byte startButton = 7;
byte stopButton = 6;

unsigned long maxRunTime = 3 * 60 * 60 * 1000L;   // pump on for max of 3hrs
unsigned long minOffTime = 4000;  // pump must be off for at least Y miliseconds
unsigned long switchDebounceTime = 3000;  // Switch must be activated for at least 3 seconds.

unsigned long lastPumpTime = 0;

unsigned long lastLowWaterDetectTime = 0;
boolean lastLowWaterState = HIGH;

boolean pumpRunning = true;


void setup(){

  pinMode(lowWaterPin, INPUT_PULLUP);
  pinMode(highWaterPin, INPUT_PULLUP);

  pinMode(startButton, INPUT_PULLUP);
  pinMode(stopButton, INPUT_PULLUP);
  
  pinMode(wasteFlushPin, OUTPUT);
  pinMode(wasteMainPin, OUTPUT);
  pinMode(roDumpPin, OUTPUT);
  pinMode(roMainPin, OUTPUT);
        
  digitalWrite(wasteFlushPin, RELAY_OFF);
  digitalWrite(wasteMainPin, RELAY_ON);
  digitalWrite(roDumpPin, RELAY_OFF);
  digitalWrite(roMainPin, RELAY_ON);   

}

void loop(){

  unsigned long currentMillis = millis();

  boolean lowWaterState = digitalRead(lowWaterPin);
  boolean highWaterState = digitalRead(highWaterPin);
  boolean startButtonState = digitalRead(startButton);
  boolean stopButtonState = digitalRead(stopButton);

  if(lowWaterState != lastLowWaterState){
    lastLowWaterDetectTime = currentMillis;
  }


  if (pumpRunning) {  // if the pump is on then let's see if we should turn it off yet

    if ((highWaterState == LOW) || (stopButtonState == LOW) || (currentMillis - lastPumpTime >= maxRunTime)){
      digitalWrite(wasteFlushPin, RELAY_OFF);
      digitalWrite(wasteMainPin, RELAY_OFF);
      digitalWrite(roDumpPin, RELAY_OFF);
      digitalWrite(roMainPin, RELAY_OFF);   
      pumpRunning = false;
      lastPumpTime = currentMillis;
    }
  }
  else {   // pump is not running, see if we need to turn it on

      if( (startButtonState == LOW) || ((lowWaterState == LOW)  &&  (currentMillis - lastLowWaterDetectTime >= switchDebounceTime) && (currentMillis - lastPumpTime > minOffTime))){   // switch is low and has been for at least 3 seconds
        digitalWrite(wasteFlushPin, RELAY_ON);   // Flush membrane and begin TDS creep dump
        digitalWrite(wasteMainPin, RELAY_OFF);
        digitalWrite(roDumpPin, RELAY_ON);
        digitalWrite(roMainPin, RELAY_OFF);   
        delay(1000);
        digitalWrite(wasteFlushPin, RELAY_OFF);  // Normal waste to increase flow though membrane and continue to dump last of TDS creep
        digitalWrite(wasteMainPin, RELAY_ON);
        digitalWrite(roDumpPin, RELAY_ON);
        digitalWrite(roMainPin, RELAY_OFF);   
        delay(1000);
        digitalWrite(wasteFlushPin, RELAY_OFF); // Normal operation
        digitalWrite(wasteMainPin, RELAY_ON);
        digitalWrite(roDumpPin, RELAY_OFF);
        digitalWrite(roMainPin, RELAY_ON);   
        pumpRunning = true;
        lastPumpTime = currentMillis;
      }
  }



  lastLowWaterState = lowWaterState;

}

The fault happens with or without the extra timing code. But who knows, there could be something else wrong as well

I'd write some code similar to the state change detection example, and determine if the 4 switches are, independent of any other action, operating correctly.

If the hardware is faulty, no amount of coding is going to correct that. If the hardware is good, you would have a sketch that proves that.

This sort of extended IF statement is a recipe for confusion. I strongly suggest you put each IF on a separate line

if( (startButtonState == LOW) || ((lowWaterState == LOW)  &&  (currentMillis - lastLowWaterDetectTime >= switchDebounceTime) && (currentMillis - lastPumpTime > minOffTime))){   // switch is low and has been for at least 3 seconds

...R

How quickly does it come back on again?
I can't find any obvious fault with the code, but I have a few comments..

Your start command is here

  if( (startButtonState == LOW) || ((lowWaterState == LOW)  &&  (currentMillis - lastLowWaterDetectTime >= switchDebounceTime) && (currentMillis - lastPumpTime > minOffTime))){ 
                        1                            2                                                   3                                                        4

Start command is from 1 or (2 and 3 and 4)
4. lastPumpTime will be stop time, and minOffTime is set to 4 seconds, so restart will quickly be possible.
3. lastLowWaterDetectTime was when water level was at lowest, so this will not likely prevent restart.
2. This is a float that must give signal, unless...

  1. This button does.

If pumps comes on immediately, start button might be faulty. Water inside?
If pumps is delayed a few seconds, it can be the float.

Do you have some leds to attach that show startButtonState and lowWaterState? I think it will tell you what start your pumps.

 However, whenever the 'stop button' or 'high water float' are triggered, 95% of the time it will trigger the filling sequence repeatedly rather than stopping.
…
The fault happens with or without the extra timing code.

So either the start button or the low water sensor is jammed on (LOW). The other thing I notice is that you are using an analog input pin for the water sensors. This … should work. I see you are putting them into INPUT_PULLUP mode.

I'd suggest you disconnect the start and the low water switches altogether. If the behaviour ceases, connect one and then the other and see which one is giving spurious LOWs. If the behaviour does not cease, or if the problematic sensor is the low water switch, shift it from A0 to a digital pin and see if that fixes it.

I originally had my float switches on the digital pins but moved them over to the analog for troubleshooting.

With nothing hooked up to the Arduino except the relay board and a few 4" jumpers to simulate the switches, the problem still happens. :frowning:

PaulMurrayCbr:

 However, whenever the 'stop button' or 'high water float' are triggered, 95% of the time it will trigger the filling sequence repeatedly rather than stopping.


The fault happens with or without the extra timing code.




So either the start button or the low water sensor is jammed on (LOW). The other thing I notice is that you are using an analog input pin for the water sensors. This … should work. I see you are putting them into INPUT_PULLUP mode.

I'd suggest you disconnect the start and the low water switches altogether. If the behaviour ceases, connect one and then the other and see which one is giving spurious LOWs. If the behaviour does not cease, or if the problematic sensor is the low water switch, shift it from A0 to a digital pin and see if that fixes it.

the problem still happens. :frowning:

You should re-read reply #4.

How quickly does the filling sequence start after a stop command?
If you look at uno led 13, does it blink after a stop command when filling occurs? If it does it indicate your uno restart, and as you start in filling mode it will start to fill.

Also if it goes directly to filling instead of first flushing, I am pretty sure start command comes from setup() after a restart.

Hi,
Can you please post a copy of your circuit, in CAD or a picture of a hand drawn circuit in jpg, png?

Can you post a picture of your project.

How long are the wires between the UNO and the float switches?
Do any of the sensor wires run parallel to the switched wiring?
What are the relays controlling?

Have you bypassed any of the wiring, in particular the float switch wiring and the button wiring.

How are you providing power to the project?

Thanks... Tom... :slight_smile: