#include <WiFi.h>
#include <WebServer.h>
#include <DHT.h>
#include <LiquidCrystal_I2C.h>
const char* ssid = "Wokwi-GUEST";
const char* password = "";
// --- ПІНИ ---
#define DHTPIN 2
#define SOIL_MOISTURE_PIN 34
#define RELAY_PIN 18
#define DHTTYPE DHT22
// --- Пороги ---
const int DRY_ANALOG_VALUE = 3200;
const int WET_ANALOG_VALUE = 1200;
const int MOISTURE_THRESHOLD = 40;
const int MOISTURE_STOP_THRESHOLD = 65;
const unsigned long MAX_PUMP_TIME_MS = 30000;
// Глобальні змінні
unsigned long pumpStartTime = 0;
bool manualOverride = false;
bool wifiConnected = false; // Прапорець стану Wi-Fi
float currentTemp = 0.0;
float currentHum = 0.0;
int currentMoisture = 0;
// Ініціалізація
DHT dht(DHTPIN, DHTTYPE);
LiquidCrystal_I2C lcd(0x27, 16, 2);
WebServer server(80);
// --- WEB ФУНКЦІЇ ---
String generateWebPage() {
String html = "<!DOCTYPE html><html><head><meta charset='UTF-8'><meta name='viewport' content='width=device-width, initial-scale=1'><title>Smart Farm</title>";
html += "<style>body{font-family:Arial;} .data{font-size: 20px; margin: 10px 0;} .status{font-size: 24px; font-weight: bold;}</style></head><body>";
html += "<h1>Розумна Ферма ESP32</h1><hr>";
html += "<div class='data'>Температура: " + String(currentTemp) + " °C</div>";
html += "<div class='data'>Вологість пов.: " + String(currentHum) + " %</div>";
html += "<div class='data'>Вологість ґрунту: <span class='status'>" + String(currentMoisture) + " %</span></div>";
html += "<div class='data'>Режим: <b>" + String(manualOverride ? "РУЧНИЙ" : "АВТО") + "</b></div><hr>";
html += "<h2>Керування:</h2>";
html += "<a href='/pump?state=on'><button style='background-color:green; color:white; padding: 15px;'>Увімкнути</button></a> ";
html += "<a href='/pump?state=off'><button style='background-color:red; color:white; padding: 15px;'>Вимкнути</button></a> ";
html += "<a href='/pump?state=auto'><button style='background-color:blue; color:white; padding: 15px;'>Авто</button></a> ";
html += "</body></html>";
return html;
}
void handleRoot() { server.send(200, "text/html", generateWebPage()); }
void handlePump() {
if (server.hasArg("state")) {
String state = server.arg("state");
if (state == "on") {
manualOverride = true;
digitalWrite(RELAY_PIN, LOW);
pumpStartTime = millis();
} else if (state == "off") {
manualOverride = true;
digitalWrite(RELAY_PIN, HIGH);
} else if (state == "auto") {
manualOverride = false;
}
}
server.sendHeader("Location", "/");
server.send(302, "text/plain", "Redirecting...");
}
void tryConnectWiFi() {
lcd.print("WiFi...");
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
int attempts = 0;
while (WiFi.status() != WL_CONNECTED && attempts < 10) {
delay(100);
attempts++;
}
lcd.clear();
if (WiFi.status() == WL_CONNECTED) {
wifiConnected = true;
lcd.print("WiFi OK!");
lcd.setCursor(0, 1);
lcd.print(WiFi.localIP());
server.on("/", handleRoot);
server.on("/pump", handlePump);
server.begin();
delay(1000);
} else {
wifiConnected = false;
lcd.print("WiFi PROPUSK"); // Пропускаємо, щоб не чекати
delay(500);
}
}
void setup() {
Serial.begin(115200);
pinMode(RELAY_PIN, OUTPUT);
digitalWrite(RELAY_PIN, HIGH);
dht.begin();
lcd.init();
lcd.backlight();
tryConnectWiFi();
}
void loop() {
// Якщо Wi-Fi є, обробляємо клієнтів
if (wifiConnected) {
server.handleClient();
}
currentTemp = dht.readTemperature();
currentHum = dht.readHumidity();
int sensorValue = analogRead(SOIL_MOISTURE_PIN);
currentMoisture = map(sensorValue, DRY_ANALOG_VALUE, WET_ANALOG_VALUE, 0, 100);
if (currentMoisture < 0) currentMoisture = 0;
if (currentMoisture > 100) currentMoisture = 100;
String pumpStatus;
bool pumpIsOn = (digitalRead(RELAY_PIN) == LOW);
if (pumpIsOn) {
if (millis() - pumpStartTime >= MAX_PUMP_TIME_MS) {
digitalWrite(RELAY_PIN, HIGH);
pumpIsOn = false;
manualOverride = false;
}
}
if (!manualOverride) {
if (currentMoisture < MOISTURE_THRESHOLD && !pumpIsOn) {
digitalWrite(RELAY_PIN, LOW);
pumpStartTime = millis();
pumpStatus = "УВІМК (Авто)";
}
else if (currentMoisture >= MOISTURE_STOP_THRESHOLD && pumpIsOn) {
digitalWrite(RELAY_PIN, HIGH);
pumpStatus = "ВИМК (Авто)";
}
else {
pumpStatus = pumpIsOn ? "УВІМК (Утрим)" : "ВИМК (Авто)";
}
} else {
pumpStatus = pumpIsOn ? "УВІМК (Ручн)" : "ВИМК (Ручн)";
}
lcd.clear();
lcd.print("T:"); lcd.print(currentTemp, 1); lcd.print("C Vol:"); lcd.print(currentHum, 0); lcd.print("%");
lcd.setCursor(0, 1);
lcd.print("Gr:"); lcd.print(currentMoisture); lcd.print("% P:");
if(pumpStatus.startsWith("УВІМК")) lcd.print("ON"); else lcd.print("OFF");
static unsigned long lastPrint = 0;
if (millis() - lastPrint > 2000) {
Serial.print("Температура: "); Serial.print(currentTemp); Serial.print(" C | ");
Serial.print("Вологість пов.: "); Serial.print(currentHum); Serial.print(" % | ");
Serial.print("Вологість ґрунту: "); Serial.print(currentMoisture); Serial.print("% | ");
Serial.print("Насос: "); Serial.println(pumpStatus);
if (wifiConnected) {
Serial.print("IP Адреса панелі: "); Serial.println(WiFi.localIP());
} else {
Serial.println("WiFi: Не підключено (Автономний режим)");
}
lastPrint = millis();
}
delay(100);
}