#include <WiFi.h>
#include <ThingSpeak.h>
#include <Adafruit_SSD1306.h>
#include <DHT.h>
// Sensor Pins (from your diagram.json)
#define SOIL_MOISTURE_PIN 34 // chip1:SIG -> esp:34
#define DHT_PIN 32 // dht1:SDA -> esp:32
#define PH_PIN 26 // chip3:OUT0 -> esp:26
#define TDS_PIN 27 // chip3:OUT1 -> esp:27
#define LED_PIN 19 // led1:A -> esp:19
#define NPK_RX 16 // chip2:TX -> esp:16 (RX1)
#define NPK_TX 17 // chip2:RX -> esp:17 (TX1)
// OLED Display
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
// WiFi Credentials
char* WIFI_NAME = "Wokwi-GUEST";
char* WIFI_PASSWORD = "";
// ThingSpeak Settings
unsigned long myChannelNumber = 2564339;
const char* myApiKey = "3PDPDDF1RA32WIER";
WiFiClient client;
// Sensor Objects
DHT dht(DHT_PIN, DHT22);
// NPK Sensor Protocol
#define NPK_REQUEST_NITROGEN 1
#define NPK_REQUEST_PHOSPHORUS 3
#define NPK_REQUEST_POTASSIUM 5
// Variables
float temperature, humidity;
int soilMoisture;
int tdsValue = 0;
float phValue = 0;
int nitrogen = 0, phosphorus = 0, potassium = 0;
// Soil Health Thresholds
const int MOISTURE_THRESHOLD_LOW = 15;
const int MOISTURE_THRESHOLD_HIGH = 85;
const int N_THRESHOLD = 50;
const int P_THRESHOLD = 30;
const int K_THRESHOLD = 40;
const float PH_THRESHOLD_LOW = 5.5;
const float PH_THRESHOLD_HIGH = 7.5;
const int TDS_THRESHOLD = 500; // ppm
void setup() {
Serial.begin(115200);
Serial1.begin(15200, SERIAL_8N1, NPK_RX, NPK_TX); // Initialize Serial1 for NPK sensor
// Initialize OLED
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println(F("SSD1306 allocation failed"));
for(;;);
}
display.display();
delay(2000);
display.clearDisplay();
// Initialize DHT
dht.begin();
// Initialize LED
pinMode(LED_PIN, OUTPUT);
digitalWrite(LED_PIN, LOW);
// Connect to WiFi
WiFi.begin(WIFI_NAME, WIFI_PASSWORD);
Serial.print("Connecting to WiFi");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println();
Serial.println("Connected to WiFi");
// Initialize ThingSpeak
ThingSpeak.begin(client);
// Configure analog pins for TDS/pH
pinMode(PH_PIN, INPUT);
pinMode(TDS_PIN, INPUT);
}
void loop() {
// Read all sensors
readSensors();
// Check soil health
bool isSoilHealthy = checkSoilHealth();
// Control LED based on soil health
digitalWrite(LED_PIN, isSoilHealthy ? LOW : HIGH);
// Display data on OLED
displayData();
// Send data to ThingSpeak
sendToThingSpeak();
delay(8000); // Wait 15 seconds between updates
}
void readSensors() {
// Read DHT22 (Temperature and Humidity)
humidity = dht.readHumidity();
temperature = dht.readTemperature();
// Read Soil Moisture (0-100%)
int soilValue = analogRead(SOIL_MOISTURE_PIN);
soilMoisture = map(soilValue, 0, 4095, 0, 100);
// Read TDS
int16_t tdsRaw = analogRead(TDS_PIN);
float tdsVoltage = tdsRaw * (3.3 / 4095.0); // Changed 5.0 to 3.3
tdsValue = (tdsVoltage / 2.3) * 1000; // TDS in ppm
// Read pH
int16_t phRaw = analogRead(PH_PIN);
float phVoltage = phRaw * (3.3 / 4095.0); // Changed 5.0 to 3.3
phValue = (phVoltage / 2.3) * 14.0; // pH value
// Debugging
Serial.println("------ Sensor Readings ------");
Serial.print("Temperature: "); Serial.print(temperature); Serial.println("°C");
Serial.print("Humidity: "); Serial.print(humidity); Serial.println("%");
Serial.print("Soil Moisture: "); Serial.print(soilMoisture); Serial.println("%");
// Debug Raw Values
Serial.print("Raw pH: "); Serial.print(phRaw); Serial.print(" | Voltage: "); Serial.println(phVoltage, 2);
Serial.print("Raw TDS: "); Serial.print(tdsRaw); Serial.print(" | Voltage: "); Serial.println(tdsVoltage, 2);
Serial.print("pH Value: "); Serial.println(phValue, 2); // 2 decimal places
Serial.print("TDS Value: "); Serial.print(tdsValue); Serial.println(" ppm");
// Read NPK sensor through custom protocol
readNPKSensor();
}
void readNPKSensor() {
// Request nitrogen
Serial1.write(NPK_REQUEST_NITROGEN);
delay(10);
if (Serial1.available()) {
nitrogen = Serial1.read();
}
// Request phosphorus
Serial1.write(NPK_REQUEST_PHOSPHORUS);
delay(10);
if (Serial1.available()) {
phosphorus = Serial1.read();
}
// Request potassium
Serial1.write(NPK_REQUEST_POTASSIUM);
delay(10);
if (Serial1.available()) {
potassium = Serial1.read();
}
}
bool checkSoilHealth() {
// Check if any parameter is outside healthy range
if (soilMoisture < MOISTURE_THRESHOLD_LOW || soilMoisture > MOISTURE_THRESHOLD_HIGH ||
phValue < PH_THRESHOLD_LOW || phValue > PH_THRESHOLD_HIGH ||
tdsValue > TDS_THRESHOLD ||
nitrogen < N_THRESHOLD || phosphorus < P_THRESHOLD || potassium < K_THRESHOLD) {
return false; // Soil health is bad
}
return true; // Soil health is good
}
void displayData() {
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.println("Soil Monitoring System");
display.println("---------------------");
display.print("Temp: "); display.print(temperature); display.println(" C");
display.print("Hum: "); display.print(humidity); display.println(" %");
display.print("Moist:"); display.print(soilMoisture); display.println(" %");
display.print("pH: "); display.println(phValue, 1); // 1 decimal place
display.print("TDS: "); display.print(tdsValue); display.println(" ppm");
display.print("NPK: N"); display.print(nitrogen);
display.print(" P"); display.print(phosphorus);
display.print(" K"); display.println(potassium);
// Add soil health status
display.setCursor(0, 56);
display.print("Soil: ");
display.print(checkSoilHealth() ? "HEALTHY" : "UNHEALTHY");
display.display();
}
void sendToThingSpeak() {
ThingSpeak.setField(1, temperature);
ThingSpeak.setField(2, humidity);
ThingSpeak.setField(3, soilMoisture);
ThingSpeak.setField(4, phValue);
ThingSpeak.setField(5, tdsValue);
ThingSpeak.setField(6, nitrogen);
ThingSpeak.setField(7, phosphorus);
ThingSpeak.setField(8, potassium);
int statusCode = ThingSpeak.writeFields(myChannelNumber, myApiKey);
if (statusCode == 200) {
Serial.println("Data sent to ThingSpeak successfully");
} else {
Serial.println("Problem sending data to ThingSpeak");
}
}