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

/*
************************************************************************
********* PythiaMultiSensorSystemAquarium_PH_ORP_Timer.ino **********
************************************************************************
************************************************************************
*********** Pythia Water Condition Sensor ***********
*********** Created and programmed by Jos Richters ***********
*********** Version 1.0.1.2 Date 2018-07-04 ***********
************************************************************************
************************************************************************

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.

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.
-- pH for fish and plant health to get the best environment possible.
-- ORP for a healty water quality in which pollutants are safely eliminated.

I want hereby thanks a lot of people who unknowingly contributed to the end stringResult 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.

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 stringResults 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 "Timer.h"
#include
#include
#define int5Volt 5 //The 5 volt operational power.
#define ONE_WIRE_BUS 8 //Digital input on digital pin 8 for measuring temperature.
#define analogPinLightA0 A0 //AnalogPin for measuring light units.
#define analogPHpinA1 A1 //AnalogPin for measuring pH units.
#define analogORPpinA2 A2 //AnalogPin for measuring ORP units.
#define analogPinA3 A3 //AnalogPin for measuring (NotInUse).
#define analogPinA4 A4 //AnalogPin for measuring (NotInUse).
#define analogPinA5 A5 //AnalogPin for measuring (NotInUse).
#define digitalPinHertz6 6 //digitalPinHertz6 6.
#define digitalPinHertz7 7 //digitalPinHertz7 7.
#define digitalPinPH 12 //digitalPinPH 12.
#define digitalPinORP 13 //digitalPinORP 13.
#define NumSamples 60 //Number of samples collection.
//*********************************************************************************************************************************************************************************

//Headers.
#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 LineMail "#S|PYTHIA01|[ =*= For more information send mail a request to: info@visualdata.nl\t\t\t\t\t\t\t\t\t\t\t=*=]#"
#define LineInit "#S|PYTHIA01|[ =*= Initializing sensors. Please be patient, this will take about 1 minute...\t\t\t\t\t\t\t\t\t\t\t\t\t\t=*=]#"
#define LineLegend "#S|PYTHIA01|[ =*= (1)Light; (2)Temp; (3)pH; (4)ORP; (5)rH;\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t=*=]#"

//Miscellaneous.
#define Device1 "Controller temperature"
#define Device2 "Aquarium temperature"
#define Device3 "NotInUse"

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

#define LineVDWQ "#S|PYTHIA01|[ =*= Visual Data Webservices: www.rca-pythia.net\t\t\t\t\t\t\t=*=]#"
#define LineMailQ "#S|PYTHIA01|[ =*= For more information send a mail request to: info@visualdata.nl\t\t=*=]#"
//#define DoubleLineQ "#S|PYTHIA01|[\n\n\n\n\n\t\t\t\t\t=*===================================================================================*=]#"
#define DoubleLineQ "#S|PYTHIA01|[ =*=======================================================================*=]#"
//*********************************************************************************************************************************************************************************

//Timekeeping.
Timer tmeMinute;
bool showTiming = false; //Show the timing values for the delay in order to sample every one minute.
//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
unsigned long startSampleTime = 0; //Variable to store the start moment for the total delay time.
const unsigned long totalDelayValue = 60000; //Variable to store the total delay for one measurement on all sensors on one minute.
const int correctedDelay = 200; //Delay: 150; Variable to store the correction time in order to keep the sensoring period exactly 1 minute.
const unsigned long QuickTestTime = 10000; //Variable to store the quickTest delay for one measurement on all sensors on one minute.
unsigned long Delay = 20; //Variable to store the delay for the measurement loop.
/*
Increase correctedDelay with steps of 10 when the timing goes up during sampling, otherwise decrease.
When timing set all other sensor info's to their designated status and determine the correction time in order to run a loop in exactly 60.000 milliseconds (= one minute).
During looping thru the program, the date and time are displayed in the left columns. observe whether the second part is changing during this test.
When the next loop has another second in it, you will know that the timing needs adjustment; a second higher means subtracting the correctedDelay from the calculated delay value, and vice versa when otherwise.
Determine the difference between the timeCounts from the start moment and the first changed number of seconds. Set the numberOfReadings variable to this number and run the sketch again.
Adjust for a positive correctedDelay when the next second is HIGHER as the previous one; or correct for a negative correction in case otherwise.

Upload the sketch again and retrieve the timing calibration. Place this in variable [correctedDelay].
*/
//*********************************************************************************************************************************************************************************

//*********************************************************************************************************************************************************************************

//Calculate pH from Vcc = 5Volt.
static double Calculate_pH5Volt (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 = (2.5 - Vad) / 4.745;
return ((E0 - E) / C);
}//double Calculate_pH5Volt
//*********************************************************************************************************************************************************************************

//Calculate rH from ORP and pH.
static double Calculate_rH (double ORP, double pH)
{
double rH;
rH = (ORP / 29) + (2 * pH) + 6.76;
return rH;
}//double Calculate_rH

//Pin voltage determination.
/* Volt = (analogRead(pin) + k) * int5Volt / 1024;
with k of
0 for floor
0.5 for mean
1 for ceiling
*/

//Record reading.
//C:\WINDOWS\system32\WindowsPowerShell\v1.0\PowerShell.exe
bool setToThingSpeak = true; //Set to TRUE when printing to the ThingSpeak channel at: https://thingspeak.com/channels/531447/private_show
unsigned long Entry_id = 0; //The entry_id value holds the number of written loglines for uploading the log to a ThingSpeak Channel
double rHValue = 0.00; //rH can only be calculated when ALL parameters (exept light) are measured!
String Remark = "Remark: ";
int SampleCount = 0; //Counts the number of readings for all sensors during one loop.
int serInLen = 25;
char serInString[25];
int QuickRuns = 3; //Number of quickTest runs before the test exits.
bool prnPlotAll = 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 setTestAll = false; //When testing and calibrating the pH probe or the Quicktest. This must ALWAYS set to TRUE when testing or calibrating!
bool QuickTest = false; //QuickTest is for individual tests.
//*********************************************************************************************************************************************************************************

//Light.
//*********************************************************************************************************************************************************************************
bool ShowInfoLight = true; //Enable/disable luminance measurement (true or false).
bool prnInfoLight = false; //Enable or disable luminance measurement (true or false).
//---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
double LightPinUnits = 0.00; //Variable that holds the amount of light in Pin Units.
double PythiaValueLight = 0.00; //Variable to store the light luminescence value going to Pythia.
//*********************************************************************************************************************************************************************************

//Temperature.
//*********************************************************************************************************************************************************************************
bool ShowInfoTemperature = true; //Enable/disable pH temperature measurement (true or false).
bool prnInfoTemperature = false; //Enable or disable temperature measurement (true or false).
//---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire); //Pass our oneWire reference to Dallas Temperature sensor.
//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
//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 TemperatureTolerances.
float Celcius1 = 0, Celcius2 = 0, Celcius3 = 0, Fahrenheit1 = 0, Fahrenheit2 = 0, Fahrenheit3 = 0;
double TemperatureMarginPercentage = 0.15; //Set the deviation percentage to establish the margin TemperatureTolerances for the optimal value. (Default: 0.15%)
int TemperaturePinUnits = 0; //Variable that holds the amount of light in Pin Units.
double TemperatureVoltage = 0.00; //Variable to store the light luminescence value going to Pythia.
//---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
//The CalibrationTemperature value must be preferably as close to the optimal temperature as possible. Best is between the tolerances.
const double CalibrationTemperature1 = 0.00; //Sensor 1: Variable only for the calibration. This is the actual temperature at the moment that is used for calibrating this parameter.
const double CalibrationTemperature2 = 0.00; //Sensor 2: Variable only for the calibration. This is the actual temperature at the moment that is used for calibrating this parameter.
const double CalibrationTemperature3 = 0.00; //Sensor 3: Variable only for the calibration. This is the actual temperature at the moment that is used for calibrating this parameter.

//Last Process calibration date (yyyy-mm-dd): 2018-04-05.

//Set this pin values to the actual measured Arduino output pin values. Conductivity and pH measurementsare influenced by temperature. So this value is being taken into account on these parameters, if you use them.
const double TemperatureProcessOptimalValue = 24.00; //Value of the optimal temperature. Used for both conductivity as for pH measurements.
//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
double PythiaValueTemperature = TemperatureProcessOptimalValue; //Variable to store the temperature value going to Pythia.
//*********************************************************************************************************************************************************************************

//pH
//*********************************************************************************************************************************************************************************
bool ShowInfoPH = true; //Enable/disable pH measurement (true or false).
bool prnInfoPH = false; //Enable/disable pH show on screen (true or false).
//---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
/*
pH = 7 - (2.5 - SensorValue / 200) / (0.257179 + 0.000941468 * Temperature)
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 'PHPinUnits' 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 PHPinUnits drifts off from the desired 511 units, you can calibrate the sensor by setting the 'pHValueCorrection' after following the Process as described below.
https://www.vitens.nl/over-water/waterhardheid?Postcode=7609MA
UnitValue for tapwater: ca. 580 units; Acidity: 7,86 pH.
UnitValue for demiwater: ca. 600 units;
*/
//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
//Attention: The 'setTestAll' has to be 'true', otherwise no Process is executed.
//Step 1: The "zero" Process.
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 = 0.00; //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.
//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 int PinCalibrationShortCutUnits = 511; //Arduino pin units in the shortcut probe BNC plug.
const float pHCalibrationShortCutPH = 7.00; //Value of the pH in the shortcut probe BNC plug.

const int PinProcessUnitsTopHigh = 10; //Arduino pin units in the acidic buffer solution.
const double pHProcessValueTopHigh = 4.00; //Value of the pH in the acidic buffer solution.
const int pHProcessOptimalUnits = 580; //Arduino pin units in the neutral buffer solution.
const double pHProcessOptimalValue = 7.86; //Value of the pH in the neutral buffer solution.
const int pHProcessUnitsDownLow = 800; //Arduino pin units in the alkaline buffer solution.
const double pHProcessValueDownLow = 9.18; //Value of the 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!
//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
int PHPinUnits = 0; //This variable holds the actual measurement from Arduino on the pH probe.
float pHVoltage = 0.00; //pH sensor voltage.
double pHValue = 0.00; //pH sensor value.
double PythiaValuePH = 0.00; //The end result goes in here and will be exported to the log file.
//*********************************************************************************************************************************************************************************

//ORP.
//*********************************************************************************************************************************************************************************
bool ShowInfoORP = true; //Enable/disable ORP measurement (true or false).
bool prnInfoORP = false; //Enable or disable ORP measurement (true or false).
//---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
int ORPPinUnits = 0; //Variable that holds the amount of ORP in Pin Units.
double ORPVoltage = 0.00; //Variable to store the ORP voltage.
double ORPValue = 0.00; //Variable to store the ORP value going to Pythia.
double PythiaORPVoltage = 0.00; //Variable to store the ORP value going to Pythia.
//*********************************************************************************************************************************************************************************

void setup(void)
{
Serial.begin(9600);
sensors.begin(); //Start up the OneWire library.
if ((prnPlotAll == false) && (QuickTest == false))
{
tmeMinute.every(totalDelayValue - correctedDelay, LogAll); //Set logging timer on 1 minute.
Header_VDW();
Header_Init();
}
else
{
Delay = 5000;
if (setTestAll == false)
{
Header_VDW_Quick();
}//if
}//if

}//setup
//*********************************************************************************************************************************************************************************

void loop(void)
{
startSampleTime = millis();
SampleCount++;

//----------------------------- Start Light Measurement AnalogRead ------------------------------------
if (ShowInfoLight == true)
{
LightPinUnits = 0;
while (LightPinUnits < analogRead(analogPinLightA0))
{
LightPinUnits = analogRead(analogPinLightA0);
if (setTestAll == true)
{
Serial.print("#S|PYTHIA01|[ =*= LightPinUnits: ");
Serial.print(LightPinUnits);
Serial.println(" units]#");
}//if
delay(Delay);
}//while
if (prnInfoLight == true)
{
Serial.print("#S|PYTHIA01|[ =*= LightPinUnits: ");
Serial.print(LightPinUnits);
Serial.println(" units]#");
Serial.println(SingleLine);
}//if
PythiaValueLight = PythiaValueLight + LightPinUnits;
}//if
//----------------------------- End Light Measurement AnalogRead --------------------------------------
/*
//----------------------------- Start Light Measurement DigitalRead ------------------------------------
if (ShowInfoLight == true)
{
LightPinUnits = 0;
while (LightPinUnits < digital(analogPinLightA0))
{
LightPinUnits = analogRead(analogPinLightA0);
if (setTestAll == true)
{
Serial.print("#S|PYTHIA01|[ =*= LightPinUnits: ");
Serial.print(LightPinUnits);
Serial.println(" units]#");
}//if
delay(Delay);
}//while
if (prnInfoLight == true)
{
Serial.print("#S|PYTHIA01|[ =*= LightPinUnits: ");
Serial.print(LightPinUnits);
Serial.println(" units]#");
Serial.println(SingleLine);
}//if
PythiaValueLight = PythiaValueLight + LightPinUnits;
}//if
//----------------------------- End Light Measurement DigitalRead --------------------------------------
*/
//----------------------------- Start OneWire DS18B20 Temperature Measurement ------------------------------
if (ShowInfoTemperature == true)
{
//Because the DS18B20 temperature sensor is digital, there is no need to test every loop. Once in a sensing run is sufficient.
//Call sensors.requestTemperatures() to issue a global temperature request to all devices on the bus.
sensors.requestTemperatures(); //Send the command to get temperatures.
if (sensors.getTempCByIndex(0) > -127)
{
Celcius1 = sensors.getTempCByIndex(0) + CalibrationTemperature1;
Fahrenheit1 = sensors.toFahrenheit(Celcius1);
if ((prnInfoTemperature == true))
{
Serial.print("#S|PYTHIA01|[ =*= " Device1 " in Celsius: ");
Serial.print(Celcius1);
Serial.print(" °C; Fahrenheit: ");
Serial.print(Fahrenheit1);
Serial.println(" °F]#");
Serial.println(SingleLine);
}//if
if (sensors.getTempCByIndex(1) > -127)
{
Celcius2 = sensors.getTempCByIndex(1) + CalibrationTemperature2;
Fahrenheit2 = sensors.toFahrenheit(Celcius2);
if (prnInfoTemperature == true)
{
Serial.print("#S|PYTHIA01|[ =*= " Device2 " in Celsius: ");
Serial.print(Celcius2);
Serial.print(" °C; Fahrenheit: ");
Serial.print(Fahrenheit2);
Serial.println(" °F]#");
Serial.println(SingleLine);
}//if
}//if
if (sensors.getTempCByIndex(2) > -127)
{
Celcius3 = sensors.getTempCByIndex(2) + CalibrationTemperature3;
Fahrenheit3 = sensors.toFahrenheit(Celcius3);
if (prnInfoTemperature == true)
{
Serial.print("#S|PYTHIA01|[ =*= " Device3 " in Celsius: ");
Serial.print(Celcius3);
Serial.print(" °C; Fahrenheit: ");
Serial.print(Fahrenheit3);
Serial.println(" °F]#");
Serial.println(SingleLine);
}//if
}//if
} else
{
Serial.println("#S|PYTHIA01|[ =*= requestTemperature; Sensor ERROR!]#");
}//if else
PythiaValueTemperature = Celcius1;
}//if
//----------------------------- End OneWire DS18B20 Temperature Measurement ------------------------------

//----------------------------- Start pH Measurement -----------------------------------------
if (ShowInfoPH == true)
{
PHPinUnits = 0;
while (PHPinUnits < analogRead(analogPHpinA1))
{
PHPinUnits = analogRead(analogPHpinA1);
if (setTestAll == true)
{
Serial.print("#S|PYTHIA01|[ =*= PHPinUnits: ");
Serial.print(PHPinUnits);
Serial.println(" units]#");
}//if
delay(Delay);
}//while
pHVoltage = (PHPinUnits + 0.5) * (int5Volt / 1024.0);
pHValue = Calculate_pH5Volt(pHVoltage, PythiaValueTemperature);
if (prnInfoPH == true)
{
Serial.print("#S|PYTHIA01|[ =*= PHPinUnits: ");
Serial.print(PHPinUnits);
Serial.print(" units; pHVoltage: ");
Serial.print(pHVoltage);
Serial.print(" Volt; ProbeValuePH: ");
Serial.print(pHValue);
if ((setTestShortCutPH == true))
{
if (PHPinUnits < PinCalibrationShortCutUnits - 1)
{
Serial.print("; units to LOW; turn probe setting UP.");
} else if (PHPinUnits > PinCalibrationShortCutUnits + 1)
{
Serial.print("; units to HIGH; turn probe setting DOWN.");
} else
{
Serial.print("; units OK! pH set to " + String(pHCalibrationShortCutPH));
Serial.print("; pH to Unit ratio: ");
Serial.print(pHCalibrationShortCutPH /PHPinUnits);
Serial.print(" pH/Unit.");
}//if else
} else if (setTestAcidic == true)
{
Serial.print(" pH; Test on Acidic ");
Serial.print(PinProcessUnitsTopHigh);
} else if (setTestNeutral == true)
{
Serial.print("; Test on Neutral pH; ratio: ");
Serial.print(pHProcessOptimalValue / pHProcessOptimalUnits);
Serial.println(" pH/Unit]#");
Serial.print("#S|PYTHIA01|[ =*= pHProcessOptimalValue: ");
Serial.print(pHProcessOptimalValue);
} else if (setTestAlkaline == true)
{
Serial.print(" pH; Test on Alkaline ");
Serial.print(pHProcessValueDownLow);
}//if else
Remark = "at " + String(PythiaValueTemperature, 2) + " °C: ";
if (pHValue < 6.99)
{
Remark = Remark + "Acidic";
} else if (pHValue > 7.01)
{
Remark = Remark + "Alkaline";
} else
{
Remark = Remark + "Optimal/Neutral within tolerance of ± 0.01 pH";
}//if else
Serial.println(" pH; " + Remark + ".]#");
Serial.println(SingleLine);
}//if
PythiaValuePH = PythiaValuePH + pHValue;
}//if
//----------------------------- End pH Measurement -----------------------------------------

//----------------------------- Start ORP Measurement -----------------------------------------
if (ShowInfoORP == true)
{
ORPPinUnits = 0;
while (ORPPinUnits < analogRead(analogORPpinA2))
{
ORPPinUnits = analogRead(analogORPpinA2);
if (setTestAll == true)
{
Serial.print("#S|PYTHIA01|[ =*= ORPPinUnits: ");
Serial.print(ORPPinUnits);
Serial.println(" units]#");
}//if
delay(Delay);
}//while
ORPVoltage = (ORPPinUnits + 0.5) * (int5Volt / 1024.0);
ORPValue = ((2.5 - ORPVoltage) / 1.037) * 1000;
if (prnInfoORP == true)
{
Serial.print("#S|PYTHIA01|[ =*= ORPPinUnits: ");
Serial.print(ORPPinUnits);
Serial.print(" units; ORPVoltage: ");
Serial.print(ORPVoltage);
Serial.print(" Volt; ORP: ");
Serial.print(ORPValue);
Serial.println(" milliVolt]#");
Serial.println(SingleLine);
}//if
PythiaORPVoltage = PythiaORPVoltage + ORPValue;
}//if
//----------------------------- End ORP Measurement -----------------------------------------
if ((ShowInfoPH == true) && (ShowInfoORP == true))
{
rHValue = (Calculate_rH(ORPValue, pHValue));
}//if
if ((prnPlotAll == false) && (QuickTest == false))
{
tmeMinute.update();
}
else if (prnPlotAll == true)
{
if (ShowInfoLight == true)
{
Serial.print(LightPinUnits / 100);
Serial.print(",");
}//if
if (ShowInfoTemperature == true)
{
//Serial.print(Celcius1 / 10);
//Serial.print(",");
}//if
if (ShowInfoPH == true)
{
Serial.print(pHValue);
Serial.print(",");
}//if
if (ShowInfoORP == true)
{
Serial.print(ORPValue / 100);
Serial.print(",");
}//if
if ((ShowInfoPH == true) && (ShowInfoORP == true))
{
Serial.print(rHValue / 10);
Serial.print(",");
}//if
Serial.println();
}//if else
if ((QuickTest == true) && (setTestAll == false) && (SampleCount <= QuickRuns))
{
Serial.print("#S|PYTHIA01|[ =*------------- Sample: ");
Serial.print(SampleCount);
if (SampleCount == 1)
{
Serial.println(" -----------------------------------------------*=]#");
}
else
{
Serial.println(" -----------*=]#");
}//if else
rHValue = (Calculate_rH(ORPValue, pHValue));
Serial.print("#S|PYTHIA01|[ =*=\tTemperature:\t");
Serial.print(Celcius1);
Serial.println(" Celsius\t=*=]#");
Serial.print("#S|PYTHIA01|[ =*=\tORP:\t\t\t");
Serial.print(ORPValue);
Serial.println(" mVolt\t=*=]#");
Serial.print("#S|PYTHIA01|[ =*=\tAcidity:\t\t");
Serial.print(pHValue);
Serial.println(" pH\t\t\t=*=]#");
Serial.print("#S|PYTHIA01|[ =*=\tRedox:\t\t\t");
Serial.print(rHValue);
Serial.println(" rH\t\t=*=]#");
}
else if ((QuickTest == true) && (setTestAll == false) && (SampleCount > QuickRuns))
{
rHValue = (Calculate_rH(PythiaORPVoltage / SampleCount, PythiaValuePH / SampleCount));
Serial.println("#S|PYTHIA01|[ =*============ Conclusion ===============================================*=]#");
Serial.print("#S|PYTHIA01|[ =*= The acidity of this sample is ");
Serial.print(PythiaValuePH / SampleCount);
Serial.println(" pH.\t\t\t\t\t\t\t\t=*=]#");
Serial.print("#S|PYTHIA01|[ =*= The potential of this sample is ");
Serial.print(PythiaORPVoltage / SampleCount);
Serial.println(" mVolt.\t\t\t\t\t\t=*=]#");
Serial.print("#S|PYTHIA01|[ =*= The Relative Hydrogen Score is ");
Serial.print(rHValue);
Serial.println(" rH.\t\t\t\t\t\t\t=*=]#");
Serial.print("#S|PYTHIA01|[ =*= Due to the pH and ORP value, the rH of this sample is ");
if (rHValue < 10)
{
Remark = "Advice: Check the pH and replenish at least 60% with fresh water.\t=*=";
Serial.println("much to LOW.\t=*=]#");
}
else if ((rHValue >= 10) && (rHValue < 26))
{
Remark = "Advice: Check the pH and replenish at least 30% with fresh water.\t=*=";
Serial.println("to LOW.\t\t=*=]#");
}
else if ((rHValue >= 26) && (rHValue < 30))
{
Remark = "Well done!\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t=*=";
Serial.println("FINE.\t\t\t=*=]#");
}
else if ((rHValue >= 30) && (rHValue < 40))
{
Remark = "Advice: Check the pH and replenish at least 30% with fresh water.\t=*=";
Serial.println("to HIGH.\t\t=*=]#");
}
else if (rHValue >= 40)
{
Remark = "Advice: Check the pH and replenish at least 60% with fresh water.\t=*=";
Serial.println("much to HIGH.\t=*=]#");
}//if else
Serial.println("#S|PYTHIA01|[ =*= " + Remark + "]#");
Serial.println("#S|PYTHIA01|[ =*============ End of Test ==============================================*=]#");
delay(500);
exit(0);
}//if else
if ((showTiming == true) && (prnPlotAll == false) && (QuickTest == false))
{
Serial.print("#S|PYTHIA01|[ =*= sampleTime: ");
Serial.print(millis() - startSampleTime);
Serial.println(" mSec]#");
}//if
}//loop
//*********************************************************************************************************************************************************************************

void LogAll(void)
{
//----------------------------- Get the value as measurement recording -------------
PythiaValueLight = PythiaValueLight / SampleCount;
PythiaValuePH = PythiaValuePH / SampleCount;
PythiaORPVoltage = PythiaORPVoltage / SampleCount;
logData(PythiaValueLight, PythiaValueTemperature, PythiaValuePH, PythiaORPVoltage, rHValue);
if (setToThingSpeak == true)
{
Entry_id += 1;
logDataWeb(Entry_id, PythiaValueLight, PythiaValueTemperature, PythiaValuePH, PythiaORPVoltage, rHValue);
Serial.println("#S|PWRSHELL|[]#");
}//if
//Initialize all variables for the next loop.
Serial.flush();
Remark = "Remark: ";
SampleCount = 0;
PythiaValueLight = 0.00;
PythiaValueTemperature = TemperatureProcessOptimalValue;
PythiaORPVoltage = 0.00;
PythiaValuePH = 0.00;
}//void LogAll
//*********************************************************************************************************************************************************************************

//Data logging
void logData(double Light, double Temperature, double PH, double ORP, double RH)
{
Serial.print("#S|PYTHIA01|["); //Initialize Gobetwino command., String WaterPH, String LoopTimeWaterPH
//Datefield = #01
Serial.print(String(Light, 2)); //#02
Serial.print(";");
Serial.print(String(Temperature, 2)); //#03
Serial.print(";");
Serial.print(String(PH, 2)); //#04
Serial.print(";");
Serial.print(String(ORP, 2)); //#05
Serial.print(";");
Serial.print(String(RH, 2)); //#06
Serial.println(";]#"); //Finalize Gobetwino command.
readSerialString(serInString, 1000); //Convert the values to strings.
}//void logData.
//*********************************************************************************************************************************************************************************

void logDataWeb(unsigned long Entry_id, double Light, double Temperature, double PH, double ORP, double RH)
{
/*
#S|PYTHIAWEB|LGFIL|[C:\Pythia_Arduino\Pythia_SensorFiles\Aquarium\CSV_Pythia_Aquarium.txt&$1&-1]#
*/
Serial.print("#S|PYTHIAWEB|["); //Initialize Gobetwino command., String WaterPH, String LoopTimeWaterPH
//Datefield = #01
Serial.print(String(Entry_id)); //#02 (Field1)
Serial.print(",");
Serial.print(String(Light, 2)); //#03 (Field2)
Serial.print(",");
Serial.print(String(Temperature, 2)); //#04 (Field3)
Serial.print(",");
Serial.print(String(PH, 2)); //#05 (Field4)
Serial.print(",");
Serial.print(String(ORP, 2)); //#06 (Field5)
Serial.print(",");
Serial.print(String(RH, 2)); //#07 (Field1)
Serial.println("]#"); //Finalize Gobetwino command.
readSerialString(serInString, 1000); //Convert the values to strings.
}//void logDataWeb.
//*********************************************************************************************************************************************************************************

//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.
//*********************************************************************************************************************************************************************************

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

//Header_Init
//*********************************************************************************************************************************************************************************
void Header_Init(void)
{
Serial.println(DoubleLine);
Serial.println(LineInit);
Serial.println(LineLegend);
Serial.println(SingleLine);
}//void Header_Init
//*********************************************************************************************************************************************************************************
//Header_VDW
//*********************************************************************************************************************************************************************************
void Header_VDW_Quick(void)
{
//Serial.println(DoubleLineQ);
//Serial.println(LineVDWQ);
Serial.println(LineMailQ);
}//void Header_VDW_Quick
//*********************************************************************************************************************************************************************************
//End sketch