#include #include #include #include #include #include #include #include #include // Pin tanımlamaları #define RELAY_IRRIGATION_PIN 16 #define RELAY_LIGHT_PIN 17 #define RELAY_CLIMATE_PIN 25 #define RELAY_SPRAY_PIN 26 #define SENSOR_PIN 39 #define LED_PIN 33 // API URL'leri #define SECOND_API_URL "https://eegsmartfarm.com/apiler/getapi.php?api_key=Cihaz Apiniz" #define WEATHER_API_URL "http://api.openweathermap.org/data/2.5/weather?q=Antalya&appid=Open Weather Apiniz" #define DATA_API_URL "https://eegsmartfarm.com/apiler/api.php" // WiFi bilgileri const char* ssid = "Wifi ADI"; const char* password = "WIFI Şifreniz"; const char* apiKey = "Cihaz Apiniz"; // Sistem durum değişkenleri bool otomatikSulamaAktif = false; bool uzaktanSulamaDurumu = false; bool iklimlendirmeDurumu = false; bool aydinlatmaDurumu = false; bool ilaclamaDurumu = false; bool zamanliSulamaDurumu = false; float temperatureCelsius = 0; int _moisture, sensor_analog; int minNem = 30; int maxNem = 70; // Hidroponik sulama değişkenleri unsigned long hidroponikBaslangicZamani = 0; unsigned long hidroponikSulamaSuresi = 0; // dakika cinsinden unsigned long sonSulamaZamani = 0; const unsigned long BIR_SAAT_MS = 3600000; // 1 saat milisaniye cinsinden // Zamanlama değişkenleri WiFiUDP ntpUDP; NTPClient timeClient(ntpUDP, "pool.ntp.org", 10800, 60000); unsigned long previousWeatherApiMillis = 0; unsigned long previousSensorUpdateMillis = 0; unsigned long previousGetApiMillis = 0; const unsigned long WEATHER_API_INTERVAL = 3600000; // 1 saat const unsigned long SENSOR_UPDATE_INTERVAL = 60000; // 1 dakika const unsigned long GET_API_INTERVAL = 5000; // 5 saniye struct tm sulamaBaslangicSaati; struct tm sulamaBitisSaati; String replaceTurkishChars(String input) { input.replace("ü", "u"); input.replace("ğ", "g"); input.replace("ı", "i"); input.replace("ö", "o"); input.replace("ç", "c"); input.replace("Ü", "U"); input.replace("İ", "I"); input.replace("Ç", "C"); input.replace("Ğ", "G"); input.replace("Ö", "O"); return input; } void setup() { Serial.begin(115200); Serial.println("\n\nSistem baslatiliyor..."); // Pin ayarları pinMode(RELAY_IRRIGATION_PIN, OUTPUT); digitalWrite(RELAY_IRRIGATION_PIN, HIGH); Serial.println("IRRIGATION relesi HIGH olarak ayarlandi"); pinMode(RELAY_LIGHT_PIN, OUTPUT); digitalWrite(RELAY_LIGHT_PIN, HIGH); Serial.println("LIGHT relesi HIGH olarak ayarlandi"); pinMode(RELAY_CLIMATE_PIN, OUTPUT); digitalWrite(RELAY_CLIMATE_PIN, HIGH); Serial.println("CLIMATE relesi HIGH olarak ayarlandi"); pinMode(RELAY_SPRAY_PIN, OUTPUT); digitalWrite(RELAY_SPRAY_PIN, HIGH); Serial.println("SPRAY relesi HIGH olarak ayarlandi"); pinMode(LED_PIN, OUTPUT); Serial.println("LED pini cikis olarak ayarlandi"); // EEPROM'dan nem değerlerini oku EEPROM.begin(512); minNem = EEPROM.read(0); maxNem = EEPROM.read(1); Serial.printf("[EEPROM] Min Nem: %d, Max Nem: %d\n", minNem, maxNem); // WiFi bağlantısı Serial.printf("[WiFi] %s agina baglaniliyor...\n", ssid); WiFi.begin(ssid, password); unsigned long wifiBaslangic = millis(); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); if(millis() - wifiBaslangic > 10000) { Serial.println("\n[WiFi] Baglanti zaman asimi! Yeniden deniyor..."); wifiBaslangic = millis(); } } Serial.printf("\n[WiFi] Baglandi! IP: %s\n", WiFi.localIP().toString().c_str()); // NTP istemcisi Serial.println("[NTP] Zaman sunucusuna baglaniliyor..."); timeClient.begin(); timeClient.update(); Serial.printf("[NTP] Zaman ayarlandi: %s\n", timeClient.getFormattedTime().c_str()); // Telnet sunucusu başlat TelnetStream.begin(); Serial.println("[Telnet] Telnet sunucusu baslatildi (port 23)"); // İlk verileri al Serial.println("[WEATHER] Hava durumu verisi aliniyor..."); updateWeatherData(); // OTA güncelleme ArduinoOTA.begin(); Serial.println("[OTA] OTA guncelleme hazir"); } void log(String message) { message = replaceTurkishChars(message); String logMessage = "[" + timeClient.getFormattedTime() + "] " + message; Serial.println(logMessage); TelnetStream.println(logMessage); } void kontrolEtVeSulamaYonet() { Serial.println("[API] Kontrol API'sine istek gonderiliyor..."); HTTPClient http; http.begin(SECOND_API_URL); http.setTimeout(2000); int httpCode = http.GET(); if(httpCode == HTTP_CODE_OK) { Serial.println("[API] Yanit alindi, veri isleniyor..."); DynamicJsonDocument doc(1024); deserializeJson(doc, http.getString()); // Manuel sulama kontrolü bool yeniManuelDurum = doc["manuel_sulama"] == 1; if(yeniManuelDurum != uzaktanSulamaDurumu) { uzaktanSulamaDurumu = yeniManuelDurum; digitalWrite(RELAY_IRRIGATION_PIN, uzaktanSulamaDurumu ? LOW : HIGH); log("[RELAY] Sulama " + String(uzaktanSulamaDurumu ? "ACILDI" : "KAPATILDI") + " (Manuel)"); if(uzaktanSulamaDurumu) { otomatikSulamaAktif = false; Serial.println("[MODE] Otomatik sulama devre disi birakildi"); } } // Aydınlatma kontrolü bool yeniAydinlatma = doc["aydinlatma"] == 1; if(yeniAydinlatma != aydinlatmaDurumu) { aydinlatmaDurumu = yeniAydinlatma; digitalWrite(RELAY_LIGHT_PIN, aydinlatmaDurumu ? LOW : HIGH); log("[RELAY] Aydinlatma " + String(aydinlatmaDurumu ? "ACILDI" : "KAPATILDI")); } // İklimlendirme kontrolü bool yeniIklim = doc["iklimlendirme"] == 1; if(yeniIklim != iklimlendirmeDurumu) { iklimlendirmeDurumu = yeniIklim; digitalWrite(RELAY_CLIMATE_PIN, iklimlendirmeDurumu ? LOW : HIGH); log("[RELAY] Iklimlendirme " + String(iklimlendirmeDurumu ? "ACILDI" : "KAPATILDI")); } // İlaçlama kontrolü bool yeniIlaclama = doc["ilaclama"] == 1; if(yeniIlaclama != ilaclamaDurumu) { ilaclamaDurumu = yeniIlaclama; digitalWrite(RELAY_SPRAY_PIN, ilaclamaDurumu ? LOW : HIGH); log("[RELAY] Ilaclama " + String(ilaclamaDurumu ? "ACILDI" : "KAPATILDI")); } // Zamanlı sulama ayarları bool yeniZamanliSulama = doc["zamanli_sulama"] == 1; if(yeniZamanliSulama != zamanliSulamaDurumu) { zamanliSulamaDurumu = yeniZamanliSulama; if(zamanliSulamaDurumu) { hidroponikBaslangicZamani = millis(); sonSulamaZamani = 0; // Sıfırlama } log("[MODE] Zamanli sulama " + String(zamanliSulamaDurumu ? "AKTIF" : "PASIF")); } if(zamanliSulamaDurumu) { String baslangic = doc["baslangic_tarihi"]; String bitis = doc["bitis_tarihi"]; hidroponikSulamaSuresi = doc["hidroponik_sure"]; // 15, 30, 60, 120, 180, 240 dakika strptime(baslangic.c_str(), "%Y-%m-%d %H:%M:%S", &sulamaBaslangicSaati); strptime(bitis.c_str(), "%Y-%m-%d %H:%M:%S", &sulamaBitisSaati); Serial.printf("[TIME] Zamanli sulama araligi: %s - %s\n", baslangic.c_str(), bitis.c_str()); Serial.printf("[HIDRO] Sulama suresi: %d dakika\n", hidroponikSulamaSuresi); } // Nem eşik değerlerini güncelle int yeniMinNem = doc["minnem"]; int yeniMaxNem = doc["maxnem"]; if(yeniMinNem != minNem || yeniMaxNem != maxNem) { minNem = yeniMinNem; maxNem = yeniMaxNem; EEPROM.write(0, minNem); EEPROM.write(1, maxNem); EEPROM.commit(); log("[SETTING] Nem esikleri guncellendi: Min=" + String(minNem) + ", Max=" + String(maxNem)); } } else { log("[ERROR] API hatasi: " + String(httpCode)); } http.end(); } void sendSensorData() { Serial.println("[API] Sensor verileri gonderiliyor..."); HTTPClient http; http.begin(DATA_API_URL); http.addHeader("Content-Type", "application/x-www-form-urlencoded"); http.setTimeout(3000); String postData = "apiKey=" + String(apiKey) + "&_moisture=" + String(_moisture) + "&temperature=" + String(temperatureCelsius, 1); int httpCode = http.POST(postData); if(httpCode > 0) { log("[API] Veri gonderimi basarili. Kod: " + String(httpCode)); } else { log("[ERROR] Veri gonderimi basarisiz. Kod: " + String(httpCode)); } http.end(); } void updateWeatherData() { Serial.println("[WEATHER] Hava durumu guncelleniyor..."); HTTPClient http; http.begin(WEATHER_API_URL); http.setTimeout(5000); int httpCode = http.GET(); if(httpCode == HTTP_CODE_OK) { DynamicJsonDocument doc(1024); deserializeJson(doc, http.getString()); float yeniSicaklik = doc["main"]["temp"].as() - 273.15; if(yeniSicaklik != temperatureCelsius) { temperatureCelsius = yeniSicaklik; log("[WEATHER] Yeni sicaklik: " + String(temperatureCelsius, 1) + "°C"); } else { Serial.println("[WEATHER] Sicaklik degismedi"); } } else { log("[ERROR] Hava durumu guncelleme hatasi: " + String(httpCode)); } http.end(); } void nemOlc() { static int oncekiNem = -1; // İlk değer ataması için sensor_analog = analogRead(SENSOR_PIN); _moisture = map(sensor_analog, 0, 4095, 100, 0); if(_moisture != oncekiNem) { log("[SENSOR] Nem olculdu: " + String(_moisture) + "%"); oncekiNem = _moisture; // Otomatik sulama kontrolü (anlık) if(!uzaktanSulamaDurumu && !zamanliSulamaDurumu) { if(_moisture < minNem && !otomatikSulamaAktif) { digitalWrite(RELAY_IRRIGATION_PIN, LOW); otomatikSulamaAktif = true; digitalWrite(LED_PIN, HIGH); log("[MODE] Otomatik sulama BASLADI (Nem dusuk)"); } else if(_moisture >= maxNem && otomatikSulamaAktif) { digitalWrite(RELAY_IRRIGATION_PIN, HIGH); otomatikSulamaAktif = false; digitalWrite(LED_PIN, LOW); log("[MODE] Otomatik sulama DURDURULDU (Nem yeterli)"); } } } Serial.printf("[DEBUG] Analog deger: %d, Hesaplanan nem: %d%%\n", sensor_analog, _moisture); } void kontrolHidroponikSulama() { if(!zamanliSulamaDurumu) return; timeClient.update(); time_t simdikiZaman = timeClient.getEpochTime(); time_t baslangic = mktime(&sulamaBaslangicSaati); time_t bitis = mktime(&sulamaBitisSaati); // 24 saatlik periyot kontrolu unsigned long simdi = millis(); unsigned long hidroponikGecenSure = simdi - hidroponikBaslangicZamani; // 24 saat doldu mu kontrolu if(hidroponikGecenSure > 86400000) { // 24 saat = 86400000 ms hidroponikBaslangicZamani = simdi; // Sifirla sonSulamaZamani = 0; log("[HIDRO] 24 saatlik periyot sifirlandi"); } // Zaman araligi kontrolu bool zamanAraliginda = (simdikiZaman >= baslangic && simdikiZaman <= bitis); if(zamanAraliginda) { // Saat basi kontrolu (her 3600000 ms'de bir) if(simdi - sonSulamaZamani >= BIR_SAAT_MS) { sonSulamaZamani = simdi; // Sulamayi baslat digitalWrite(RELAY_IRRIGATION_PIN, LOW); otomatikSulamaAktif = true; digitalWrite(LED_PIN, HIGH); log("[HIDRO] Sulama basladi (" + String(hidroponikSulamaSuresi) + " dakika)"); // Sulama suresini ayarla unsigned long sulamaSuresiMs = hidroponikSulamaSuresi * 60000UL; // dakikadan ms'ye cevir unsigned long sulamaBitisZamani = simdi + sulamaSuresiMs; // Sulama bitisini bekle (non-blocking) while(millis() < sulamaBitisZamani) { ArduinoOTA.handle(); delay(100); } // Sulamayi durdur digitalWrite(RELAY_IRRIGATION_PIN, HIGH); otomatikSulamaAktif = false; digitalWrite(LED_PIN, LOW); log("[HIDRO] Sulama tamamlandi"); } } else if(otomatikSulamaAktif) { digitalWrite(RELAY_IRRIGATION_PIN, HIGH); otomatikSulamaAktif = false; digitalWrite(LED_PIN, LOW); log("[HIDRO] Zaman araligi disinda, sulama durduruldu"); } } void handleTelnetCommands() { if (TelnetStream.available()) { String command = TelnetStream.readStringUntil('\n'); command.trim(); log("[TELNET] Komut alindi: " + command); if (command == "durum") { TelnetStream.println("=== SISTEM DURUMU ==="); TelnetStream.println("Nem: " + String(_moisture) + "%"); TelnetStream.println("Sicaklik: " + String(temperatureCelsius, 1) + "°C"); TelnetStream.println("Otomatik Sulama: " + String(otomatikSulamaAktif ? "ACIK" : "KAPALI")); TelnetStream.println("Manuel Sulama: " + String(uzaktanSulamaDurumu ? "ACIK" : "KAPALI")); TelnetStream.println("Aydinlatma: " + String(aydinlatmaDurumu ? "ACIK" : "KAPALI")); TelnetStream.println("Iklimlendirme: " + String(iklimlendirmeDurumu ? "ACIK" : "KAPALI")); TelnetStream.println("Ilaclama: " + String(ilaclamaDurumu ? "ACIK" : "KAPALI")); TelnetStream.println("Zamanli Sulama: " + String(zamanliSulamaDurumu ? "AKTIF" : "PASIF")); if(zamanliSulamaDurumu) { TelnetStream.println("Hidroponik Sulama Suresi: " + String(hidroponikSulamaSuresi) + " dakika"); } TelnetStream.println("Nem Esikleri: Min=" + String(minNem) + "%, Max=" + String(maxNem) + "%"); } else if (command == "yardim") { TelnetStream.println("Kullanilabilir komutlar:"); TelnetStream.println("durum - Sistem durumunu goster"); TelnetStream.println("yardim - Bu yardim mesajini goster"); } else { TelnetStream.println("Bilinmeyen komut: '" + command + "'"); } } } void loop() { unsigned long currentMillis = millis(); // API'den durumlari kontrol et if(currentMillis - previousGetApiMillis >= GET_API_INTERVAL) { previousGetApiMillis = currentMillis; kontrolEtVeSulamaYonet(); } // Hava durumu verisini guncelle if(currentMillis - previousWeatherApiMillis >= WEATHER_API_INTERVAL) { previousWeatherApiMillis = currentMillis; updateWeatherData(); } // Sensör verilerini oku ve gönder if(currentMillis - previousSensorUpdateMillis >= SENSOR_UPDATE_INTERVAL) { previousSensorUpdateMillis = currentMillis; nemOlc(); sendSensorData(); } else { // Sensörü sürekli oku ama veriyi belirli aralıklarla gönder nemOlc(); } // Sulama kontrolleri kontrolHidroponikSulama(); // Telnet komutlarını işle handleTelnetCommands(); // OTA güncellemeleri dinle ArduinoOTA.handle(); delay(1500); }