#define BLYNK_TEMPLATE_ID "TMPL3rD0gnMV-"
#define BLYNK_TEMPLATE_NAME "nirmal"
#define BLYNK_AUTH_TOKEN "4bsRQAT_YlvNr_UG1Kv9R1tBSL9wiUDr"
#define BLYNK_TEMPLATE_NAME "smart soil nutrition monitoring system  for sustai"
#define BLYNK_AUTH_TOKEN "UgIOVt3CJlP-FAiavn8Fao72LVpvlTUf"
#define BLYNK_TEMPLATE_ID "TMPL3-ylmStED"
#include <WiFi.h>
#include <WiFiClient.h>
#include <BlynkSimpleEsp32.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <LiquidCrystal_I2C.h>
#include "DHTesp.h"
#include <HardwareSerial.h>

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
#define OLED_RESET -1    // Reset pin # (or -1 if sharing Arduino reset pin)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

char ssid[] = "Wokwi-GUEST";
char pass[] = "";

LiquidCrystal_I2C lcd(0x27, 16, 2);

const int DHT_PIN = 15;
DHTesp dhtSensor;

// Potentiometer is connected to GPIO 34 (Analog ADC1_CH6) 
const int potPin = 34;
const int pHSensorPin = 32;
// Calibration parameters (you need to calibrate your sensor)
const float acidVoltage = 2032.44;  // voltage at pH 4.0
const float neutralVoltage = 1500.0; // voltage at pH 7.0

// variable for storing the potentiometer value
int potValue = 0;

#define ncom 3 //  number of commands.
char commar[ncom] = {0x1,0x3,0x5}; // Actual commands
// Response Strings can be stored like this
char respar[ncom][30]={"Phosphorous value is: ","Potassium value is: ","Nitrogen value is: "};
uint8_t rtValue[ncom]; // Store the return values from the custom chip in here. you can use the same
//values to forward to the IOT part.

BlynkTimer timer;

int displayState = 0; // Variable to keep track of the current display state

float temperature, humidity, pHValue;

void setup() {
  Serial.begin(115200);
  Serial2.begin(15200, SERIAL_8N1, 16, 17); //initialize the custom chip communication line.

  Blynk.begin(BLYNK_AUTH_TOKEN, ssid, pass);  
  
  dhtSensor.setup(DHT_PIN, DHTesp::DHT22);
  
  timer.setInterval(500L, sendData); // Send data every 1/2 seconds
  timer.setInterval(2000L, updateLCD); // Change LCD display every 3 seconds

  display.begin(SSD1306_SWITCHCAPVCC, 0x3C); // Initialize with the I2C address 0x3C

  Serial.println("Hello, ESP32!");

  display.clearDisplay();                    // Clear the buffer
  display.display();                         // Display initial buffer

  // Display title for 5 seconds
  displayTitle();
  delay(5000);

  // Display team members for 5 seconds
  displayTeamMembers();
  delay(5000);

  
  // Display "Thank you" message
  displayThankYou();
  delay(5000);

  // Turn off the OLED display
  display.ssd1306_command(SSD1306_DISPLAYOFF);

  // Initialize the LCD
  Wire.begin(23, 22);
  lcd.init();
  lcd.backlight();

  Serial.println("LCD Initialized.");
}

void displayTitle() 
{
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(0, 10);
  display.println("Smart Soil Monitoring");
  display.println("System Using IoT");
  display.display();
}

void displayTeamMembers() 
{
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(0, 10);
  display.println("Team Members:");
  display.println("Sutharsan V");
  display.println("Murugan G");
  display.println("Shabareeson R");
  display.println("Naresh K");
  display.display();
}

void displayThankYou() {
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(0, 20);
  display.println("Thank you!");
  display.display();
}

void sendData() {
  temperature = dhtSensor.getTemperature();
  humidity = dhtSensor.getHumidity();
  
  if (isnan(humidity) || isnan(temperature)) {
    Serial.println("Failed to read from DHT sensor!");
    return;
  }

  Serial.print("Humidity: ");
  Serial.print(humidity);
  Serial.print("%\t");
  Serial.print("Temperature: ");
  Serial.print(temperature);
  Serial.println(" °C");

  potValue = analogRead(potPin);
  Serial.println("Moisture: " + String(potValue));

  for (uint8_t i = 0; i < ncom; i++) {
    Serial2.print((char)commar[i]); // send the command stored in ncom array through serial2
    if (Serial2.available()) { //if serial2 data is there
      rtValue[i] = Serial2.read(); // read serial2 
      Serial2.flush(); // flush serial2, very important. otherwise extra bits may interfere with communication
      Serial.print(respar[i]); // print the response array to the console.
      Serial.println(rtValue[i]); // print the return value with newline at console
    }
  }

  int analogValue = analogRead(pHSensorPin);

  // Convert the analog value to voltage
  float voltage = analogValue * (3.3 / 4095.0); // 3.3V reference, 12-bit ADC

  // Convert the voltage to pH value
  pHValue = (voltage * 14.0) / 3.3;
  // Print the analog value, voltage, and pH value
  Serial.print("Analog Value: ");
  Serial.print(analogValue);
  Serial.print(" | Voltage: ");
  Serial.print(voltage, 3);
  Serial.print("V | pH Value: ");
  Serial.println(pHValue, 2);

  //send data to blynk
  Blynk.virtualWrite(V0, temperature);  //Temperature
  Blynk.virtualWrite(V1, humidity);  //Humidity
  Blynk.virtualWrite(V2, potValue); //soil Moisture
  Blynk.virtualWrite(V4, rtValue[0]); //Phosphorous
  Blynk.virtualWrite(V3, rtValue[2]); //Nitrogen
  Blynk.virtualWrite(V5, rtValue[1]); //Potassium
}

void updateLCD() {
  // Switch to the next display state
  displayState = (displayState + 1) % 3;

  // Update the LCD display based on the current state
  lcd.clear();
  switch (displayState) {
    case 0:
      lcd.setCursor(0, 0);
      lcd.print("Temp: ");
      lcd.print(temperature);
      lcd.setCursor(0, 1);
      lcd.print("Humidity: ");
      lcd.print(humidity);
      break;
    case 1:
      lcd.setCursor(0, 0);
      lcd.print("Moisture: ");
      lcd.print(potValue);
      lcd.setCursor(0, 1);
      lcd.print("pH: ");
      lcd.print(pHValue, 2);
      break;
    case 2:
      lcd.setCursor(0, 0);
      lcd.print("Nitrogen: ");
      lcd.print(rtValue[2]);
      lcd.setCursor(0, 1);
      lcd.print("Phos:");
      lcd.print(rtValue[0]);
      lcd.setCursor(8, 1);
      lcd.print("Potas:");
      lcd.print(rtValue[1]);
      break;
  }
}

void loop() 
{
  Blynk.run();
  timer.run();
}
NPK-SensorBreakout
Moisture SensorBreakout