Visual Data's software sketch for an Arduino -do-it-yourself- multi sensoring system

This sketch is free for use on any Arduino microprocessor. It is designed on an Arduino Uno, but it shoud also run on other types.
Feel free to alter or change this program, but please respect my name as developer.

Thanks!
Jos Richters.

//*********************************************************************************************************************************************************************************
/* PythiaMultiSensorSystem.ino
************************************************************************
************************************************************************
*********** Pythia Water Condition Sensor ***********
*********** Created and programmed by Jos Richters ***********
************************************************************************
************************************************************************

This sketch is free for use in any of your projects, but please, do not remove this header text.
It is designed for Arduino Uno (mine is an Arduino/Genuino Uno), but it should be possible to re-write it for other types of Arduino too.

Acknowledgments:
I developed this Arduino sketch because I wanted to keep track of the water condition of my tropical aquarium.
So I built a circuit on my breadboard. Now I am able to measure:
-- light intensity: for plant life.
-- Temperature: for overall fish and plant health and happiness.
-- Conductivity: to get an idea of ionic concentration in the tank.
-- pH for fish and plant health to get the best environment possible.

I want hereby thanks a lot of people who unknowingly contributed to the end result of this project: both the circuit and the sketch.
The ResponsiveAnalogRead; by Damien Clarke (https://github.com/dxinteractive/ResponsiveAnalogRead)
The readVcc() routine by: Wiebe Nieuwenhuis (http://www.wiebenieuwenhuis.nl)

The GoBetwino team (http://www.mikmo.dk/gobetwino.html) who made it possible for me to export the data from my Arduino to an external file and into my analysis application: "Pythia".
And the many contributors in the Arduino community who posted lot of suggestions on problems in the Arduino forum and elsewhere.

Gobetwino is kind of a “generic proxy” for Arduino. It’s a program running on a PC (Windows only – sorry), that will act on behalf of Arduino
and do some of the things that Arduino can’t do on its own. So it works like a go between, hence the name.
Gobetwino can be downloaded here: http://www.mikmo.dk/gobetwino. This is also the place to watch for updates and info.

I can now read all the data into my "Predictive Analytics Application" called "Pythia".
You can find all the information of this Arduino project, sketch, circuit, Gobetwino communication and Pythia on my website:
http://rca-pythia.net/

Who is “The Pythia”? The Pythia – Priestess and Oracle of Ancient Delphi.
The Pythia (or Oracle of Delphi) was the priestess who held court at Pytho, the sanctuary of the Delphinians, a sanctuary dedicated to the Greek god Apollo.
Pythia were highly-regarded, for it was believed that she channeled prophecies from Apollo himself, while steeped in a dreamlike trance.
Originally the god was channeled only once a year, but at the height of its popularity up to three Pythiai were known to hold office.
The sanctuary at Delphi was constructed in the 8th century BC, and the final prophecy given around AD 393, after the Roman Emperor Theodosius ordered the closure of all pagan sanctuaries.

What is Pythia, the application?
Pythia Predictive Analytics is developed as an aid in predictive computer models and decision support tools for assessing environmental change,
the effects of both human and natural influences in processes, on the environment, and the integrated management of natural and cultural resources
as well in production facilities and services.
Pythia can be situated on top of process monitoring systems like ARDUINO, SCADA or similar applications, but is completely independent of them.
It merely uses the results to predict events, based on historical data that was collected earlier.
Pythia is created for identifying, designing, and/or developing a computing system environment and protocols to facilitate interactions between analysis tools
and common delivery mechanisms in use or under development. These computational techniques promise a significant cost savings and increased productivity that will
maximize knowledge gained from more costly laboratory experimentation, and will provide analytical input to future automated risk assessment and reduction applications
for service providers and end users.

If you want to know more about Pythia, drop me an email and I will send you all the available information to date.

The Pythia Water Condition Sensor project:
To start with: if you have not already done so; get the latest version of the Arduino sketch compiler. I currently use version 1.8.5
Download the Gobetwino software (free) from their website download page and install it somewhere near your Arduino compiler.
Go and get the electronic components like resistors, Light Depended Resistors (LDR's), a MCP9700 Temperature sensor and a pH sensor set.
A complete and extensive list of necessities can be found on my Arduino pages on my website.
Most of these items are easily and cheap available on the Internet, just search and you will get lots of on-line stores who sell them.

The main measurement way of working is the "voltage divider rule". This means that most (except one: the conductivity sensor) uses this principle.
So I built my three sensors rather standardized: Arduino minus to the 100 KOhm resistor, the Arduino analog read pin tho the junction of the resistor and the probe, and the Arduino plus to the other pole of the probe.
I created this sketch in a modular setup, with possibilities to enable or disable certain sensors, in order to calibrate each one individually.
The conductivity sensor is more complex, it is essential built from two voltage dividers which are feed alternately by a digital pin. (see the image of the circuit and this sketch)

Now build the Arduino Water Condition Sensor circuit as shown on the pictures on my website.
Then load this sketch into your Arduino micro processor and have fun!
*/
//*********************************************************************************************************************************************************************************

#include

#define analogPinLightA0 A0 //AnalogPin for measuring light voltage.
#define analogPinTemperatureA1 A1 //AnalogPin for measuring temperature voltage.
#define analogPinConductivityA2 A2 //AnalogPin for measuring WaterVoltage voltage.
#define analogPinConductivityA3 A3 //AnalogPin for measuring WaterVoltage voltage.
#define analogPHpinA4 A4 //AnalogPin for measuring pH voltage.
#define analogTempPinA5 A5 //Temperature meter on pH probe Analog output to Arduino Analog Input 5.

#define digitalPinLight11 11 //digitalPinTemp11 11.
#define digitalPinHertz12 12 //digitalPinHertz12 12.
#define digitalPinHertz13 13 //digitalPinHertz13 13.

#define NumSamples 30 //Number of samples collection.
#define maxSampleTime pow(7.5,300) //Maximal milli seconds that the sensors can run; after that: reset Arduino!
//*********************************************************************************************************************************************************************************

//Headers
#define LineInit "#S|PYTHIA01|[ =*= Initializing sensors. Please be patient, this will take about 3 minutes.....\t\t\t\t\t\t\t=*=]#"
#define LineVDW "#S|PYTHIA01|[ =*= Visual Data Webservices and Visual Data's Pythia: www.rca-pythia.net\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t=*=]#"
#define LineLegend "#S|PYTHIA01|[ =*= (1,2)Light; (3,4)Temp; (5,6)Conductivity; (7,8)pH; (9 - 11)PinValues; (12)VCC;\t\t\t\t\t\t\t\t\t\t\t\t\t=*=]#"

//Miscellaneous
#define SingleLine "#S|PYTHIA01|[ =*-----------------------------------------------------------------------------------------------------------------------------------*=]#"
#define DoubleLine "#S|PYTHIA01|[ =*===================================================================================================================================*=]#"
//*********************************************************************************************************************************************************************************

//Stabilized pin readings
ResponsiveAnalogRead analog0(A0, true); //Light
ResponsiveAnalogRead analog1(A1, true); //Temperature
ResponsiveAnalogRead analog2(A2, true); //Conductivity Minus
ResponsiveAnalogRead analog3(A3, true); //Conductivity Plus
ResponsiveAnalogRead analog4(A4, true); //pH
ResponsiveAnalogRead analog5(A5, false); //NotInUse
//*********************************************************************************************************************************************************************************
unsigned long int avgValue;
float VCC = 0.00;
float inVoltage = 0.00;
double ADCValue = 0.00;
const float ResistorReferenceValue = 10000.00;
float Resistance = 0.00;

//VCC voltage determination
long readVcc() {
long result;
//Read 1.1V reference against AVcc.
// set the reference to Vcc and the measurement to the internal 1.1V reference
#if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
#elif defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
ADMUX = _BV(MUX5) | _BV(MUX0);
#elif defined (__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
ADMUX = _BV(MUX3) | _BV(MUX2);
#else
ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
#endif
delay(2); //Wait for Vref to settle
ADCSRA |= _BV(ADSC); //Convert
while (bit_is_set(ADCSRA,ADSC));
result = ADCL;
result |= ADCH << 8;
result = 1126400 / result; //Calculate Vcc (in mV); 1126400 = 1.1*1024*1000
return result;
}//long readVcc
//*********************************************************************************************************************************************************************************
//PinReadVoltage determination Part II
double PinReadVoltage(int PinID){
inVoltage = readVcc();
switch (PinID) {
case 0:
analog0.update();
ADCValue = analog0.getValue();
break;
case 1:
analog1.update();
ADCValue = analog1.getValue();
break;
case 2:
analog2.update();
ADCValue = analog2.getValue();
break;
case 3:
analog3.update();
ADCValue = analog3.getValue();
break;
case 4:
analog4.update();
ADCValue = analog4.getValue();
break;
case 5:
analog5.update();
ADCValue = analog5.getValue();
break;
default:
ADCValue = analogRead(0);
}//switch case
float Voltage = ADCValue * inVoltage / 1000;
return Voltage;
}//double PinReadVoltage
//*********************************************************************************************************************************************************************************

//Calculate pH
static double calculate_ph(double VCC, double Vad, double temperature){
double E, E0, C, T;
const double R=8.31441, N=1, F=96484.6;
T=(273.15)+temperature;
C = 2.3 * ((R*T)/(N*F));
E0 = 7*C;
E = ((VCC / 2) - Vad) / 4.745;
return ((E0 - E) / C);
}//double calculate_ph
//*********************************************************************************************************************************************************************************

//Timekeeping
double startSampleValue = 0; //Variable to store the start moment for the total delay time.
double totalSampleTime = 0; //Variable to store the overall time needed for one measurement cycle on all sensors.
double sampleTime = 0; //Variable to store the time needed for one measurement cycle on all sensors.
double loopTime = 0; //Variable to store the time needed for overhead time on all sensors.
//If the totalDelayValue needs to be corrected by one second, just add or subtract 1000 milli seconds from this variable value.
unsigned long totalDelayValue = 57000; //Variable to store the total delay for one measurement on all sensors on one minute, corrected for -3 seconds
//*********************************************************************************************************************************************************************************

//Record reading
int lineCount = 0; //Counts the number of readings for all sensors.
int PythiaCycles = 10; //Number of cycles for the Digital pins 12 and 13 to construct an alternate current.
int serInLen = 25;
char serInString[25];
double SensorHighLow = 0.00;
//*********************************************************************************************************************************************************************************

//About Process
//*********************************************************************************************************************************************************************************
/*
Some elementary steps for calibrating the sensors.
At least you should have a basic understanding of the physics of the process that is under investigation.
In this example we consider a biological process that happens in an aquarium. We want to know whether individual parameters interact with each other so we understand the behavior of it
and we can act appropriately when things are not going as expected. We also aim to deliver the best optimal water conditions for fish and plants to thrive and prosper.
So we need to know what water condition parameters are of interest, and whether we can find, or build, sensors to measure them.
We consider the following water condition parameters that are commonly used by average aquarium keeping enthusiasts.
All the sensors for these measurements are easily and relatively cheap to buy or even to build yourself.
Start with the determination of the optimum values for each parameter and also set the percentual deviation for it that allows best conditions.
Then set the high and low value within the process is still in reasonable, although weak, performance; if a process runs outside these values the situation will be critical.
So, in my case, these are the set up values to investigate and control the aquarium:
# Temperature; Measured in degrees Celsius: Optimal condition value: 24 degrees Celsius with 5% deviation. (It is a tropical fresh water aquarium)
# Light condition; Measured in Light: Optimal condition value: 100% light with 15% deviation. (The environment mimics a creek in the Amazon basin)
# Conductivity; Measured in microSiemens: Optimal condition value: 20 microSiemens with 15% deviation. (Amazon water is known for it's extreme low amount of ionic components in the solution)
# Acidity; Measured in pH: Optimal condition value: 6.8 pH with 2% deviation. (Amazon water is also reasonable acidic due to the lack of calcium carbonate (amongst others)) and low DH values)

Calibrating the sensors is essentially setting all the parameter variables for a known value and then, during the run of the process, constantly compare the captured process values to the known values.
This means that it is key that the base equipment, against we will test the captured values, are as exact as possible. Therefore the best we can do is to get the best instruments that are available.
These instruments need to be precise in their measurements, the measurement range must be well within the range of our process parameter values, and they must be easy and accurate readable.
Preparation:
Step 1: Prepare a work scheme. Determine the order of the sensors that you are going to calibrate. Not all of the sensors need to be calibrated in the same time frame.
Step 2: Prepare the Process carefully; get all the necessary equipment ready (like thermometer, pH buffer solutions, containers, water heater, etcetera) and place them orderly so you can work properly.
Step 3: Set the parameter values for the real values in this sketch to the ones you have previous defined. These are labeled with the term "Process" in the name.
Step 4: set the setTestPinValue back to 'true' and start with calibrating a sensor for the "Optimal Value". This will make it easier for you to work out the high and low values for the process.
Calibrate: See the instructions below for each of the parameter sensors.
Do not forget to upload the sketch after every Process when you changed the value, otherwise yous next test will prove to be wrong!
After calibrating (and cleaning the conductivity sensor is appropriate) you have to set the setTestPinValue back to 'false'
*/
//*********************************************************************************************************************************************************************************

//Light
//*********************************************************************************************************************************************************************************
/*
Calibrating for light brightness is difficult because this is fairy subjective parameter to measure.
This example is about the brightness of the illumination of an aquarium in which the maximum amount of light is determined by the lamps that are fitted.
In this case there are 3 different types of fluorescent tubes and LED's.
So in this case the brightness will be regarded as the maximum percentage (=100%) for all the lamps on.
The darkest situation, which is all the lights off and during the night when there is no ambient light will be 0%.
And when just not all the lamps are on, the real brightness will be somewhere in between.
Use the SerialMonitor to set-up and calibrate the light sensor.
Set-up the light sensor: Cover the LDR with a cap to create full darkness and note the pin value in the LightProcessValueLow variable.
Read the 'LightPinValue' in the SerialMonitor, wait for at least 60 cycles after each turn to settle.
Perform the same procedure for the high value: Point the LDR into the brightest region of the process that is available and note the value in the LightProcessValueHigh variable.
It is a bit tricky to get a reasonable pin reading for the middle section. Be creative, switch some light off or set the LightPinOptimalValue variable to an educated guess value.
Set the "LightOptimalMarginPercentage" to an appropriate value to determine the midsection range for the brightness calculation.
*/
//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
//Set the MarginPercentage to the value that you allow the optimal value to differ within save tolerances.
bool prnInfoLight = false; //Enable or disable luminance measurement (true or false).

//Set these three Process values to the actual parameter values.
const double LightProcessValueTopHigh = 95; //Value of the luminance in the top high position equals 95% intensity.
const double LightProcessOptimalValue = 50; //Value of the luminance in the optimal position equals 50% intensity.
const double LightProcessValueDownLow = 10; //Value of the luminance in the down low position equals 10% intensity.

//Set these three pin values to the actual measured Arduino output pin values.
const double LightPinValueTopHigh = 13.00; //units of the highest possible pin value.
const double LightPinOptimalValue = 11.40;
const double LightPinValueDownLow = 9.00; //units of the highest possible pin value.
//---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
double LightPinValue = 0.00; //Variable that holds the amount of light in Pin Units.
double ValueLight = 0.00; //Variable to store the light value going to Pythia.
double TempPythiaValueLight = 0.00; //Variable to store the light value going to Pythia.
double PythiaValueLight = 0.00; //Variable to store the light value going to Pythia.
unsigned int loopTimeLight = 0; //Variable to store the loop time for the light measurement.
int KOhmResistance = 10; //Resistance in the circuit of light sensor 0 (KOhms).
//*********************************************************************************************************************************************************************************

//Temperature
//*********************************************************************************************************************************************************************************
/*
If you are also measuring for conductivity, you MUST calibrate the temperature first! (See Conductivity below)
Calibrating for temperature is relative easy. Just heat up a container with water with a calibrated thermometer and submerge the temperature sensor probe in it.
This example is about the temperature of an aquarium in which the temperature is allowed to fluctuate between 21 and 28 degrees Celsius.
The optimum temperature is 24.5 degrees Celsius, and may vary a couple of centigrades above or under.
Use the SerialMonitor to set-up and calibrate the temperature sensor.
Set-up the sensor: Put the probe in water that is approximately 10 degrees warmer than the maximum allowed value; check with the thermometer.
Wait and check the temperature during cooling down until it reaches the upper temperature value. Note the pin value at the TemperatureProcessValueHigh variable.
Read the 'TemperaturePinValue' in the SerialMonitor, wait for at least 60 cycles after each turn to settle.
Perform the same procedure for the optimum value; again, wait and check the falling values. Then, at optimum temperature, note the note the value at the TemperatureProcessOptimalValue variable.
AT last perform the same procedure for the low range value; again, wait and check the falling values. Then, at optimum temperature, note the note the value at the TemperatureProcessValueLow variable.
Set the "TemperatureOptimalMarginPercentage" to an appropriate value to determine the midsection range for the temperature calculation.
*/
//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
//Set the MarginPercentage to the value that you allow the optimal value to differ within save tolerances.
bool prnInfoTemperature = false; //Enable/disable temperature measurement (true or false).
const float TemperatureCalibration = 26.40; //Heat the water sample up to approcimately the optimal temperature.
const float TemperatureOffset = 12.75; //Set this offset to correct the raw measurement to the average temperature during sampling.
const float TemperatureCorrection = -2.30; //Set this correction to correct the avarage temperature to the real temperature after sampling.

//Last Process calibration date (yyyy-mm-dd): 2018-03-26.

//Set these three pin values to the actual measured Arduino output pin values.
const double TemperatureProcessValueTopHigh = 30.00; //Value of the high temperature in the aquarium.
const double TemperatureProcessOptimalValue = 25.00; //Value of the optimal temperature in the aquarium.
const double TemperatureProcessValueDownLow = 20.00; //Value of the high temperature in the aquarium.

//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
double TemperaturePinValue = 0.00;
double ValueTemperature = 20.00; //Variable to store the temperature value going to Pythia. Because other process variable also use temperature, this needs to be set to average room temperature.
double TempPythiaValueTemperature = 0.00; //Variable to store the temperature value going to Pythia.
double PythiaValueTemperature = 0.00; //Variable to store the temperature value going to Pythia.
unsigned int loopTimeTemperature = 0; //Variable to store the loop time for the temperature measurement.
//*********************************************************************************************************************************************************************************

//Conductivity
//*********************************************************************************************************************************************************************************
/*
Determination of conductivity is relative easy, but it is quite a different measurement due to the nature of the chemical reactions that are involved.
This example is about the conductivity of an aquarium in which the conductivity is allowed to fluctuate between 10 and 50 microSiemens.
The optimum conductivity is 24.5 microSiemens, and conductivity is highly temperature dependent.
So first get the temperature Process right because this will be needed for a proper conductivity Process.
In fact, the conductivity measurement is based on the pin voltage of the Arduino; approximately five Volt.
This voltage is not a fixed value; it can widely vary between 4 and 5.5 volt. So there is a catch in this conversion.
In this sketch we will use a special routine that reads the true Arduino voltage: readVcc(). This routine will return the true voltage the Arduino emits.
And this will be converted into the real conductivity value.
About the probe:
Conductivity measurement in a liquid is not as straight forward as the measurement through a regular resistor.
It involves chemical processes that eventually will destroy the probe because of electrolysis. This is caused by the ions in the solution. (Please search the Internet for more information)
Now, Arduino produces only DC (=Direct Current). This will act as an electrolysis cell in the liquid because it will pull the ions to the respective sensor poles and thereby fouling or damaging them.
This, in turn, will ruin the sensor and the measurements.
So we need AC (=Alternating Current). This will prevent the probe from getting hurt and the sensor and the measurements will last much longer.
The AC is produced with the help of some diodes and resistors on the circuit and by alternating two digital pins on the Arduino thru this sketch.
So, in effect, the ions in the solution are not traveling to one of the sensor's poles (at least very less) and the measurement is a double; one for each direction of the current.
The real process conductivity is then calculated from these two partial results.
*/
//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
bool prnInfoConductivity = false; //Enable/disable conductivity measurement (true or false).

double sensorReadValueA2 = 0.00; //Variable to store the value coming from the conductivity sensor.
double sensorReadValueA3 = 0.00; //Variable to store the value coming from the conductivity sensor.
double MicroSiemens = 0.00; //Variable to store the WaterVoltage value going to Pythia.
double TempAvgVCC = 0.00; //Variable that holds the actual measurement from Arduino.
double AvgVCCA2 = 0.00; //Variable to store the average VCC.
double AvgVCCA3 = 0.00; //Variable to store the average VCC.

double avgConductivityPinValueA2 = 0.00; //Variable to store the WaterVoltage coming from the WaterVoltagesensor.
double avgConductivityPinValueA3 = 0.00; //Variable to store the WaterVoltage coming from the WaterVoltagesensor.
double TempPythiaMicroSiemens = 0.00; //Variable to store the WaterVoltage value going to Pythia.
double PythiaMicroSiemens = 0.00; //Variable to store the WaterVoltage value going to Pythia.
unsigned int loopTimeConductivity = 0; //Variable to store the loop time for the conductivity measurement.
//*********************************************************************************************************************************************************************************

//pH
//*********************************************************************************************************************************************************************************
/*
Use the SerialMonitor to set-up and calibrate the pH sensor.
Set-up the pH sensor: shortcut the BNC connector on the pH interface and start this Arduino sketch.
Read the 'ProbePHPinUnits' in the SerialMonitor, wait for at least 60 cycles after each turn to settle. This should be around 511 units plus-minus 10 units.
If not, turn the screw on the pH-to-Arduino interface until the value is as close as possible to 511 units, which is very near the pH 7 value reference.
In case the ProbePHPinUnits drifts off from the desired 511 units, you can calibrate the sensor by setting the 'pHValueCorrection' after following the Process as described below.
*/
//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
//Attention: The 'setTestAll' has to be 'true', otherwise no Process is executed.
//Step 1: The "zero" Process.
bool setTestAll = false; //When testing and calibrating the pH probe. This must ALWAYS set to TRUE when testing or calibrating!
bool setTestShortCutPH = false; //When testing on the shortcut probe BNC plug for pH7.00
bool setTestAcidic = false; //When testing on an acidic calibration solution.
bool setTestNeutral = false; //When testing on the Neutral buffer solution.
bool setTestAlkaline = false; //When testing on an alkaline calibration solution.

//Set the 'setTestShortCutPH' back to 'false' after setting the pHValueCorrection is set to the suggested value during the Process process.
//Step 2: The "Neutral" Process. ATTENTION! Do NOT CHANGE this value EXEPT when you are using the pH sensor, otherwise the sketch will present odd results!
double pHValueAcidicCorrection = 0.00; //Use this variable to correct the ACIDIC pH value from the sensor to the correct result.
double pHValueNeutralCorrection = 1.88; //Use this variable to correct the NEUTRAL pH value from the sensor to the correct result.
double pHValueAlkalicCorrection = 0.00; //Use this variable to correct the ALKALIC pH value from the sensor to the correct result.
//If the pHValueCorrection is set (back) to zero, you can re-calibrate the pH sensor and Arduino will prompt you to set this correction.
//Step 3: The "rest" Process.
//Last Process date ShortCut pHprobe: (yyyy-mm-dd): 2018-03-26; Value: 526.00 PinUnits. This is the value on the shortcut test.
//Last Process date on buffer fluids: (yyyy-mm-dd): 2018-03-26; refreshed the buffer solutions.

//The pH sensor is now set and ready to calibrate against the buffer solutions.
//Start with the determination of the allowed margin (bandwidth) above and below the optimal pH for this process.
//Set the MarginPercentage to the value that you allow the optimal value to differ within save tolerances.
bool prnInfoPH = true; //Enable/disable pH measurement (true or false).
//Prepare the pH Process solutions in three containers and assign the pH values to the variables.
//This value will be added or subtracted from the optimal value in order to get the optimal range.
const double pHCalibrationShortCutValue = 7.00; //Value of the pH in the shortcut probe BNC plug.
const double pHProcessValueTopHigh = 4.00; //Value of the pH in the acidic buffer solution.
const double pHProcessOptimalValue = 6.86; //Value of the pH in the neutral buffer solution.
const double pHProcessValueDownLow = 9.18; //Value of the pH in the alkaline buffer solution.

//Set the measured pH PinValues to the Process variable that you got from the Process setting.
//Load and restart Arduino with the new sketch after each value correction.
//Again, wait for the pH probe to settle for the new solution measurement.
const double pHPinValueTopHigh = 695.00; //Units of 4.00 pH in the Acidic buffer solution.
const double pHPinOptimalValue = 588.00; //Units of 6.86 pH in the Neutral buffer solution.
const double pHPinValueDownLow = 520.00; //Units of 9.18 pH in the Alkaline buffer solution.

//After the completed calibration: Rinse the pH probe in clear de-mineralized water and set the "setTestPinValue" to 'false'; now place the pH probe in the aquarium.
//Now make the measurements and observe the result!
//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
float ProbeVoltage = 0.00;
double ProbePHPinUnits = 0.00; //This variable holds the actual measurement from Arduino on the pH probe.
double TempPythiaValuePH = 0.00; //This variable gets the calculated pH and adds it with itself for 'PythiaCycle' times. (Default: 60 cycles)
double PythiaValuePH = 0.00; //The end result goes in here and will be exported to the log file.
unsigned int loopTimePH = 0; //Variable to store the loop time for the pH measurement.
double deltaXold = 0;
double deltaXnew = 0;
double deltaYold = 0;
double deltaYnew = 0 ;
//*********************************************************************************************************************************************************************************

//Print; Test & Calibrate
//*********************************************************************************************************************************************************************************
bool setTestPinValue = false; //Set to TRUE when testing on the pin Process value.
bool setToCalibration = false; //Set to TRUE when you are calibrating a sensor. Be sure that only the boolean prn-X- for that sensor is also TRUE, the others are FALSE.
bool prnPlotter = false; //Set to TRUE when printing to the serial plotter in the Arduino compiler, when calibrating, might be helpful. You can either plot or list the output.
//---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
bool ShowInfoLight = false; //Enable/disable luminance measurement (true or false).
bool ShowInfoTemperature = true; //Enable/disable pH temperature measurement (true or false).
bool ShowInfoConductivity = true; //Enable/disable conductivity measurement (true or false).
bool ShowInfoPH = true; //Enable/disable pH measurement (true or false).
//*********************************************************************************************************************************************************************************

void setup(void){
Serial.begin(9600);
if (prnPlotter == false){
if ((setTestAll == false) && (setTestPinValue == false) && ((ShowInfoPH == true) || (ShowInfoLight == true) || (ShowInfoTemperature == true) || (ShowInfoConductivity == true))){
Header_VDW();
} else {
Header_Init();
}//if else
}//if
}//setup
//*********************************************************************************************************************************************************************************

void loop(void){
startSampleValue = millis();

//----------------------------- Start Light Measurement ------------------------------------
if (ShowInfoLight == true){
loopTimeLight = millis();
for (int i = 0; i < PythiaCycles; i++){
analog0.update();
ADCValue = analog0.getValue();
SensorHighLow = ADCValue; //Read the analog sensor from Arduino 5 Volt source and store the light value.
}//for
LightPinValue = SensorHighLow / PythiaCycles;
SensorHighLow = 0.00;
if (setToCalibration == true) {
CalibrateSensorValues("Light", LightPinValue, LightPinOptimalValue, LightPinValueTopHigh, LightPinValueDownLow, LightProcessOptimalValue, LightProcessValueTopHigh, LightProcessValueDownLow);
} else {
/*
Algorithm: Rf(Vt - Vm) / Vm = RL
Where RL is the resistance of the light dependent resistor.
Vt is the total voltage across the divider in this case 5v.
Rf is the resistance of the fixed resistor.
Vm is the voltage you measure.
*/
//ValueLight = = NewAlgorithm;
}//if else
loopTimeLight = millis() - loopTimeLight;
}//if
TempPythiaValueLight = TempPythiaValueLight + ValueLight;
//----------------------------- End Light Measurement --------------------------------------

//----------------------------- Start Temperature Measurement ------------------------------
if (ShowInfoTemperature == true){
loopTimeTemperature = millis();
for (int i = 0; i < PythiaCycles; i++){
analog1.update();
SensorHighLow = SensorHighLow + analog1.getValue(); //Read the analog sensor from Arduino 5 Volt source and store the Temperature value.
}//for
TemperaturePinValue = SensorHighLow / PythiaCycles;
SensorHighLow = 0.00;
ValueTemperature = TemperaturePinValue * (readVcc() / 1000) / 1024.0;
ValueTemperature = (ValueTemperature - 0.5)/0.01;
if (setToCalibration == true) {
Serial.print("#S|PYTHIA01|[ =*= Calibrate on raw ValueTemperature: ");
Serial.print(ValueTemperature);
Serial.println(" Celsius]#");
Serial.print("Offset ValueTemperature: ");
Serial.print(TemperatureCalibration - ValueTemperature);
Serial.println(" Celsius]#");
Serial.print("Calibrated ValueTemperature: ");
Serial.print(ValueTemperature + (TemperatureCalibration - ValueTemperature));
Serial.println(" Celsius\n]#");
delay(2000);
} else {
ValueTemperature = ValueTemperature + TemperatureOffset;
}//if else
loopTimeTemperature = millis() - loopTimeTemperature;
}//if
TempPythiaValueTemperature = TempPythiaValueTemperature + ValueTemperature;
//----------------------------- End Temperature Measurement ----------------------------------

//----------------------------- Start Water Conductivity Measurement -------------------------
if (ShowInfoConductivity == true){
loopTimeConductivity = millis();
digitalWrite(digitalPinHertz13, HIGH); //Set digitalPinHertz13 HIGH.
for (int i = 0; i < PythiaCycles; i++){
SensorHighLow = SensorHighLow + PinReadVoltage(analogPinConductivityA2);
TempAvgVCC = TempAvgVCC + PinReadVoltage(analogPinConductivityA2);
}//for
digitalWrite(digitalPinHertz13, LOW); //Set digitalPinHertz13 LOW.
if (avgConductivityPinValueA2 < SensorHighLow){
avgConductivityPinValueA2 = SensorHighLow;
}//if
SensorHighLow = 0.00;
if (AvgVCCA2 < TempAvgVCC){
AvgVCCA2 = TempAvgVCC;
}//if
TempAvgVCC = 0.00;
avgConductivityPinValueA2 = avgConductivityPinValueA2 / PythiaCycles;
digitalWrite(digitalPinHertz12, HIGH); //Set digitalPinHertz12 HIGH.
for (int i = 1; i <= PythiaCycles; i++){
SensorHighLow = SensorHighLow + PinReadVoltage(analogPinConductivityA3);
TempAvgVCC = TempAvgVCC + PinReadVoltage(analogPinConductivityA3);
}//for
digitalWrite(digitalPinHertz12, LOW); //Set digitalPinHertz12 LOW.
if (avgConductivityPinValueA3 < SensorHighLow){
avgConductivityPinValueA3 = SensorHighLow;
}//if
SensorHighLow = 0.00;
if (AvgVCCA3 < TempAvgVCC){
AvgVCCA3 = TempAvgVCC;
}//if
TempAvgVCC = 0.00;
avgConductivityPinValueA3 = avgConductivityPinValueA3 / PythiaCycles;
Resistance = (((((AvgVCCA2 + AvgVCCA3) / 20000) * ResistorReferenceValue) / ((avgConductivityPinValueA2 + avgConductivityPinValueA3) / 5000)) - ResistorReferenceValue);
MicroSiemens = 1.0 / (Resistance / 1000000);
loopTimeConductivity = millis() - loopTimeConductivity;
}//if
TempPythiaMicroSiemens = TempPythiaMicroSiemens + MicroSiemens;
//----------------------------- End Water Conductivity Measurement ---------------------------

//----------------------------- Start pH Measurement -----------------------------------------
if (ShowInfoPH == true){
loopTimePH = millis();
float PinVoltage = readVcc() / 1000;
float ProbePH = 0.00;
for (int i = 0; i < PythiaCycles; i++){
analog4.update();
SensorHighLow = SensorHighLow + analog4.getValue();
delay(30);
}//for
ProbePHPinUnits = SensorHighLow / PythiaCycles;
SensorHighLow = 0.00;
if (setToCalibration == true) {
inVoltage = PinVoltage * ProbePHPinUnits;
ProbeVoltage = inVoltage / 1000;
if (setTestShortCutPH == true) {
PythiaValuePH = pHCalibrationShortCutValue + (ProbeVoltage / (pHPinValueTopHigh - pHPinValueDownLow) / (pHProcessValueDownLow - pHProcessValueTopHigh));
} else if (setTestAcidic == true) {
PythiaValuePH = pHProcessValueTopHigh + (ProbeVoltage / (pHPinValueTopHigh - pHPinValueDownLow) / (pHProcessValueDownLow - pHProcessValueTopHigh));
} else if (setTestNeutral == true) {
PythiaValuePH = pHProcessOptimalValue + (ProbeVoltage / (pHPinValueTopHigh - pHPinValueDownLow) / (pHProcessValueDownLow - pHProcessValueTopHigh));
} else if (setTestAlkaline == true) {
PythiaValuePH = pHProcessValueDownLow + (ProbeVoltage / (pHPinValueTopHigh - pHPinValueDownLow) / (pHProcessValueDownLow - pHProcessValueTopHigh));
} else {
if ((ProbePHPinUnits <= pHPinValueTopHigh) && (ProbePHPinUnits > pHPinOptimalValue)){
deltaXold = pHPinValueTopHigh - pHPinOptimalValue;
deltaXnew = pHPinValueTopHigh - ProbePHPinUnits;
deltaYold = pHProcessValueTopHigh - pHProcessOptimalValue;
deltaYnew = (deltaYold * deltaXold) / ProbePHPinUnits;
PythiaValuePH = pHProcessOptimalValue + deltaYnew;
} else if ((ProbePHPinUnits <= pHPinOptimalValue) && (ProbePHPinUnits > pHPinValueDownLow)){
deltaXold = pHPinOptimalValue - pHPinValueDownLow;
deltaXnew = pHPinOptimalValue - ProbePHPinUnits;
deltaYold = pHProcessOptimalValue - pHProcessValueDownLow;
deltaYnew = (deltaYold * deltaXold) / ProbePHPinUnits;
PythiaValuePH = pHProcessValueDownLow + deltaYnew;
}//if else
PythiaValuePH = PythiaValuePH;
}//if else
Serial.print("#S|PYTHIA01|[ =*= ProbePinUnits: ");
Serial.print(ProbePHPinUnits);
Serial.print("; ProbeVoltage: ");
Serial.print(ProbeVoltage);
if (setTestAll == true) {
if (setTestShortCutPH == true) {
if (PythiaValuePH < pHCalibrationShortCutValue){
Serial.print("; pH to LOW; turn probe setting UP");
} else if (PythiaValuePH > pHCalibrationShortCutValue) {
Serial.print("; pH to HIGH; turn probe setting DOWN");
} else {
Serial.print("; pH OK!");
}//if else
} else if (setTestAcidic == true) {
Serial.print(" Volt; Raw ProbeValuePH: ");
Serial.print(PythiaValuePH);
Serial.print(" pH");
Serial.print("; Acidic; Set pHValueAcidicCorrection to: ");
Serial.print(pHProcessValueTopHigh - PythiaValuePH);
Serial.print(" pH; Calibrated ProbeValuePH: ");
Serial.print(PythiaValuePH + pHValueAcidicCorrection);
} else if (setTestNeutral == true) {
Serial.print(" Volt; Raw ProbeValuePH: ");
Serial.print(PythiaValuePH);
Serial.print(" pH");
Serial.print("; Neutral; Set pHValueNeutralCorrection to: ");
Serial.print(pHProcessOptimalValue - PythiaValuePH);
Serial.print(" pH; Calibrated ProbeValuePH: ");
Serial.print(PythiaValuePH + pHValueNeutralCorrection);
} else if (setTestAlkaline == true) {
Serial.print(" Volt; Raw ProbeValuePH: ");
Serial.print(PythiaValuePH);
Serial.print(" pH");
Serial.print("; Alkaline; Set pHValueAlkalicCorrection to: ");
Serial.print(pHProcessValueDownLow - PythiaValuePH);
Serial.print(" pH; Calibrated ProbeValuePH: ");
Serial.print(PythiaValuePH + pHValueAlkalicCorrection);
} else {
if ((ProbePHPinUnits <= pHPinValueTopHigh) && (ProbePHPinUnits > pHPinOptimalValue)){
Serial.print(";\tHigh part; ");
} else if ((ProbePHPinUnits <= pHPinOptimalValue) && (ProbePHPinUnits > pHPinValueDownLow)){
Serial.print(";\tLow part; ");
}//if else
Serial.print(" deltaXold: ");
Serial.print(deltaXold);
Serial.print("; deltaXnew: ");
Serial.print(deltaXnew);
Serial.print("; deltaYold: ");
Serial.print(deltaYold);
Serial.print("; deltaYnew: ");
Serial.print(deltaYnew);
Serial.print(";\tPythiaValuePH: ");
Serial.print(PythiaValuePH);
}//if else
Serial.println(" pH]#");
delay(1000);
}//if
}//if else
if ((ProbePHPinUnits <= pHPinValueTopHigh) && (ProbePHPinUnits > pHPinOptimalValue)){
deltaXold = pHPinValueTopHigh - pHPinOptimalValue;
deltaXnew = pHPinValueTopHigh - ProbePHPinUnits;
deltaYold = pHProcessValueTopHigh - pHProcessOptimalValue;
deltaYnew = (deltaYold * deltaXold) / ProbePHPinUnits;
PythiaValuePH = pHProcessOptimalValue + deltaYnew;
} else if ((ProbePHPinUnits <= pHPinOptimalValue) && (ProbePHPinUnits > pHPinValueDownLow)){
deltaXold = pHPinOptimalValue - pHPinValueDownLow;
deltaXnew = pHPinOptimalValue - ProbePHPinUnits;
deltaYold = pHProcessOptimalValue - pHProcessValueDownLow;
deltaYnew = (deltaYold * deltaXold) / ProbePHPinUnits;
PythiaValuePH = pHProcessValueDownLow + deltaYnew;
}//if else
loopTimePH = millis() - loopTimePH;
}//if
//----------------------------- End pH Measurement -----------------------------------------

//----------------------------- Get the highest value as measurement recording -------------
totalSampleTime = loopTimeLight + loopTimeTemperature + loopTimeConductivity + loopTimePH; //Calculate the four process sample times to get a clear time stamp on the process measurements.
if (lineCount < (NumSamples - 1)){
lineCount += 1;
} else if ((setToCalibration == false) && (setTestAll == false) && (setTestPinValue == false) && ((ShowInfoPH == true) || (ShowInfoLight == true) || (ShowInfoTemperature == true) || (ShowInfoConductivity == true))){
if ((lineCount * 1) == ((NumSamples - 1) * 60)){
Header_VDW();
}//if
TempPythiaValueLight = TempPythiaValueLight / lineCount;
if (PythiaValueLight < TempPythiaValueLight){
PythiaValueLight = TempPythiaValueLight;
}//if
TempPythiaValueTemperature = TempPythiaValueTemperature / lineCount;
if (PythiaValueTemperature < TempPythiaValueTemperature){
PythiaValueTemperature = TempPythiaValueTemperature + TemperatureCorrection;
}//if
TempPythiaMicroSiemens = TempPythiaMicroSiemens / lineCount;
if (PythiaMicroSiemens < TempPythiaMicroSiemens){
PythiaMicroSiemens = TempPythiaMicroSiemens;
}//if
sampleTime = millis() - startSampleValue;
loopTime = totalDelayValue - sampleTime;
logData(PythiaValueLight * 100, loopTimeLight * 100, PythiaValueTemperature * 100, loopTimeTemperature * 100, PythiaMicroSiemens * 100, loopTimeConductivity * 100, PythiaValuePH * 100, loopTimePH * 100, LightPinValue, TemperaturePinValue, ProbePHPinUnits, readVcc());
//Initialize all variables for the next loop.
lineCount = 0;
TempPythiaValueLight = 0.00;
PythiaValueLight = 0.00;
TemperaturePinValue = 0.00;
TempPythiaValueTemperature = 0.00;
PythiaValueTemperature = 0.00;
avgConductivityPinValueA2 = 0.00;
avgConductivityPinValueA3 = 0.00;
PythiaMicroSiemens = 0.00;
AvgVCCA2 = 0.00;
AvgVCCA3 = 0.00;
ProbePHPinUnits = 0.00;
TempPythiaValuePH = 0.00;
sampleTime = millis() - startSampleValue;
if ((setTestPinValue = false) && ((sampleTime < 0) || (sampleTime > totalDelayValue) || startSampleValue > maxSampleTime)){
Delay_Error(totalDelayValue, sampleTime, loopTimeLight, loopTimeTemperature, loopTimeConductivity, loopTimePH, maxSampleTime);
totalDelayValue = totalDelayValue + 1000;
} else {
if ((setTestPinValue == false) && (prnPlotter == false)){
delay(totalDelayValue - (millis() - startSampleValue));
} else if (setTestPinValue == true){
delay(totalDelayValue);
}//if else
}//if else
} else {
lineCount = 0;
}//if else
}//loop
//*********************************************************************************************************************************************************************************

void logData(long Light, long LoopTimeLight, long Temperature, long LoopTimeTemperature, long WaterConductivity, long LoopTimeWaterConductivity, long WaterPH, long LoopTimeWaterPH, long LightPinValue, long TemperaturePinValue, long ProbePHPinUnits, long VCC){
char buffer[10];
Serial.print("#S|PYTHIA01|["); //Initialize Gobetwino command.
Serial.print(itoa((Light), buffer, 10)); //#02
Serial.print(";");
Serial.print(itoa((LoopTimeLight), buffer, 10)); //#03
Serial.print(";");
Serial.print(itoa((Temperature), buffer, 10)); //#04
Serial.print(";");
Serial.print(itoa((LoopTimeTemperature), buffer, 10)); //#05
Serial.print(";");
Serial.print(itoa((WaterConductivity), buffer, 10)); //#06
Serial.print(";");
Serial.print(itoa((LoopTimeWaterConductivity), buffer, 10)); //#07
Serial.print(";");
Serial.print(itoa((WaterPH), buffer, 10)); //#08
Serial.print(";");
Serial.print(itoa((LoopTimeWaterPH), buffer, 10)); //#09
Serial.print(";");
Serial.print(itoa((LightPinValue), buffer, 10)); //#10
Serial.print(";");
Serial.print(itoa((TemperaturePinValue), buffer, 10)); //#11
Serial.print(";");
Serial.print(itoa((ProbePHPinUnits), buffer, 10)); //#12
Serial.print(";");
Serial.print(itoa((VCC), buffer, 10)); //#13
Serial.println(";]#"); //Finalize Gobetwino command.
readSerialString(serInString, 1000);
}//void logData.
//*********************************************************************************************************************************************************************************

//Read a string from the serial and store it in an array.
//You must supply the array variable - return if timeOut ms passes before the sting is read.
void readSerialString (char * strArray, long timeOut){
long startTime = millis();
int i = 0;
while (!Serial.available()){
if ((unsigned)millis() - (unsigned)startTime >= (unsigned)timeOut) {
return;
}//if
}//while
while (Serial.available() && i < serInLen){
strArray[i] = Serial.read();
i++;
}//while
}//void readSerialString.
//*********************************************************************************************************************************************************************************

//pH Calibration & Measurement
void CalibrateSensorValues(String Parameter, double PinInputValue, double PinOptimalValue, double PinValueTopHigh, double PinValueDownLow, double ProcessOptimalValue, double ProcessTopHighValue, double ProcessDownLowValue){
if (setTestShortCutPH == true){ //Only for the pH calibration!
Serial.println("\n=*= Calibration Step 0: Set TempAvgValuePh to 0.00 and turn the screw on the pH sensor to around 511 units, or as close as you can.");
Serial.print("=*= Actual PinInputValue: ");
Serial.print(PinInputValue);
Serial.print(" units. Turn the screw until 511 units is reached, and/or set the pHPinCorrection to ");
Serial.println(511 - PinInputValue);
Serial.println("=*= Switch the shortcut plug with the probe plug and place the probe into the neutral buffer solution.");
Serial.println("=*= Set setTestShortCutPH = false and re-start the sketch.");
Serial.println("=*= Now decide how much tolerance you accept for the optimum pH to differ from the optimum value. Set this in ProcessTolerancePercentage. (Default: 0.25%)");
} else if (PinOptimalValue == 0.00) {
Serial.print("\n=*= Calibration Step 1: Set the optimal pin value. (Wait until readings are stable on reference ");
Serial.print(ProcessOptimalValue);
if (Parameter == "Light") {
Serial.println(" Lux)");
} else if (Parameter == "Temperature") {
Serial.println(" degrees Celsius)");
} else if (Parameter == "pH"){
Serial.println(" pH)");
}//if else
Serial.print("=*= Set Optimal PinValue to: ");
Serial.print(PinInputValue);
Serial.println(" units. ATTENTION! This value MUST correspond with the designed optimal calibration value!");
delay(1000);
} else if ((PinOptimalValue != 0.00) && (PinValueTopHigh == 0.00) && (PinValueDownLow == 0.00)) {
Serial.print("\n=*= Calibration Step 2: Set the HIGH pin value. (Wait until readings are stable on reference ");
Serial.print(ProcessTopHighValue);
if (Parameter == "Light") {
Serial.println(" BURNING lights)");
} else if (Parameter == "Temperature") {
Serial.print(" degrees Celsius)");
} else if (Parameter == "pH"){
Serial.print(" ACIDIC buffer");
}//if else
Serial.print(". Read PinInputValue: ");
Serial.print(PinInputValue);
Serial.println(" units.\n=*= Now set PinValueTopHigh; next PinValueDownLow.]#");
delay(1000);
} else if ((PinOptimalValue != 0.00) && (PinValueTopHigh != 0.00) && (PinValueDownLow == 0.00)) {
Serial.print("\n=*= Calibration Step 3: Set the LOW pin value. (Wait until readings are stable on reference ");
Serial.print(ProcessDownLowValue);
if (Parameter == "Light") {
Serial.println(" DARKNESS)");
} else if (Parameter == "Temperature") {
Serial.print(" degrees Celsius)");
} else if (Parameter == "pH"){
Serial.print(" ALKALIC buffer");
}//if else
Serial.print(". Read PinInputValue: ");
Serial.print(PinInputValue);
Serial.println(" units.\nNow set PinValueDownLow accordingly.]#");
delay(1000);
} else if ((setToCalibration == true) && (PinInputValue != 0.00) && (PinValueTopHigh != 0.00) && (PinValueDownLow != 0.00)){
Serial.println("\n=*= DONE! Congratulations, you have successfully calibrated the sensor.");
Serial.println("=*= Reset setToCalibration and setTestPinValue to false and place the probe in the process to monitor.");
Serial.println("=*= Don't forget to re-calibrate every week or month or whatever period is appropriate, as far as you trust the drift of the sensor probe.... (It will deteriorate in time!)");
delay(1000);
} else if ((setToCalibration == false) && (setTestPinValue == true)){
Serial.println("\n=*= Due time the pH probe will deteriorate and the measurements will drift off.");
Serial.println("=*= Therefore there is a correction to be made, now and in the future.");
Serial.print("=*= Set Arduino pHPinCorrection to: ");
//Serial.print(511 + pHPinCorrection - PinInputValue);
Serial.print(" units.\n");
delay(1000);
}//if else
}//void CalibrateSensorValues
//*********************************************************************************************************************************************************************************

//Delay_Error
//*********************************************************************************************************************************************************************************
void Delay_Error(double totalDelayValue, double sampleTime, double loopTimeLight, double loopTimeTemperature, double loopTimeConductivity, double loopTimePH, double overLoad) {
Serial.print("#S|PYTHIA01|[ =*= Delay overflow ERROR! Delay: "); //Initialize Gobetwino command.
Serial.print(totalDelayValue);
Serial.print(" mSec; sampleTime (after logData): ");
Serial.print(sampleTime);
Serial.println(" mSec;\t\t\t\t\t\t\t\t=*=]#");
Serial.print("#S|PYTHIA01|[ =*= Correct totalDelayValue for ");
Serial.print(totalDelayValue - sampleTime);
Serial.println(" mSec to the next 1000 mSeconds\t\t\t\t\t\t\t\t\t\t\t\t\t=*=]#"); //Finalize Gobetwino command.
Serial.print("#S|PYTHIA01|[ =*= sampleTime Light: ");
Serial.print(loopTimeLight);
Serial.print(" mSec; Time Temperature: ");
Serial.print(loopTimeTemperature);
Serial.print(" mSec; Time Conductivity: ");
Serial.print(loopTimeConductivity);
Serial.print(" mSec; Time pH: ");
Serial.print(loopTimePH);
Serial.println(" mSec\t\t=*=]#"); //Finalize Gobetwino command.
if (startSampleValue > overLoad){
Serial.print("#S|PYTHIA01|[ =*= Delay overflow ERROR! On startSampleValue\t");
Serial.print(startSampleValue,0);
Serial.println(" milli seconds\t\t\t\t=*=]#");
Serial.print("#S|PYTHIA01|[ =*= Delay overflow ERROR! On millis()\t\t\t");
Serial.print(millis());
Serial.println(" milli seconds\t\t\t\t=*=]#");
Serial.print("#S|PYTHIA01|[ =*= Delay overflow ERROR! On sampleTime\t\t\t");
Serial.print(sampleTime,0);
Serial.println(" milli seconds\t\t\t\t=*=]#");
Serial.print("#S|PYTHIA01|[ =*= Delay overflow ERROR! On delay\t\t\t\t");
Serial.print(totalDelayValue - sampleTime,0);
Serial.println(" milli seconds\t\t\t\t=*=]#");
}//if
}//void Delay_Error

//Header_Init
//*********************************************************************************************************************************************************************************
void Header_Init(void) {
Serial.println(DoubleLine);
Serial.println(LineInit);
Serial.println(DoubleLine);
}//void Header_Init

//Header_VDW
//*********************************************************************************************************************************************************************************
void Header_VDW(void) {
Serial.println(DoubleLine);
Serial.println(LineVDW);
Serial.println(DoubleLine);
Serial.println(LineLegend);
Serial.println(SingleLine);
}//void Header_VDW