//=========================================Blynk setup =======================================================================
#define BLYNK_TEMPLATE_ID "TMPL6yEZFxTY8"
#define BLYNK_TEMPLATE_NAME "test1"
#define BLYNK_AUTH_TOKEN "2fxSsboW8-1-G2fbsjlmgG7dyU7U3mkk"
#define BLYNK_PRINT Serial
char ssid[] = "Wokwi-GUEST";
char pass[] = "";
char auth[] = BLYNK_AUTH_TOKEN;
//===========================================Libraries =========================================================================
#include <WiFi.h>
#include <BlynkSimpleEsp32.h>
#include <WiFiClient.h>
#include "DHT.h"
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
//==================================== Hardwre setup =======================================================================
#define pHSensor 35
#define TPHSensor 2
#define DHTPIN 26 //Connect Out pin to D2 in NODE MCU
#define DHTTYPE DHT22
#define pin_tds_pumpA 27
#define pin_tds_pumpB 14
#define pin_ph_plus 13
#define pin_ph_minus 12
#define pin_watering 15
#define TdsSensorPin 34
#define VREF 3.3 // analog reference voltage(Volt) of the ADC
#define samples 15 // Number of sample point
#define SCREEN_WIDTH 128 // OLED width, in pixels
#define SCREEN_HEIGHT 64 // OLED height, in pixels
//================================== Others setup ==========================================================================
float temperature = 25;
unsigned long overFlow = 4294967295 ;
float adc_resolution = 4095.0; //ESP 32 ADC Resolution
//=================================Initializing variables =================================================================
//pump
bool watering_flag = false ;
///=============================== Sensor Variables ========================================
float averageVoltage = 0;
//tds
int analogBuffertds[samples]; // store the analog value in the array, read from ADC (tds)
int Indextds = 0;
float tdsValue = 0;
int value_overFlow_td=0 ;
int tds_lampDuration_overflow = 0;
long tds_pumpDuration = 3000; // 3 seconds in milliseconds
long tds_pumpOffTime = 1000; // 1 minute in milliseconds
bool tds_pump_state = 0 ;
int pwm_tds_pumpA = 150;
int pwm_tds_pumpB = 150;
unsigned long tds_currentMillis = 0;
unsigned long tds_pumpStartTime=0 ;
unsigned long tds_overFlowCompensation = 0;
int waiting_time_tds= 0 ;
int watering_duration_tds = 0 ;
unsigned long tds_previousMillisReading = 0;
unsigned long tds_currentMillisReading = 0;
bool tds_currentReading =0;
//PH
float voltage = 0.0 ;
int analogBufferph[samples]; // store the analog value in the array, read from ADC (ph)
int Indexph = 0;
int value_overFlow_p=0 ;
int ph_lampDuration_overflow = 0;
long ph_pumpDuration = 3000; // 3 seconds in milliseconds
long ph_pumpOffTime = 1000; // 1 minute in milliseconds
bool ph_pump_state = 0 ;
int pwm_tds_pumpMinus = 150;
int pwm_tds_pumpPlus = 150;
unsigned long ph_pumpStartTime=0 ;
unsigned long ph_overFlowCompensation = 0;
unsigned long ph_previousMillisReading = 0;
unsigned long ph_currentMillisReading = 0;
/// DHT
float h = 0.0;
float t = 0.0;
float temp_low =0 ;
float temp_high =0 ;
/// =========================== Pumps variables ==========================================
/// watering pump
unsigned long pumpDuration_overflow = 0;
unsigned long pump_time =0 ;
unsigned long pumpStartTime = 0;
unsigned long waitStartTime = 0;
unsigned long pumpDuration = 0;
unsigned long waitDuration = 0;
unsigned long overFlowCompensation = 0;
bool pump_state= 0 ;
int pump_waiting_time = 0 ;
int watering_duration = 0 ;
int counter = 0 ;
/// Calibration pumps
bool ph_plus = 0, ph_minus = 0, tds_pumpON = 0, tds_pumpOFF = 0 ;
//calibration
bool start=0 ;
unsigned long calb_OffTime = 15000;
unsigned long calb_overFlow=0;
unsigned long calb_StartTime=0 ;
bool Suction=1;
bool Suction_pump_state =1 ;
unsigned long Suction_pumpDuration=10000;
unsigned long Suction_pumpOffTime=10000;
unsigned long Suction_overFlowCompensation=0;
unsigned long Suction_pumpStartTime=0;
unsigned long Suction_currentMillis=0;
// ==========================================Expert System Knowledge base =======================================
int plants_PH[5][3] = {
{0, 5.5, 6},
{1, 5.0, 5.5},
{2, 6, 6.5},
{3, 5.2, 6.4},
{4, 5.5, 6}
};
int plants_tds[5][3] = {
{0, 550, 1100},
{1, 850, 1000},
{2, 1000, 2000},
{3, 1000, 2000},
{4, 500, 800}
};
int value = 0 ; // plants Slider
//====================================== initializing hardware =======================================================
// create an OLED display object connected to I2C
Adafruit_SSD1306 oled(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
WiFiClient espClient;
BlynkTimer timer;
DHT dht(DHTPIN, DHTTYPE);
//======================================= Feunction definition =====================================================
/// initialize on connection
BLYNK_CONNECTED() {
Blynk.syncVirtual(V0);
Blynk.syncVirtual(V1);
Blynk.syncVirtual(V2);
Blynk.syncVirtual(V3);
Blynk.syncVirtual(V4);
Blynk.syncVirtual(V5);
}
/// median filtering algorithm
int getMedianNum(int bArray[], int iFilterLen) {
int bTab[iFilterLen];
for (byte i = 0; i < iFilterLen; i++)
{ bTab[i] = bArray[i];
}
int i, j, bTemp;
for (j = 0; j < iFilterLen - 1; j++) {
for (i = 0; i < iFilterLen - j - 1; i++) {
if (bTab[i] > bTab[i + 1]) {
bTemp = bTab[i];
bTab[i] = bTab[i + 1];
bTab[i + 1] = bTemp;
}
}
}
if ((iFilterLen & 1) > 0) {
bTemp = bTab[(iFilterLen - 1) / 2];
}
else {
bTemp = (bTab[iFilterLen / 2] + bTab[iFilterLen / 2 - 1]) / 2;
}
return bTemp;
}
/// Initialize the wifi connection
void setup_wifi() {
delay(10);
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, pass);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
randomSeed(micros());
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
}
//Declaration of virtual ports
BLYNK_WRITE(V0)
{
tds_pumpOffTime = param.asInt() * 1000 ; // Get value as integer
Serial.print("Waiting Time TDS: ");
Serial.println(tds_pumpOffTime);
}
BLYNK_WRITE(V1)
{
ph_pumpOffTime = param.asInt() * 1000 ; // Get value as integer
Serial.print("Watering TDS: ");
Serial.println(watering_duration_tds);
}
BLYNK_WRITE(V2)
{
pump_waiting_time = param.asInt(); // Get value as integer
Serial.print("Waitting Time: ");
Serial.println(pump_waiting_time);
}
BLYNK_WRITE(V3)
{
pump_time = param.asInt(); // Get value as integer
Serial.print("Pump Time: ");
Serial.println(pump_time);
}
//get value from slider
BLYNK_WRITE(V4)
{
value = param.asInt(); // Get value as integer
Serial.println(value);
}
void TDS_sensor()
{
Suction_currentMillis = millis();
if (Suction_currentMillis < Suction_pumpStartTime) { // Check for overflow condition
// Overflow occurred, compensate and reset the start time
Suction_overFlowCompensation = overFlow - Suction_pumpStartTime;
Suction_pumpStartTime = Suction_currentMillis;
}
if (Suction_pump_state)
{
if ((Suction_currentMillis - Suction_pumpStartTime + Suction_overFlowCompensation) >= Suction_pumpOffTime)
{ Suction=0;
Suction_pump_state = false;
Serial.println("------------------------------------------------------------");
}
}
if (Suction)
Serial.println("hhhhhhhhhhhhheeeeeeeeeeeeeelllllllllllllooooooooooooooooooo");
else
Serial.println("rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr");
if (!Suction)
{
tds_currentMillisReading = millis();
if (tds_currentMillisReading - tds_previousMillisReading >= 1000) {
Serial.println(analogRead(TdsSensorPin));
tds_previousMillisReading = tds_currentMillisReading;
analogBuffertds[Indextds] = analogRead(TdsSensorPin); //read the analog value and store into the buffer
Indextds++;
if (Indextds == samples) {
Indextds = 0;
}
}
// read the analog value more stable by the median filtering algorithm, and convert to voltage value
averageVoltage = getMedianNum(analogBuffertds, samples) * (float)VREF / adc_resolution;
//temperature compensation formula: fFinalResult(25^C) = fFinalResult(current)/(1.0+0.02*(fTP-25.0));
float compensationCoefficient = 1.0 + 0.02 * (temperature - 25.0);
//temperature compensation
float compensationVoltage = averageVoltage / compensationCoefficient;
//convert voltage value to tds value
tdsValue = (133.42 * compensationVoltage * compensationVoltage * compensationVoltage - 255.86 * compensationVoltage * compensationVoltage + 857.39 * compensationVoltage) * 0.5;
Serial.print("TDS Value:");
Serial.print(tdsValue, 0);
Serial.println("ppm");
//Blynk.virtualWrite(V3, tdsValue);
tds_currentMillis = millis();
if (tds_currentMillis < tds_pumpStartTime) { // Check for overflow condition
// Overflow occurred, compensate and reset the start time
tds_overFlowCompensation = overFlow - tds_pumpStartTime;
tds_pumpStartTime = tds_currentMillis;
Serial.print("Overflow compensated:");
Serial.println(tds_overFlowCompensation);
}
if (!tds_pump_state)
{ // If pump is currently off
if ((tds_currentMillis - tds_pumpStartTime + tds_overFlowCompensation) >= tds_pumpOffTime)
{ // Check if pump off time has elapsed
if (tdsValue < (plants_tds[value][1]))
{
Serial.println("tds");
tds_pumpON=1;// Turn on the pump
tds_pumpOFF=0;
}
else
{
tds_pumpON=0;// Turn off the pump
tds_pumpOFF=1;
}
tds_pump_state = true;// Update pump state
tds_pumpStartTime = tds_currentMillis; // Reset start time for pump operation
Serial.println("On");
tds_overFlowCompensation=0;
}
}
else { // If pump is currently on
if ((tds_currentMillis - tds_pumpStartTime +tds_overFlowCompensation)>= tds_pumpDuration)
{ // Check if pump on time has elapsed
tds_pumpOFF=1 ; // Turn off the pump
tds_pumpON = 0;
tds_pump_state = false; // Update pump state
tds_pumpStartTime = tds_currentMillis; // Reset start time for pump off period
Serial.println("Off");
tds_overFlowCompensation=0;
}
}
}
}
void DHT_sensor()
{
h = dht.readHumidity();
t = dht.readTemperature(); // or dht.readTemperature(true) for Fahrenheit
if (isnan(h) || isnan(t)) {
Serial.println("Failed to read from DHT sensor!");
return;
}
if(t < temp_low || t> temp_high)
{
Blynk.logEvent("test1");
}
//Blynk.virtualWrite(V0, t);
//Blynk.virtualWrite(V1, h);
Serial.print("Temperature : ");
Serial.print(t);
Serial.print(" Humidity : ");
Serial.println(h);
}
float ph (float voltage) {
return 7 + ((2.50 - voltage) / 0.18);
}
void PH_sensor() {
ph_currentMillisReading = millis();
if (ph_currentMillisReading - ph_previousMillisReading >= 1000) {
ph_previousMillisReading = ph_currentMillisReading;
analogBufferph[Indexph] = analogRead(pHSensor); //read the analog value and store into the buffer
Indexph++;
if (Indexph == samples) {
Indexph = 0;
}
}
delay(10);
voltage = 3.3 * getMedianNum(analogBufferph, samples) / 4095.0; //adc
Serial.print("pH= ");
Serial.println(ph(voltage));
//Blynk.virtualWrite(V2, ph(voltage));
unsigned long ph_currentMillis = millis();
Serial.print("m=");
Serial.println(ph_currentMillis);
Serial.print("pump_state=");
Serial.println(ph_pump_state);
// Check pH conditions
if (ph_currentMillis < ph_pumpStartTime) { // Check for overflow condition
// Overflow occurred, compensate and reset the start time
ph_overFlowCompensation = overFlow - ph_pumpStartTime;
ph_pumpStartTime = ph_currentMillis;
Serial.print("Overflow compensated:");
Serial.println(ph_overFlowCompensation);
}
if (!ph_pump_state) { // If pump is currently off
if ((ph_currentMillis - ph_pumpStartTime + ph_overFlowCompensation) >= ph_pumpOffTime) { // Check if pump off time has elapsed
if (ph(voltage) < (plants_PH[value][1])) {
ph_minus = 0 ;
ph_plus = 1 ;
}
else if (ph(voltage) > (plants_PH[value][2])) {
ph_minus = 1 ;
ph_plus = 0 ;
}
else
{
ph_minus = 0 ;
ph_plus = 0 ;
}
ph_pump_state = true;// Update pump state
ph_pumpStartTime = ph_currentMillis; // Reset start time for pump operation
ph_overFlowCompensation=0;
}
} else { // If pump is currently on
if ((ph_currentMillis - ph_pumpStartTime +ph_overFlowCompensation)>= ph_pumpDuration) { // Check if pump on time has elapsed
ph_minus = 0 ;
ph_plus = 0 ;
ph_pump_state = false; // Update pump state
ph_pumpStartTime = ph_currentMillis; // Reset start time for pump off period
ph_overFlowCompensation=0;
}
}
}
void Actuation()
{
if (ph_plus)
{
//digitalWrite(pin_ph_plus, HIGH); // move the actuation to a seperat part at the end of the code and use marker to store the decesions such as in PLC
//digitalWrite(pin_ph_minus, LOW);
analogWrite(pin_ph_plus,255);
analogWrite(pin_ph_minus,0);
// ledcWrite(1, pwm_tds_pumpPlus);
// ledcWrite(2, 0);
}
if (ph_minus)
{
//digitalWrite(pin_ph_minus, HIGH);
//digitalWrite(pin_ph_plus, LOW);
analogWrite(pin_ph_minus,255);
analogWrite(pin_ph_plus,0);
// ledcWrite(2, pwm_tds_pumpMinus);
// ledcWrite(1, 0);
}
if (ph_plus == 0)
{
//digitalWrite(pin_ph_plus, LOW);
analogWrite(pin_ph_plus,0);
//ledcWrite(1, 0);
}
if (ph_minus == 0)
{
//digitalWrite(pin_ph_minus, LOW);
analogWrite(pin_ph_minus,0);
//ledcWrite(2,0);
}
if (tds_pumpON)
{
// ledcWrite(0, pwm_tds_pumpA);
// ledcWrite(0, pwm_tds_pumpB);
analogWrite(pin_tds_pumpA,255);
analogWrite(pin_tds_pumpB,255);
}
if (tds_pumpOFF)
{
// ledcWrite(0,0);
// ledcWrite(0,0);
analogWrite(pin_tds_pumpA,0);
analogWrite(pin_tds_pumpB,0);
}
}
void watering()
{
counter = 6 ;
pump_waiting_time = 24/counter ;
waitDuration = pump_waiting_time*1000 ; //*60*60; // modified to speedup the code should be *1000 instead of *10
pumpDuration = pump_time*1000;//*60 ; // modified to speedup the code should be *1000 instead of *10
unsigned long currentMillis = millis();
if (currentMillis < pumpStartTime) { // Check for overflow condition
// Overflow occurred, compensate and reset the start time
overFlowCompensation = overFlow - pumpStartTime;
tds_pumpStartTime = tds_currentMillis;
Serial.print("Overflow compensated:");
Serial.println(overFlowCompensation);
}
if (!pump_state) { // If pump is currently off
if ((currentMillis - pumpStartTime + overFlowCompensation) >= waitDuration ) { // Check if pump off time has elapsed
digitalWrite(pin_watering,HIGH);
pump_state = true;// Update pump state
pumpStartTime = currentMillis; // Reset start time for pump operation
Serial.println("On");
overFlowCompensation=0;
}
}
else { // If pump is currently on
if ((currentMillis - pumpStartTime +overFlowCompensation)>= pumpDuration) { // Check if pump on time has elapsed
digitalWrite(pin_watering,LOW);
pump_state = false; // Update pump state
pumpStartTime = currentMillis; // Reset start time for pump off period
Serial.println("Off");
overFlowCompensation=0;
}
}
}
void display()
{
oled.clearDisplay();
oled.setTextSize(1); // set text size
oled.setTextColor(WHITE); // set text color
oled.setCursor(0, 10); // set position to display
oled.println("tds = ");
oled.setCursor(40, 10);
oled.println(tdsValue); // set tds value
oled.setCursor(0, 25); // set position to display
oled.println("temp = ");
oled.setCursor(40, 25);
oled.println(t); // set temp value
oled.setCursor(0, 40); // set position to display
oled.println("hum = "); // set text
oled.setCursor(40, 40);
oled.println(h); // set hum value
oled.setCursor(0, 50); // set position to display
oled.println("ph = "); // set text
oled.setCursor(40, 50);
oled.println(ph(voltage)); // set ph value
oled.display();
}
void calb()
{
Serial.println("start==========");
Serial.print(start);
unsigned long calb_currentMillis = millis();
if (calb_currentMillis < calb_StartTime) { // Check for overflow condition
// Overflow occurred, compensate and reset the start time
calb_overFlow = overFlow - calb_StartTime;
calb_StartTime = calb_currentMillis;
Serial.print("Overflow compensated:");
}
if ((calb_currentMillis - calb_StartTime + calb_overFlow) >= calb_OffTime)
{ start =1 ;
Suction_pumpStartTime = millis();
timer.setInterval(0L, PH_sensor);
timer.setInterval(0L, TDS_sensor);
Serial.println("l am hereeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee ");
calb_StartTime = calb_currentMillis; // Reset start time for pump operation
calb_overFlow=0;
}
}
void setup()
{
pinMode(pin_ph_plus, OUTPUT);
pinMode(pin_ph_minus, OUTPUT);
pinMode(pin_tds_pumpA, OUTPUT);
pinMode(pin_tds_pumpB, OUTPUT);
pinMode(pin_watering, OUTPUT);
setup_wifi();
Serial.begin(115200);
Serial.println("helllo") ;
WiFi.begin(ssid, pass);
Blynk.config(auth);
Blynk.begin(auth, ssid, pass, "blynk.cloud", 80);
dht.begin();
timer.setInterval(0L, DHT_sensor);
timer.setInterval(0L, Actuation);
timer.setInterval(0L, watering);
timer.setInterval(0L,display);
timer.setInterval(0L,calb);
if (!oled.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println(F("failed to start SSD1306 OLED"));
while (1);
}
}
void loop()
{
Blynk.run();
timer.run();
}