Help in blynk timer

hi Blynkers
i am using
• esp32 + WIFI
• Smartphone Android + version 10
• Blynk server
• Blynk Library version 0.6.1

and my problem for now is for coding time interval inside my function to ask pump to run for 10 sec. and i tried with millis() function and it some time run for 5 sec. and another time only for 1 sec and its not constant time interval i also tried it using the rtc i will post the codes i used
first code

#include <BlynkSimpleEsp8266.h>
#elif defined(ESP32)
#include <BlynkSimpleEsp32.h>
#else
#error "Board not found"
#endif
#include <TimeLib.h>
#include <WidgetRTC.h>
#include <WiFi.h>
#include <WiFiClient.h>

WidgetRTC rtc;
BlynkTimer timer;                    // SimpleTimer instance named timer
WidgetTerminal terminal(V8);
unsigned long Time_intervel = 10000;
int priming_pump_1 = 0;

BLYNK_WRITE(V10) {
  priming_pump_1 = param.asInt();

void Priming()
{
if(priming_pump_1==1)  // 
{
    Blynk.virtualWrite(V11, 0);  // to assure the pin is not active while other pump is runing
    Blynk.virtualWrite(V12, 0);  // to assure the pin is not active while other pump is runing
  digitalWrite(pumpPin[0], HIGH);
  static unsigned long timepoint = 0;
   if (millis() - timepoint > Time_intervel) //time interval: 1s
  {
    Serial.println("timepoint:");
    Serial.println(timepoint);
    timepoint = millis();
    digitalWrite(pumpPin[0], LOW);
    Blynk.virtualWrite(V10, 0);
    priming_pump_1 = 0;
  }
  }
}
void setup()

{

  Serial.begin(115200);
 timer.setInterval(500L, Priming);
 for (int p = 0; p<= 2; p++)
  {
    pinMode(pumpPin[p],OUTPUT);
  }
  Blynk.virtualWrite(V10,0);

void loop()
{
   Blynk.run();
    timer.run();
  }
}

this is not working good with time
i tried

if(priming_pump_1==1)  // pumpRunning false to assure only one pump running atime
{
    Blynk.virtualWrite(V11, 0);  // to assure the pin is not active while other pump is runing
    Blynk.virtualWrite(V12, 0);  // to assure the pin is not active while other pump is runing
  digitalWrite(pumpPin[0], HIGH);
  static unsigned long timepoint = second();
   if (second() - timepoint > Time_intervel) 
  {
    timepoint = second();
    digitalWrite(pumpPin[0], LOW);
    Blynk.virtualWrite(V10, 0);
    priming_pump_1 = 0;
  }

I think you need to explain in detail what widgets you have set up in your app, what pins they are attached to, and what their function is.
You also need to explain the operational logic behind what you are trying to achieve.

Your first piece of code has clearly been changed from the code you have actually compiled and tested, as it has a missing closing curly bracket in the BLYNK_WRITE(V10) function.

I’m also not clear where the second piece of code is meant to go. Is it a replacement for a function in the first code, or an addition.

Other comments…

I don’t understand why you are calling the Priming function once every 500ms, 24 hours per day. I would have assumed that this would be an infrequent action?

Your choice of variable type for the timepoint variable seems odd, and the way it is used is also odd. If you want to work using millis comparisons in this way (which I wouldn’t recommend) then you need to structure your code differently and not attempt to achieve a 10 second time comparison inside a function which executes once every half second.

When trying to understand the program flow and why you are achieving strange results, you should add some serial print statements to show variable values at various points, and to indicate that a particular point in the code has been reached. You do this with your 'timepointvariable, but only inside anif` statement and you don’t show the current millis() value at the same time.

If you want to achieve a non-blocking timer then the simplest way is to use a timeout timer, preferably as part of a lambda function. Like this…

  timer.setTimeout(10000L, []() 
  {  // Wait 10 seconds then...
     // The actions here will be executed once the timeout timer expires...
     // do some stuff

  });  // END Lambda Function

Pete.

1 Like

i have set up terminal widgets and three buttons as switch for runing 3 dosing pumps on/off for priming/filling there lines
i also have 2 data input for selecting the pump to be calibrate and to provide the software with the calibration amount
i would have also data output on display widgets for the test results and the PH

and this code is to make automatic water alkalinity tester based on PH testing
and i just posted the peace of code i was trying to just run the pump for 10 sec. and then will input the amount the water pumped as reference for pump rate in sec.

regarding
the 500ms i do not understand you question i think this priming function will not be active till the priming function active by button to start the pump …

regarding you comment “(which I wouldn’t recommend) then you need to structure your code differently and not attempt to achieve a 10 second time comparison inside a function which executes once every half second.”
could you please give me just an example for that or anything help me to how to structure my code to serve time compare and calibrating pumps… i want to tell you this my first time to write code i spend 2 months reading now every day more than 8 hours and practicing because i feel coding is something great i feel its like art in imagination and nothing stop your imagination …

regarding the full code its not yet complete but for now its complied and working but with some flaws in timing

#include "OTABlynkCredentials.h"

#ifdef ESP8266
#include <BlynkSimpleEsp8266.h>
#elif defined(ESP32)
#include <BlynkSimpleEsp32.h>
#else
#error "Board not found"
#endif
#include <TimeLib.h>
#include <WidgetRTC.h>
#include <WiFi.h>
#include <WiFiClient.h>
#include "DFRobot_ESP_PH.h"
#include "EEPROM.h"
#include <OneWire.h>
#include <DallasTemperature.h>
#define PH_PIN 35    //the esp gpio data pin number
credentials Credentials;
const int stirrer = 28 ;
const int pumpPin[3] = { 25, 26, 27};
unsigned long Time_intervel = 10L;
float multiplier[3] = { 0, 0, 0}; //ms per ml
float caliberation_1 =  5; //ml per 10sec  thos just assumption till finishing calibertion method which still not done in code
float caliberation_2 =  8;
float caliberation_3 =  7;
uint32_t startPump = 0;
uint32_t runCount;
bool pumpRunning = false;
int regect_time_MS = 25000;
float titrant_amount ;
int  startPump2;
int runCount2 ;
int stopPump ;
float Alkalinity_dKH;
float Alkalinity_meq;
int start_Regect; // used in testing sequance for pump used to reject the water
int button = 0;   //Button Widget set to Switch
int priming_pump_1 = 0; // used as pump flage
int priming_pump_2 = 0;
int priming_pump_3 = 0;
int button_on = 0;
int x;           //Correlates Array Positions with Pump Motor Pins
int calibration;

BLYNK_WRITE(V10) {
  priming_pump_1 = param.asInt();
}
BLYNK_WRITE(V11) {
  priming_pump_2 = param.asInt();
}
BLYNK_WRITE(V12) {
  priming_pump_3 = param.asInt();
}

BLYNK_WRITE(V4) {
  x = param.asInt() - 1;
}
BLYNK_WRITE(V5) {
  DOSEml = param.asFloat();
}
BLYNK_WRITE(V6) {
  button = param.asInt();
}
BLYNK_WRITE(V13) {
  calibration = param.asInt();
}
BLYNK_WRITE(V14) {
  button_on = param.asInt();
}

WidgetRTC rtc;
BlynkTimer timer;                    // SimpleTimer instance named timer
WidgetTerminal terminal(V8);


//Variables
char auth_token[33];
bool connected_to_internet = 0;
const int Erasing_button = 0;


//Provide credentials for your ESP server
char* esp_ssid = "Egyreef.com";
char* esp_pass = "";



#define ONE_WIRE_BUS 4
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
DeviceAddress insideThermometer;

DFRobot_ESP_PH ph;


float voltage, phValue, temperature = 25;

/*void myTimerEvent()
{
  Serial.print("Requesting temperatures...");
  sensors.requestTemperatures(); // Send the command to get temperatures
  Serial.println("DONE");
  temperature = sensors.getTempCByIndex(0); // Save the reading to use later
  Serial.print("Temperature is: ");
  Serial.println(temperature); // print the reading that we just took
  Blynk.virtualWrite(V1, temperature); // and send the same reading to virtual pin 5
 }*/
void test(){
  digitalWrite(pumpPin[2], HIGH); //taking the probe water saving out to be readyfor next measuring
    pumpRunning = true;
    start_Regect = millis();
    terminal.print("preparing for next test");
if (millis() - start_Regect> regect_time_MS)
  {
    digitalWrite(pumpPin[0], LOW);
}

   *(multiplier) = caliberation_1;// taking 50 ml sample
    pumpRunning = true;
    digitalWrite(pumpPin[0], HIGH);
    startPump = millis();
    runCount = 50 * multiplier[0];
    terminal.print("taking sample ");
    terminal.println("50 ml from tank water");
  if (millis() - startPump > runCount)
  {
    digitalWrite(pumpPin[0], LOW);
    terminal.flush();
    terminal.print("taking 50ml sample was completed");
    pumpRunning = false;
  }
  
  *(multiplier+1) = caliberation_2; // titration and caculation of the pump 
      pumpRunning = true;
    digitalWrite(pumpPin[1], HIGH);
    digitalWrite(stirrer, HIGH);
    startPump2 = millis();
    runCount2 = titrant_amount * multiplier[1];
    terminal.print("titrating/measuring KH ");
    if (phValue<4.4)
{
    digitalWrite(pumpPin[1], LOW);
    digitalWrite(stirrer, LOW);
    terminal.print("titration is finished");
    stopPump = millis();
    runCount2 = stopPump - startPump ;
}
    titrant_amount = runCount2/ multiplier[1] ;
    terminal.print("titrant amount is :");
    terminal.print(titrant_amount);
    Alkalinity_dKH = titrant_amount/50 * 280;
    Alkalinity_meq = titrant_amount/50 * 100;
        terminal.print("Alkalinty measured is : ");
        terminal.print(Alkalinity_dKH); 
digitalWrite(pumpPin[2], HIGH);
    pumpRunning = true;
    start_Regect = millis();
    terminal.print("preparing for next test");
if (millis() - start_Regect> regect_time_MS)
  {
    digitalWrite(pumpPin[0], LOW);
}

    terminal.flush();
    
*(multiplier) = caliberation_1;;
    pumpRunning = true;
    digitalWrite(pumpPin[0], HIGH);
    startPump = millis();
    runCount = 50 * multiplier[0];
    terminal.print("preparing for next reading ");
  if (millis() - startPump > runCount)
  {
    digitalWrite(pumpPin[0], LOW);
    terminal.flush();
    pumpRunning = false;
  }

}
 
void myTimerEvent2() // this is called to give the PH of the water
{
  static unsigned long timepoint = millis();
  if ( millis()- timepoint >= 1000u) //time interval: 1s
  {
    timepoint = millis();
    //voltage = rawPinValue / esp32ADC * esp32Vin
    voltage = analogRead(PH_PIN); // read the voltage
    phValue = ph.readPH(voltage, temperature); // convert voltage to pH with temperature compensation
    Serial.print("pH:");
    Serial.println(phValue, 4);
    Blynk.virtualWrite(V3, phValue);
  }
  ph.calibration(voltage, temperature); // calibration process by Serail CMD
   
}
 void calibration_dosing_pumps() // this should run the pump for 10 second and the user should enter the amount the pump dosed and the this amount should be divided /10 and the result should be saved in eeprom
 {
  if(priming_pump_1==1)  // pumpRunning false to assure only one pump running atime
{
    Blynk.virtualWrite(V11, 0);  // to assure the pin is not active while other pump is runing
    Blynk.virtualWrite(V12, 0);  // to assure the pin is not active while other pump is runing
  digitalWrite(pumpPin[0], HIGH);
  static unsigned long timepoint = 0;
   if (second()- timepoint > Time_intervel) //time interval: 1s
  {
    
    Serial.println(second());
    timepoint = second();
    Serial.println(second());
    digitalWrite(pumpPin[0], LOW);
    Blynk.virtualWrite(V10, 0);
    priming_pump_1 = 0;
  }
  }
  
  }           

void Priming() // this working as manual toggel on/of for the pumps for me to fill the lines before testing
{
  if(priming_pump_1==1 && pumpRunning==false) // pumpRunning false to assure only one pump running atime
    {
    Blynk.virtualWrite(V11, 0); // to assure the pin is not active while other pump is runing
    Blynk.virtualWrite(V12, 0);  // to assure the pin is not active while other pump is runing
    pumpRunning = true;
    digitalWrite(pumpPin[0], HIGH);
    Serial.print("pump1 is priming");
  }
  else{
    digitalWrite(pumpPin[1], LOW);
    Serial.print("pump1 stoped priming");
    pumpRunning = false;
    }

    
    if(priming_pump_2==1 && pumpRunning==false) // pumpRunning false to assure only one pump running atime
    {
    Blynk.virtualWrite(V10, 0); // to assure the pin is not active while other pump is runing
    Blynk.virtualWrite(V12, 0);  // to assure the pin is not active while other pump is runing
    pumpRunning = true;
    digitalWrite(pumpPin[1], HIGH);
    Serial.print("pump2 is priming");
  }
  else{
    digitalWrite(pumpPin[1], LOW);
    Serial.print("pump2 is stoped priming");
    pumpRunning = false;
    }
    if(priming_pump_3==1 && pumpRunning==false) 
    {
    Blynk.virtualWrite(V10, 0); 
    Blynk.virtualWrite(V11, 0);  
    pumpRunning = true;
    digitalWrite(pumpPin[2], HIGH);
    Serial.print("pump3 is priming");
  }
  else{
    digitalWrite(pumpPin[2], LOW);
     Serial.print("pump3 is stoped priming");
    pumpRunning = false;
    }
}



void setup()

{

  Serial.begin(115200);
  pinMode(Erasing_button, INPUT);
pinMode(stirrer, OUTPUT);

  for (uint8_t t = 4; t > 0; t--) {
    Serial.println(t);
    delay(1000);
  }

  // Press and hold the button to erase all the credentials
  if (digitalRead(Erasing_button) == LOW)
  {
    Credentials.Erase_eeprom();

  }

  String auth_string = Credentials.EEPROM_Config();
  auth_string.toCharArray(auth_token, 33);

  if (Credentials.credentials_get())
  {

    Blynk.config(auth_token);
    connected_to_internet = 1;

  }
  else
  {
    Credentials.setupAP(esp_ssid, esp_pass);
    connected_to_internet = 0;
  }


  if (connected_to_internet)
  {

     ph.begin();
  sensors.begin();
  // timer.setInterval(1000L, myTimerEvent);
  timer.setInterval(1200L, myTimerEvent2);
  timer.setInterval(500L, Priming);
  for (int p = 0; p<= 2; p++)
  {
    pinMode(pumpPin[p],OUTPUT);
  }
  Blynk.virtualWrite(V10,0);
  Blynk.virtualWrite(V11,0);
  Blynk.virtualWrite(V12,0);
  Blynk.virtualWrite(V14,0);

  }



}



void loop()
{
  Credentials.server_loops();

  if (connected_to_internet)
  {


    Blynk.run();
    timer.run();
  }
}

and to confirm this code

void calibration_dosing_pumps()
{
if(priming_pump_1==1)  // pumpRunning false to assure only one pump running atime
{
  digitalWrite(pumpPin[0], HIGH);
   timer.setTimeout(10000L, []() 
  {  
    digitalWrite(pumpPin[0], LOW);
    Blynk.virtualWrite(V10, 0);
    priming_pump_1 = 0;

  }); 
  }
  }

is working good to just give the pump 10sec. to run then stop … but i need to understand why my code was not working when i used millis or second

It’s difficult to give you a quick example about how to totally restructure your code! But. think about it this way…

You are currently using the switch widget to set a flag.
Then, every half a second,.24 hours per day, you are calling a function that checks if that flag is set and “does something” if it is.

My approach would be to forget the flag, and ONLY run the “does something” if the switch widget has changed state and is now in the “do some stuff” setting.

As I said, putting some serial print statements in there will allow you to understand your variable values and your program flow.

Pete.

hello all why this code is not working properly the pump is on all the time and never stopped after 8000ms time …

BLYNK_WRITE(V10) {
  priming_pump_1 = param.asInt();
  
  if(priming_pump_1==1) 
{
  digitalWrite(pumpPin[0], HIGH);
 int start_time = millis();
 Serial.println (start_time);
 if(millis() - start_time > 8000){
  digitalWrite(pumpPin[0], LOW);
  start_time = 0 ;
  Serial.println (millis());
   Blynk.virtualWrite(V10, 0);
   priming_pump_1 = 0 ;
  } 
  }   
}

The BLYNK_WRITE callback isn’t a loop, it’s a one-shot piece of code that triggers once when the value of the virtual pin changes.

You are saying:

  • Turn the pump on
  • Grab the current millis value and save it to a variable called start_time
  • Do a Serial.print process, which takes maybe 1 millisecond
  • Check if the current millis value is more than 8000 greater than when you grabbed it 1 milliseciond ago (it’s not of course)
  • Exit the BLYNK_WRITE callback without performing any further actions

Instead of doing millis comparisons, which I’ve already said I wouldn’t recommend…

you’d be better using a timeout timer in a lambda function…

Pete.

i used time out but my need for this way is i want to run this pump later based in condition like i am reading ph of water and this pump is dumping liquid in this water until we reach a certain ph . then pump should stop and i should get the amount of liquid this pump dosed in the water based on its running time … so i must get the start time and the stop time and then get the running time to get the amount it dosed based my my pervious calibration

Not in the code snippet you posted.

In that case you need to do this in a loop, not a one-shot callback.

Pete.

how ? i think once the blynk(); is runing in the loop that means all blynk read and write function is runing in the loop as well … am i not righ ? or what do you mean by runing it in the loop you mean like i do this as function and its called from void loop(){} ?

I think you’re confusing the void loop() with a piece of code which performs a looping process.

Pete.

i am sorry if i am not understanding what you mean if you could give me example this will be very helpful … i am so confused

The coding solution you choose will depend very much on the overall functionality of your project.
So far, you’ve onmdly posted about the specific problems that you’ve encountered, and provided segments of code relating to your project.

I cant advise on the best way of solving your problem or provide examples unless i have a better understanding of what the big picture nd detailed functional requirements of your project are.

I’ve already said that there are many similar projects on the forum that you ought to look at, and maybe use one of those as your starting point.

however, you need to improve your coding skills first, so maybe some C++ programming videos would be a good starting point?

Pete.

thank you alot for the advice i really now using sololearn and almost finished all lessons for c++ and also in the youtube i am watching channel called codebeauty where there is 10 hour video is very usfull and i watched it i think i am not that bad now to understand the codes but still need some time to write codes myself to get used to it i think the practical is good more than theoretical … any way i was going in the code step by step … your timeout example was so good to make the pumps runing for 10 sec and then i get the amount of water it pumped and save it as variable which later will provide my code with the rate of each pump based on time … the peace of code i provided will help me a lot as i told you i need to get the start and stop time based in certain condition . i was looking in the website here for similar codes i think i found one but still not working for me i will past it here

/*
eightPumps
*/
#include <SPI.h>                      //Used by Blynk
#include <Ethernet.h>                 //Used by Blynk
#include <BlynkSimpleEthernet.h>      //Used by Blynk
#include <SimpleTimer.h>
char auth[] = "PasteYourAuthCodeBetweenQuotes";       //Paste code that app emailed you between "quotes"

SimpleTimer timer;
WidgetTerminal terminal(V3);

int pumpPin[8] = { 2, 3, 4, 5, 6, 7, 8, 9 };         //Digital pins used
uint32_t multiplier[8] =  { 858, 827, 872, 865, 887, 895, 913, 843 }; //ms per ml
uint32_t startPump = 0;
uint32_t runCount;
float DOSEml;           //V1 Step Widget (0.25 per step, send step/NO, loop values ON)
int button = 0;         //V2 Button Widget set to Switch
bool pumpRunning = false;
int x;     

BLYNK_WRITE(V0) {                 // Choose Pump
  x = param.asInt() - 1; 
}
BLYNK_WRITE(V1) {                 // Adjust Dosage
  DOSEml = param.asFloat();
}
BLYNK_WRITE(V2) {                 // Activate Chosen Pump
  button = param.asInt();
}

void checkPump()
{

  if (button == 1 && pumpRunning == false)   
  {
    Blynk.virtualWrite(V0, 0);
    Blynk.virtualWrite(V1, 0);
    Blynk.virtualWrite(V2, 0);
    pumpRunning = true; 
    digitalWrite(pumpPin[x], HIGH); 
    startPump = millis();           
    runCount = DOSEml * multiplier[x];
    terminal.println("Dosing from Pump:");
    terminal.println(x + 1);
    terminal.println("Milliliters:");
    terminal.println(DOSEml);
    terminal.flush();
  } 
  
  if (millis() - startPump > runCount)
  {
    digitalWrite(pumpPin[x], LOW);
    pumpRunning = false;
    button = 0;
  }
  
}

void setup()
{
  Serial.begin(9600);
  Blynk.begin(auth);
  while (Blynk.connect() == false) {}
  timer.setInterval(1500L, checkPump);
  for (int p = 0; p <= 7; p++) 
  {
    pinMode(pumpPin[p], OUTPUT);
  }
  Blynk.virtualWrite(V0, 0);
  Blynk.virtualWrite(V1, 0);
  Blynk.virtualWrite(V2, 0);
}

void loop()
{
  Blynk.run();
  timer.run();
}

if you see here he is only allowing one pump to run in one time also he is using millis to ask the pump to run for certain time to dose certain amount of liquid

i think now i understand something
to run this the function should called from the void loop() as the Blynk_write is called only up on in action on the app and not runing in loop … so i made the following

const int pumpPin[3] = { 25, 26, 27};
int cal_amount[3] = {0 , 0 , 0};
unsigned long timepoint;
int start_time = 0;
int priming_pump_1 = 0;
int priming_pump_2 = 0;
int priming_pump_3 = 0;
bool pumpRunning = 0;
bool if_terminator = 0 ; 
BlynkTimer timer;
WidgetTerminal terminal(V8);
WidgetRTC rtc;
void test (){
  if(priming_pump_1== 1 && pumpRunning == false) 
{
    Serial.print ("priming_pump_1=");
    Serial.println (priming_pump_1);
    pumpRunning = true; 
  digitalWrite(pumpPin[0], HIGH);
    start_time = millis();
    Serial.print ("start_time = ");
    Serial.println (start_time);
 Blynk.virtualWrite(V10, 0);
    if_terminator = 1 ; 
}
 if(millis() - start_time > 8000L && if_terminator == 1){
  digitalWrite(pumpPin[0], LOW);
  pumpRunning = false;
  Serial.print ("stop time = ");
  Serial.println (millis());
   Blynk.virtualWrite(V10, 0);
   priming_pump_1 = 0 ;
       Serial.print ("priming_pump_1=");
  Serial.println (priming_pump_1);
  if_terminato = 0 ; 
  }  
  else {
    priming_pump_1 = 0 ;
    }
  }
BLYNK_WRITE(V10) {
  priming_pump_1 = param.asInt();
  
  }
void loop()
{
  test();
    
   
  Blynk.run();
  timer.run();
}

now its working in loop and the timing is perfect and the function is running based in condition … excellent

lets move on into the code i promise i will keep this thread open till i finish it and past it here maybe i will do this coding as class and members functions and objects but lets first get the codesworking and understand everything in blynk first !!
thank you for referring to the loops !

This approach is not the way to do it. Having a function call in your void loop will cause you problems in the long term when using Blynk.

You are still approaching this project from the wrong angle, which is to focus on the coding rather than writing a functional specification.

Pete.

“This approach is not the way to do it. Having a function call in your void loop will cause you problems in the long term when using Blynk.”

if i set blynk timer to call it every certain say 2 sec. is that will not interfere timing in the code ?

It depends what you do inside the function, and how long it takes to complete. It it’s a process that takes 8 seconds to complete then calling it every 2 seconds isn’t te way to go is it?

But, I really do think that you need to step away from the Arduino IDE and focus on documenting the functionality of your project. Once you’ve done this, the experienced Blynk users will be able to guide you toward the best approach.

Pete.

1 Like

the term functionality is not well understand by me buy i think its something like what do i need from the project to do … lets show you something i wrote this is the main process of the device like the mean function which is measure water alkalinity (KH)
i wrote function its with no error in IDE but i am sure logically it will not work properly … this project is contains the following:
1- ph sensor
2- 3 dosing pump
3- magnetic stirrer
so dosing pump should get calibrations method and the calibration data to be saved in EEprom … and then i should run the pumps manually to have access in the device to fill the lines with water …
and the main part which is measuring the KH on some time period and save the result in report to check it every day

i will past the main function which i thought about it but badly its not yet working good

if ( Eventor == 1 && pumpRunning == false){
    
    // start the reject/waste pump to empity the measuring beacker
    pumpRunning = true;
    digitalWrite(pumpPin[2], HIGH);
    terminal.print("Preparing For NEW KH Test");
    Serial.println("reject pump started");
    timer.setTimeout(Reject_Time, []() 
    {  
    digitalWrite(pumpPin[2], LOW);
    Serial.println("reject pump stoped");
    terminal.print("reject pump stopped");

    }); 
    terminal.clear();
    Eventor == 1
    pumpRunning == false

    
  // taking 50 ml of water as sample

    
    digitalWrite(pumpPin[0], HIGH);
    terminal.print("Taking Water Sample");
    Serial.println("Taking Water Sample");
    pumpRunning = true;
    timer.setTimeout(Sampling_Time, []() 
    {  
    digitalWrite(pumpPin[0], LOW);
    pumpRunning = false;

    }); 
    terminal.clear();
    Serial.println(" Water Sampling finished");  
    

  // starting the Water Magnetic Stirrer

      terminal.println("starting the Water Magnetic Stirrer");
      digitalWrite(pumpPin[3], HIGH);

  // titration process to start the titration pump , stop it at 4.5 PH and calculate its runing time

     pumpRunning = true;
     digitalWrite(pumpPin[1], HIGH);
     terminal.print("Measuring KH ....");
     terminal.println("Measuring KH ....");
     start_titration_time = millis();
     if (phValue <= 4.5)
     {
         digitalWrite(pumpPin[1], LOW);
         digitalWrite(pumpPin[3], LOW);
     }
     
     Stop_titration_time = millis();

     Titration_time = Stop_titration_time - start_titration_time ;

     Titration_amount = Titration_time * Titration_pump_rate ;
    Alkalinity_dKH = Titration_amount/50 * 280;
    Alkalinity_meq = Titration_amount/50 * 100;
        terminal.print("Alkalinty measured is : ");
        terminal.print(Alkalinity_dKH);      


      Eventor = 0 ;
      Blynk.virtualWrite(V6, 0);
    
    }
  
  }

A functional specification won’t contain ay code.
It is a description of what the project does, and how.

If it’s meant to constantly monitor pH levels and dose with one chemical if it’s too high and another if it’s too low, then that’s the opening paragraph of your functional specification. If manual intervention, pump priming, flow monitoring etc are required then an explanation of how these work is contained in the detail, along with any other relevant information.

You’re getting bogged-down in the detail of how to achieve some of the functionality in code, and looking for guidance about how to overcome these issues, without providing any overview and perspective on the actual process that is required in the end product.

Pete.