//glowny kod POMPA 2.3 z Pullup
/*
10/22/24 - poprawiona linijka aby pompa sie wlaczyla nawet jak zbiornik pokazuje -X%
*/
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C LCD(0x27, 16, 2);
//TDS Sensor variables
const int TDS = 36; // on ESP32 pin VP (analog pin required)
//Ultrasonic Sensor variables
const int UltrSonicTrig= 19; //(digital pin required) OUTPUT
const int UltrSonicEcho = 23; //(digital pin required) INPUT
//short int ContainerSize = 40; //Container's depth in inches REAL ESP32 >>> ADJUSTABLE <<<
short int ContainerSize = 157; //Container's depth in inches SIMULATOR >>> ADJUSTABLE <<<
short int LevelHalf = 50; //At what percentage pump on >>> ADJUSTABLE <<<
short int LevelFull = 90; //At what percentage pump off >>> ADJUSTABLE <<<
short int TDSlimit = 50; //At what percentage pump off >>> ADJUSTABLE <<<
String PumpState = "";
float PercentageFilled = 0;
//for LCD
//LCD SCL = 22 PIN (required)
//LCD SDA = 21 PIN (required)
//Buttons and switches variables
#define BUTTON_PIN 2
byte lastButtonState = HIGH;
unsigned long debounceDuration = 50; // millis
unsigned long lastTimeButtonStateChanged = 0;
const int SwitchFlush = 34; // Switch Left - FLUSH
const int SwitchCIP = 35; // Switch Right - CIP
//Output devices variables
const int PP = 32;//Product pump - yellow LED #1
const int WAT = 33; //water valve - yellow LED #2
const int DRAIN = 25; //drain - green LED #1
const int CV = 26;// cylculation - green LED #2
const int PV1 = 27; //product fill valve - red LED #1
const int CHP = 14; //chemical pump - red LED #2
const int PV = 12; // product valve inlet - blue LED #1
const int CP = 13; //cylculation pump - blue LED #2
//GPIOs 34 to 39 are GPIs – input only pins, don't use them
String Mode = "RUN";
//bool Active = false; //variable controlled by a push button
volatile byte Active = false;
bool FirstRun = true; //Flag to show first run of the loop to display copyrights message
int i = 0;
int j = 0;
int FLUSH_Outer_Loop1 = 1; // >>> ADJUSTABLE <<<
int FLUSH_Inner_Loop1_1 = 6; // >>> ADJUSTABLE <<<
int FLUSH_Inner_Loop1_2 = 6; // >>> ADJUSTABLE <<<
int FLUSH_Outer_Loop2 = 1; // >>> ADJUSTABLE <<<
int FLUSH_Inner_Loop2_1 = 6; // >>> ADJUSTABLE <<<
int FLUSH_Inner_Loop2_2 = 6; // >>> ADJUSTABLE <<<
int CIP_Outer_Loop1 = 1; // >>> ADJUSTABLE <<<
int CIP_Inner_Loop1_1 = 6; // >>> ADJUSTABLE <<<
int CIP_Inner_Loop1_2 = 6; // >>> ADJUSTABLE <<<
int CIP_Outer_Loop2 = 1; // >>> ADJUSTABLE <<<
int CIP_Inner_Loop2_1 = 6; // >>> ADJUSTABLE <<<
int CIP_Inner_Loop2_2 = 6; // >>> ADJUSTABLE <<<
void setup()
{
Serial.begin(9600); //Activate Terminal for detailed logs
LCD.init();
LCD.backlight();
pinMode(BUTTON_PIN, INPUT_PULLUP);
pinMode(SwitchFlush,INPUT);
pinMode(SwitchCIP,INPUT);
pinMode(UltrSonicTrig, OUTPUT);
pinMode(UltrSonicEcho, INPUT);
pinMode(TDS,INPUT);
pinMode(PP,OUTPUT);
pinMode(WAT,OUTPUT);
pinMode(DRAIN,OUTPUT);
pinMode(CV,OUTPUT);
pinMode(PV1,OUTPUT);
pinMode(CHP,OUTPUT);
pinMode(PV,OUTPUT);
pinMode(CP,OUTPUT);
//attachInterrupt(digitalPinToInterrupt(2), pushButton, FALLING); //interrupt attached to a push button
}
void loop()
{
if(FirstRun)
{
msg("Copyrights", "Design by Zielak"); //welcome message for 2 sec
DelayMicroCustom(2000000, !Active,"All"); //controls length of welcome message in microsec, 2sec
FirstRun = false;
}
readButtons();
//if a switch button was changed during any pin high then it will stay so we need to reset all
Serial.println("PP=0, WAT=0, DRAIN=0, CV=0, PV1=0, CHP=0, PV=0, CP=0");
digitalWrite(WAT,LOW);
digitalWrite(DRAIN,LOW);
digitalWrite(PV,LOW);
digitalWrite(PP,LOW);
digitalWrite(CV,LOW);
digitalWrite(PV1,LOW);
digitalWrite(CHP,LOW);
digitalWrite(CP,LOW);
if(Mode == "RUN")
{
Serial.println("Mode = RUN. Waiting for push button");
Active = false;
msg("RUN | Stopped","");
while(Mode == "RUN" && !Active)
{
readButtons();
}
if(Mode == "RUN" && Active)
{
msg("FLUSH | Loop 1","");
Serial.println("Mode = RUN. Push button pressed.");
Serial.println("Mode = RUN. Starting.");
while(Mode == "RUN" && Active)
{
readButtons();
PumpState = (digitalRead(PP) == 1) ? "ON" : "OFF";
PercentageFilled = (1-readUltrasonicDistance("RUN")/float(ContainerSize))*100;
msg("RUN | Pump "+String(PumpState),"Filled: "+String(int(trunc(PercentageFilled)))+"%");
if( PercentageFilled > float(LevelFull))
{
digitalWrite(PP, LOW); //Pump OFF
Serial.println("PP=0, WAT=0, DRAIN=0, CV=0, PV1=0, CHP=0, PV=0, CP=0");
}
else if ( PercentageFilled < float(LevelHalf))
{
digitalWrite(PP, HIGH); //Pump ON
Serial.println("PP=1, WAT=0, DRAIN=0, CV=0, PV1=0, CHP=0, PV=0, CP=0");
}
}
}
}
else if(Mode == "FLUSH")
{
Serial.println("Mode = FLUSH. Waiting for push button");
Active = false;
msg("FLUSH | Stopped","");
while(Mode == "FLUSH" && !Active)
{
readButtons();
}
if(Mode == "FLUSH" && Active)
{
msg("FLUSH | Loop 1","");
Serial.println("Mode = FLUSH. Push button pressed.");
Serial.println("Mode = FLUSH. Loop 1 starting, will run : "+String(FLUSH_Outer_Loop1)+" times.");
i = 1;
while(Mode == "FLUSH" && Active && i<= FLUSH_Outer_Loop1)
{
readButtons();
Serial.println("Mode = FLUSH, Loop_1 - Round: "+String(i));
digitalWrite(WAT,HIGH);
digitalWrite(DRAIN,HIGH);
digitalWrite(PV,HIGH);
Serial.println("PP=0, WAT=1, DRAIN=1, CV=0, PV1=0, CHP=0, PV=1, CP=0");
Serial.println("Ultrasonic_Sensor=1");
PercentageFilled = 0;
while(Mode == "FLUSH" && Active && PercentageFilled < float(LevelFull))
{
readButtons();
PercentageFilled = (1-readUltrasonicDistance("FLUSH")/float(ContainerSize))*100;
msg("FLUSH | Loop 1","Filled: "+String(int(trunc(PercentageFilled)))+"%");
}
if(Mode == "FLUSH" && Active)
{
Serial.println("Ultrasonic_Sensor=0");
digitalWrite(WAT,LOW);
digitalWrite(DRAIN,LOW);
digitalWrite(PV,LOW);
digitalWrite(PP,HIGH);
Serial.println("PP=1, WAT=0, DRAIN=0, CV=0, PV1=0, CHP=0, PV=0, CP=0");
Serial.println("Mode = FLUSH, Loop_1 - Inner_Loop1 will run: "+String(FLUSH_Inner_Loop1_1)+" times.");
msg("FLUSH | Loop 1","PV1 ON/OFF");
InnerLoop(FLUSH_Inner_Loop1_1,"FLUSH");
digitalWrite(PP,LOW);
Serial.println("PP=0, WAT=0, DRAIN=0, CV=0, PV1=0, CHP=0, PV=0, CP=0");
Serial.println("Mode = FLUSH, Loop_1 - Inner_Loop2 will run: "+String(FLUSH_Inner_Loop1_2)+" times.");
msg("FLUSH | Loop 1","PV1 ON/OFF");
InnerLoop(FLUSH_Inner_Loop1_2,"FLUSH");
i++;
}
} //FLUSH_Outer_Loop1 end
if(Mode == "FLUSH" && Active)
{
Serial.println("Mode = FLUSH. Loop 1 finished.");
i = 1;
msg("FLUSH | Loop 2","");
Serial.println("Mode = FLUSH. Loop 2 starting, will run : "+String(FLUSH_Outer_Loop2)+" times.");
}
while(Mode == "FLUSH" && Active && i<= FLUSH_Outer_Loop2)
{
readButtons();
Serial.println("Mode = FLUSH, Loop_2 - Round: "+String(i));
digitalWrite(WAT,HIGH);
digitalWrite(PV,HIGH);
digitalWrite(DRAIN,HIGH);
Serial.println("PP=0, WAT=1, DRAIN=1, CV=0, PV1=0, CHP=0, PV=1, CP=0");
Serial.println("Ultrasonic_Sensor=1");
PercentageFilled = 0;
while(Mode == "FLUSH" && Active && PercentageFilled < float(LevelFull))
{
readButtons();
PercentageFilled = (1-readUltrasonicDistance("FLUSH")/float(ContainerSize))*100;
msg("FLUSH | Loop 2","Filled: "+String(int(trunc(PercentageFilled)))+"%");
}
if(Mode == "FLUSH" && Active)
{
Serial.println("Ultrasonic_Sensor=0");
digitalWrite(WAT,LOW);
digitalWrite(PV,LOW);
digitalWrite(CP,HIGH);
digitalWrite(CV,HIGH);
digitalWrite(PP,HIGH);
Serial.println("PP=1, WAT=0, DRAIN=1, CV=1, PV1=0, CHP=0, PV=0, CP=1");
Serial.println("Mode = FLUSH, Loop_2 - Inner_Loop1 will run: "+String(FLUSH_Inner_Loop2_1)+" times.");
msg("FLUSH | Loop 2","PV1 ON/OFF");
InnerLoop(FLUSH_Inner_Loop2_1,"FLUSH");
digitalWrite(DRAIN,LOW);
Serial.println("PP=1, WAT=0, DRAIN=0, CV=1, PV1=0, CHP=0, PV=0, CP=1");
Serial.println("Mode = FLUSH, Loop_2 - Inner_Loop2 will run: "+String(FLUSH_Inner_Loop2_2)+" times.");
msg("FLUSH | Loop 2","PV1 ON/OFF");
InnerLoop(FLUSH_Inner_Loop2_2,"FLUSH");
i++;
}
} //FLUSH_Outer_Loop2 end
if(Mode == "FLUSH" && Active)
{
Serial.println("Mode = FLUSH. Loop 2 finished.");
digitalWrite(CV,LOW);
digitalWrite(CP,LOW);
digitalWrite(WAT,LOW);
digitalWrite(PP,LOW);
Serial.println("PP=0, WAT=0, DRAIN=0, CV=0, PV1=0, CHP=0, PV=0, CP=0");
msg("FLUSH | Finished","");
}
}
}
else if(Mode == "CIP")
{
Serial.println("Mode = CIP. Waiting for push button");
Active = false;
msg("CIP | Stopped","");
while(Mode == "CIP" && !Active)
{
readButtons();
}
if(Mode == "CIP" && Active)
{
Serial.println("Mode = CIP. Push button pressed.");
Serial.println("Mode = CIP. Starting.");
digitalWrite(DRAIN,HIGH);
digitalWrite(PV,HIGH);
digitalWrite(WAT,HIGH);
digitalWrite(CV,HIGH);
Serial.println("PP=0, WAT=1, DRAIN=1, CV=1, PV1=0, CHP=0, PV=1, CP=0");
Serial.println("Ultrasonic_Sensor=1");
PercentageFilled = 0;
while(Mode == "CIP" && Active && PercentageFilled < float(LevelFull))
{
readButtons();
PercentageFilled = (1-readUltrasonicDistance("CIP")/float(ContainerSize))*100;
msg("CIP","Filled: "+String(int(trunc(PercentageFilled)))+"%");
}
if(Mode == "CIP" && Active)
{
Serial.println("Ultrasonic_Sensor=0");
digitalWrite(PV,LOW);
digitalWrite(WAT,LOW);
digitalWrite(CP,HIGH);
digitalWrite(PP,HIGH);
digitalWrite(CHP,HIGH);
Serial.println("PP=1, WAT=0, DRAIN=1, CV=1, PV1=0, CHP=1, PV=0, CP=1");
Serial.println("Mode = CIP, TDS_sensor=1");
}
int TDSvalue = 999999;
while(Mode == "CIP" && Active && TDSvalue > TDSlimit)
{
//TDSvalue = readTDS(); //used for a real ESP32
TDSvalue = readTDS_FAKE(); //used only for a simulator
msg("MODE: CIP","TDS: "+String(TDSvalue)+" PPM");
}
if(Mode == "CIP" && Active)
{
Serial.println("Mode = CIP, TDS_sensor=0");
digitalWrite(CV,HIGH);
digitalWrite(CHP,LOW);
Serial.println("PP=1, WAT=0, DRAIN=1, CV=1, PV1=0, CHP=0, PV=0, CP=1");
i = 1;
msg("CIP | Loop 1","");
Serial.println("Mode = CIP. Loop 1 starting.");
Serial.println("Mode = CIP. Loop 1 starting, will run: "+String(CIP_Outer_Loop1)+" times.");
}
while(Mode == "CIP" && Active && i<= CIP_Outer_Loop1)
{
readButtons();
Serial.println("Mode = CIP. Loop 1 - Round: "+String(i));
Serial.println("Mode = CIP, Loop_1 - Inner_Loop1 will run: "+String(CIP_Inner_Loop1_1)+" times.");
msg("CIP | Loop 1","PV1 ON/OFF");
InnerLoop(CIP_Inner_Loop1_1,"CIP");
digitalWrite(DRAIN,LOW);
Serial.println("PP=1, WAT=0, DRAIN=0, CV=1, PV1=0, CHP=0, PV=0, CP=1");
Serial.println("Mode = CIP, Loop_1 - Inner_Loop2 will run: "+String(CIP_Inner_Loop1_2)+" times.");
msg("CIP | Loop 1","PV1 ON/OFF");
InnerLoop(CIP_Inner_Loop1_2,"CIP");
i++;
} //CIP_Outer_Loop1 end
if(Mode == "CIP" && Active)
{
Serial.println("Mode = CIP. Loop 1 finished.");
digitalWrite(PP,LOW);
Serial.println("PP=0, WAT=0, DRAIN=0, CV=1, PV1=0, CHP=0, PV=0, CP=1");
i = 1;
msg("CIP | Loop 2","");
Serial.println("Mode = CIP. Loop 2 starting, will run:"+String(CIP_Outer_Loop2));
}
while(Mode == "CIP" && Active && i<= CIP_Outer_Loop2)
{
readButtons();
Serial.println("Mode = CIP. Loop 2 - Round: "+String(i));
Serial.println("Mode = CIP, Loop_2 - Inner_Loop1 will run: "+String(CIP_Inner_Loop2_1)+" times.");
msg("CIP | Loop 2","PV1 ON/OFF");
InnerLoop(CIP_Inner_Loop2_1,"CIP");
digitalWrite(PP,HIGH);
Serial.println("PP=1, WAT=0, DRAIN=0, CV=1, PV1=0, CHP=0, PV=0, CP=1");
Serial.println("Mode = CIP, Loop_2 - Inner_Loop2 will run: "+String(CIP_Inner_Loop2_2)+" times.");
msg("CIP | Loop 2","PV1 ON/OFF");
InnerLoop(CIP_Inner_Loop2_2,"CIP");
i++;
} //CIP_Outer_Loop1 end
if(Mode == "CIP" && Active)
{
Serial.println("Mode = CIP. Loop 2 finished.");
digitalWrite(PP,LOW);
digitalWrite(CP,LOW);
digitalWrite(CV,LOW);
Serial.println("PP=0, WAT=0, DRAIN=0, CV=0, PV1=0, CHP=0, PV=0, CP=0");
Serial.println("Mode = CIP. Finished.");
}
}
}
}
void InnerLoop(int roundsCount, String ActiveMode)
{
int n = 1;
while(Active && n <= roundsCount)
{
digitalWrite(PV1,HIGH);
DelayMicroCustom(3000000, Active, ActiveMode); //wait 3sec
digitalWrite(PV1,LOW);
DelayMicroCustom(3000000, Active, ActiveMode); //wait 3sec
n++;
}
}
void DelayMicroCustom(float WaitTime, bool Activate, String ActiveMode)
{
//delay replacement which is stop by push button / zamiennik delay() zatrzymywany przez push button
//delay() can not be used because interrupt is present / delay() nie moze byc uzyty bo jest interrupt
unsigned long currentMicros = micros();
unsigned long previousMicros = micros();
float timeDiff = 0;
while(timeDiff < WaitTime && Activate && (Mode == ActiveMode || ActiveMode == "All")){
currentMicros = micros();
timeDiff = currentMicros - previousMicros;
readButtons();
}
}
void msg(String first_line, String second_line) //Function to display messages on LCD and Terminal, first param controls first row and second param controls second row
{
LCD.clear();
LCD.setCursor(0,0);
LCD.print(first_line);
LCD.setCursor(0,1);
LCD.print(second_line);
Serial.println(first_line);
Serial.println(second_line);
}
int readTDS_FAKE() //used only for a simulator
{
int TDSvalue = map(analogRead(TDS), 0, 4095, 0, 500);
DelayMicroCustom(100000,Active,"CIP");
return TDSvalue;
}
int readTDS() //used only for a real ESP32
{
unsigned long int avgval_ADC;
int buffer_tds[10],temp1;
for(int i=0;i<10;i++)
{
buffer_tds[i]=analogRead(TDS); //collects 10 samples and put into array
DelayMicroCustom(30000,Active, "CIP"); //wait 30 millisec
}
for(int i=0;i<9;i++) //sort array
{
for(int j=i+1;j<10;j++)
{
if(buffer_tds[i]>buffer_tds[j])
{
temp1=buffer_tds[i];
buffer_tds[i]=buffer_tds[j];
buffer_tds[j]=temp1;
}
}
}
avgval_ADC=0;
for(int i=2;i<8;i++)
{
avgval_ADC+=buffer_tds[i]; //sum few items from array
}
float voltage_value = (float)avgval_ADC*5.0/1024.0/6; //calculate the avg value
float TDS = (133.42/voltage_value*voltage_value-255.86*voltage_value*voltage_value + 857.39*voltage_value)*0.5; //formula copied
return (voltage_value == 0) ? 0 : int(trunc(TDS)) ; //returns value or 0 if voltage is 0
}
long readUltrasonicDistance(String ActiveMode)
{
pinMode(UltrSonicTrig, OUTPUT); // Clear the trigger
digitalWrite(UltrSonicTrig, LOW);
DelayMicroCustom(2,true, ActiveMode); //wait 2 microsec
digitalWrite(UltrSonicTrig, HIGH);
DelayMicroCustom(10,true, ActiveMode); //wait 10 microsec
digitalWrite(UltrSonicTrig, LOW);
pinMode(UltrSonicEcho, INPUT); // Reads the echo pin, and returns the sound wave travel time in microseconds
float cm = 0.01723 * pulseIn(UltrSonicEcho, HIGH);
float inches = (cm / 2.54);
DelayMicroCustom(100000,true, ActiveMode); //wait 100 millisec
return inches ; //returns value in inches
}
void readButtons()
{
String ActiveMsg;
if (millis() - lastTimeButtonStateChanged > debounceDuration)
{
byte buttonState = digitalRead(BUTTON_PIN);
if (buttonState != lastButtonState)
{
lastTimeButtonStateChanged = millis();
lastButtonState = buttonState;
if (buttonState == LOW)
{
Active = (Active == false) ? true : false; //push button changes the variable from 1 to 0 or other way around
ActiveMsg = (Active == false) ? "STOP" : "START";
msg(String(ActiveMsg)+" pressed.","");
Serial.println("Push button pressed.");
}
}
}
int FLUSHpin = 0;
int CIPpin = 0;
FLUSHpin = digitalRead(SwitchFlush);
CIPpin = digitalRead(SwitchCIP);
if(FLUSHpin == 0 && CIPpin == 0)
{
Mode = "RUN";
}
else if(FLUSHpin == 1 && CIPpin == 0)
{
Mode = "FLUSH";
}
else if(FLUSHpin == 0 && CIPpin == 1)
{
Mode = "CIP";
}
}