share with you guys my wifi KH tester and lets try to help each others

Gogo007

Active Member
Review score
+0 /0 /-0
View Badges
Joined
Dec 18, 2020
Messages
125
Reaction score
43
Review score
+0 /0 /-0
Location
Egypt
hello my fellow reefers
i want to share with you my DIY KH doser , i am not that expert in programing and its just a hobby for me so lets get started
first i wanted something to be testing KH regularly and to be accurate as much as possible , think for using KH acid titration to certain PH value as all commercial products doing
so i started with buying 3 kamoer dosing pumps 12v from here then used small driver its very cheap but good and doing the job ULN2003 driver board from here then small DC fan pump to be used as magnetic stirrer from here size 4010 or any size you want and magnet from here and the stirrer magnet from here and ph probe with driver here make sure it is DFRobot Gravity Analog pH Sensor Meter Kit V2 and then the esp32 board from here and then last thing for now is the DC-DC buck converter to convert 12V to 5V from here now you bought everything you need uh still need 250ml biker here

we will use arduino IOT sign up there
then you need to creat this thing i will attch pictures
1.jpg
2.jpg

this maybe required you to to be charged for all this things but you can use only two things i used all of that to make everything accessible for me to do the calibration and pump priming but if you will use premium account you can use this iot for anything in your tank so it really worth the money and its not much based on the price we are paying for our marine stuff !
then in the skitch you can go to full editor
then add libraries



3.jpg

click there
then include
EEPROM
and SimpleTimer
also DFRobot_ESP_PH_WITH_ADC
now you upload the code

#include "SimpleTimer.h"
#include "EEPROM.h"

SimpleTimer timer;

// DFRobot_ESP_PH_WITH_ADC_BY_GREENPONIK - Version: Latest
#include <DFRobot_ESP_PH_WITH_ADC.h>
#include "EEPROM.h"

DFRobot_ESP_PH_WITH_ADC ph;
#define ESPADC 4096.0 //the esp Analog Digital Convertion value
#define ESPVOLTAGE 3300 //the esp voltage supply value
#define PH_PIN 35 //the esp gpio data pin number
#define PHVALUEADDR 0

float voltage, phValue, temperature = 25;
const int pumpPin[4] = { 25, 26, 27, 33};
bool pumpPinState[4] = { 0, 0, 0, 0};
bool pumpRunning = false;
bool r1 = 0, r2 = 0, r3 = 0;
bool Eventor = 0;
float Reject_Time;
float Sampling_Time;
float Reagent_volume_per_second;
float calsample_eeprom, calreject_eeprom, calreagent_eeprom, correction_eeprom, reagent_volume, Kh;
unsigned long start_titration_time = 0;
unsigned long int avgval;
unsigned long t1 = 0 ;
unsigned long t_1 = 0 ;
long previousMillis = 0 ;
unsigned long currentMillis;
long interval = 10000;
const unsigned long period = 10000;
int buffer_arr[20], temp;
unsigned long s1;
unsigned long s2;


/*
Sketch generated by the Arduino IoT Cloud Thing "Untitled"
https://create.arduino.cc/cloud/things/882fa250-9400-472d-b8e5-9eca9629491f

Arduino IoT Cloud Variables description

The following variables are automatically generated and updated when changes are made to the Thing

float correctionValue;
float kH;
float reagentCalValue;
float rejectCalValue;
float sampleCalValue;
CloudSchedule schedule_test;
bool calReagent;
bool calReject;
bool calSample;
bool reagentPump;
bool rejectPump;
bool samplePump;
bool stirrer;
CloudTime time_read;

Variables which are marked as READ/WRITE in the Cloud Thing will also have functions
which are called when their values are changed from the Dashboard.
These functions are generated with the Thing and added at the end of this sketch.
*/

#include "thingProperties.h"



void setup() {
// Initialize serial and wait for port to open:
Serial.begin(9600);
// This delay gives the chance to wait for a Serial Monitor without blocking if none is found
delay(1500);
EEPROM.begin(512);//needed to permit storage of calibration value in eeprom
ph.begin();
for (int p = 0; p <= 3; p++)
{
pinMode(pumpPin[p], OUTPUT);
}

// Defined in thingProperties.h
initProperties();

// Connect to Arduino IoT Cloud
ArduinoCloud.begin(ArduinoIoTPreferredConnection);

/*
The following function allows you to obtain more information
related to the state of network and IoT Cloud connection and errors
the higher number the more granular information you’ll get.
The default is 0 (only errors).
Maximum is 4
*/
setDebugMessageLevel(2);
ArduinoCloud.printDebugInfo();
}

void loop() {
ArduinoCloud.update();
timer.run();
static unsigned long timepoint = millis();
if (millis() - timepoint > 30U)
{
timepoint = millis();
for (int i = 0; i < 20; i++)
buffer_arr = analogRead(PH_PIN) / ESPADC * ESPVOLTAGE; // read the voltage;
for (int i = 0; i < 19; i++)
{
for (int j = i + 1; j < 20; j++)
{
if (buffer_arr > buffer_arr[j])
{
temp = buffer_arr;
buffer_arr = buffer_arr[j];
buffer_arr[j] = temp;
}
}
}
avgval = 0;
for (int i = 2; i < 18; i++)
avgval += buffer_arr;
float volt = (float)avgval / 16;

voltage = volt;
phValue = ph.readPH(voltage, temperature); // convert voltage to pH with temperature compensation
/*Serial.print("voltage:");
Serial.println(voltage);
Serial.print("PhValue:");
Serial.println(phValue);*/
}


ph.calibration(voltage, temperature); // calibration process by Serail CMD

if (stirrer == 1) {
Eventor = 1;
KH_Test();
kH = Kh;


}

}



/*
Since Led is READ_WRITE variable, onLedChange() is
executed every time a new value is received from IoT Cloud.
*/
void onLedChange() {
// Add your code here to act upon Led change
}


/*
Since SamplePump is READ_WRITE variable, onSamplePumpChange() is
executed every time a new value is received from IoT Cloud.
*/
void onSamplePumpChange() {
if (samplePump == 1)
{
digitalWrite(pumpPin[0], HIGH);
}
else
digitalWrite(pumpPin[0], LOW);
}

/*
Since ReagentPump is READ_WRITE variable, onReagentPumpChange() is
executed every time a new value is received from IoT Cloud.
*/
void onReagentPumpChange() {
if (reagentPump == 1)
{
digitalWrite(pumpPin[1], HIGH);
}
else
digitalWrite(pumpPin[1], LOW);
}

/*
Since RejectPump is READ_WRITE variable, onRejectPumpChange() is
executed every time a new value is received from IoT Cloud.
*/
void onRejectPumpChange() {
if (rejectPump == 1)
{
digitalWrite(pumpPin[2], HIGH);
}
else
digitalWrite(pumpPin[2], LOW);
}

/*
Since CalSample is READ_WRITE variable, onCalSampleChange() is
executed every time a new value is received from IoT Cloud.
*/
void onCalSampleChange() {

if (calSample == 1) { // 10 sec timer to run the sample pump for caliberation

previousMillis = millis();
currentMillis = previousMillis ;
digitalWrite(pumpPin[0], HIGH);

while (currentMillis - previousMillis < interval )
{
currentMillis = millis();

Serial.println(((currentMillis - previousMillis) / 1000 )) ;
calSample = 0;
}
Serial.println((currentMillis - previousMillis) / 1000 );
digitalWrite(pumpPin[0], LOW);
calSample = 0;
}
}

/*cal1test = 1 ;
if (cal1test == 1) { // 10 sec timer for caliberation of sampling pump

digitalWrite(pumpPin[0], HIGH);
Serial.println("sample pump calibration started");
timer.setTimeout(10000L, []()
{
digitalWrite(pumpPin[0], LOW);
Serial.println(" calibration for sample pump finished");
calSample = 0 ;
Serial.println(" calsample false");
cal1test = 0;
});
}

}
}*/



/*
Since CalReagent is READ_WRITE variable, onCalReagentChange() is
executed every time a new value is received from IoT Cloud.
*/
void onCalReagentChange() {
if ( calReagent == 1 ) {

previousMillis = millis();
currentMillis = previousMillis ;
digitalWrite(pumpPin[1], HIGH);

while (currentMillis - previousMillis < interval )
{
currentMillis = millis();

Serial.println(((currentMillis - previousMillis) / 1000 )) ;
calReagent = 0;
}
Serial.println((currentMillis - previousMillis) / 1000 );
digitalWrite(pumpPin[1], LOW);
calReagent = 0;
}
}

/*cal2test = 1 ;
if (cal2test == 1) { // 10 sec timer for caliberation of reagent pump

digitalWrite(pumpPin[1], HIGH);
Serial.println("reagent pump calibration started");
timer.setTimeout(10000L, []()
{
digitalWrite(pumpPin[1], LOW);
Serial.println(" calibration for reagent pump finished");
calReagent = 0 ;
cal2test = 0;
});
}
}
}*/

/*
Since CalReject is READ_WRITE variable, onCalRejectChange() is
executed every time a new value is received from IoT Cloud.
*/
void onCalRejectChange() {
if ( calReject == 1 ) {
previousMillis = millis();
currentMillis = previousMillis ;
digitalWrite(pumpPin[1], HIGH);

while (currentMillis - previousMillis < interval )
{
currentMillis = millis();

Serial.println(((currentMillis - previousMillis) / 1000 )) ;
calReagent = 0;
}
Serial.println((currentMillis - previousMillis) / 1000 );
digitalWrite(pumpPin[1], LOW);
calReject = 0;
}
}

/*
Since SampleCalValue is READ_WRITE variable, onSampleCalValueChange() is
executed every time a new value is received from IoT Cloud.
*/
void onSampleCalValueChange() {
// Add your code here to act upon SampleCalValue change
calsample_eeprom = EEPROM.readFloat(PHVALUEADDR + sizeof(float) + sizeof(float));
if (sampleCalValue != calsample_eeprom)
{
EEPROM.writeFloat(PHVALUEADDR + sizeof(float) + sizeof(float), sampleCalValue);
EEPROM.commit();
Serial.println("SampleCalValue = ");
Serial.println(EEPROM.readFloat(PHVALUEADDR + sizeof(float) + sizeof(float)));
}
}

/*
Since RejectCalValue is READ_WRITE variable, onRejectCalValueChange() is
executed every time a new value is received from IoT Cloud.
*/
void onRejectCalValueChange() {
calreject_eeprom = EEPROM.readFloat(PHVALUEADDR + sizeof(float) + sizeof(float) + sizeof(float));
if (rejectCalValue != calreject_eeprom)
{
EEPROM.writeFloat(PHVALUEADDR + sizeof(float) + sizeof(float) + sizeof(float), rejectCalValue);
EEPROM.commit();
Serial.println("rejectCalValue = ");
Serial.println(EEPROM.readFloat(PHVALUEADDR + sizeof(float) + sizeof(float) + sizeof(float)));
}

}


/*
Since ReagentCalValue is READ_WRITE variable, onReagentCalValueChange() is
executed every time a new value is received from IoT Cloud.
*/
void onReagentCalValueChange() {

calreagent_eeprom = EEPROM.readFloat(PHVALUEADDR + sizeof(float) + sizeof(float) + sizeof(float) + sizeof(float));

if (reagentCalValue != calreagent_eeprom)
{
EEPROM.writeFloat(PHVALUEADDR + sizeof(float) + sizeof(float) + sizeof(float) + sizeof(float), reagentCalValue);
EEPROM.commit();
Serial.println("reagentCalValue = ");
Serial.println(EEPROM.readFloat(PHVALUEADDR + sizeof(float) + sizeof(float) + sizeof(float) + sizeof(float)));
}
}



/*
Since Eventor is READ_WRITE variable, onEventorChange() is
executed every time a new value is received from IoT Cloud.
*/
void onEventorChange() {
// Add your code here to act upon Eventor change
}

/*
Since Stirrer is READ_WRITE variable, onStirrerChange() is
executed every time a new value is received from IoT Cloud.
*/
void onStirrerChange() {

if (stirrer == 1) {
stirrer = 1 ;
}
}


/*
Since ScheduleTest is READ_WRITE variable, onScheduleTestChange() is
executed every time a new value is received from IoT Cloud.
*/
void onScheduleTestChange() {

if (schedule_test.isActive()) {
Eventor = 1;
pumpRunning = false;
void KH_Test();
}

}
void KH_Test() {

if ( Eventor == 1 && pumpRunning == false) {

Serial.print("acid voltage:");
Serial.print(EEPROM.readFloat(PHVALUEADDR + sizeof(float)));

Serial.println("neutral voltage:");
Serial.print(EEPROM.readFloat(PHVALUEADDR));

calsample_eeprom = EEPROM.readFloat(PHVALUEADDR + sizeof(float) + sizeof(float));
calreject_eeprom = EEPROM.readFloat(PHVALUEADDR + sizeof(float) + sizeof(float) + sizeof(float));
calreagent_eeprom = EEPROM.readFloat(PHVALUEADDR + sizeof(float) + sizeof(float) + sizeof(float) + sizeof(float));
correction_eeprom = EEPROM.readFloat(PHVALUEADDR + sizeof(float) + sizeof(float) + sizeof(float) + sizeof(float) + sizeof(float));

Sampling_Time = ( 100 / (calsample_eeprom / 10)) * 1000 ;
Reject_Time = ( 130 / (calreject_eeprom / 10)) * 1000 ;
Reagent_volume_per_second = (calreagent_eeprom / 10) ; // reagent volume per second
ArduinoCloud.update();

// start the reject/waste pump to empity the measuring beacker
pumpRunning = true;
previousMillis = millis();
currentMillis = previousMillis;
digitalWrite(pumpPin[2], HIGH);
pumpPinState[2] = 1;
Serial.println("reject pump started");

while (currentMillis - previousMillis < Reject_Time )
{
currentMillis = millis();
Serial.print((currentMillis - previousMillis)/(Reject_Time/45)) ;
Serial.println("ml");
}
digitalWrite(pumpPin[2], LOW);
pumpPinState[2] = 0 ;
Serial.println("reject pump stopped");
r1 = 1 ;
}
ArduinoCloud.update();
if ( Eventor == 1 && pumpPinState[2] == 0 && r1 == 1 )// taking water sample after 3 sec. of reject pump stopped
{
previousMillis = millis();
currentMillis = previousMillis ;
Serial.println("3 Sec. Delay before starting sample pump");
while (currentMillis - previousMillis < 3000 )
{
currentMillis = millis();
Serial.print(((currentMillis - previousMillis)/1000 )) ;
Serial.println("sec");
}


previousMillis = millis();
currentMillis = previousMillis ;
digitalWrite(pumpPin[0], HIGH); // sampling pump started here
Serial.println("Taking Water Sample");
pumpPinState[0] = 1;

while (currentMillis - previousMillis < Sampling_Time )
{
currentMillis = millis();
Serial.print((currentMillis - previousMillis)/(Sampling_Time/30)) ;
Serial.println("ml");
}
digitalWrite(pumpPin[0], LOW); // sampling pump will stop based on the sampling timmer
Serial.println(" Water Sampling finished");
pumpPinState[0] = 0;
r1 = 0 ;
r2 = 1 ;
ArduinoCloud.update();

}
if (pumpPinState[0] == 0 && pumpPinState[2] == 0 && Eventor == 1 && pumpRunning == true && r2 == 1 && r1 == 0 )
{

r2 = 0;
r3 = 1;
if (r3 == 1 && pumpPinState[3] == 0)
{
pumpPinState[3] = 1;
previousMillis = millis();
currentMillis = previousMillis ;
Serial.println("3sec delay");

while (currentMillis - previousMillis < 3000 )
{
currentMillis = millis();

Serial.print(((currentMillis - previousMillis)/1000 )) ;
Serial.println("ml");
}

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




}
}

ArduinoCloud.update();
if (phValue <= 4.2 && pumpPinState[3] == 1)
{
Serial.println ("titration start and calculation");
digitalWrite(pumpPin[1], LOW);
digitalWrite(pumpPin[3], LOW);
unsigned long Stop_titration_time = millis();
s2 = Stop_titration_time ;
Serial.print ("Stop_titration_time = ");
Serial.println (Stop_titration_time);
unsigned long Titration_time = (s2 - s1) ;
Serial.print ("Titration_time = ");
Serial.println (Titration_time);

Serial.print ("Reagent_volume_per_second = ");
Serial.println (Reagent_volume_per_second);

reagent_volume = (Titration_time / 1000) * Reagent_volume_per_second ; // titration_time in milisec /1000 to covert to sec
Kh = ((reagent_volume / 100) * 70) + correction_eeprom ;
Serial.print ("reagent_volume = ");
Serial.println (reagent_volume);
Serial.print ("KH/perDKH = ");
Serial.println (Kh);
kH = Kh;

pumpPinState[1] = 0;
pumpPinState[3] = 0;
Stop_titration_time = 0;
start_titration_time = 0;
pumpRunning = false;
Eventor = 0 ;
stirrer = 0 ;
r1 = 0 ;
r2 = 0 ;
r3 = 0 ;

}
}

/*
Since CorrectionValue is READ_WRITE variable, onCorrectionValueChange() is
executed every time a new value is received from IoT Cloud.
*/
void onCorrectionValueChange() {
correction_eeprom = EEPROM.readFloat(PHVALUEADDR + sizeof(float) + sizeof(float) + sizeof(float) + sizeof(float) + sizeof(float));
if (correctionValue != correction_eeprom)
{
EEPROM.writeFloat(PHVALUEADDR + sizeof(float) + sizeof(float) + sizeof(float) + sizeof(float) + sizeof(float), correctionValue);
EEPROM.commit();
Serial.println("correctionValue = ");
Serial.println(EEPROM.readFloat(PHVALUEADDR + sizeof(float) + sizeof(float) + sizeof(float) + sizeof(float) + sizeof(float)));
}
}

here is my code we can continue later i may be make some good picture and will try to make video for it Enjoy and happy reefing uhh forget if you new to arduino iot cloud i will give you like to some one will make you expert so make sure you see this video before start coding so you get familiar of it here
also forget to show you my dashboard so you have to make the same dashboard with the widget to get it work Note: stirrer is button to activate manual test
4.jpg
 
BRS
OP
Gogo007

Gogo007

Active Member
Review score
+0 /0 /-0
View Badges
Joined
Dec 18, 2020
Messages
125
Reaction score
43
Review score
+0 /0 /-0
Location
Egypt
#include "SimpleTimer.h"
#include "EEPROM.h"

SimpleTimer timer;

// DFRobot_ESP_PH_WITH_ADC_BY_GREENPONIK - Version: Latest
#include <DFRobot_ESP_PH_WITH_ADC.h>
#include "EEPROM.h"

DFRobot_ESP_PH_WITH_ADC ph;
#define ESPADC 4096.0 //the esp Analog Digital Convertion value
#define ESPVOLTAGE 3300 //the esp voltage supply value
#define PH_PIN 35 //the esp gpio data pin number
#define PHVALUEADDR 0

float voltage, phValue, temperature = 25;
const int pumpPin[4] = { 25, 26, 27, 33};
bool pumpPinState[4] = { 0, 0, 0, 0};
bool pumpRunning = false;
bool r1 = 0, r2 = 0, r3 = 0;
bool Eventor = 0;
float Reject_Time;
float Sampling_Time;
float Reagent_volume_per_second;
float calsample_eeprom, calreject_eeprom, calreagent_eeprom, correction_eeprom, reagent_volume, Kh;
unsigned long start_titration_time = 0;
unsigned long int avgval;
unsigned long t1 = 0 ;
unsigned long t_1 = 0 ;
long previousMillis = 0 ;
unsigned long currentMillis;
long interval = 10000;
const unsigned long period = 10000;
int buffer_arr[20], temp;
unsigned long s1;
unsigned long s2;


/*
Sketch generated by the Arduino IoT Cloud Thing "Untitled"
https://create.arduino.cc/cloud/things/882fa250-9400-472d-b8e5-9eca9629491f

Arduino IoT Cloud Variables description

The following variables are automatically generated and updated when changes are made to the Thing

float correctionValue;
float kH;
float reagentCalValue;
float rejectCalValue;
float sampleCalValue;
CloudSchedule schedule_test;
bool calReagent;
bool calReject;
bool calSample;
bool reagentPump;
bool rejectPump;
bool samplePump;
bool stirrer;
CloudTime time_read;

Variables which are marked as READ/WRITE in the Cloud Thing will also have functions
which are called when their values are changed from the Dashboard.
These functions are generated with the Thing and added at the end of this sketch.
*/

#include "thingProperties.h"



void setup() {
// Initialize serial and wait for port to open:
Serial.begin(9600);
// This delay gives the chance to wait for a Serial Monitor without blocking if none is found
delay(1500);
EEPROM.begin(512);//needed to permit storage of calibration value in eeprom
ph.begin();
for (int p = 0; p <= 3; p++)
{
pinMode(pumpPin[p], OUTPUT);
}

// Defined in thingProperties.h
initProperties();

// Connect to Arduino IoT Cloud
ArduinoCloud.begin(ArduinoIoTPreferredConnection);

/*
The following function allows you to obtain more information
related to the state of network and IoT Cloud connection and errors
the higher number the more granular information you’ll get.
The default is 0 (only errors).
Maximum is 4
*/
setDebugMessageLevel(2);
ArduinoCloud.printDebugInfo();
}

void loop() {
ArduinoCloud.update();
timer.run();
static unsigned long timepoint = millis();
if (millis() - timepoint > 30U)
{
timepoint = millis();
for (int i = 0; i < 20; i++)
buffer_arr = analogRead(PH_PIN) / ESPADC * ESPVOLTAGE; // read the voltage;
for (int i = 0; i < 19; i++)
{
for (int j = i + 1; j < 20; j++)
{
if (buffer_arr > buffer_arr[j])
{
temp = buffer_arr;
buffer_arr = buffer_arr[j];
buffer_arr[j] = temp;
}
}
}
avgval = 0;
for (int i = 2; i < 18; i++)
avgval += buffer_arr;
float volt = (float)avgval / 16;

voltage = volt;
phValue = ph.readPH(voltage, temperature); // convert voltage to pH with temperature compensation
/*Serial.print("voltage:");
Serial.println(voltage);
Serial.print("PhValue:");
Serial.println(phValue);*/
}


ph.calibration(voltage, temperature); // calibration process by Serail CMD

if (stirrer == 1) {
Eventor = 1;
KH_Test();


}

}



/*
Since Led is READ_WRITE variable, onLedChange() is
executed every time a new value is received from IoT Cloud.
*/
void onLedChange() {
// Add your code here to act upon Led change
}


/*
Since SamplePump is READ_WRITE variable, onSamplePumpChange() is
executed every time a new value is received from IoT Cloud.
*/
void onSamplePumpChange() {
if (samplePump == 1)
{
digitalWrite(pumpPin[0], HIGH);
}
else
digitalWrite(pumpPin[0], LOW);
}

/*
Since ReagentPump is READ_WRITE variable, onReagentPumpChange() is
executed every time a new value is received from IoT Cloud.
*/
void onReagentPumpChange() {
if (reagentPump == 1)
{
digitalWrite(pumpPin[1], HIGH);
}
else
digitalWrite(pumpPin[1], LOW);
}

/*
Since RejectPump is READ_WRITE variable, onRejectPumpChange() is
executed every time a new value is received from IoT Cloud.
*/
void onRejectPumpChange() {
if (rejectPump == 1)
{
digitalWrite(pumpPin[2], HIGH);
}
else
digitalWrite(pumpPin[2], LOW);
}

/*
Since CalSample is READ_WRITE variable, onCalSampleChange() is
executed every time a new value is received from IoT Cloud.
*/
void onCalSampleChange() {

if (calSample == 1) { // 10 sec timer to run the sample pump for caliberation

previousMillis = millis();
currentMillis = previousMillis ;
digitalWrite(pumpPin[0], HIGH);

while (currentMillis - previousMillis < interval )
{
currentMillis = millis();

Serial.println(((currentMillis - previousMillis) / 1000 )) ;
calSample = 0;
}
Serial.println((currentMillis - previousMillis) / 1000 );
digitalWrite(pumpPin[0], LOW);
calSample = 0;
}
}

/*cal1test = 1 ;
if (cal1test == 1) { // 10 sec timer for caliberation of sampling pump

digitalWrite(pumpPin[0], HIGH);
Serial.println("sample pump calibration started");
timer.setTimeout(10000L, []()
{
digitalWrite(pumpPin[0], LOW);
Serial.println(" calibration for sample pump finished");
calSample = 0 ;
Serial.println(" calsample false");
cal1test = 0;
});
}

}
}*/



/*
Since CalReagent is READ_WRITE variable, onCalReagentChange() is
executed every time a new value is received from IoT Cloud.
*/
void onCalReagentChange() {
if ( calReagent == 1 ) {

previousMillis = millis();
currentMillis = previousMillis ;
digitalWrite(pumpPin[1], HIGH);

while (currentMillis - previousMillis < interval )
{
currentMillis = millis();

Serial.println(((currentMillis - previousMillis) / 1000 )) ;
calReagent = 0;
}
Serial.println((currentMillis - previousMillis) / 1000 );
digitalWrite(pumpPin[1], LOW);
calReagent = 0;
}
}

/*cal2test = 1 ;
if (cal2test == 1) { // 10 sec timer for caliberation of reagent pump

digitalWrite(pumpPin[1], HIGH);
Serial.println("reagent pump calibration started");
timer.setTimeout(10000L, []()
{
digitalWrite(pumpPin[1], LOW);
Serial.println(" calibration for reagent pump finished");
calReagent = 0 ;
cal2test = 0;
});
}
}
}*/

/*
Since CalReject is READ_WRITE variable, onCalRejectChange() is
executed every time a new value is received from IoT Cloud.
*/
void onCalRejectChange() {
if ( calReject == 1 ) {
previousMillis = millis();
currentMillis = previousMillis ;
digitalWrite(pumpPin[2], HIGH);

while (currentMillis - previousMillis < interval )
{
currentMillis = millis();

Serial.println(((currentMillis - previousMillis) / 1000 )) ;
calReagent = 0;
}
Serial.println((currentMillis - previousMillis) / 1000 );
digitalWrite(pumpPin[2], LOW);
calReject = 0;
}
}

/*
Since SampleCalValue is READ_WRITE variable, onSampleCalValueChange() is
executed every time a new value is received from IoT Cloud.
*/
void onSampleCalValueChange() {
// Add your code here to act upon SampleCalValue change
calsample_eeprom = EEPROM.readFloat(PHVALUEADDR + sizeof(float) + sizeof(float));
if (sampleCalValue != calsample_eeprom)
{
EEPROM.writeFloat(PHVALUEADDR + sizeof(float) + sizeof(float), sampleCalValue);
EEPROM.commit();
Serial.println("SampleCalValue = ");
Serial.println(EEPROM.readFloat(PHVALUEADDR + sizeof(float) + sizeof(float)));
}
}

/*
Since RejectCalValue is READ_WRITE variable, onRejectCalValueChange() is
executed every time a new value is received from IoT Cloud.
*/
void onRejectCalValueChange() {
calreject_eeprom = EEPROM.readFloat(PHVALUEADDR + sizeof(float) + sizeof(float) + sizeof(float));
if (rejectCalValue != calreject_eeprom)
{
EEPROM.writeFloat(PHVALUEADDR + sizeof(float) + sizeof(float) + sizeof(float), rejectCalValue);
EEPROM.commit();
Serial.println("rejectCalValue = ");
Serial.println(EEPROM.readFloat(PHVALUEADDR + sizeof(float) + sizeof(float) + sizeof(float)));
}

}


/*
Since ReagentCalValue is READ_WRITE variable, onReagentCalValueChange() is
executed every time a new value is received from IoT Cloud.
*/
void onReagentCalValueChange() {

calreagent_eeprom = EEPROM.readFloat(PHVALUEADDR + sizeof(float) + sizeof(float) + sizeof(float) + sizeof(float));

if (reagentCalValue != calreagent_eeprom)
{
EEPROM.writeFloat(PHVALUEADDR + sizeof(float) + sizeof(float) + sizeof(float) + sizeof(float), reagentCalValue);
EEPROM.commit();
Serial.println("reagentCalValue = ");
Serial.println(EEPROM.readFloat(PHVALUEADDR + sizeof(float) + sizeof(float) + sizeof(float) + sizeof(float)));
}
}



/*
Since Eventor is READ_WRITE variable, onEventorChange() is
executed every time a new value is received from IoT Cloud.
*/
void onEventorChange() {
// Add your code here to act upon Eventor change
}

/*
Since Stirrer is READ_WRITE variable, onStirrerChange() is
executed every time a new value is received from IoT Cloud.
*/
void onStirrerChange() {
if (stirrer == 1) {
stirrer = 1 ;
}
}



/*
Since ScheduleTest is READ_WRITE variable, onScheduleTestChange() is
executed every time a new value is received from IoT Cloud.
*/
void onScheduleTestChange() {

if (schedule_test.isActive()) {
Eventor = 1;
pumpRunning = false;
void KH_Test();
}

}
void KH_Test() {

if ( Eventor == 1 && pumpRunning == false) {

Serial.print("acid voltage:");
Serial.print(EEPROM.readFloat(PHVALUEADDR + sizeof(float)));

Serial.println("neutral voltage:");
Serial.print(EEPROM.readFloat(PHVALUEADDR));

calsample_eeprom = EEPROM.readFloat(PHVALUEADDR + sizeof(float) + sizeof(float));
calreject_eeprom = EEPROM.readFloat(PHVALUEADDR + sizeof(float) + sizeof(float) + sizeof(float));
calreagent_eeprom = EEPROM.readFloat(PHVALUEADDR + sizeof(float) + sizeof(float) + sizeof(float) + sizeof(float));
correction_eeprom = EEPROM.readFloat(PHVALUEADDR + sizeof(float) + sizeof(float) + sizeof(float) + sizeof(float) + sizeof(float));

Sampling_Time = ( 100 / (calsample_eeprom / 10)) * 1000 ;
Reject_Time = ( 130 / (calreject_eeprom / 10)) * 1000 ;
Reagent_volume_per_second = (calreagent_eeprom / 10) ; // reagent volume per second
ArduinoCloud.update();

// start the reject/waste pump to empity the measuring beacker
pumpRunning = true;
previousMillis = millis();
currentMillis = previousMillis;
digitalWrite(pumpPin[2], HIGH);
pumpPinState[2] = 1;
Serial.println("reject pump started");

while (currentMillis - previousMillis < Reject_Time )
{
currentMillis = millis();
Serial.print((currentMillis - previousMillis)/(Reject_Time/45)) ;
Serial.println("ml");
}
digitalWrite(pumpPin[2], LOW);
pumpPinState[2] = 0 ;
Serial.println("reject pump stopped");
r1 = 1 ;
}
ArduinoCloud.update();
if ( Eventor == 1 && pumpPinState[2] == 0 && r1 == 1 )// taking water sample after 3 sec. of reject pump stopped
{
previousMillis = millis();
currentMillis = previousMillis ;
Serial.println("3 Sec. Delay before starting sample pump");
while (currentMillis - previousMillis < 3000 )
{
currentMillis = millis();
Serial.print(((currentMillis - previousMillis)/1000 )) ;
Serial.println("sec");
}


previousMillis = millis();
currentMillis = previousMillis ;
digitalWrite(pumpPin[0], HIGH); // sampling pump started here
Serial.println("Taking Water Sample");
pumpPinState[0] = 1;

while (currentMillis - previousMillis < Sampling_Time )
{
currentMillis = millis();
Serial.print((currentMillis - previousMillis)/(Sampling_Time/30)) ;
Serial.println("ml");
}
digitalWrite(pumpPin[0], LOW); // sampling pump will stop based on the sampling timmer
Serial.println(" Water Sampling finished");
pumpPinState[0] = 0;
r1 = 0 ;
r2 = 1 ;
ArduinoCloud.update();

}
if (pumpPinState[0] == 0 && pumpPinState[2] == 0 && Eventor == 1 && pumpRunning == true && r2 == 1 && r1 == 0 )
{

r2 = 0;
r3 = 1;
if (r3 == 1 && pumpPinState[3] == 0)
{
pumpPinState[3] = 1;
previousMillis = millis();
currentMillis = previousMillis ;
Serial.println("3sec delay");

while (currentMillis - previousMillis < 3000 )
{
currentMillis = millis();

Serial.print(((currentMillis - previousMillis)/1000 )) ;
Serial.println("ml");
}

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




}
}

ArduinoCloud.update();
if (phValue <= 4.2 && pumpPinState[3] == 1)
{
Serial.println ("titration start and calculation");
digitalWrite(pumpPin[1], LOW);
digitalWrite(pumpPin[3], LOW);
unsigned long Stop_titration_time = millis();
s2 = Stop_titration_time ;
Serial.print ("Stop_titration_time = ");
Serial.println (Stop_titration_time);
unsigned long Titration_time = (s2 - s1) ;
Serial.print ("Titration_time = ");
Serial.println (Titration_time);

Serial.print ("Reagent_volume_per_second = ");
Serial.println (Reagent_volume_per_second);

reagent_volume = (Titration_time / 1000) * Reagent_volume_per_second ; // titration_time in milisec /1000 to covert to sec
Kh = ((reagent_volume / 100) * 70) + correction_eeprom ;
Serial.print ("reagent_volume = ");
Serial.println (reagent_volume);
Serial.print ("KH/perDKH = ");
Serial.println (Kh);
kH = Kh;

pumpPinState[1] = 0;
pumpPinState[3] = 0;
Stop_titration_time = 0;
start_titration_time = 0;
pumpRunning = false;
Eventor = 0 ;
stirrer = 0 ;
r1 = 0 ;
r2 = 0 ;
r3 = 0 ;

}
}

/*
Since CorrectionValue is READ_WRITE variable, onCorrectionValueChange() is
executed every time a new value is received from IoT Cloud.
*/
void onCorrectionValueChange() {
correction_eeprom = EEPROM.readFloat(PHVALUEADDR + sizeof(float) + sizeof(float) + sizeof(float) + sizeof(float) + sizeof(float));
if (correctionValue != correction_eeprom)
{
EEPROM.writeFloat(PHVALUEADDR + sizeof(float) + sizeof(float) + sizeof(float) + sizeof(float) + sizeof(float), correctionValue);
EEPROM.commit();
Serial.println("correctionValue = ");
Serial.println(EEPROM.readFloat(PHVALUEADDR + sizeof(float) + sizeof(float) + sizeof(float) + sizeof(float) + sizeof(float)));
}
}
 
Avast
OP
Gogo007

Gogo007

Active Member
Review score
+0 /0 /-0
View Badges
Joined
Dec 18, 2020
Messages
125
Reaction score
43
Review score
+0 /0 /-0
Location
Egypt
Congratulation @Gogo007

Really clean dashboard, can you post more details on the HW build?
Sure i will post more details and i am currently bulding new version which is using stepper motor and only one pump it will be very nice and accurate and small footprint
 
OP
Gogo007

Gogo007

Active Member
Review score
+0 /0 /-0
View Badges
Joined
Dec 18, 2020
Messages
125
Reaction score
43
Review score
+0 /0 /-0
Location
Egypt
and small update in the code:
#include "EEPROM.h"
#include <DFRobot_ESP_PH_WITH_ADC.h>
#include "EEPROM.h"

DFRobot_ESP_PH_WITH_ADC ph;
#define ESPADC 4096.0 //the esp Analog Digital Convertion value
#define ESPVOLTAGE 3300 //the esp voltage supply value
#define PH_PIN 35 //the esp gpio data pin number
#define PHVALUEADDR 0
unsigned long SampleAmount = 10.0;
unsigned long RejectAmount = 12.0 ;

float voltage, phValue, temperature = 25;
const int pumpPin[4] = { 25, 26, 27, 33};
bool pumpPinState[4] = { 0, 0, 0, 0};
bool pumpRunning = false;
bool r1 = 0, r2 = 0, r3 = 0;
bool Eventor = 0;
float Reject_Time;
float Sampling_Time;
float Reagent_volume_per_second;
float calsample_eeprom, calreject_eeprom, calreagent_eeprom, correction_eeprom, reagent_volume, Kh;
unsigned long start_titration_time = 0;
unsigned long int avgval;
unsigned long t1 = 0 ;
unsigned long t_1 = 0 ;
long previousMillis = 0 ;
unsigned long currentMillis;
long interval = 10000;
const unsigned long period = 10000;
int buffer_arr[20], temp;
unsigned long s1;
unsigned long s2;



/*
Sketch generated by the Arduino IoT Cloud Thing "Untitled"
https://create.arduino.cc/cloud/things/882fa250-9400-472d-b8e5-9eca9629491f

Arduino IoT Cloud Variables description

The following variables are automatically generated and updated when changes are made to the Thing

float correctionValue;
float kH;
float reagentCalValue;
float rejectCalValue;
float sampleCalValue;
CloudSchedule schedule_test;
bool calReagent;
bool calReject;
bool calSample;
bool reagentPump;
bool rejectPump;
bool samplePump;
bool stirrer;
CloudTime time_read;

Variables which are marked as READ/WRITE in the Cloud Thing will also have functions
which are called when their values are changed from the Dashboard.
These functions are generated with the Thing and added at the end of this sketch.
*/

#include "thingProperties.h"
//************************************* regect function used to pass the watchdog timer for cloud update to run for 10ml for 10 times to put 100ml
void rejectFunction()
{
previousMillis = millis();
currentMillis = previousMillis;
digitalWrite(pumpPin[2], HIGH);
pumpPinState[2] = 1;
Serial.println("reject pump started");

while (currentMillis - previousMillis < Reject_Time )
{
currentMillis = millis();
Serial.print((currentMillis - previousMillis)/(Reject_Time/RejectAmount)) ;
Serial.println("ml");
}
digitalWrite(pumpPin[2], LOW);
}
//*************************************
//*************************************
void PHSample(){
static unsigned long timepoint = millis();
if (millis() - timepoint > 30U)
{
timepoint = millis();
for (int i = 0; i < 20; i++)
buffer_arr = analogRead(PH_PIN) / ESPADC * ESPVOLTAGE; // read the voltage;
for (int i = 0; i < 19; i++)
{
for (int j = i + 1; j < 20; j++)
{
if (buffer_arr > buffer_arr[j])
{
temp = buffer_arr;
buffer_arr = buffer_arr[j];
buffer_arr[j] = temp;
}
}
}
avgval = 0;
for (int i = 2; i < 18; i++)
avgval += buffer_arr;
float volt = (float)avgval / 16;

voltage = volt;
phValue = ph.readPH(voltage, temperature); // convert voltage to pH with temperature compensation
/*Serial.print("voltage:");
Serial.println(voltage);*/
Serial.print("PhValue:");
Serial.println(phValue);
}
}
//*************************************

//*************************************sample function used to pass the watchdog timer for cloud update to run for 10ml for 10 times to put 100ml
void sampleFunction()
{
previousMillis = millis();
currentMillis = previousMillis ;
digitalWrite(pumpPin[0], HIGH);
pumpPinState[0] = 1;

while (currentMillis - previousMillis < Sampling_Time )
{
currentMillis = millis();
Serial.print((currentMillis - previousMillis)/(Sampling_Time/SampleAmount)) ;
Serial.println("ml");

}
digitalWrite(pumpPin[0], LOW);
}
//*************************************

//*************************************
void KH_Test() {

if ( Eventor == 1 && pumpRunning == false) {

Serial.print("acid voltage:");
Serial.print(EEPROM.readFloat(PHVALUEADDR + sizeof(float)));

Serial.println("neutral voltage:");
Serial.print(EEPROM.readFloat(PHVALUEADDR));

calsample_eeprom = EEPROM.readFloat(PHVALUEADDR + sizeof(float) + sizeof(float));
calreject_eeprom = EEPROM.readFloat(PHVALUEADDR + sizeof(float) + sizeof(float) + sizeof(float));
calreagent_eeprom = EEPROM.readFloat(PHVALUEADDR + sizeof(float) + sizeof(float) + sizeof(float) + sizeof(float));
correction_eeprom = EEPROM.readFloat(PHVALUEADDR + sizeof(float) + sizeof(float) + sizeof(float) + sizeof(float) + sizeof(float));

Sampling_Time = ( SampleAmount / (calsample_eeprom / 10)) * 1000 ;
Reject_Time = ( RejectAmount / (calreject_eeprom / 10)) * 1000 ;
Reagent_volume_per_second = (calreagent_eeprom / 10) ; // reagent volume per second
ArduinoCloud.update();

// start the reject/waste pump to empity the measuring beacker
pumpRunning = true;
rejectFunction();
ArduinoCloud.update();
rejectFunction();
ArduinoCloud.update();
rejectFunction();
ArduinoCloud.update();
rejectFunction();
ArduinoCloud.update();
rejectFunction();
ArduinoCloud.update();
rejectFunction();
ArduinoCloud.update();
rejectFunction();
ArduinoCloud.update();
rejectFunction();
ArduinoCloud.update();
rejectFunction();
ArduinoCloud.update();
rejectFunction();
ArduinoCloud.update();
pumpPinState[2] = 0 ;
Serial.println("reject pump stopped");
r1 = 1 ;
ArduinoCloud.update();
}

if ( Eventor == 1 && pumpPinState[2] == 0 && r1 == 1 )// taking water sample after 3 sec. of reject pump stopped
{
previousMillis = millis();
currentMillis = previousMillis ;
Serial.println("3 Sec. Delay before starting sample pump");
while (currentMillis - previousMillis < 3000 )
{
currentMillis = millis();
Serial.print(((currentMillis - previousMillis)/1000 )) ;
Serial.println("sec");
ArduinoCloud.update();
}


Serial.println("Taking Water Sample");
sampleFunction();
ArduinoCloud.update();
sampleFunction();
ArduinoCloud.update();
sampleFunction();
ArduinoCloud.update();
sampleFunction();
ArduinoCloud.update();
sampleFunction();
ArduinoCloud.update();
sampleFunction();
ArduinoCloud.update();
sampleFunction();
ArduinoCloud.update();
sampleFunction();
ArduinoCloud.update();
sampleFunction();
ArduinoCloud.update();
sampleFunction();
ArduinoCloud.update();
Serial.println(" Water Sampling finished");
pumpPinState[0] = 0;
r1 = 0 ;
r2 = 1 ;
ArduinoCloud.update();

}
if (pumpPinState[0] == 0 && pumpPinState[2] == 0 && Eventor == 1 && pumpRunning == true && r2 == 1 && r1 == 0 )
{

r2 = 0;
r3 = 1;
if (r3 == 1 && pumpPinState[3] == 0 )
{
pumpPinState[3] = 1;
previousMillis = millis();
currentMillis = previousMillis ;
Serial.println("3sec delay");

while (currentMillis - previousMillis < 8000 )
{
currentMillis = millis();
PHSample();
ArduinoCloud.update();
Serial.print(((currentMillis - previousMillis)/1000 )) ;
Serial.println("sec");
}

ArduinoCloud.update();
PHSample();
digitalWrite(pumpPin[3], HIGH); //start the magnetic stirrer
digitalWrite(pumpPin[1], HIGH); // start the titration pump after 3 second of sample finished
unsigned long start_titration_time = millis();
s1 = start_titration_time;
Serial.print ("start_titration_time = ");
Serial.println (start_titration_time);
pumpPinState[1] = 1;
r3 = 0 ;


}
}
//Serial.println ("Before titration start and calculation");
if (phValue <= 4.2 && pumpPinState[3] == 1 )
{
Serial.println ("titration start and calculation");
digitalWrite(pumpPin[1], LOW);
digitalWrite(pumpPin[3], LOW);
unsigned long Stop_titration_time = millis();
s2 = Stop_titration_time ;
Serial.print ("Stop_titration_time = ");
Serial.println (Stop_titration_time);
unsigned long Titration_time = (s2 - s1) ;
Serial.print ("Titration_time = ");
Serial.println (Titration_time);
Serial.print ("Reagent_volume_per_second = ");
Serial.println (Reagent_volume_per_second);
reagent_volume = (Titration_time / 1000) * Reagent_volume_per_second ; // titration_time in milisec /1000 to covert to sec
SampleAmount = 10 * SampleAmount;
Kh = ((reagent_volume / SampleAmount) * 70) + correction_eeprom ;
Serial.print ("reagent_volume = ");
Serial.println (reagent_volume);
Serial.print ("KH/perDKH = ");
Serial.println (Kh);
kH = Kh;
SampleAmount = SampleAmount / 10;

pumpPinState[1] = 0;
pumpPinState[3] = 0;
Stop_titration_time = 0;
start_titration_time = 0;
pumpRunning = false;
Eventor = 0 ;
stirrer = 0 ;
r1 = 0 ;
r2 = 0 ;
r3 = 0 ;

}
//Serial.println ("after titration start and calculation");


}
//************************************





void setup() {
// Initialize serial and wait for port to open:
Serial.begin(9600);
// This delay gives the chance to wait for a Serial Monitor without blocking if none is found
delay(1500);
EEPROM.begin(512);//needed to permit storage of calibration value in eeprom
ph.begin();
for (int p = 0; p <= 3; p++)
{
pinMode(pumpPin[p], OUTPUT);
}

// Defined in thingProperties.h
initProperties();

// Connect to Arduino IoT Cloud
ArduinoCloud.begin(ArduinoIoTPreferredConnection);

/*
The following function allows you to obtain more information
related to the state of network and IoT Cloud connection and errors
the higher number the more granular information you’ll get.
The default is 0 (only errors).
Maximum is 4
*/
setDebugMessageLevel(2);
ArduinoCloud.printDebugInfo();
}

void loop() {
ArduinoCloud.update();
static unsigned long timepoint = millis();
if (millis() - timepoint > 30U)
{
timepoint = millis();
for (int i = 0; i < 20; i++)
buffer_arr = analogRead(PH_PIN) / ESPADC * ESPVOLTAGE; // read the voltage;
for (int i = 0; i < 19; i++)
{
for (int j = i + 1; j < 20; j++)
{
if (buffer_arr > buffer_arr[j])
{
temp = buffer_arr;
buffer_arr = buffer_arr[j];
buffer_arr[j] = temp;
}
}
}
avgval = 0;
for (int i = 2; i < 18; i++)
avgval += buffer_arr;
float volt = (float)avgval / 16;

voltage = volt;
phValue = ph.readPH(voltage, temperature); // convert voltage to pH with temperature compensation
/*Serial.print("voltage:");
Serial.println(voltage);*/
Serial.print("PhValue:");
Serial.println(phValue);
}


ph.calibration(voltage, temperature); // calibration process by Serail CMD

KH_Test();


}



/*
Since Led is READ_WRITE variable, onLedChange() is
executed every time a new value is received from IoT Cloud.
*/
void onLedChange() {
// Add your code here to act upon Led change
}


/*
Since SamplePump is READ_WRITE variable, onSamplePumpChange() is
executed every time a new value is received from IoT Cloud.
*/
void onSamplePumpChange() {
if (samplePump == 1)
{
digitalWrite(pumpPin[0], HIGH);
}
else
digitalWrite(pumpPin[0], LOW);
}

/*
Since ReagentPump is READ_WRITE variable, onReagentPumpChange() is
executed every time a new value is received from IoT Cloud.
*/
void onReagentPumpChange() {
if (reagentPump == 1)
{
digitalWrite(pumpPin[1], HIGH);
}
else
digitalWrite(pumpPin[1], LOW);
}

/*
Since RejectPump is READ_WRITE variable, onRejectPumpChange() is
executed every time a new value is received from IoT Cloud.
*/
void onRejectPumpChange() {
if (rejectPump == 1)
{
digitalWrite(pumpPin[2], HIGH);
}
else
digitalWrite(pumpPin[2], LOW);
}

/*
Since CalSample is READ_WRITE variable, onCalSampleChange() is
executed every time a new value is received from IoT Cloud.
*/
void onCalSampleChange() {

if (calSample == 1) { // 10 sec timer to run the sample pump for caliberation

previousMillis = millis();
currentMillis = previousMillis ;
digitalWrite(pumpPin[0], HIGH);

while (currentMillis - previousMillis < interval )
{
currentMillis = millis();

Serial.println(((currentMillis - previousMillis) / 1000 )) ;
calSample = 0;
}
Serial.println((currentMillis - previousMillis) / 1000 );
digitalWrite(pumpPin[0], LOW);
calSample = 0;
}
}

/*cal1test = 1 ;
if (cal1test == 1) { // 10 sec timer for caliberation of sampling pump

digitalWrite(pumpPin[0], HIGH);
Serial.println("sample pump calibration started");
timer.setTimeout(10000L, []()
{
digitalWrite(pumpPin[0], LOW);
Serial.println(" calibration for sample pump finished");
calSample = 0 ;
Serial.println(" calsample false");
cal1test = 0;
});
}

}
}*/



/*
Since CalReagent is READ_WRITE variable, onCalReagentChange() is
executed every time a new value is received from IoT Cloud.
*/
void onCalReagentChange() {
if ( calReagent == 1 ) {

previousMillis = millis();
currentMillis = previousMillis ;
digitalWrite(pumpPin[1], HIGH);

while (currentMillis - previousMillis < interval )
{
currentMillis = millis();

Serial.println(((currentMillis - previousMillis) / 1000 )) ;
calReagent = 0;
}
Serial.println((currentMillis - previousMillis) / 1000 );
digitalWrite(pumpPin[1], LOW);
calReagent = 0;
}
}

/*cal2test = 1 ;
if (cal2test == 1) { // 10 sec timer for caliberation of reagent pump

digitalWrite(pumpPin[1], HIGH);
Serial.println("reagent pump calibration started");
timer.setTimeout(10000L, []()
{
digitalWrite(pumpPin[1], LOW);
Serial.println(" calibration for reagent pump finished");
calReagent = 0 ;
cal2test = 0;
});
}
}
}*/

/*
Since CalReject is READ_WRITE variable, onCalRejectChange() is
executed every time a new value is received from IoT Cloud.
*/
void onCalRejectChange() {
if ( calReject == 1 ) {
previousMillis = millis();
currentMillis = previousMillis ;
digitalWrite(pumpPin[2], HIGH);

while (currentMillis - previousMillis < interval )
{
currentMillis = millis();

Serial.println(((currentMillis - previousMillis) / 1000 )) ;
calReagent = 0;
}
Serial.println((currentMillis - previousMillis) / 1000 );
digitalWrite(pumpPin[2], LOW);
calReject = 0;
}
}

/*
Since SampleCalValue is READ_WRITE variable, onSampleCalValueChange() is
executed every time a new value is received from IoT Cloud.
*/
void onSampleCalValueChange() {
// Add your code here to act upon SampleCalValue change
calsample_eeprom = EEPROM.readFloat(PHVALUEADDR + sizeof(float) + sizeof(float));
if (sampleCalValue != calsample_eeprom)
{
EEPROM.writeFloat(PHVALUEADDR + sizeof(float) + sizeof(float), sampleCalValue);
EEPROM.commit();
Serial.println("SampleCalValue = ");
Serial.println(EEPROM.readFloat(PHVALUEADDR + sizeof(float) + sizeof(float)));
}
}

/*
Since RejectCalValue is READ_WRITE variable, onRejectCalValueChange() is
executed every time a new value is received from IoT Cloud.
*/
void onRejectCalValueChange() {
calreject_eeprom = EEPROM.readFloat(PHVALUEADDR + sizeof(float) + sizeof(float) + sizeof(float));
if (rejectCalValue != calreject_eeprom)
{
EEPROM.writeFloat(PHVALUEADDR + sizeof(float) + sizeof(float) + sizeof(float), rejectCalValue);
EEPROM.commit();
Serial.println("rejectCalValue = ");
Serial.println(EEPROM.readFloat(PHVALUEADDR + sizeof(float) + sizeof(float) + sizeof(float)));
}

}


/*
Since ReagentCalValue is READ_WRITE variable, onReagentCalValueChange() is
executed every time a new value is received from IoT Cloud.
*/
void onReagentCalValueChange() {

calreagent_eeprom = EEPROM.readFloat(PHVALUEADDR + sizeof(float) + sizeof(float) + sizeof(float) + sizeof(float));

if (reagentCalValue != calreagent_eeprom)
{
EEPROM.writeFloat(PHVALUEADDR + sizeof(float) + sizeof(float) + sizeof(float) + sizeof(float), reagentCalValue);
EEPROM.commit();
Serial.println("reagentCalValue = ");
Serial.println(EEPROM.readFloat(PHVALUEADDR + sizeof(float) + sizeof(float) + sizeof(float) + sizeof(float)));
}
}



/*
Since Eventor is READ_WRITE variable, onEventorChange() is
executed every time a new value is received from IoT Cloud.
*/
void onEventorChange() {
// Add your code here to act upon Eventor change
}

/*
Since Stirrer is READ_WRITE variable, onStirrerChange() is
executed every time a new value is received from IoT Cloud.
*/
void onStirrerChange() {

if (stirrer == 1) {
Eventor = 1;
KH_Test();


}
}




/*
Since ScheduleTest is READ_WRITE variable, onScheduleTestChange() is
executed every time a new value is received from IoT Cloud.
*/
void onScheduleTestChange() {

if (schedule_test.isActive()) {
Eventor = 1;
pumpRunning = false;
KH_Test();
}

}


/*
Since CorrectionValue is READ_WRITE variable, onCorrectionValueChange() is
executed every time a new value is received from IoT Cloud.
*/
void onCorrectionValueChange() {
correction_eeprom = EEPROM.readFloat(PHVALUEADDR + sizeof(float) + sizeof(float) + sizeof(float) + sizeof(float) + sizeof(float));
if (correctionValue != correction_eeprom)
{
EEPROM.writeFloat(PHVALUEADDR + sizeof(float) + sizeof(float) + sizeof(float) + sizeof(float) + sizeof(float), correctionValue);
EEPROM.commit();
Serial.println("correctionValue = ");
Serial.println(EEPROM.readFloat(PHVALUEADDR + sizeof(float) + sizeof(float) + sizeof(float) + sizeof(float) + sizeof(float)));
}
}
 
Tidal Gardens
OP
Gogo007

Gogo007

Active Member
Review score
+0 /0 /-0
View Badges
Joined
Dec 18, 2020
Messages
125
Reaction score
43
Review score
+0 /0 /-0
Location
Egypt
@Gogo007.

Awesome work!!! HW looks simple, which IMHO helps with reliability and maintenance.

Can you provide more information on tests such as?
-Accuracy
-Sample volume
-Test duration

Once more, congrats for such a clean project.
Accuracy is about 0.1 dkh and will depend on how much accurate you gona make the reagent each time by the way the reagent used here is hydrochloric acid 0.1 normal and dilluated 1:3 hcl to ro water
Sample volume is 100ml and its very safe to send it back to the tank like alkteonic and such products
Test duration you can set the time widget for doing at as frequently as you want no limit i am testing two times per day but you can test every hour easy
 

How have you used eggcrate in or around your aquarium?

  • Aquarium lid

    Votes: 59 33.7%
  • Frag rack

    Votes: 93 53.1%
  • Skimmer stand

    Votes: 58 33.1%
  • Sump Divider

    Votes: 36 20.6%
  • Other (please describe in the discussion)

    Votes: 28 16.0%
  • I have not used eggcrate in or around my aquarium

    Votes: 41 23.4%
UniqueCorals.com shop rare & farmed corls
Top