This is a simple Ebb & Flow or Flood & Drain system depending on what you want to call it. I’m not going to go into much detail on the ebb & flow hydroponic system. I am more focused on the programming to to flood and drain my buckets.

The Set Up

I purchased an Ebb & Flow System from some online store. I won’t tell you which one because after a little research, I found that I could have build the same system for half the cost.

Basically, I have a 60 gallon reservoir and twelve 5-gallon buckets. Each bucket has a 5 gallon cloth bucket. I have a 13th bucket, this is my control bucket. I also have 2 water pumps that push about 350 GPH, and a lot of 5/8″ plastic tubing. If your buckets are not dark, you will need a can of black spray paint. Any light hitting the nutrient solution will cause mold to grow.

Inside the Control Tank
Control Bucket outside with the Arduino on top
Reservoir with the Fill and Drain hoses

So I have a pump going from the reservoir to my control tank ( Fill pump ), and another pump going from my control tank back into the reservoir ( Drain pump ). In the control bucket, you put the horizontal float switch at the bottom, make sure to leave room so the switch can open fully. When this switch disengages, it will turn the drain pump off Placing the switch to low will cause it to always be engaged. Place the pp float switch about 3 inches from the top of the control bucket. When this switch engages, it will turn off the fill pump.

To set up the rest of the system, you will need the tubing, Elbow and Tee connections (make sure the have the same IO as the tubing or you will have leaks) and matching grommets.

Cut 2 holes at the bottom of the control bucket, insert a grommet in each of the holes the push the elbow into the grommet. In the other buckets, drill one hole at the bottom, shove a grommet in the hole and a Tee connector in the grommet. With the hose, connect all the Tee connectors in a continuous loop however with the control bucket connected with the elbows making it the start and stop point of the loop.

Pin Diagram

So the diagram uses a breadboard, in real life, I like wire nuts. They take up less room to.

Here, the breadboard is used solely for power purposes. The relays require 5v so I ran tthe 5V to the breakboard and the (-) to the black and the (+) to the red.

The switches have one lead in (-) side to ground out.

The relays connect to the Arduino:

  • Drain S-Pin connected to Digital Input 13
  • Fill S-Pin connected to Digital Input 12.

The other pin from the switches connect to the Arduino as:

  • PP Float Switch connected to Digital Input 7
  • Horizontal Float Switch connected to Digital Input 8

Power Cord Splitter Cable

To prepare the power cord splitter, you will been an Exacto knife. Make 2 cuts around the cord to expose the wires. Cut the neutral (usually the black) wire and add attach 2 female spade connectors to each end. Then black tape it all shut:


The Code


#include <time.h>

int pump_fill  = 12; // pump from reservoir to control tank - purple
int pump_drain = 13; // pump from control tank to reservoir - brown

// switches
int switch_full = 7; // Switch engages when control tank is filled   
int switch_empty = 8; // Switch disengages when control tank is empty
int switch_cutoff = 4; // If switch engages, water is going to overflow

// int mTime, mInc, iLoopCount, iLastTime, ;
unsigned long iStartMin = 240; 
unsigned long iSubMin = .25;

unsigned long iStartUp = 0;
unsigned long iLoopCount = 0;
unsigned long iCycleCount = 0;

unsigned long iCurrentMillis = 0;
unsigned long iNext = 0;
unsigned long iDelay = 60000L;
unsigned long iFillCheckDelay = 30000L;
unsigned long mUntil = 0;

unsigned long iMinute = 60000L;

enum eStatus {
  Drain, Empty, Fill, Full, Off
};

eStatus currentStatus = Off;
bool bFilled = false;
bool bEmpty = true;

void setup() {
  Serial.begin(9600); 
  pinMode( pump_drain, OUTPUT );
  pinMode( pump_fill, OUTPUT );
  pinMode( switch_empty, INPUT_PULLUP );
  pinMode( switch_full, INPUT_PULLUP );
  digitalWrite(pump_drain, LOW);
  digitalWrite(pump_fill, LOW);
  iDelay = 5000L;
}

void loop() {
  iCurrentMillis = millis();
  Serial.println( "loop: " + String(iCurrentMillis));
  Serial.println( "currentStatus: " + String(currentStatus));
  bool ba = iNext == 0;
  Serial.println( "iNext == 0: " + String(ba));
  bool bb = iNext >= iCurrentMillis;
  Serial.println( "iNext >= iCurrentMillis: " + String(bb));
  Serial.println( "iNext: " + String(iNext));
  if( iNext == 0 || iNext <= iCurrentMillis ) {
    if( currentStatus == Off ) {
      Serial.println( "Start DoFill: " + String(iCurrentMillis));
      // start everyting
      iLoopCount++;
      DoFill();
    }
  }

  if( currentStatus == Fill ) {
    Serial.println( "Check Fill: " + String(iCurrentMillis));
    // if currently filling, check switch_full 
    if(digitalRead(switch_full) == LOW ) { // if switch_full is ON
      // Turn off pump_fill
      digitalWrite( pump_fill, LOW );
      DoDrain();

    }
  }
  if( currentStatus == Drain ) {
    Serial.println( "Check Drain: " + String(millis()));
    // if draining, check switch_empty
    if( digitalRead(switch_empty) == HIGH ) { // if switch_empty is OFF
      // control tank is empty, turn pump off
      digitalWrite(pump_drain, LOW );
      if( isEmpty()) {
        currentStatus = Off;
        iNext = iCurrentMillis + ( ( iStartMin - iLoopCount ) * iMinute ) ;
        iDelay = 30000L;//( ( iStartMin - iLoopCount ) * iMinute );
        Serial.println("iCurrentMillis: " + String( iCurrentMillis ) + " || iNext: " + String(iNext));
      }
      else {
        digitalWrite( pump_drain, HIGH );
        iDelay = 1000;
      }
    }
  }
  Serial.println( "Time: " + String(iCurrentMillis) + " || iDelay: " + String(iDelay) );
  delay(iDelay);
}

int isFullCheck = 0;
bool isFull() {
  if( isFullCheck == 3 ) return true;
  bool result = true;
  Serial.println( "Run isFull");
  delay( iFillCheckDelay ); // wait `iFillCheckDelay` ms to check if the float switch has fallen back down
  Serial.println( "digitalRead(switch_full): " + (digitalRead(switch_full)));
  if( digitalRead(switch_full) == HIGH ) {
    result = false;
  }
  isFullCheck++;
  return result;
}

int isEmptyCheck = 0;
bool isEmpty() {
  if( isEmptyCheck == 3 ) return true;
  bool result = true;
  Serial.println( "Run isEmpty");
  delay( iFillCheckDelay ); // wait `iFillCheckDelay` ms to check if the float switch has fallen back down
  Serial.println( "digitalRead(switch_empty): " + (digitalRead(switch_empty)));
  if( digitalRead(switch_empty) == LOW ) {
    result = false;
  }
  isEmptyCheck++;
  return result;

}

void DoFill() {
  Serial.println( "DoFill" );
  if( currentStatus == Off ) {
    // If the current status is off, turn pump_fill ON
    digitalWrite( pump_fill, HIGH );
    currentStatus = Fill;
    iDelay = 1000L; // while filling, check switch every second
  }
}

void DoDrain() {
  Serial.println( "DoDrain" );
  //delay( (60 * HANGTIME) * 1000 );
  // start draining
  digitalWrite(pump_drain, HIGH);
  currentStatus = Drain;
  iDelay = 1000L; // while draining, check switch every second
}

Download the Code

The Final Product

I mounted the Arduino and relays to a piece of peg board and then stuck it in a super stacker pencil box.

Add comment

Your email address will not be published.