Help in blynk timer

well i will write all here in details the full functionality of the end product i am willing in that product

this product is going to make time scheduled water analysis it will measure the total alkalinity in water by taking sample of 50ml water and titrate with weak acid like 1 normal sulphuric acid … the end point of the titration will be based in ph and then the amount of the sulphuric acid added will be equivalent to the alkalinity through simple equation … this is the short hint about the product so lets go in details what i am thinking how this will work

i got 3 dosing pumps and one ph probe and one magnetic stirrer

so pumps should got method for calibrations to save the rate of how many millilitre it dosed in one sec. this will be done by allowing the user to run the pump for lets say 8 sec and in measuring beaker see how many millilitre the pump dosed in this preriod and pass it to the program which will divide this by the 8 sec to get the rate in one sec and save it in eeprom to use it further in the program

pumps also should got manual running to start priming the pumps and the lines .

now we made calibration we can start the test lets say first pump is the sampling pump 2nd one is the titration pump … and 3rd is the pump used the remove the water from the test beaker …

so now we have the ph probe inside the beaker lets start the program of test the sample pump will deliver 50ml of water as sample then stop then the stirrer will run then the titration pump will start dosing the acid so the ph will starts to drop will monitor the ph till it go to 4.5 then titration pump stops then based on its start time and stop time we can get the amount it dosed … then calculate the alkalinity then we will not remove the water from the beaker till the next test just to keep the ph probe in water so the next test run we will start the waste water pump removing the water then start the sample water and so on

KH should be save in report and we get details each day for the KH measuring during the day

i wish this is help

so please please i need some help in that i need to learn i really like the programming and i can give it more than 8 hours every day or more to be good in programming and doing such things i wish some one can help me and guide me how i can achieve this skills and help me to do this program

Okay, some questions…

  1. is the calibration process a one-off task, or is it repeated at a given frequency (daily, weekly etc) or when something changes (a new batch of acid is used for example)?

  2. are you aware of the problems associated with reading/writing EEPROM? There are far better approaches to this, either by hard-coding the calibration values, storing them against virtual pins in Blynk, or using SPIFFS or littleFS. The choice of which to use will depend on your answer to question 1.

  3. Does the “lets say 8 sec” calibration time need to be user definable/adjustable?

  4. Will the magnetic stirrer be controlled by the MCU as well?

5 What does KH mean?

  1. what sort of report are you looking to produce, where will it be stored, how many tests will be done in a typical day, and what timespan do you need to cover in the report? Do you have a sample report format?

Pete.

1- the calibration task is not one off task and maybe monthly or yearly .
2- no i do not know about eeprom problems but i know about spiffs and if it can be saved in blynk virtrual pin i think this is good but virtual pin can store the data as string ?
3- the 8 sec is not user definable its hard coded
4- yes it will run via MCU it will be connected to relay module as well as the dosing pumps
5- KH is short cut to water alkalinity … actually KH is total alkalinity and its unite is DKH unite and each 1 DKH is 17.9 PPM " part per million"
6- report will be some alkalinity measuring data and its time of measure so i can make trend and see if its increasing or decreasing or constant … if this trend graph can be accessed by blynk app it will be great or to email the data and i do it in excel or to save it to mobile or any way does not matter
regarding the time span lets say that each test the device proceed it will give alkalinity measuring result in time … if we are doing 8 test per day i need to be able to see that in graph and i can check the pervious days … so the graph will show data for one day

forget to tell you that the ph also need calibration but the library i used has calibration method via serial monitor i think i can Edit to be done via blynk

Okay, so the thing I don’t understand is why you feel that you need to use millis() for the 8 second run time during calibration.
Why can’t you simply run the pump for 8 seconds using a timeout timer to give you the method of calculating the flow per second based upon the change in pH over that 8 second period?

Why do you need to store the data as a string? if it’s going to be used for a calculation then I would have thought that a floating point value is what you need?
Either way, you can treat teh stored value as an integer, float or string variable.

Can you document the process for how this works?

Pete.

both way in calibration process will work for to know how much the the titration pump runs in the test method i think its can not be that good

you are right i should store them as floating point value

yes i will write it for let me take my dinner and i will back

Can you explain more about what this means?

Pete.

okay for the time out code the pump will run for the time duration you give it tills time is over and then the pump will stop … but regarding the titration but pump will start based in code sequence with known start time till certain condition happens in this case ph < 4.5 then the pump will stop so the stopping action is not based on time its based in certain value behaviour but the stop and start time will help to know how much it dosed in that time …
for the time out if the time duration became a variable and lets say this variable will take its value as time from the ph condition like if the ph<4.5 stopTime=millis() and the start time is the time the pumpPin came HIGH is that will work ? is tis time out can take variable ? also is not at this way we also used millis to calculate the running condtion ?
thats may though and i said not that good sorry if this misunderstood i did not mean your code is not good :slight_smile: i am zero beside you Sir

regarding the PH code i grab library made by GREENPONIK which is based on DFRobot_ESP_PH library this library i adjust it a littel to match my ph module and working well … its like class with header file and code file i will past you the header file first

/*
 * file DFRobot_ESP_PH.h * @ https://github.com/GreenPonik/DFRobot_ESP_PH_BY_GREENPONIK
 *
 * Arduino library for Gravity: Analog pH Sensor / Meter Kit V2, SKU: SEN0161-V2
 * 
 * Based on the @ https://github.com/DFRobot/DFRobot_PH
 * Copyright   [DFRobot](http://www.dfrobot.com), 2018
 * Copyright   GNU Lesser General Public License
 *
 * ##################################################
 * ##################################################
 * ########## Fork on github by GreenPonik ##########
 * ############# ONLY ESP COMPATIBLE ################
 * ##################################################
 * ##################################################
 * 
 * version  V1.1
 * date  2019-06
 */

#ifndef _DFROBOT_ESP_PH_H_
#define _DFROBOT_ESP_PH_H_

#include "Arduino.h"

#define PHVALUEADDR 0x00 //the start address of the pH calibration parameters stored in the EEPROM

#define PH_8_VOLTAGE 1308
#define PH_6_VOLTAGE 1126
#define PH_5_VOLTAGE 1035
#define PH_3_VOLTAGE 853

#define ReceivedBufferLength 10 //length of the Serial CMD buffer

class DFRobot_ESP_PH
{
public:
    DFRobot_ESP_PH();
    ~DFRobot_ESP_PH();
    void calibration(float voltage, float temperature, char *cmd); //calibration by Serial CMD
    void calibration(float voltage, float temperature);
    float readPH(float voltage, float temperature); // voltage to pH value, with temperature compensation
    void begin();                                   //initialization

private:
    float _phValue;
    float _acidVoltage;
    float _neutralVoltage;
    float _voltage;
    float _temperature;

    char _cmdReceivedBuffer[ReceivedBufferLength]; //store the Serial CMD
    byte _cmdReceivedBufferIndex;

private:
    boolean cmdSerialDataAvailable();
    void phCalibration(byte mode); // calibration process, wirte key parameters to EEPROM
    byte cmdParse(const char *cmd);
    byte cmdParse();
};

#endif

i do not know why he made two private: operator instead of one he made the variables togthers and function togther
this is the two functions making the calibrations i also do not know why two instead one but for me one taking the cmd with it
void calibration(float voltage, float temperature, char *cmd); //calibration by Serial CMD
void calibration(float voltage, float temperature);
and those are for serial monitor reading and getting the keywords
boolean cmdSerialDataAvailable();
void phCalibration(byte mode); // calibration process, wirte key parameters to EEPROM
byte cmdParse(const char *cmd);
byte cmdParse();
and i will past the code file he made

/*
 * file DFRobot_ESP_PH.cpp * @ https://github.com/GreenPonik/DFRobot_ESP_PH_BY_GREENPONIK
 *
 * Arduino library for Gravity: Analog pH Sensor / Meter Kit V2, SKU: SEN0161-V2
 * 
 * Based on the @ https://github.com/DFRobot/DFRobot_PH
 * Copyright   [DFRobot](http://www.dfrobot.com), 2018
 * Copyright   GNU Lesser General Public License
 *
 * ##################################################
 * ##################################################
 * ########## Fork on github by GreenPonik ##########
 * ############# ONLY ESP COMPATIBLE ################
 * ##################################################
 * ##################################################
 * 
 * version  V1.0
 * date  2019-05
 */

#include "Arduino.h"
#include "DFRobot_ESP_PH.h"
#include "EEPROM.h"

#define PH_3_VOLTAGE 2010

DFRobot_ESP_PH::DFRobot_ESP_PH()
{
    this->_temperature = 25.0;
    this->_phValue = 7.0;
    this->_acidVoltage = 955.0;   //buffer solution 4.0 at 25C
    this->_neutralVoltage = 1217; //buffer solution 7.0 at 25C
    this->_voltage = 1217;
}

DFRobot_ESP_PH::~DFRobot_ESP_PH()
{
}

void DFRobot_ESP_PH::begin()
{
    //check if calibration values (neutral and acid) are stored in eeprom
    this->_neutralVoltage = EEPROM.readFloat(PHVALUEADDR); //load the neutral (pH = 7.0)voltage of the pH board from the EEPROM
    if (this->_neutralVoltage == float() || isnan(this->_neutralVoltage))
    {
        this->_neutralVoltage = 1217.0; // new EEPROM, write typical voltage
        EEPROM.writeFloat(PHVALUEADDR, this->_neutralVoltage);
        EEPROM.commit();
    }

    this->_acidVoltage = EEPROM.readFloat(PHVALUEADDR + sizeof(float)); //load the acid (pH = 4.0) voltage of the pH board from the EEPROM
    if (this->_acidVoltage == float() || isnan(this->_acidVoltage))
    {
        this->_acidVoltage = 955.0; // new EEPROM, write typical voltage
        EEPROM.writeFloat(PHVALUEADDR + sizeof(float), this->_acidVoltage);
        EEPROM.commit();
    }
}

float DFRobot_ESP_PH::readPH(float voltage, float temperature)
{
    // Serial.print("_neutraVoltage:");
    // Serial.print(this->_neutralVoltage);
    // Serial.print(", _acidVoltage:");
    // Serial.print(this->_acidVoltage);
    float slope = (7.0 - 4.0) / (this->_neutralVoltage - this->_acidVoltage ); // two point: (_neutralVoltage,7.0),(_acidVoltage,4.0)
    float intercept = 7.0 - slope * (this->_neutralVoltage);
    // Serial.print(", slope:");
    // Serial.print(slope);
    // Serial.print(", intercept:");
    // Serial.println(intercept);
    this->_phValue = slope * voltage + intercept; //y = k*x + b
    //Serial.print("[readPH]... phValue ");
    //Serial.println(this->_phValue);
    return this->_phValue;
}

void DFRobot_ESP_PH::calibration(float voltage, float temperature, char *cmd)
{
    this->_voltage = voltage;
    this->_temperature = temperature;
    strupr(cmd);
    phCalibration(cmdParse(cmd)); // if received Serial CMD from the serial monitor, enter into the calibration mode
}

void DFRobot_ESP_PH::calibration(float voltage, float temperature)
{
    this->_voltage = voltage;
    this->_temperature = temperature;
    if (cmdSerialDataAvailable() > 0)
    {
        phCalibration(cmdParse()); // if received Serial CMD from the serial monitor, enter into the calibration mode
    }
}

boolean DFRobot_ESP_PH::cmdSerialDataAvailable()
{
    char cmdReceivedChar;
    static unsigned long cmdReceivedTimeOut = millis();
    while (Serial.available() > 0)
    {
        if (millis() - cmdReceivedTimeOut > 500U)
        {
            this->_cmdReceivedBufferIndex = 0;
            memset(this->_cmdReceivedBuffer, 0, (ReceivedBufferLength));
        }
        cmdReceivedTimeOut = millis();
        cmdReceivedChar = Serial.read();
        if (cmdReceivedChar == '\n' || this->_cmdReceivedBufferIndex == ReceivedBufferLength - 1)
        {
            this->_cmdReceivedBufferIndex = 0;
            strupr(this->_cmdReceivedBuffer);
            return true;
        }
        else
        {
            this->_cmdReceivedBuffer[this->_cmdReceivedBufferIndex] = cmdReceivedChar;
            this->_cmdReceivedBufferIndex++;
        }
    }
    return false;
}

byte DFRobot_ESP_PH::cmdParse(const char *cmd)
{
    byte modeIndex = 0;
    if (strstr(cmd, "ENTERPH") != NULL)
    {
        modeIndex = 1;
    }
    else if (strstr(cmd, "EXITPH") != NULL)
    {
        modeIndex = 3;
    }
    else if (strstr(cmd, "CALPH") != NULL)
    {
        modeIndex = 2;
    }
    return modeIndex;
}

byte DFRobot_ESP_PH::cmdParse()
{
    byte modeIndex = 0;
    if (strstr(this->_cmdReceivedBuffer, "ENTERPH") != NULL)
    {
        modeIndex = 1;
    }
    else if (strstr(this->_cmdReceivedBuffer, "EXITPH") != NULL)
    {
        modeIndex = 3;
    }
    else if (strstr(this->_cmdReceivedBuffer, "CALPH") != NULL)
    {
        modeIndex = 2;
    }
    return modeIndex;
}

void DFRobot_ESP_PH::phCalibration(byte mode)
{
    char *receivedBufferPtr;
    static boolean phCalibrationFinish = 0;
    static boolean enterCalibrationFlag = 0;
    switch (mode)
    {
    case 0:
        if (enterCalibrationFlag)
        {
            Serial.println(F(">>>Command Error<<<"));
        }
        break;

    case 1:
        enterCalibrationFlag = 1;
        phCalibrationFinish = 0;
        Serial.println();
        Serial.println(F(">>>Enter PH Calibration Mode<<<"));
        Serial.println(F(">>>Please put the probe into the 4.0 or 7.0 standard buffer solution<<<"));
        Serial.println();
        break;

    case 2:
        if (enterCalibrationFlag)
        {
            if ((this->_voltage > PH_8_VOLTAGE) && (this->_voltage < PH_6_VOLTAGE))
            { // buffer solution:7.0
                Serial.println();
                Serial.print(F(">>>Buffer Solution:7.0"));
                this->_neutralVoltage = this->_voltage;
                Serial.println(F(",Send EXITPH to Save and Exit<<<"));
                Serial.println();
                phCalibrationFinish = 1;
            }
            else if ((this->_voltage > PH_5_VOLTAGE) && (this->_voltage < PH_3_VOLTAGE))
            { //buffer solution:4.0
                Serial.println();
                Serial.print(F(">>>Buffer Solution:4.0"));
                this->_acidVoltage = this->_voltage;
                Serial.println(F(",Send EXITPH to Save and Exit<<<"));
                Serial.println();
                phCalibrationFinish = 1;
            }
            else
            {
                Serial.println();
                Serial.print(F(">>>Buffer Solution Error Try Again<<<"));
                Serial.println(); // not buffer solution or faulty operation
                phCalibrationFinish = 0;
            }
        }
        break;

    case 3: //store calibration value in eeprom
        if (enterCalibrationFlag)
        {
            Serial.println();
            if (phCalibrationFinish)
            {
                if ((this->_voltage > PH_8_VOLTAGE) && (this->_voltage < PH_5_VOLTAGE))
                {
                    EEPROM.writeFloat(PHVALUEADDR, this->_neutralVoltage);
                    EEPROM.commit();
                }
                else if ((this->_voltage > PH_5_VOLTAGE) && (this->_voltage < PH_3_VOLTAGE))
                {
                    EEPROM.writeFloat(PHVALUEADDR + sizeof(float), this->_acidVoltage);
                    EEPROM.commit();
                }
                Serial.print(F(">>>Calibration Successful"));
            }
            else
            {
                Serial.print(F(">>>Calibration Failed"));
            }
            Serial.println(F(",Exit PH Calibration Mode<<<"));
            Serial.println();
            phCalibrationFinish = 0;
            enterCalibrationFlag = 0;
        }
        break;
    }
}

thats it its based on serial monitor can not we make friend function that send the also the keyword via terminal widget ?

after more than 10 hours working i think now the test function is working properly

void KH_Test(){
    
  if ( Eventor == 1 && pumpRunning == false){
    
    // start the reject/waste pump to empity the measuring beacker
    pumpRunning = true;
    digitalWrite(pumpPin[2], HIGH);
    pumpPinState[2]= 1;
    Serial.println("reject pump started");
    timer.setTimeout(Reject_Time, []() 
    {  
    digitalWrite(pumpPin[2], LOW);
    pumpPinState[2] = 0 ;
    Serial.println("reject pump stopped");
    }); 
    terminal.clear();
  }

   if ( Eventor == 1 && pumpPinState[2] == 0 ){
    
    // start the reject/waste pump to empity the measuring beacker
    timer.setTimeout(3000, []() 
    {  
    digitalWrite(pumpPin[0], LOW);
    
    digitalWrite(pumpPin[0], HIGH);
    Serial.println("Taking Water Sample");
    pumpPinState[0]= 1;
    timer.setTimeout(Sampling_Time, []() 
    {  
    digitalWrite(pumpPin[0], LOW);
    Serial.println(" Water Sampling finished");
    pumpPinState[1] = 1; 
    });
    Serial.println(" 3 sec delay to start the sampling"); 
    }); 
   
    terminal.clear();
  }
     pumpPinState[0] = 0 ;
     
    if (pumpPinState[0] == 0 && pumpPinState[2] == 0 && Eventor == 1 && pumpRunning == true){ 
    Serial.println("out from the time out the messege reject pump stop before");
      pumpRunning = false;
      Eventor = 0 ;
      Serial.print("Eventor = ");
      Serial.println(Eventor);
      Serial.print("pumpRunning = ");
      Serial.println(pumpRunning);
      Blynk.virtualWrite(V6, 0);
    }  

    
    if (pumpPinState[1] == 1 && pumpPinState[3] == 0){

       pumpPinState[3] = 1;
       
      timer.setTimeout(3000, []() 
    {  
      
   digitalWrite(pumpPin[3], HIGH); //start the magnetic stirrer
        digitalWrite(pumpPin[1], HIGH); // start the titration pump after 3 second of sample finished
        start_titration_time = millis();
        Serial.print ("start_titration_time = ");
        Serial.println (start_titration_time);
        pumpPinState[1] = 0;

    });
    
    Serial.println ("titration start and calculation");
      }
      if (phValue <= 4.5 && pumpPinState[3] == 1)
     {
         digitalWrite(pumpPin[1], LOW);
         digitalWrite(pumpPin[3], LOW);
         Stop_titration_time = millis();
         Serial.print ("Stop_titration_time = ");
         Serial.println (Stop_titration_time);
         Titration_time = Stop_titration_time - start_titration_time ;
         Serial.print("Titration_time = ");
         Serial.print(Titration_time);
         pumpPinState[1] = 0;
         pumpPinState[3] = 0;
     }
  }

My question was about how to make the pump run for 8 seconds, as part of the calibration process. You said…

so I asked…

Your answer seems to be referring to the actual titration process, not the process of obtaining an initial flow rate calibration value for your titration pump.

You’ve then reverted to dumping two chunks of code into your two following posts, neither of which I’m going to look at.

It seems to me that there are five main processes in your overall project:

  1. Calibrate the PH sensor
  2. Calibrate the filling pump to ensure that 50ml is delivered
  3. Calibrate the dosing pump to get a flow rate per second
  4. Prime the dosing system
  5. Test a sample

The " Calibrate the dosing pump" process seems like it might have the following steps:

a) Prime the dosing system
b) Manually add 50ml of liquid to the beaker (unless the filling pump is already calibrated)
c) Turn on the stirrer
d) Take a pH reading
e) Run the dosing pump for 8 seconds
f) Take another pH reading
g) Calculate the flow in ml/sec and store this as a calibration factor
h) Stop the stirrer at some point?
i) Maybe purge the beaker and refill with clean water?

This is the sort of detail that you probably ought to work-out and document before starting to write any code for this process.

Having these steps to refer to will help you to write your code effectively, and will identify steps which could be written as discreet functions to simplify your code structure. It will also help others to guide you through the process of giving you advice, and it will prove extremely useful to you in future when you come to debug or enhance the sketch once you’ve been using it for a while.

Pete.