Proje için yardım/öneri (03..04.25 güncelleme)

Kodda ufak farklar var, evdeki pc de kaldı son yüklediğim. şuan kodda güncellemeler yapıyorum resetleme halinde kaldığı yerden devam etmesi ile ilgili. Güncel kodu bittiğinde yeniden paylaşırım.


Evet arduino üzerinden besledim röleleri 9v 1a. Bende dolabı karıştırıp eski telefon adaptörünü buldum azönce 5v 2a yeterli olur inşallah :) Kabloları kısaltmaya kalkarsam çok gergin olacakmış gibi. 2-3cm de olsa kısatmamı önerirseniz onu da yapayım.
Denediğim yer ile aramda 60km mesafe var, haftasonu deneyip haftaiçi düzeltmeleri yapıyorum. Almam gereken birşey varsa gitmeden toparlamak için öğrenmeye çalışıyorum.
Eski yaptığım sistemde şuan kaz yumurtalarını koydum, o karadüzen çalıştığı için böyle sorunlarla karşılaşmıyorum. Kayınpeder tavuk yumurtalarını biriktirmeye başladı, bayramda çalıştırabilirsem çok güzel olacak :) :)
2-3 cm kısaltmaya gerek yok. Haftada 1 deneme yaparak sorun çözmek zor. Ama beslemeden gidelim. 3 röle kullanıyorsun gibi görünüyor.
1742824601976.png

5V olan röleler eğer bunlarla aynıysa 89mA akım çekiyorlar üçü aynı anda açılsa ~270mA çeker arduino ve ekran da 50mA çekse 320mA 9V beslemeden 5V'ye voltaj düşümünden 4*0,32=1,28W güç yapıyor.
Değerler regülatörün datasheetten, bazıları 150C/W bir tanesi 90C/W denk geldi >>>
1742825400043.png


SOT-223 kılıf için regülatörün junction sıcaklığı 90*1,28=115 derece + ortam sıcaklığı olur. Bu da iyimser hesap. Muhtemelen bu rölelerin beraber açıldığı bir süre denk gelince regülatör sıcaklıktan dolayı voltaj kesiyordur.

Önce arduinoyu USB girişten, USB şarj adaptörüyle beslemeyi deneyin, olmadı röle beslemesini ayırmayı denersiniz. En son kablolarla uğraşırsınız.
 
Sorun yazılımsal da olabilir. değişkenlerin taşıyor olabilir. Röle kartini söküp devreyi bir kaç gün acik bırakın. resetlenme olup olmadığını kontrol edin.
 
Kod:
#include <Wire.h>
#include <Adafruit_PCD8544.h>
#include <Adafruit_SHT31.h>
#include <RTClib.h>
#include <EEPROM.h>
#include <avr/wdt.h>

// Pin tanımlamaları
#define RELAY1 5        // Isıtıcı
#define RELAY2 6        // Nemlendirici
#define RELAY3 7        // Fan
#define RELAY4 8        // Motor
#define ROW1 22         // Tuş takımı satır 1
#define ROW2 24         // Tuş takımı satır 2
#define ROW3 26         // Tuş takımı satır 3
#define ROW4 28         // Tuş takımı satır 4
#define COL1 30         // Tuş takımı sütun 1
#define COL2 32         // Tuş takımı sütun 2
#define COL3 34         // Tuş takımı sütun 3
#define COL4 36         // Tuş takımı sütun 4
#define BACKLIGHT_PIN A5 // LCD Arka ışık

// SHT31 Sensör adresleri
#define SHT31_1_ADDR 0x44  // İlk sensör I2C adresi
#define SHT31_2_ADDR 0x45  // İkinci sensör I2C adresi

// EEPROM adres haritası
#define EEPROM_TYPE 0           // Kuluçka tipi (1 byte)
#define EEPROM_START_TIME 1     // Başlangıç zamanı (4 byte)
#define EEPROM_TEMP 5           // Hedef sıcaklık (4 byte)
#define EEPROM_HUM 9            // Hedef nem (4 byte)
#define EEPROM_ERROR_FLAG 13    // Hata durumu (1 byte)
#define EEPROM_TEMP_OFFSET 14   // Sıcaklık offset (4 byte)
#define EEPROM_HUM_OFFSET 18    // Nem offset (4 byte)
#define EEPROM_MOTOR_DURATION 22 // Motor çalışma süresi (4 byte)
#define EEPROM_MOTOR_INTERVAL 26 // Motor çalışma aralığı (4 byte)
#define EEPROM_CHECKSUM 30      // Veri doğrulama (1 byte)

// Menü durumları
#define MENU_MAIN 0          // Ana menü
#define MENU_SETTINGS 1      // Ayarlar menüsü
#define MENU_MOTOR 2         // Motor ayarları menüsü
#define MENU_SENSORS 3       // Sensör bilgileri menüsü
#define MENU_CALIBRATION 4   // Kalibrasyon menüsü

// Kontrol parametreleri
#define TEMP_HYSTERESIS 0.3  // Sıcaklık kontrolü için histerezis (0.3°C)
#define HUM_HYSTERESIS 2.0   // Nem kontrolü için histerezis (%2)
#define DEBOUNCE_DELAY 250   // Tuş kontrolü için debounce süresi (250ms)

// Zaman sabitleri
const unsigned long MOTOR_INTERVAL_DEFAULT = 7200000; // Motor dönüş aralığı (2 saat)
const unsigned long MOTOR_DURATION_DEFAULT = 3000;    // Motor çalışma süresi (3 saniye)
const unsigned long BACKLIGHT_TIMEOUT = 10000;        // Arka ışık kapanma süresi (10 saniye)
const unsigned long MESSAGE_DURATION = 2000;          // Mesaj gösterim süresi (2 saniye)
const unsigned long EEPROM_WRITE_INTERVAL = 300000;   // EEPROM yazma aralığı (5 dakika)

// Hata yönetimi için sabitler
#define MAX_ERRORS 3          // Maksimum ardışık hata sayısı
#define SENSOR_TIMEOUT 5000   // Sensör okuma zaman aşımı (ms)

// Veri yapıları
struct SensorData {
    float temp;         // Sıcaklık değeri
    float hum;          // Nem değeri
    bool isValid;       // Sensör verisi geçerli mi?
};

struct MotorSettings {
    unsigned long duration;  // Motor çalışma süresi
    unsigned long interval;  // Motor çalışma aralığı
};

struct IncubatorSettings {
    int type;               // Kuluçka tipi (0:Tavuk, 1:Kaz, 2:Bıldırcın, 3:Manuel, 4:Sıfırlama)
    float targetTemp;       // Hedef sıcaklık
    float targetHum;        // Hedef nem
    int totalDays;          // Toplam kuluçka süresi
    uint32_t startTime;     // Başlangıç zamanı (time_t yerine uint32_t kullanıyoruz)
    bool motorActive;       // Motor aktif mi?
    bool heaterState;       // Isıtıcı durumu
    bool humidifierState;   // Nemlendirici durumu
    float tempOffset;       // Sıcaklık kalibrasyon offseti
    float humOffset;        // Nem kalibrasyon offseti
};

struct ErrorManager {
    int tempErrors;         // Sıcaklık sensörü hata sayacı
    int humErrors;          // Nem sensörü hata sayacı
    int rtcErrors;          // RTC hata sayacı
    unsigned long lastSensorRead;   // Son sensör okuma zamanı
    unsigned long lastEEPROMWrite;  // Son EEPROM yazma zamanı
    bool safeMode;          // Güvenli mod aktif mi?
    
    ErrorManager() {
        tempErrors = 0;
        humErrors = 0;
        rtcErrors = 0;
        lastSensorRead = 0;
        lastEEPROMWrite = 0;
        safeMode = false;
    }
    
    void resetErrors() {
        tempErrors = 0;
        humErrors = 0;
        rtcErrors = 0;
    }
    
    bool checkSensor(float value, float min, float max) {
        if (isnan(value) || value < min || value > max) {
            return false;
        }
        return true;
    }
};

// Donanım nesneleri
Adafruit_PCD8544 lcd(A0, A1, A2, A3, A4);  // LCD ekran
Adafruit_SHT31 sht31_1 = Adafruit_SHT31();  // İlk SHT31 sensörü
Adafruit_SHT31 sht31_2 = Adafruit_SHT31();  // İkinci SHT31 sensörü
RTC_DS3231 rtc;                             // RTC modülü

// Global değişkenler
IncubatorSettings settings;           // Kuluçka ayarları
MotorSettings motorSettings;          // Motor ayarları
ErrorManager errorMgr;                // Hata yöneticisi
int currentMenu = MENU_MAIN;          // Mevcut menü durumu
bool inSubMenu = false;               // Alt menüde miyiz?
unsigned long lastKeyPressTime = 0;   // Son tuş basma zamanı
unsigned long lastDebounceTime = 0;   // Son debounce zamanı
bool backlightState = false;          // Arka ışık durumu
unsigned long previousMillis = 0;     // Önceki millis değeri
char lastKey = 0;                     // Son basılan tuş
float tempOffset = 0.0;               // Sıcaklık kalibrasyon offseti
float humOffset = 0.0;                // Nem kalibrasyon offseti

// Kuluçka tipi isimleri
const char* typeNames[] = {"Tavuk", "Kaz", "Bildircin", "Manuel"};

// Fonksiyon prototipleri
void handleMainMenu(char key);
void handleSettingsMenu(char key);
void handleMotorMenu(char key);
void handleCalibrationMenu(char key);
void handleNormalOperation(char key);
void showMainMenu();
void showSettingsMenu();
void showMotorMenu();
void showSensorInfo();
void showCalibrationMenu();
void showMessage(const char* message);
void showError(const char* message);
void setupChicken();
void setupGoose();
void setupQuail();
void setupManual();
void resetSystem();
void askForReset();
void saveState();
void savePersistentState();
void loadState();
void loadMotorSettings();
uint8_t calculateChecksum();
void updateSensorsAndControl();
void updateMainDisplay(float temp, float hum, int currentDay);
void updateBacklight();
void testMotor();
void controlMotor(uint32_t currentTime);
void controlTemperature(float currentTemp);
void controlHumidity(float currentHum);
void checkAndUpdateSettings(int currentDay);
void getAverageReadings(float &avgTemp, float &avgHum);
char getKey();
float getNumberInput();
void enterSafeMode(const char* errorMsg);
void calibrateTemperature();
void calibrateHumidity();
SensorData readSHT31_1();
SensorData readSHT31_2();
uint32_t getTimeFromRTC();
int getMotorCountdown();
void setMotorDuration();
void setMotorInterval();

// Saat çevirimi için yardımcı fonksiyon - time_t yerine uint32_t kullanıyoruz
uint32_t getTimeFromRTC() {
    DateTime now = rtc.now();
    return now.unixtime();  // .get() yerine .unixtime() kullanıyoruz
}

void setup() {
    Serial.begin(9600);
    Wire.begin();
    
    // Pin modlarını ayarla
    pinMode(RELAY1, OUTPUT);
    pinMode(RELAY2, OUTPUT);
    pinMode(RELAY3, OUTPUT);
    pinMode(RELAY4, OUTPUT);
    pinMode(ROW1, INPUT_PULLUP);
    pinMode(ROW2, INPUT_PULLUP);
    pinMode(ROW3, INPUT_PULLUP);
    pinMode(ROW4, INPUT_PULLUP);
    pinMode(COL1, OUTPUT);
    pinMode(COL2, OUTPUT);
    pinMode(COL3, OUTPUT);
    pinMode(COL4, OUTPUT);
    pinMode(BACKLIGHT_PIN, OUTPUT);

    // Başlangıç durumları
    digitalWrite(RELAY1, LOW);  // Isıtıcı kapalı
    digitalWrite(RELAY2, LOW);  // Nemlendirici kapalı
    digitalWrite(RELAY3, HIGH); // Fanlar sürekli çalışacak
    digitalWrite(RELAY4, LOW);  // Motor kapalı
    digitalWrite(BACKLIGHT_PIN, LOW); // Arka ışık kapalı

    // Röle durumlarını sıfırla
    settings.heaterState = false;
    settings.humidifierState = false;

    // LCD başlatma
    lcd.begin();
    lcd.setContrast(50);
    lcd.clearDisplay();
    lcd.setTextSize(1);
    lcd.setCursor(0,0);
    lcd.println("Kulucka");
    lcd.println("Makinesi v2.0");
    lcd.println("Baslatiliyor...");
    lcd.display();
    delay(2000);
    
    // Sensörleri başlat
    if (!sht31_1.begin(SHT31_1_ADDR)) {
        showError("Sensor 1 Hata!");
        delay(2000);
    }
    
    if (!sht31_2.begin(SHT31_2_ADDR)) {
        showError("Sensor 2 Hata!");
        delay(2000);
    }
    
    // Sensör heater'larını kapat
    sht31_1.heater(false);
    sht31_2.heater(false);
    
    // RTC başlatma - düzeltilmiş
    if (!rtc.begin()) {
        showError("RTC Hatasi!");
        delay(2000);
    }

    // RTC pil kontrolü
    if (rtc.lostPower()) {
        showError("RTC Pil Zayif!");
        delay(2000);
        rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
    }

    // EEPROM'dan ayarları yükle
    loadState();
    
    // Motor ayarlarını yükle
    loadMotorSettings();
    
    // İlk açılışta menüyü göster
    if (settings.type == 4 || settings.type == 255) {
        settings.type = 4;
        showMainMenu();
        currentMenu = MENU_MAIN;
    } else {
        // Normal çalışma modunda, ilk ekranı güncelle
        float avgTemp = 0.0, avgHum = 0.0;
        SensorData sensor1 = readSHT31_1();
        SensorData sensor2 = readSHT31_2();
        
        if (sensor1.isValid && sensor2.isValid) {
            avgTemp = (sensor1.temp + sensor2.temp) / 2.0;
            avgHum = (sensor1.hum + sensor2.hum) / 2.0;
        } else if (sensor1.isValid) {
            avgTemp = sensor1.temp;
            avgHum = sensor1.hum;
        } else if (sensor2.isValid) {
            avgTemp = sensor2.temp;
            avgHum = sensor2.hum;
        }
        
        uint32_t currentTime = getTimeFromRTC();
        int currentDay = 1; // Varsayılan olarak 1. gün
        
        if (settings.startTime > 0 && currentTime > settings.startTime) {
            currentDay = (currentTime - settings.startTime) / 86400 + 1;
            if (currentDay > settings.totalDays) {
                currentDay = settings.totalDays;
            }
        }
        
        updateMainDisplay(avgTemp, avgHum, currentDay);
        currentMenu = -1; // Normal çalışma modu
    }
    
    // Watchdog timer başlat - 8 saniye
    wdt_enable(WDTO_8S);
}

void loop() {
    // Watchdog timer'ı sıfırla
    wdt_reset();
    
    // Arka ışık kontrolü
    updateBacklight();
    
    // Tuş kontrolü
    char key = getKey();
    
    // Menü durumunu kontrol et
    if (currentMenu == MENU_SETTINGS) {
        if(key) {
            handleSettingsMenu(key);
        }
    }
    else if (currentMenu == MENU_MOTOR) {
        if(key) {
            handleMotorMenu(key);
        }
    }
    else if (currentMenu == MENU_CALIBRATION) {
        if(key) {
            handleCalibrationMenu(key);
        }
    }
    // Ana menü modu
    else if (settings.type == 4 || currentMenu == MENU_MAIN) {
        if(key) {
            handleMainMenu(key);
        }
    }
    // Normal çalışma modu
    else {
        // Sensör değerlerini oku ve kontrolleri yap
        updateSensorsAndControl();
        
        // Tuş işlemlerini yönet
        if(key) {
            handleNormalOperation(key);
        }
        
        // EEPROM'a periyodik kayıt
        savePersistentState();
    }
    
    // Gecikme - ana döngüyü yavaşlat
    delay(100);
}

void updateSensorsAndControl() {
    // Sensör değerlerini oku
    float avgTemp, avgHum;
    getAverageReadings(avgTemp, avgHum);
    
    uint32_t currentTime = getTimeFromRTC();
    int currentDay = 0;
    
    // Gün hesaplama güvenliği ekle
    if (settings.startTime > 0 && settings.startTime <= currentTime) {
        currentDay = (currentTime - settings.startTime) / 86400 + 1;
        
        // Geçersiz gün değerlerini düzelt
        if (currentDay <= 0 || currentDay > settings.totalDays) {
            currentDay = 1;
        }
    } else {
        currentDay = 1;
    }
    
    // Son günlerde özel ayarları kontrol et
    checkAndUpdateSettings(currentDay);
    
    // Sıcaklık kontrolü
    controlTemperature(avgTemp);
    
    // Nem kontrolü
    controlHumidity(avgHum);
    
    // Motor kontrolü
    controlMotor(currentTime);
    
    // Ekranı güncelle
    updateMainDisplay(avgTemp, avgHum, currentDay);
}

void handleMainMenu(char key) {
    switch(key) {
        case '1':
            setupChicken();
            showMessage("Tavuk secildi\n21 gun");
            currentMenu = -1; // Normal çalışma moduna geç
            break;
        case '2':
            setupGoose();
            showMessage("Kaz secildi\n30 gun");
            currentMenu = -1; // Normal çalışma moduna geç
            break;
        case '3':
            setupQuail();
            showMessage("Bildircin secildi\n18 gun");
            currentMenu = -1; // Normal çalışma moduna geç
            break;
        case '4':
            setupManual();
            currentMenu = -1; // Normal çalışma moduna geç
            break;
        case '5':
            showSettingsMenu();
            currentMenu = MENU_SETTINGS;
            break;
    }
}

void handleNormalOperation(char key) {
    switch(key) {
        case 'A': // Sıcaklık artır
            settings.targetTemp += 0.1;
            if(settings.targetTemp > 39.0) settings.targetTemp = 39.0;
            saveState();
            break;
        case 'B': // Sıcaklık azalt
            settings.targetTemp -= 0.1;
            if(settings.targetTemp < 35.0) settings.targetTemp = 35.0;
            saveState();
            break;
        case 'C': // Nem artır
            settings.targetHum += 1.0;
            if(settings.targetHum > 85) settings.targetHum = 85;
            saveState();
            break;
        case 'D': // Nem azalt
            settings.targetHum -= 1.0;
            if(settings.targetHum < 30) settings.targetHum = 30;
            saveState();
            break;
        case '5': // Ayarlar menüsüne git
            showSettingsMenu();
            currentMenu = MENU_SETTINGS;
            break;
        case '6': // Manuel motor kontrolü
            testMotor();
            break;
    }
}

void handleSettingsMenu(char key) {
    switch(key) {
        case '1': // Sıcaklık
            lcd.clearDisplay();
            lcd.setCursor(0,0);
            lcd.println("Sicaklik (C):");
            lcd.setCursor(0,8);
            lcd.print("Mevcut: ");
            lcd.println(settings.targetTemp, 1);
            lcd.setCursor(0,16);
            lcd.println("Yeni Deger:");
            lcd.display();
            
            settings.targetTemp = getNumberInput();
            if(settings.targetTemp < 35.0) settings.targetTemp = 35.0;
            if(settings.targetTemp > 39.0) settings.targetTemp = 39.0;
            saveState();
            showSettingsMenu();
            break;
            
        case '2': // Nem
            lcd.clearDisplay();
            lcd.setCursor(0,0);
            lcd.println("Nem (%):");
            lcd.setCursor(0,8);
            lcd.print("Mevcut: ");
            lcd.println(settings.targetHum, 1);
            lcd.setCursor(0,16);
            lcd.println("Yeni Deger:");
            lcd.display();
            
            settings.targetHum = getNumberInput();
            if(settings.targetHum < 30) settings.targetHum = 30;
            if(settings.targetHum > 85) settings.targetHum = 85;
            saveState();
            showSettingsMenu();
            break;
            
        case '3': // Motor
            showMotorMenu();
            currentMenu = MENU_MOTOR;
            break;
            
        case '4': // Kalibrasyon
            showCalibrationMenu();
            currentMenu = MENU_CALIBRATION;
            break;
            
        case '5': // Sensör bilgileri
            showSensorInfo();
            break;
            
        case '6': // Resetleme seçeneği (Ayarlar menüsünde güvenli)
            askForReset();
            break;
            
        case '*': // Geri
            if (settings.type == 4) {
                showMainMenu();
                currentMenu = MENU_MAIN;
            } else {
                currentMenu = -1; // Normal çalışma moduna dön
                // Geri dönerken ekranı güncelle
                float avgTemp, avgHum;
                getAverageReadings(avgTemp, avgHum);
                uint32_t currentTime = getTimeFromRTC();
                int currentDay = (currentTime - settings.startTime) / 86400 + 1;
                if (currentDay <= 0 || currentDay > settings.totalDays) currentDay = 1;
                updateMainDisplay(avgTemp, avgHum, currentDay);
            }
            break;
    }
}

void handleMotorMenu(char key) {
    // Loglama ekle
    Serial.print("Motor Menu Key: ");
    Serial.println(key);
    
    switch(key) {
        case '1': // Aralık değiştir
            setMotorInterval();
            break;
            
        case '2': // Süre değiştir
            setMotorDuration();
            break;
            
        case '*': // Geri tuşu
            showSettingsMenu();
            currentMenu = MENU_SETTINGS;
            break;
    }
}

void handleCalibrationMenu(char key) {
    switch(key) {
        case '1': // Sıcaklık kalibrasyonu
            calibrateTemperature();
            break;
            
        case '2': // Nem kalibrasyonu
            calibrateHumidity();
            break;
            
        case '*': // Geri tuşu
            showSettingsMenu();
            currentMenu = MENU_SETTINGS;
            break;
    }
}

/* Motor ayar fonksiyonları */
void setMotorDuration() {
    lcd.clearDisplay();
    lcd.setCursor(0,0);
    lcd.println("Sure (sn):");
    lcd.setCursor(0,8);
    lcd.print("Mevcut: ");
    lcd.println(motorSettings.duration / 1000);
    lcd.setCursor(0,16);
    lcd.println("Yeni Deger:");
    lcd.display();
    
    float seconds = getNumberInput();
    if(seconds < 1) seconds = 1;
    if(seconds > 30) seconds = 30;
    
    motorSettings.duration = seconds * 1000;
    EEPROM.put(EEPROM_MOTOR_DURATION, motorSettings.duration);
    
    showMotorMenu();
}

void setMotorInterval() {
    lcd.clearDisplay();
    lcd.setCursor(0,0);
    lcd.println("Aralik (dk):");
    lcd.setCursor(0,8);
    lcd.print("Mevcut: ");
    lcd.println(motorSettings.interval / 60000);
    lcd.setCursor(0,16);
    lcd.println("Yeni Deger:");
    lcd.display();
    
    float minutes = getNumberInput();
    if(minutes < 60) minutes = 60;
    if(minutes > 480) minutes = 480;
    
    motorSettings.interval = minutes * 60000;
    EEPROM.put(EEPROM_MOTOR_INTERVAL, motorSettings.interval);
    
    showMotorMenu();
}

void setupChicken() {
    settings.type = 0;
    settings.targetTemp = 37.8;  // Başlangıç sıcaklığı 37.8°C
    settings.targetHum = 65;     // Başlangıç nemi %65
    settings.totalDays = 21;
    settings.startTime = getTimeFromRTC();
    settings.motorActive = true;
    settings.heaterState = false;
    settings.humidifierState = false;
    saveState();
}

void setupGoose() {
    settings.type = 1;
    settings.targetTemp = 37.7;  // Başlangıç sıcaklığı 37.7°C
    settings.targetHum = 60;     // Başlangıç nemi %60
    settings.totalDays = 30;
    settings.startTime = getTimeFromRTC();
    settings.motorActive = true;
    settings.heaterState = false;
    settings.humidifierState = false;
    saveState();
}

void setupQuail() {
    settings.type = 2;
    settings.targetTemp = 37.7;  // Başlangıç sıcaklığı 37.7°C
    settings.targetHum = 65;     // Başlangıç nemi %65
    settings.totalDays = 18;
    settings.startTime = getTimeFromRTC();
    settings.motorActive = true;
    settings.heaterState = false;
    settings.humidifierState = false;
    saveState();
}

void setupManual() {
    settings.type = 3;
    
    lcd.clearDisplay();
    lcd.setCursor(0,0);
    lcd.println("Manuel Ayar");
    lcd.setCursor(0,8);
    lcd.println("Sicaklik (C):");
    lcd.display();
    
    float temp = getNumberInput();
    if(temp < 35.0) temp = 35.0;
    if(temp > 39.0) temp = 39.0;
    settings.targetTemp = temp;
    
    lcd.clearDisplay();
    lcd.setCursor(0,0);
    lcd.println("Nem (%):");
    lcd.display();
    float hum = getNumberInput();
    if(hum < 30) hum = 30;
    if(hum > 85) hum = 85;
    settings.targetHum = hum;
    
    lcd.clearDisplay();
    lcd.setCursor(0,0);
    lcd.println("Gun Sayisi:");
    lcd.display();
    int days = (int)getNumberInput();
    if(days < 1) days = 1;
    if(days > 60) days = 60;
    settings.totalDays = days;
    
    settings.startTime = getTimeFromRTC();
    settings.motorActive = true;
    settings.heaterState = false;
    settings.humidifierState = false;
    saveState();
}

void resetSystem() {
    settings.type = 4;
    saveState();
    showMainMenu();
}

void askForReset() {
    lcd.clearDisplay();
    lcd.setTextSize(1);
    lcd.setCursor(0,0);
    lcd.println("Sifirlama?");
    lcd.println("#-Evet *-Hayir");
    lcd.display();
    
    while(true) {
        char key = getKey();
        if(key == '#') {
            settings.type = 4;
            saveState();
            showMainMenu();
            currentMenu = MENU_MAIN;
            break;
        }
        else if(key == '*') {
            showSettingsMenu();
            currentMenu = MENU_SETTINGS;
            break;
        }
        
        // Watchdog resetleme
        wdt_reset();
    }
}

void checkAndUpdateSettings(int currentDay) {
    switch(settings.type) {
        case 0: // Tavuk
            if (currentDay >= 19) {
                settings.targetTemp = 37.5;  // Son 3 gün sıcaklık 37.5°C
                settings.targetHum = 75;     // Son 3 gün nem %75
                settings.motorActive = false;
            }
            break;
        case 1: // Kaz
            if (currentDay >= 27) {
                settings.targetTemp = 37.5;  // Son 4 gün sıcaklık 37.5°C
                settings.targetHum = 80;     // Son 4 gün nem %80
                settings.motorActive = false;
            }
            break;
        case 2: // Bıldırcın
            if (currentDay >= 16) {
                settings.targetTemp = 37.5;  // Son 3 gün sıcaklık 37.5°C
                settings.targetHum = 75;     // Son 3 gün nem %75
                settings.motorActive = false;
            }
            break;
    }
}

void controlTemperature(float currentTemp) {
    if(!errorMgr.safeMode) {
        if(currentTemp < (settings.targetTemp - TEMP_HYSTERESIS)) {
            digitalWrite(RELAY1, HIGH);
            settings.heaterState = true;
        }
        else if(currentTemp > (settings.targetTemp + TEMP_HYSTERESIS)) {
            digitalWrite(RELAY1, LOW);
            settings.heaterState = false;
        }
        // Histerezis aralığında durumu değiştirme
    }
}

void controlHumidity(float currentHum) {
    if(!errorMgr.safeMode) {
        if(currentHum < (settings.targetHum - HUM_HYSTERESIS)) {
            digitalWrite(RELAY2, HIGH);
            settings.humidifierState = true;
        }
        else if(currentHum > (settings.targetHum + HUM_HYSTERESIS)) {
            digitalWrite(RELAY2, LOW);
            settings.humidifierState = false;
        }
        // Histerezis aralığında durumu değiştirme
    }
}

void controlMotor(uint32_t currentTime) {
    if (!settings.motorActive || errorMgr.safeMode) return;
    
    unsigned long currentMillis = millis();
    if (currentMillis - previousMillis >= motorSettings.interval) {
        digitalWrite(RELAY4, HIGH);
        
        // Motor çalışma süresi
        lcd.clearDisplay();
        lcd.setCursor(0,0);
        lcd.println("Motor");
        lcd.println("Donduruluyor...");
        lcd.display();
        
        delay(motorSettings.duration);
        
        digitalWrite(RELAY4, LOW);
        previousMillis = currentMillis;
    }
}

void testMotor() {
    if(errorMgr.safeMode) {
        showMessage("Guvenli Mod!\nMotor Pasif");
        return;
    }
    
    lcd.clearDisplay();
    lcd.setCursor(0,0);
    lcd.println("Motor Test");
    lcd.println("Calistiriliyor...");
    lcd.display();
    
    digitalWrite(RELAY4, HIGH);
    delay(1000);
    digitalWrite(RELAY4, LOW);
    
    showMessage("Motor Testi\nTamamlandi");
}

SensorData readSHT31_1() {
    SensorData data;
    data.temp = sht31_1.readTemperature() + settings.tempOffset;
    data.hum = sht31_1.readHumidity() + settings.humOffset;
    data.isValid = (!isnan(data.temp) && !isnan(data.hum) &&
                     data.temp > -10 && data.temp < 60 &&
                     data.hum >= 0 && data.hum <= 100);
    return data;
}

SensorData readSHT31_2() {
    SensorData data;
    data.temp = sht31_2.readTemperature() + settings.tempOffset;
    data.hum = sht31_2.readHumidity() + settings.humOffset;
    data.isValid = (!isnan(data.temp) && !isnan(data.hum) &&
                     data.temp > -10 && data.temp < 60 &&
                     data.hum >= 0 && data.hum <= 100);
    return data;
}

void getAverageReadings(float &avgTemp, float &avgHum) {
    SensorData sensor1 = readSHT31_1();
    SensorData sensor2 = readSHT31_2();
    
    if(sensor1.isValid && sensor2.isValid) {
        avgTemp = (sensor1.temp + sensor2.temp) / 2.0;
        avgHum = (sensor1.hum + sensor2.hum) / 2.0;
        
        // Sensörlerin farkı çok fazlaysa uyarı - fark eşiğini 15 dereceye yükselttik
        if(abs(sensor1.temp - sensor2.temp) > 15.0) {
            errorMgr.tempErrors++;
            if(errorMgr.tempErrors > MAX_ERRORS) {
                enterSafeMode("Sicaklik Fark!\nCok Fazla!");
            }
        } else {
            errorMgr.tempErrors = 0;
        }
    }
    else if(sensor1.isValid) {
        // Tek sensör çalışıyorsa hata sayacını artırma, normal çalışmaya devam et
        avgTemp = sensor1.temp;
        avgHum = sensor1.hum;
        // errorMgr.tempErrors++ satırını kaldırdık
    }
    else if(sensor2.isValid) {
        // Tek sensör çalışıyorsa hata sayacını artırma, normal çalışmaya devam et
        avgTemp = sensor2.temp;
        avgHum = sensor2.hum;
        // errorMgr.tempErrors++ satırını kaldırdık
    }
    else {
        // Tüm sensörler arızalıysa güvenli moda geç
        errorMgr.tempErrors++;
        if(errorMgr.tempErrors > MAX_ERRORS) {
            enterSafeMode("Tum Sensorler\nHatali!");
        }
        
        // Geçersiz değerler
        avgTemp = 0;
        avgHum = 0;
    }
}

int getMotorCountdown() {
    unsigned long timeSinceLastMotor = millis() - previousMillis;
    if(timeSinceLastMotor >= motorSettings.interval) return 0;
    
    return (motorSettings.interval - timeSinceLastMotor) / 60000;
}

void loadState() {
    // EEPROM'dan veri oku
    uint8_t storedType;
    EEPROM.get(EEPROM_TYPE, storedType); // Önce bir byte olarak oku
    
    // EEPROM ilk kez kullanılıyorsa veya geçersiz değer varsa
    if (storedType == 255 || storedType < 0 || storedType > 4) {
        settings.type = 4; // Sıfırlama durumu - kuluçka tipi seçimi
        settings.targetTemp = 37.5; // Varsayılan sıcaklık
        settings.targetHum = 65.0;  // Varsayılan nem
        settings.totalDays = 0;
        settings.startTime = 0;     // Başlangıç zamanı 0 olarak ayarla
        settings.motorActive = false;
        settings.heaterState = false;
        settings.humidifierState = false;
        settings.tempOffset = 0;
        settings.humOffset = 0;
        
        // Varsayılanları EEPROM'a kaydet
        EEPROM.put(EEPROM_TYPE, settings.type);
        EEPROM.put(EEPROM_START_TIME, settings.startTime);
        EEPROM.put(EEPROM_TEMP, settings.targetTemp);
        EEPROM.put(EEPROM_HUM, settings.targetHum);
        EEPROM.put(EEPROM_TEMP_OFFSET, settings.tempOffset);
        EEPROM.put(EEPROM_HUM_OFFSET, settings.humOffset);
        
        return;
    }
    
    // Geçerli bir kuluçka tipi varsa diğer ayarları oku
    settings.type = storedType;
    EEPROM.get(EEPROM_START_TIME, settings.startTime);
    EEPROM.get(EEPROM_TEMP, settings.targetTemp);
    EEPROM.get(EEPROM_HUM, settings.targetHum);
    EEPROM.get(EEPROM_TEMP_OFFSET, tempOffset);
    EEPROM.get(EEPROM_HUM_OFFSET, humOffset);
    settings.tempOffset = tempOffset;
    settings.humOffset = humOffset;
    
    // Tutarlılık kontrolü - değerler mantıklı aralıkta değilse düzelt
    if (settings.targetTemp < 30.0 || settings.targetTemp > 40.0) {
        settings.targetTemp = 37.5; // Varsayılan sıcaklık
    }
    
    if (settings.targetHum < 0.0 || settings.targetHum > 100.0) {
        settings.targetHum = 65.0; // Varsayılan nem
    }
    
    // RTC kontrolü - startTime çok eski veya gelecekte ise düzelt
    uint32_t currentTime = getTimeFromRTC();
    if (settings.startTime > currentTime || (currentTime - settings.startTime) > 86400 * 60) { // 60 günden eski ise
        // RTC ile ayarla
        settings.startTime = currentTime;
        EEPROM.put(EEPROM_START_TIME, settings.startTime);
    }
}

void loadMotorSettings() {
    EEPROM.get(EEPROM_MOTOR_DURATION, motorSettings.duration);
    EEPROM.get(EEPROM_MOTOR_INTERVAL, motorSettings.interval);
    
    // Geçersiz değerler için varsayılanları kullan
    if (motorSettings.duration < 1000 || motorSettings.duration > 30000) {
        motorSettings.duration = MOTOR_DURATION_DEFAULT;
    }
    if (motorSettings.interval < 3600000 || motorSettings.interval > 28800000) {
        motorSettings.interval = MOTOR_INTERVAL_DEFAULT;
    }
}

void saveState() {
    EEPROM.put(EEPROM_TYPE, settings.type);
    EEPROM.put(EEPROM_START_TIME, settings.startTime);
    EEPROM.put(EEPROM_TEMP, settings.targetTemp);
    EEPROM.put(EEPROM_HUM, settings.targetHum);
    EEPROM.put(EEPROM_TEMP_OFFSET, settings.tempOffset);
    EEPROM.put(EEPROM_HUM_OFFSET, settings.humOffset);
    
    // Checksum hesapla ve kaydet
    uint8_t checksum = calculateChecksum();
    EEPROM.put(EEPROM_CHECKSUM, checksum);
}

// Kalıcı durum kaydetme - sadece değişen verileri kaydet
void savePersistentState() {
    static uint8_t lastType = 255;
    static float lastTargetTemp = 0;
    static float lastTargetHum = 0;
    static unsigned long lastSaveTime = 0;
    
    // EEPROM'a çok sık yazma yapmamak için - en fazla 5 dakika arayla
    if (millis() - lastSaveTime < EEPROM_WRITE_INTERVAL) {
        return;
    }
    
    // Sadece değişen değerleri kaydet - EEPROM ömrünü uzatır
    if (settings.type != lastType) {
        EEPROM.put(EEPROM_TYPE, settings.type);
        lastType = settings.type;
    }
    
    if (abs(settings.targetTemp - lastTargetTemp) > 0.1) {
        EEPROM.put(EEPROM_TEMP, settings.targetTemp);
        lastTargetTemp = settings.targetTemp;
    }
    
    if (abs(settings.targetHum - lastTargetHum) > 0.1) {
        EEPROM.put(EEPROM_HUM, settings.targetHum);
        lastTargetHum = settings.targetHum;
    }
    
    // Sadece 6 saatte bir startTime güncelle (çok sık yazma yapma)
    static unsigned long lastTimeUpdate = 0;
    if (millis() - lastTimeUpdate > 21600000) { // 6 saat
        EEPROM.put(EEPROM_START_TIME, settings.startTime);
        lastTimeUpdate = millis();
    }
    
    lastSaveTime = millis();
}

// Checksum hesaplama
uint8_t calculateChecksum() {
    uint8_t checksum = 0;
    
    // settings içindeki kritik değerleri kullanarak basit bir checksum oluştur
    checksum += settings.type;
    checksum += (uint8_t)(settings.targetTemp * 10);
    checksum += (uint8_t)(settings.targetHum * 10);
    checksum += (uint8_t)(settings.totalDays);
    
    // Başlangıç zamanından da bir değer al
    checksum += (uint8_t)(settings.startTime & 0xFF);
    
    return checksum;
}

void showMainMenu() {
    lcd.clearDisplay();
    lcd.setTextSize(1);
    lcd.setCursor(0,0);
    lcd.println("Kulucka Tipi:");
    lcd.setCursor(0,8);
    lcd.println("1-Tavuk");
    lcd.setCursor(0,16);
    lcd.println("2-Kaz");
    lcd.setCursor(0,24);
    lcd.println("3-Bildircin");
    lcd.setCursor(0,32);
    lcd.println("4-Manuel");
    lcd.setCursor(0,40);
    lcd.println("5-Ayarlar");
    lcd.display();
}

void showSettingsMenu() {
    lcd.clearDisplay();
    lcd.setTextSize(1);
    lcd.setCursor(0,0);
    lcd.println("Ayarlar:");
    lcd.setCursor(0,8);
    lcd.println("1-Sicaklik");
    lcd.setCursor(0,16);
    lcd.println("2-Nem");
    lcd.setCursor(0,24);
    lcd.println("3-Motor");
    lcd.setCursor(0,32);
    lcd.println("4-Kalibrasyon");
    lcd.setCursor(0,40);
    lcd.println("5-Sens  6-Reset");
    lcd.display();
}

void showMotorMenu() {
    lcd.clearDisplay();
    lcd.setTextSize(1);
    lcd.setCursor(0,0);
    lcd.println("Motor Ayarlari:");
    lcd.setCursor(0,8);
    lcd.print("Aralik: ");
    lcd.print(motorSettings.interval / 60000);
    lcd.println(" dk");
    lcd.setCursor(0,16);
    lcd.print("Sure: ");
    lcd.print(motorSettings.duration / 1000);
    lcd.println(" sn");
    lcd.setCursor(0,24);
    lcd.println("1-Aralik D.");
    lcd.setCursor(0,32);
    lcd.println("2-Sure D.");
    lcd.display();
}

void showSensorInfo() {
    lcd.clearDisplay();
    lcd.setTextSize(1);
    lcd.setCursor(0,0);
    lcd.println("Sensor Bilgileri:");
    
    SensorData sensor1 = readSHT31_1();
    SensorData sensor2 = readSHT31_2();
    
    lcd.setCursor(0,8);
    lcd.print("S1: ");
    if (sensor1.isValid) {
        lcd.print(sensor1.temp, 1);
        lcd.print("C ");
        lcd.print(sensor1.hum, 1);
        lcd.print("%");
    } else {
        lcd.print("Hata!");
    }
    
    lcd.setCursor(0,16);
    lcd.print("S2: ");
    if (sensor2.isValid) {
        lcd.print(sensor2.temp, 1);
        lcd.print("C ");
        lcd.print(sensor2.hum, 1);
        lcd.print("%");
    } else {
        lcd.print("Hata!");
    }
    
    lcd.setCursor(0,24);
    lcd.print("Fark: ");
    if (sensor1.isValid && sensor2.isValid) {
        lcd.print(abs(sensor1.temp - sensor2.temp), 1);
        lcd.print("C ");
        lcd.print(abs(sensor1.hum - sensor2.hum), 1);
        lcd.print("%");
    } else {
        lcd.print("--");
    }
    
    lcd.display();
    
    // Tuş bekle
    while(true) {
        char key = getKey();
        if(key == '*') {
            showSettingsMenu();
            currentMenu = MENU_SETTINGS;
            break;
        }
        wdt_reset(); // Watchdog'u resetle
    }
}

void showCalibrationMenu() {
    lcd.clearDisplay();
    lcd.setTextSize(1);
    lcd.setCursor(0,0);
    lcd.println("Kalibrasyon:");
    
    lcd.setCursor(0,12);
    lcd.print("Sicaklik: ");
    lcd.print(settings.tempOffset, 1);
    lcd.println("C");
    
    lcd.setCursor(0,24);
    lcd.print("Nem: ");
    lcd.print(settings.humOffset, 1);
    lcd.println("%");
    
    lcd.setCursor(0,36);
    lcd.println("1-Sicak. 2-Nem Kal.");
    
    lcd.display();
}

void showMessage(const char* message) {
    lcd.clearDisplay();
    lcd.setTextSize(1);
    lcd.setCursor(0,16);
    lcd.println(message);
    lcd.display();
    delay(MESSAGE_DURATION);
}

void showError(const char* message) {
    lcd.clearDisplay();
    lcd.setTextSize(1);
    lcd.setCursor(0,0);
    lcd.println("HATA!");
    lcd.setCursor(0,16);
    lcd.println(message);
    lcd.display();
}

void updateMainDisplay(float temp, float hum, int currentDay) {
    lcd.clearDisplay();
    lcd.setTextSize(1);
    
    // Sıcaklık gösterimi
    lcd.setCursor(0,0);
    lcd.print("S:");
    if (temp < 100 && temp > -40) {
        lcd.print(temp, 1);
        lcd.print(settings.heaterState ? "+" : " ");
    } else {
        lcd.print("--.-");
    }
    lcd.print("/");
    lcd.print(settings.targetTemp, 1);
    lcd.print("C");
    
    // Nem gösterimi
    lcd.setCursor(0,8);
    lcd.print("N:");
    if (hum < 100 && hum >= 0) {
        lcd.print(hum, 1);
        lcd.print(settings.humidifierState ? "+" : " ");
    } else {
        lcd.print("--.-");
    }
    lcd.print("/");
    lcd.print(settings.targetHum, 1);
    lcd.print("%");
    
    // Gün ve tür gösterimi
    lcd.setCursor(0,16);
    lcd.print("G:");
    if (currentDay > 0 && currentDay <= settings.totalDays) {
        lcd.print(currentDay);
        lcd.print("/");
        lcd.print(settings.totalDays);
    } else {
        lcd.print("--/--");
    }
    
    lcd.setCursor(0,24);
    if (settings.type >= 0 && settings.type <= 3) {
        lcd.print(typeNames[settings.type]);
        
        // Motor zamanını göster
        if (settings.motorActive) {
            lcd.print(" M:");
            lcd.print(getMotorCountdown());
            lcd.print("dk");
        }
    }
    
    // Saat gösterimi
    DateTime now = rtc.now();
    lcd.setCursor(0,32);
    if (now.hour() < 10) lcd.print("0");
    lcd.print(now.hour());
    lcd.print(":");
    if (now.minute() < 10) lcd.print("0");
    lcd.print(now.minute());

    // Alt bilgi satırı - hangi sensörlerin aktif olduğunu göster
    lcd.setCursor(0,40);
    if (currentDay > 0 && currentDay <= settings.totalDays &&
        currentDay >= settings.totalDays - 2) {
        lcd.print("!SON GUNLER!");
    } else if (errorMgr.safeMode) {
        lcd.print("!GUVENLI MOD!");
    } else {
        // Aktif sensörleri göster
        SensorData sensor1 = readSHT31_1();
        SensorData sensor2 = readSHT31_2();
        lcd.print("S:");
        lcd.print(sensor1.isValid ? "1" : "-");
        lcd.print(sensor2.isValid ? "2" : "-");
        lcd.print(" 5-Menu 6-Motor");
    }
    
    lcd.display();
}

void updateBacklight() {
    unsigned long currentTime = millis();
    if (backlightState && (currentTime - lastKeyPressTime >= BACKLIGHT_TIMEOUT)) {
        digitalWrite(BACKLIGHT_PIN, LOW);
        backlightState = false;
    }
}

char getKey() {
    static unsigned long lastDebounceTime = 0;
    static char lastKey = 0;
    const unsigned long debounceDelay = 250; // Tuş sıçraması için daha kısa bekleme süresi
    
    char keys[4][4] = {
        {'1','2','3','A'},
        {'4','5','6','B'},
        {'7','8','9','C'},
        {'*','0','#','D'}
    };
    
    // Geçen son tuş basma süresini kontrol et
    unsigned long currentTime = millis();
    if (currentTime - lastDebounceTime < debounceDelay) {
        return 0; // Debounce süresi dolmadan yeni tuş algılamayı reddet
    }
    
    for(int i = 0; i < 4; i++) {
        digitalWrite(COL1 + i*2, LOW);
        for(int j = 0; j < 4; j++) {
            if(digitalRead(ROW1 + j*2) == LOW) {
                // Tuş basıldığında arka ışığı aç
                lastKeyPressTime = currentTime;
                if (!backlightState) {
                    digitalWrite(BACKLIGHT_PIN, HIGH);
                    backlightState = true;
                }
                
                digitalWrite(COL1 + i*2, HIGH);
                lastDebounceTime = currentTime; // Debounce zamanını güncelle
                return keys[j][i];
            }
        }
        digitalWrite(COL1 + i*2, HIGH);
    }
    return 0;
}

float getNumberInput() {
    String input = "";
    bool hasDecimal = false;
    
    while(true) {
        char key = getKey();
        if(key) {
            if(key >= '0' && key <= '9') {
                if(input.length() < 5) { // Maksimum 5 karakter
                    input += key;
                    lcd.print(key);
                    lcd.display();
                }
            }
            else if(key == '*' && !hasDecimal) {
                if(!input.length()) input = "0";
                input += '.';
                hasDecimal = true;
                lcd.print('.');
                lcd.display();
            }
            else if(key == '#' && input.length() > 0) {
                return input.toFloat();
            }
        }
        
        // Watchdog resetleme
        wdt_reset();
    }
}

void calibrateTemperature() {
    lcd.clearDisplay();
    lcd.setCursor(0,0);
    lcd.println("Sicaklik Kalibr.:");
    lcd.setCursor(0,8);
    lcd.println("Referans olcum:");
    lcd.display();
    
    float refTemp = getNumberInput();
    
    // Sensör değerlerini oku
    float avgTemp, avgHum;
    getAverageReadings(avgTemp, avgHum);
    
    // Offset hesapla
    float newOffset = refTemp - (avgTemp - settings.tempOffset);
    settings.tempOffset = newOffset;
    tempOffset = newOffset;
    
    EEPROM.put(EEPROM_TEMP_OFFSET, tempOffset);
    
    lcd.clearDisplay();
    lcd.setCursor(0,0);
    lcd.println("Kalibrasyon");
    lcd.println("Tamamlandi");
    lcd.setCursor(0,16);
    lcd.print("Yeni Offset: ");
    lcd.print(settings.tempOffset, 1);
    lcd.display();
    delay(2000);
    
    showCalibrationMenu();
}

void calibrateHumidity() {
    lcd.clearDisplay();
    lcd.setCursor(0,0);
    lcd.println("Nem Kalibr.:");
    lcd.setCursor(0,8);
    lcd.println("Referans olcum:");
    lcd.display();
    
    float refHum = getNumberInput();
    
    // Sensör değerlerini oku
    float avgTemp, avgHum;
    getAverageReadings(avgTemp, avgHum);
    
    // Offset hesapla
    float newOffset = refHum - (avgHum - settings.humOffset);
    settings.humOffset = newOffset;
    humOffset = newOffset;
    
    EEPROM.put(EEPROM_HUM_OFFSET, humOffset);
    
    lcd.clearDisplay();
    lcd.setCursor(0,0);
    lcd.println("Kalibrasyon");
    lcd.println("Tamamlandi");
    lcd.setCursor(0,16);
    lcd.print("Yeni Offset: ");
    lcd.print(settings.humOffset, 1);
    lcd.display();
    delay(2000);
    
    showCalibrationMenu();
}

void enterSafeMode(const char* errorMsg) {
    if (!errorMgr.safeMode) {
        errorMgr.safeMode = true;
        
        // Tüm çıkışları güvenli duruma al
        digitalWrite(RELAY1, LOW);  // Isıtıcıyı kapat
        digitalWrite(RELAY2, LOW);  // Nemlenidiriciyi kapat
        digitalWrite(RELAY4, LOW);  // Motoru kapat
        digitalWrite(RELAY3, HIGH); // Fanı çalıştır
        
        // Durumları güncelle
        settings.heaterState = false;
        settings.humidifierState = false;
        
        showError(errorMsg);
        
        // Hata durumunu EEPROM'a kaydet
        EEPROM.write(EEPROM_ERROR_FLAG, 1);
    }
}

Kod güncellemesiyle uğraştım biraz. Herhangi bir elektrik kesintisi veya sistem resetlenmesi/donması halinde kendini resetleyip kaldığı yerden devam edecek şekilde revize edildi.
Donanımdan kaynaklanabilecek sorunu bu şekilde biraz aşabileceğimi düşündüm.
Kablo düzenlemesi, röle beslemesini ayırmayı da yaptığımda daha stabil çalışır diye umuyorum.

Kodlama bilgim de yok, tamamen yapay zekaya yazdırıp proteusta simülasyon yaparak buraya kadar getirdim
 
role-karti-devre-semasi.png
Harici besleme için biraz kafam karıştı.
Gnd ler ortak olacak, burası tamam.
Vcc ve jd-vcc deki jumper i çıkarıp, harici 5v jd-vcc pinine bağlanacak. Vcc arduinodan gelen 5v ile bağlı kalacak mı?
Buradaki şemada böyle göstermiş.

Başka kaynaklarda iki pine de harici 5v verin diyen de var.

hangisi doğru bağlantı şekli olur?
 
41079 eklentisine bak
Harici besleme için biraz kafam karıştı.
Gnd ler ortak olacak, burası tamam.
Vcc ve jd-vcc deki jumper i çıkarıp, harici 5v jd-vcc pinine bağlanacak. Vcc arduinodan gelen 5v ile bağlı kalacak mı?
Buradaki şemada böyle göstermiş.

Başka kaynaklarda iki pine de harici 5v verin diyen de var.

hangisi doğru bağlantı şekli olur?
Kullandığınız röle kartının devre şemasına bakmak lazım. Ama bağlantı girişlerinin isimlerini görünecek şekilde fotoğraflasanız da anlaşılabilir. Ayrı beslemeye ihtiyaç kalmayabilir. Arduinoyu USB girişinden 5V ile beslediğinizde üzerindeki regülatör devre dışı kalır ve ısınma derdi olmaz, voltaj düşmez.

Eğer bu durumda da çalışmaz ise röleler açılır-kapanırken arduinonun resetleniyor olduğunu varsayarak röle kartının beslemesini ayrırsınız. Bununla beraber @triyak 'ın önerdiği gibi röle kartı bağlı değilken açık bekletmeyi deneyin, kodda bir hata olup da sorun çıkıyor da olabilir. Yani elinizdeki imkanlarla test ekipmanları kullanmadan bunları denemek çözüme götürebilir.

Röle kartını bir görmek lazım
1743099710888.png

jumper çıkarıldığında ve röle kartı harici besleme ile beslendiğinde GND'ler birleştirilmemeli.

@mkara Aslında Fotoğraftaki açıklama teknik olarak doğru değil. Jumper takılıyken optokuplör devre dışı değil, hala çalışıyor fakat izolasyon işlevini yerine getirmiyor. Jumper çıkarıldığındaki devre şemasında optokuplör aynı şekilde çalışıyor fakat bu sefer izolasyon da sağlanmış oluyor. Tabii bunun için röle kartı ve arduinonun 5V ve GND'leri birbirinden ayrıolmalı, yani izole kaynaklarla beslenmeli
 
Son düzenleme:
images (1).jpeg
Kullandığım röle kartı birebir olarak bu.
Arduinoyu 9v 1a adaptör ile besliyorum. Yaklaşık 15 saat rölesiz çalıştırdım resetleme yapmadı.
Röleleri beslemek için 5v 2a bir adaptör daha aldım şimdi.
Sinyallerin doğru gitmesi için gnd ler ortak bağlanmalı denmiş birkaç eğitim videosunda.

Yapay zekaya şöyle bir soru sordum;

"Jumper zaten aradaki bağlantıyı sağlamıyor mu? Neden jumper ı çıkartıp iki yerden besleme yapılıyor? Sadece vcc pinine harici 5v verip jumper takılı olduğu durumda jd-vcc pini de beslenmiş olmazmı"

Kod:
Bu soru çok iyi bir nokta. Aslında röle kartlarındaki jumper'ın işlevi tam olarak bu. Biraz daha açıklama gerekiyor.

Röle kartında:

1. VCC: Optokuplörler ve kontrol mantığı için güç girişi
2. JD-VCC: Röle bobinleri için güç girişi

Jumper'ın durumları:

1. Jumper TAKILI iken:
   - VCC'ye verilen güç, jumper üzerinden JD-VCC'ye de aktarılır
   - Yani sadece VCC'ye güç vermek yeterlidir
   - Bu durumda röle bobinleri ve kontrol mantığı aynı güç kaynağını paylaşır

2. Jumper ÇIKARILDIĞINDA:
   - VCC ve JD-VCC arasında bağlantı kesilir
   - Her ikisine de ayrı ayrı güç verilmesi gerekir
   - Bu durumda tam izolasyon sağlanır

Kullanıcının sorusu tamamen haklı. Eğer harici beslemeyi sadece VCC'ye bağlayıp jumper'ı takılı bırakırsak, hem kontrol mantığı hem de röle bobinleri beslenmiş olur.

Ancak jumper'ı çıkarmamız ve iki beslemeden bahsetmemizin nedeni, genel olarak bu tür röle kartlarıyla çalışırken iki farklı güç seviyesine ihtiyaç duyulabilmesidir:

1. Mantık seviyesi: 3.3V veya 5V (VCC'ye bağlanır)
2. Röle bobinleri: Genellikle 5V veya 12V (JD-VCC'ye bağlanır)

Bazı durumlarda, mantık girişi için Arduino'nun 3.3V'unu kullanırken, röle bobinleri için 5V veya 12V kullanmak isteyebilirsiniz. Bu durumda jumper'ı çıkarıp farklı besleme yapmak gerekir.

Ancak bu kullanıcının durumunda, tüm sistem 5V seviyesinde çalışacağı için, kullanıcının dediği tamamen doğru:

> Sadece VCC pinine harici 5V verip jumper takılı olduğu durumda JD-VCC pini de beslenmiş olur.

Bu şekilde de bağlantı çalışır ve daha basittir. Tek dezavantajı, bu yapılandırmada Arduino ve röle bobinleri arasında tam izolasyon olmayacak olmasıdır, ama her şey aynı harici güç kaynağından beslendiği için bu genellikle sorun olmaz.

# Röle Kartı Jumper ve Besleme Bağlantısı Açıklaması

Haklısınız! Bu önemli bir noktayı açıklığa kavuşturmuş oldunuz.

## Jumper'ın İşlevi ve Besleme Seçenekleri

Röle kartındaki jumper tam olarak bu amaçla var - VCC ve JD-VCC arasında bağlantı sağlamak için.

### Seçenek 1: Jumper TAKILI (Basit Bağlantı)
- Sadece VCC pinine harici 5V bağlanır
- Jumper, VCC'den JD-VCC'ye güç aktarır
- **Tek besleme noktası** yeterlidir
- Bu durumda röle kontrol mantığı ve bobinleri aynı kaynaktan beslenir

### Seçenek 2: Jumper ÇIKARILMIŞ (Tam İzolasyon)
- VCC ve JD-VCC arasında bağlantı kesilir
- Her ikisine de ayrı ayrı güç verilmesi gerekir
- Bu genellikle farklı voltaj seviyeleri gerektiren durumlarda kullanılır:
  * VCC: 3.3V (düşük güç mantık devreleri için)
  * JD-VCC: 5V veya 12V (röle bobinleri için)

## Sizin Durumunuzda En İyi Çözüm

Eğer tüm sisteminiz 5V seviyesinde çalışacaksa (Arduino ve röle bobinleri aynı voltaj), o zaman **sizin önerdiğiniz şekilde** bağlantı yapmak tamamen doğru ve daha basittir:

1. VCC pinine harici 5V bağlayın
2. Jumper'ı TAKILI bırakın
3. GND pinini Arduino GND ve harici besleme GND ile bağlayın

Bu yapılandırma:
- Daha az kablo gerektirir
- Kurulumu basitleştirir
- Aynı güç seviyesi (5V) kullanıldığı için sorun oluşturmaz

## Neden Bazen Jumper Çıkarılır?

Jumper genellikle şu durumlarda çıkarılır:
- Farklı voltaj seviyeleri kullanılacaksa (3.3V mantık, 5V/12V röle)
- Yüksek elektromanyetik gürültü olan ortamlarda tam izolasyon gerekiyorsa
- Çok hassas analog ölçümler yapan sistemlerde gürültü azaltmak için

Kuluçka makineniz için, jumper takılı kalabilir ve sadece VCC'ye harici 5V bağlamanız yeterli olacaktır. Bu, daha basit ve tamamen uygun bir çözümdür.
 
Yapay zekayı boşver. Biraz ısrar etsen halanın erkek olduğunu kabul ettirebilirsin.

>>GND'ler izole kullanımda birleştirilmemeli<< aksi taktirde izolasyon olmamış oluyor, röleler yine çalışır orası ayrı.

Fotoğraflarda tarif edilen kullanım şekli doğru. Ama eğer kodlamadan kaynaklanmıyorsa. tek 5V besleme ile kullanabileceğini düşünüyorum.
 
1.jpg2.jpg3.jpg4.jpg

Bayramda tatili fırsat görerek projeyi çalışır hale getirebildim. 4 gündür stabil olarak çalışıyor.
Röle beslemesini ayrı bir adaptörden verdim, donmalar tamamen düzeldi (şuana kadar sorun yok).
Elektrik kesilmesi veya sistem donup kendine reset atsa bile kaldığı yerden devam edecek şekilde düzenlendi.
Sıcaklık ve nemin eşit olması için havalandırma delikleri fan hızı vs ayarlandı.
Sensörleri kalibre etmek için 2 adet basit dijital, 2 adet cıvalı termometre kullandım. Dijitaller ortalama 1,5 derece düşük ölçüyor gibi geldi.
Bu hafta sonu yumurta yüklemesi yapmayı planlıyorum. Yaklaşık 25 gün sonra durum güncellemesi paylaşırım.
Son yüklediğim kodu da buraya ekliyorum. Belki yapmak, geliştirmek isteyen kullanabilir.
Şöyle yapsan daha iyi olurdu gibi fikirlere açığım.
C++:
#include <Wire.h>
#include <Adafruit_PCD8544.h>
#include <Adafruit_SHT31.h>
#include <RTClib.h>
#include <EEPROM.h>
#include <avr/wdt.h>

// Pin tanımlamaları
#define RELAY1 5        // Isıtıcı
#define RELAY2 6        // Nemlendirici
#define RELAY3 7        // Fan
#define RELAY4 8        // Motor
#define ROW1 22         // Tuş takımı satır 1
#define ROW2 24         // Tuş takımı satır 2
#define ROW3 26         // Tuş takımı satır 3
#define ROW4 28         // Tuş takımı satır 4
#define COL1 30         // Tuş takımı sütun 1
#define COL2 32         // Tuş takımı sütun 2
#define COL3 34         // Tuş takımı sütun 3
#define COL4 36         // Tuş takımı sütun 4
#define BACKLIGHT_PIN A5 // LCD Arka ışık

// SHT31 Sensör adresleri
#define SHT31_1_ADDR 0x44  // İlk sensör I2C adresi
#define SHT31_2_ADDR 0x45  // İkinci sensör I2C adresi

// EEPROM adres haritası - Güncellendi: Her sensör için ayrı offset adresleri
#define EEPROM_TYPE 0           // Kuluçka tipi (1 byte)
#define EEPROM_START_TIME 1     // Başlangıç zamanı (4 byte)
#define EEPROM_TEMP 5           // Hedef sıcaklık (4 byte)
#define EEPROM_HUM 9            // Hedef nem (4 byte)
#define EEPROM_ERROR_FLAG 13    // Hata durumu (1 byte)
#define EEPROM_TEMP_OFFSET1 14  // Sensör 1 Sıcaklık offset (4 byte)
#define EEPROM_HUM_OFFSET1 18   // Sensör 1 Nem offset (4 byte)
#define EEPROM_TEMP_OFFSET2 22  // Sensör 2 Sıcaklık offset (4 byte)
#define EEPROM_HUM_OFFSET2 26   // Sensör 2 Nem offset (4 byte)
#define EEPROM_MOTOR_DURATION 30 // Motor çalışma süresi (4 byte)
#define EEPROM_MOTOR_INTERVAL 34 // Motor çalışma aralığı (4 byte)
#define EEPROM_CHECKSUM 38      // Veri doğrulama (1 byte)
#define EEPROM_LAST_POWER_TIME 42 // Son güç kesintisi zamanı (4 byte)

// Zaman yedekleme adresleri - YENİ
#define EEPROM_START_TIME_BACKUP1 100  // Başlangıç zamanı yedek 1 (4 byte)
#define EEPROM_START_TIME_BACKUP2 104  // Başlangıç zamanı yedek 2 (4 byte)

// Menü durumları
#define MENU_MAIN 0          // Ana menü
#define MENU_SETTINGS 1      // Ayarlar menüsü
#define MENU_MOTOR 2         // Motor ayarları menüsü
#define MENU_SENSORS 3       // Sensör bilgileri menüsü
#define MENU_CALIBRATION 4   // Kalibrasyon menüsü

// Kontrol parametreleri
#define TEMP_HYSTERESIS 0.3  // Sıcaklık kontrolü için histerezis (0.3°C)
#define HUM_HYSTERESIS 2.0   // Nem kontrolü için histerezis (%2)
#define DEBOUNCE_DELAY 250   // Tuş kontrolü için debounce süresi (250ms)

// Zaman sabitleri
const unsigned long MOTOR_INTERVAL_DEFAULT = 7200000; // Motor dönüş aralığı (2 saat)
const unsigned long MOTOR_DURATION_DEFAULT = 3000;    // Motor çalışma süresi (3 saniye)
const unsigned long BACKLIGHT_TIMEOUT = 10000;        // Arka ışık kapanma süresi (10 saniye)
const unsigned long MESSAGE_DURATION = 2000;          // Mesaj gösterim süresi (2 saniye)
const unsigned long EEPROM_WRITE_INTERVAL = 300000;   // EEPROM yazma aralığı (5 dakika)

// Hata yönetimi için sabitler
#define MAX_ERRORS 3          // Maksimum ardışık hata sayısı
#define SENSOR_TIMEOUT 5000   // Sensör okuma zaman aşımı (ms)
#define DEBUG true            // Debug modu açık/kapalı

// Veri yapıları
struct SensorData {
    float temp;         // Sıcaklık değeri
    float hum;          // Nem değeri
    bool isValid;       // Sensör verisi geçerli mi?
};

struct MotorSettings {
    unsigned long duration;  // Motor çalışma süresi
    unsigned long interval;  // Motor çalışma aralığı
};

struct IncubatorSettings {
    int type;               // Kuluçka tipi (0:Tavuk, 1:Kaz, 2:Bıldırcın, 3:Manuel, 4:Sıfırlama)
    float targetTemp;       // Hedef sıcaklık
    float targetHum;        // Hedef nem
    int totalDays;          // Toplam kuluçka süresi
    uint32_t startTime;     // Başlangıç zamanı (time_t yerine uint32_t kullanıyoruz)
    bool motorActive;       // Motor aktif mi?
    bool heaterState;       // Isıtıcı durumu
    bool humidifierState;   // Nemlendirici durumu
    
    // Her sensör için ayrı offset değerleri
    float tempOffset1;      // Sıcaklık kalibrasyon offseti sensör 1
    float tempOffset2;      // Sıcaklık kalibrasyon offseti sensör 2
    float humOffset1;       // Nem kalibrasyon offseti sensör 1
    float humOffset2;       // Nem kalibrasyon offseti sensör 2
};

struct ErrorManager {
    int tempErrors;         // Sıcaklık sensörü hata sayacı
    int humErrors;          // Nem sensörü hata sayacı
    int rtcErrors;          // RTC hata sayacı
    unsigned long lastSensorRead;   // Son sensör okuma zamanı
    unsigned long lastEEPROMWrite;  // Son EEPROM yazma zamanı
    bool safeMode;          // Güvenli mod aktif mi?
    
    ErrorManager() {
        tempErrors = 0;
        humErrors = 0;
        rtcErrors = 0;
        lastSensorRead = 0;
        lastEEPROMWrite = 0;
        safeMode = false;
    }
    
    void resetErrors() {
        tempErrors = 0;
        humErrors = 0;
        rtcErrors = 0;
    }
    
    bool checkSensor(float value, float min, float max) {
        if (isnan(value) || value < min || value > max) {
            return false;
        }
        return true;
    }
};

//-------------- GLOBAL DEĞİŞKENLER --------------//
// Donanım nesneleri
Adafruit_PCD8544 lcd(A0, A1, A2, A3, A4);  // LCD ekran
Adafruit_SHT31 sht31_1 = Adafruit_SHT31();  // İlk SHT31 sensörü
Adafruit_SHT31 sht31_2 = Adafruit_SHT31();  // İkinci SHT31 sensörü
RTC_DS3231 rtc;                             // RTC modülü

// Kuluçka tipi isimleri
const char* typeNames[] = {"Tavuk", "Kaz", "Bildircin", "Manuel"};

// Global değişkenler
IncubatorSettings settings;           // Kuluçka ayarları
MotorSettings motorSettings;          // Motor ayarları
ErrorManager errorMgr;                // Hata yöneticisi
int currentMenu = MENU_MAIN;          // Mevcut menü durumu
bool inSubMenu = false;               // Alt menüde miyiz?
unsigned long lastKeyPressTime = 0;   // Son tuş basma zamanı
unsigned long lastDebounceTime = 0;   // Son debounce zamanı
bool backlightState = false;          // Arka ışık durumu
unsigned long previousMillis = 0;     // Önceki millis değeri
char lastKey = 0;                     // Son basılan tuş

// Her sensör için ayrı offset değişkenleri
float tempOffset1 = 0.0;              // Sensör 1 sıcaklık kalibrasyon offseti
float humOffset1 = 0.0;               // Sensör 1 nem kalibrasyon offseti
float tempOffset2 = 0.0;              // Sensör 2 sıcaklık kalibrasyon offseti
float humOffset2 = 0.0;               // Sensör 2 nem kalibrasyon offseti

bool isFirstMotorActivation = true;   // İlk motor aktivasyonu için bayrak
char messageBuffer[40];               // Mesaj tamponlama için

// Fonksiyon prototipleri
void handleMainMenu(char key);
void handleSettingsMenu(char key);
void handleMotorMenu(char key);
void handleCalibrationMenu(char key);
void handleNormalOperation(char key);
void showMainMenu();
void showSettingsMenu();
void showMotorMenu();
void showSensorInfo();
void showCalibrationMenu();
void showMessage(const char* message);
void showError(const char* message);
void setupChicken();
void setupGoose();
void setupQuail();
void setupManual();
void resetSystem();
void askForReset();
void saveState();
void savePersistentState();
void loadState();
void loadMotorSettings();
uint8_t calculateChecksum();
void updateSensorsAndControl();
void updateMainDisplay(float temp, float hum, int currentDay);
void updateBacklight();
void testMotor();
void controlMotor(uint32_t currentTime);
void controlTemperature(float currentTemp);
void controlHumidity(float currentHum);
void checkAndUpdateSettings(int currentDay);
void getAverageReadings(float &avgTemp, float &avgHum);
char getKey();
float getNumberInput();
void enterSafeMode(const char* errorMsg);
void handlePowerFailure();
void debugPrint(const char* message);
void debugPrint(const char* message, int value);
void debugPrint(const char* message, float value);
void debugPrint(const char* message, uint32_t value);
void resetAllOffsets();
void saveTimeWithBackup(uint32_t timeToSave);
uint32_t getStartTimeFromEEPROM();

// Yeni prototip fonksiyonlar - her sensör için ayrı kalibrasyon
void calibrateTemperature1();
void calibrateHumidity1();
void calibrateTemperature2();
void calibrateHumidity2();

SensorData readSHT31_1();
SensorData readSHT31_2();
uint32_t getTimeFromRTC();
int getMotorCountdown();
void setMotorDuration();
void setMotorInterval();

// Saat çevirimi için yardımcı fonksiyon - time_t yerine uint32_t kullanıyoruz
uint32_t getTimeFromRTC() {
    DateTime now = rtc.now();
    return now.unixtime();  // .get() yerine .unixtime() kullanıyoruz
}

// Debug mesajları için yardımcı fonksiyonlar
void debugPrint(const char* message) {
    if (DEBUG) {
        Serial.println(message);
    }
}

void debugPrint(const char* message, int value) {
    if (DEBUG) {
        Serial.print(message);
        Serial.println(value);
    }
}

void debugPrint(const char* message, float value) {
    if (DEBUG) {
        Serial.print(message);
        Serial.println(value);
    }
}

void debugPrint(const char* message, uint32_t value) {
    if (DEBUG) {
        Serial.print(message);
        Serial.println(value);
    }
}

// 4. Zamanı güvenli bir şekilde kaydetmek için özel fonksiyon
// Başlangıç zamanını 3 farklı adreste yedekleyerek kaydeder
void saveTimeWithBackup(uint32_t timeToSave) {
    Serial.print("Zaman kaydediliyor: ");
    Serial.println(timeToSave);
    
    // Ana konum + 2 yedek konuma kaydet
    EEPROM.put(EEPROM_START_TIME, timeToSave);
    delay(10);
    wdt_reset();
    
    EEPROM.put(EEPROM_START_TIME_BACKUP1, timeToSave);
    delay(10);
    wdt_reset();
    
    EEPROM.put(EEPROM_START_TIME_BACKUP2, timeToSave);
    delay(10);
    wdt_reset();
    
    // Doğrulama
    uint32_t readBack;
    EEPROM.get(EEPROM_START_TIME, readBack);
    
    if (readBack != timeToSave) {
        Serial.println("UYARI: Zaman kaydı doğrulanamadı!");
    } else {
        Serial.println("Zaman başarıyla kaydedildi ve doğrulandı.");
    }
}

// 5. Yedeklerden doğru zamanı almak için güçlendirilmiş fonksiyon
uint32_t getStartTimeFromEEPROM() {
    uint32_t time1, time2, time3;
    
    EEPROM.get(EEPROM_START_TIME, time1);
    EEPROM.get(EEPROM_START_TIME_BACKUP1, time2);
    EEPROM.get(EEPROM_START_TIME_BACKUP2, time3);
    
    Serial.print("Okunan zamanlar - Ana: ");
    Serial.print(time1);
    Serial.print(", Yedek1: ");
    Serial.print(time2);
    Serial.print(", Yedek2: ");
    Serial.println(time3);
    
    uint32_t currentTime = getTimeFromRTC();
    Serial.print("Şimdiki zaman: ");
    Serial.println(currentTime);
    
    // Üç zamandan en az ikisi aynı ise, bu zamanı kullan
    if (time1 == time2 || time1 == time3) return time1;
    if (time2 == time3) return time2;
    
    // Zamanlar tutarsız, geçerli görünen zamanı döndür
    if (time1 > 1577836800 && time1 < currentTime) return time1; // 2020'den sonra ve şimdiden önce
    if (time2 > 1577836800 && time2 < currentTime) return time2;
    if (time3 > 1577836800 && time3 < currentTime) return time3;
    
    // Hiçbiri geçerli değilse, 0 döndür
    return 0;
}

void setup() {
    Serial.begin(9600);
    debugPrint("Kuluçka Makinesi Başlatılıyor...");
    
    Wire.begin();
    
    // Pin modlarını ayarla
    pinMode(RELAY1, OUTPUT);
    pinMode(RELAY2, OUTPUT);
    pinMode(RELAY3, OUTPUT);
    pinMode(RELAY4, OUTPUT);
    pinMode(ROW1, INPUT_PULLUP);
    pinMode(ROW2, INPUT_PULLUP);
    pinMode(ROW3, INPUT_PULLUP);
    pinMode(ROW4, INPUT_PULLUP);
    pinMode(COL1, OUTPUT);
    pinMode(COL2, OUTPUT);
    pinMode(COL3, OUTPUT);
    pinMode(COL4, OUTPUT);
    pinMode(BACKLIGHT_PIN, OUTPUT);

    // Başlangıç durumları - DEĞİŞTİRİLDİ: LOW/HIGH tersine çevrildi
    digitalWrite(RELAY1, HIGH);  // Isıtıcı kapalı
    digitalWrite(RELAY2, HIGH);  // Nemlendirici kapalı
    digitalWrite(RELAY3, LOW);   // Fanlar sürekli çalışacak
    digitalWrite(RELAY4, HIGH);  // Motor kapalı
    digitalWrite(BACKLIGHT_PIN, LOW); // Arka ışık kapalı

    // Röle durumlarını sıfırla
    settings.heaterState = false;
    settings.humidifierState = false;

    // LCD başlatma
    lcd.begin();
    lcd.setContrast(50);
    lcd.clearDisplay();
    lcd.setTextSize(1);
    lcd.setCursor(0,0);
    lcd.println("Kulucka");
    lcd.println("Makinesi v2.4");
    lcd.println("Baslatiliyor...");
    lcd.display();
    delay(2000);
    
    // Sensörleri başlat
    if (!sht31_1.begin(SHT31_1_ADDR)) {
        showError("Sensor 1 Hata!");
        debugPrint("Sensor 1 başlatılamadı!");
        delay(2000);
    }
    
    if (!sht31_2.begin(SHT31_2_ADDR)) {
        showError("Sensor 2 Hata!");
        debugPrint("Sensor 2 başlatılamadı!");
        delay(2000);
    }
    
    // Sensör heater'larını kapat
    sht31_1.heater(false);
    sht31_2.heater(false);
    
    // RTC başlatma - düzeltilmiş
    if (!rtc.begin()) {
        showError("RTC Hatasi!");
        debugPrint("RTC başlatılamadı!");
        delay(2000);
    }

    // RTC pil kontrolü
    if (rtc.lostPower()) {
        showError("RTC Pil Zayif!");
        debugPrint("RTC pil zayıf, tarih ayarlanıyor");
        delay(2000);
        rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
    }

    // EEPROM'dan ayarları yükle
    loadState();
    
    // Motor ayarlarını yükle
    loadMotorSettings();
    
    // EEPROM yüklendikten sonra debug bilgisi
    debugPrint("Yüklenen ayarlar:");
    debugPrint("Tip:", settings.type);
    debugPrint("Başlangıç zamanı:", settings.startTime);
    debugPrint("Güncel RTC zamanı:", getTimeFromRTC());
    debugPrint("Hedef sıcaklık:", settings.targetTemp);
    debugPrint("Hedef nem:", settings.targetHum);
    
    // Güç kesintisi kontrolü
    handlePowerFailure();
    
    // İlk açılışta menüyü göster
    if (settings.type == 4 || settings.type == 255) {
        settings.type = 4;
        showMainMenu();
        currentMenu = MENU_MAIN;
        isFirstMotorActivation = false; // Ana menüde motor aktivasyonu yok
    } else {
        // Normal çalışma modunda, ilk ekranı güncelle
        float avgTemp = 0.0, avgHum = 0.0;
        SensorData sensor1 = readSHT31_1();
        SensorData sensor2 = readSHT31_2();
        
        if (sensor1.isValid && sensor2.isValid) {
            avgTemp = (sensor1.temp + sensor2.temp) / 2.0;
            avgHum = (sensor1.hum + sensor2.hum) / 2.0;
        } else if (sensor1.isValid) {
            avgTemp = sensor1.temp;
            avgHum = sensor1.hum;
        } else if (sensor2.isValid) {
            avgTemp = sensor2.temp;
            avgHum = sensor2.hum;
        }
        
        uint32_t currentTime = getTimeFromRTC();
        int currentDay = 1; // Varsayılan olarak 1. gün
        
        if (settings.startTime > 0 && currentTime > settings.startTime) {
            currentDay = (currentTime - settings.startTime) / 86400 + 1;
            if (currentDay > settings.totalDays) {
                currentDay = settings.totalDays;
            }
        }
        
        // Aktif kuluçka bilgisi göster
        lcd.clearDisplay();
        lcd.setTextSize(1);
        lcd.setCursor(0,0);
        lcd.println("Kulucka Aktif");
        lcd.setCursor(0,16);
        sprintf(messageBuffer, "Gun: %d/%d", currentDay, settings.totalDays);
        lcd.println(messageBuffer);
        lcd.setCursor(0,32);
        lcd.println("Devam ediyor...");
        lcd.display();
        delay(2000);
        
        updateMainDisplay(avgTemp, avgHum, currentDay);
        currentMenu = -1; // Normal çalışma modu
        
        // Güç kesintisi sonrası ilk dönüşü iptal et
        if (millis() < 3000) { // Sistem yeni açıldıysa (3 saniyeden az çalışıyorsa)
            isFirstMotorActivation = true; // İlk dönüşü aktifleştir
            previousMillis = 0; // Motor zamanını sıfırla
            debugPrint("Güç kesintisi sonrası, ilk motor dönüşü aktifleştirildi");
        } else {
            isFirstMotorActivation = false; // Normal zamanlı dönüşlere devam et
        }
    }
    
    // Son güç zamanını kaydet
    uint32_t currentTime = getTimeFromRTC();
    EEPROM.put(EEPROM_LAST_POWER_TIME, currentTime);
    
    // Watchdog timer başlat - 8 saniye
    wdt_enable(WDTO_8S);
    debugPrint("Watchdog timer aktifleştirildi (8s)");
}

void loop() {
    // Watchdog timer'ı sıfırla
    wdt_reset();
    
    // Arka ışık kontrolü
    updateBacklight();
    
    // Tuş kontrolü
    char key = getKey();
    
    // Menü durumunu kontrol et
    if (currentMenu == MENU_SETTINGS) {
        if(key) {
            handleSettingsMenu(key);
        }
    }
    else if (currentMenu == MENU_MOTOR) {
        if(key) {
            handleMotorMenu(key);
        }
    }
    else if (currentMenu == MENU_CALIBRATION) {
        if(key) {
            handleCalibrationMenu(key);
        }
    }
    // Ana menü modu
    else if (settings.type == 4 || currentMenu == MENU_MAIN) {
        if(key) {
            handleMainMenu(key);
        }
    }
    // Normal çalışma modu
    else {
        // Sensör değerlerini oku ve kontrolleri yap
        updateSensorsAndControl();
        
        // Tuş işlemlerini yönet
        if(key) {
            handleNormalOperation(key);
        }
        
        // EEPROM'a periyodik kayıt
        savePersistentState();
    }
    
    // Gecikme - ana döngüyü yavaşlat
    delay(100);
}

// Güç kesintilerini tespit ve kayıt
void handlePowerFailure() {
    uint32_t currentTime = getTimeFromRTC();
    uint32_t lastPowerTime = 0;
    
    EEPROM.get(EEPROM_LAST_POWER_TIME, lastPowerTime);
    
    if (lastPowerTime > 0 && currentTime > lastPowerTime) {
        uint32_t downtime = currentTime - lastPowerTime;
        
        if (downtime > 3600) { // 1 saatten uzun kesinti
            // Kullanıcıyı bilgilendir
            sprintf(messageBuffer, "Guc Kesintisi\nSure: %d saat", (int)(downtime / 3600));
            showMessage(messageBuffer);
            
            debugPrint("Güç kesintisi tespit edildi:");
            debugPrint("Son güç zamanı:", lastPowerTime);
            debugPrint("Şimdiki zaman:", currentTime);
            debugPrint("Kesinti süresi (saat):", (int)(downtime / 3600));
        }
    }
    
    // Şimdiki zamanı kaydet
    EEPROM.put(EEPROM_LAST_POWER_TIME, currentTime);
}

void updateSensorsAndControl() {
    // Sensör değerlerini oku
    float avgTemp, avgHum;
    getAverageReadings(avgTemp, avgHum);
    
    uint32_t currentTime = getTimeFromRTC();
    int currentDay = 0;
    
    // Gün hesaplama güvenliği ekle
    if (settings.startTime > 0 && settings.startTime <= currentTime) {
        currentDay = (currentTime - settings.startTime) / 86400 + 1;
        
        // Geçersiz gün değerlerini düzelt
        if (currentDay <= 0 || currentDay > settings.totalDays) {
            currentDay = 1;
        }
    } else {
        currentDay = 1;
    }
    
    // Son günlerde özel ayarları kontrol et
    checkAndUpdateSettings(currentDay);
    
    // Sıcaklık kontrolü
    controlTemperature(avgTemp);
    
    // Nem kontrolü
    controlHumidity(avgHum);
    
    // Motor kontrolü
    controlMotor(currentTime);
    
    // Ekranı güncelle
    updateMainDisplay(avgTemp, avgHum, currentDay);
}

void getAverageReadings(float &avgTemp, float &avgHum) {
    SensorData sensor1 = readSHT31_1();
    SensorData sensor2 = readSHT31_2();
    
    if(sensor1.isValid && sensor2.isValid) {
        avgTemp = (sensor1.temp + sensor2.temp) / 2.0;
        avgHum = (sensor1.hum + sensor2.hum) / 2.0;
        
        // Sensörlerin farkı çok fazlaysa uyarı - fark eşiğini 15 dereceye yükselttik
        if(abs(sensor1.temp - sensor2.temp) > 15.0) {
            errorMgr.tempErrors++;
            if(errorMgr.tempErrors > MAX_ERRORS) {
                enterSafeMode("Sicaklik Fark!\nCok Fazla!");
            }
        } else {
            errorMgr.tempErrors = 0;
        }
    }
    else if(sensor1.isValid) {
        // Tek sensör çalışıyorsa hata sayacını artırma, normal çalışmaya devam et
        avgTemp = sensor1.temp;
        avgHum = sensor1.hum;
        // errorMgr.tempErrors++ satırını kaldırdık
    }
    else if(sensor2.isValid) {
        // Tek sensör çalışıyorsa hata sayacını artırma, normal çalışmaya devam et
        avgTemp = sensor2.temp;
        avgHum = sensor2.hum;
        // errorMgr.tempErrors++ satırını kaldırdık
    }
    else {
        // Tüm sensörler arızalıysa güvenli moda geç
        errorMgr.tempErrors++;
        if(errorMgr.tempErrors > MAX_ERRORS) {
            enterSafeMode("Tum Sensorler\nHatali!");
        }
        
        // Geçersiz değerler
        avgTemp = 0;
        avgHum = 0;
    }
}

void handleMainMenu(char key) {
    switch(key) {
        case '1':
            setupChicken();
            showMessage("Tavuk secildi\n21 gun");
            currentMenu = -1; // Normal çalışma moduna geç
            break;
        case '2':
            setupGoose();
            showMessage("Kaz secildi\n30 gun");
            currentMenu = -1; // Normal çalışma moduna geç
            break;
        case '3':
            setupQuail();
            showMessage("Bildircin secildi\n18 gun");
            currentMenu = -1; // Normal çalışma moduna geç
            break;
        case '4':
            setupManual();
            currentMenu = -1; // Normal çalışma moduna geç
            break;
        case '5':
            showSettingsMenu();
            currentMenu = MENU_SETTINGS;
            break;
    }
}

void handleNormalOperation(char key) {
    switch(key) {
        case 'A': // Sıcaklık artır
            settings.targetTemp += 0.1;
            if(settings.targetTemp > 39.0) settings.targetTemp = 39.0;
            saveState();
            break;
        case 'B': // Sıcaklık azalt
            settings.targetTemp -= 0.1;
            if(settings.targetTemp < 35.0) settings.targetTemp = 35.0;
            saveState();
            break;
        case 'C': // Nem artır
            settings.targetHum += 1.0;
            if(settings.targetHum > 85) settings.targetHum = 85;
            saveState();
            break;
        case 'D': // Nem azalt
            settings.targetHum -= 1.0;
            if(settings.targetHum < 30) settings.targetHum = 30;
            saveState();
            break;
        case '5': // Ayarlar menüsüne git
            showSettingsMenu();
            currentMenu = MENU_SETTINGS;
            break;
        case '6': // Manuel motor kontrolü
            testMotor();
            break;
    }
}

void handleSettingsMenu(char key) {
    switch(key) {
        case '1': // Sıcaklık
            lcd.clearDisplay();
            lcd.setCursor(0,0);
            lcd.println("Sicaklik (C):");
            lcd.setCursor(0,8);
            lcd.print("Mevcut: ");
            lcd.println(settings.targetTemp, 1);
            lcd.setCursor(0,16);
            lcd.println("Yeni Deger:");
            lcd.display();
            
            settings.targetTemp = getNumberInput();
            if(settings.targetTemp < 35.0) settings.targetTemp = 35.0;
            if(settings.targetTemp > 39.0) settings.targetTemp = 39.0;
            saveState();
            showSettingsMenu();
            break;
            
        case '2': // Nem
            lcd.clearDisplay();
            lcd.setCursor(0,0);
            lcd.println("Nem (%):");
            lcd.setCursor(0,8);
            lcd.print("Mevcut: ");
            lcd.println(settings.targetHum, 1);
            lcd.setCursor(0,16);
            lcd.println("Yeni Deger:");
            lcd.display();
            
            settings.targetHum = getNumberInput();
            if(settings.targetHum < 30) settings.targetHum = 30;
            if(settings.targetHum > 85) settings.targetHum = 85;
            saveState();
            showSettingsMenu();
            break;
            
        case '3': // Motor
            showMotorMenu();
            currentMenu = MENU_MOTOR;
            break;
            
        case '4': // Kalibrasyon
            showCalibrationMenu();
            currentMenu = MENU_CALIBRATION;
            break;
            
        case '5': // Sensör bilgileri
            showSensorInfo();
            break;
            
        case '6': // Resetleme seçeneği (Ayarlar menüsünde güvenli)
            askForReset();
            break;
            
        case '*': // Geri
            if (settings.type == 4) {
                showMainMenu();
                currentMenu = MENU_MAIN;
            } else {
                currentMenu = -1; // Normal çalışma moduna dön
                // Geri dönerken ekranı güncelle
                float avgTemp, avgHum;
                getAverageReadings(avgTemp, avgHum);
                uint32_t currentTime = getTimeFromRTC();
                int currentDay = (currentTime - settings.startTime) / 86400 + 1;
                if (currentDay <= 0 || currentDay > settings.totalDays) currentDay = 1;
                updateMainDisplay(avgTemp, avgHum, currentDay);
            }
            break;
    }
}

void handleMotorMenu(char key) {
    // Loglama ekle
    Serial.print("Motor Menu Key: ");
    Serial.println(key);
    
    switch(key) {
        case '1': // Aralık değiştir
            setMotorInterval();
            break;
            
        case '2': // Süre değiştir
            setMotorDuration();
            break;
            
        case '*': // Geri tuşu
            showSettingsMenu();
            currentMenu = MENU_SETTINGS;
            break;
    }
}

// GÜNCEL KALİBRASYON MENÜSÜ - Offset sıfırlama seçeneği eklenmiş
void handleCalibrationMenu(char key) {
    switch(key) {
        case '1': // Sensör 1 Sıcaklık kalibrasyonu
            calibrateTemperature1();
            break;
            
        case '2': // Sensör 1 Nem kalibrasyonu
            calibrateHumidity1();
            break;
            
        case '3': // Sensör 2 Sıcaklık kalibrasyonu
            calibrateTemperature2();
            break;
            
        case '4': // Sensör 2 Nem kalibrasyonu
            calibrateHumidity2();
            break;
            
        case '5': // YENİ: Tüm offset değerlerini sıfırlama
            resetAllOffsets();
            break;
            
        case '*': // Geri tuşu
            showSettingsMenu();
            currentMenu = MENU_SETTINGS;
            break;
    }
}

// 3. Offset sıfırlama fonksiyonu
void resetAllOffsets() {
    lcd.clearDisplay();
    lcd.setCursor(0,0);
    lcd.println("Offsetleri");
    lcd.println("Sifirlamak Icin");
    lcd.setCursor(0,16);
    lcd.println("# tusu: Evet");
    lcd.println("* tusu: Hayir");
    lcd.display();
    
    while(true) {
        char key = getKey();
        if(key == '#') {
            // Tüm offsetleri sıfırla
            settings.tempOffset1 = 0.0;
            settings.tempOffset2 = 0.0;
            settings.humOffset1 = 0.0;
            settings.humOffset2 = 0.0;
            
            // EEPROM'a kaydet
            EEPROM.put(EEPROM_TEMP_OFFSET1, 0.0f);
            delay(10);
            EEPROM.put(EEPROM_HUM_OFFSET1, 0.0f);
            delay(10);
            EEPROM.put(EEPROM_TEMP_OFFSET2, 0.0f);
            delay(10);
            EEPROM.put(EEPROM_HUM_OFFSET2, 0.0f);
            delay(10);
            wdt_reset();
            
            lcd.clearDisplay();
            lcd.setCursor(0,16);
            lcd.println("Offsetler");
            lcd.println("Sifirlandi!");
            lcd.display();
            delay(2000);
            showCalibrationMenu();
            break;
        }
        else if(key == '*') {
            showCalibrationMenu();
            break;
        }
        wdt_reset();
    }
}

/* Motor ayar fonksiyonları */
void setMotorDuration() {
    lcd.clearDisplay();
    lcd.setCursor(0,0);
    lcd.println("Sure (sn):");
    lcd.setCursor(0,8);
    lcd.print("Mevcut: ");
    lcd.println(motorSettings.duration / 1000);
    lcd.setCursor(0,16);
    lcd.println("Yeni Deger:");
    lcd.display();
    
    float seconds = getNumberInput();
    if(seconds < 1) seconds = 1;
    if(seconds > 7) seconds = 7; // Watchdog limiti altında kalmak için maksimum 7 saniye
    
    motorSettings.duration = seconds * 1000;
    EEPROM.put(EEPROM_MOTOR_DURATION, motorSettings.duration);
    
    showMotorMenu();
}

void setMotorInterval() {
    lcd.clearDisplay();
    lcd.setCursor(0,0);
    lcd.println("Aralik (dk):");
    lcd.setCursor(0,8);
    lcd.print("Mevcut: ");
    lcd.println(motorSettings.interval / 60000);
    lcd.setCursor(0,16);
    lcd.println("Yeni Deger:");
    lcd.display();
    
    float minutes = getNumberInput();
    if(minutes < 60) minutes = 60;
    if(minutes > 480) minutes = 480;
    
    motorSettings.interval = minutes * 60000;
    EEPROM.put(EEPROM_MOTOR_INTERVAL, motorSettings.interval);
    
    showMotorMenu();
}

// GÜNCELLENMİŞ setupChicken
void setupChicken() {
    settings.type = 0;
    settings.targetTemp = 37.8;  // Başlangıç sıcaklığı 37.8°C
    settings.targetHum = 65;     // Başlangıç nemi %65
    settings.totalDays = 21;
    
    // Zamanı al ve güvenli şekilde kaydet
    uint32_t currentTime = getTimeFromRTC();
    settings.startTime = currentTime;
    
    // Hemen kaydet (acil durum için)
    EEPROM.put(EEPROM_TYPE, settings.type);
    delay(5);
    
    // Güvenli zaman kaydı
    saveTimeWithBackup(settings.startTime);
    
    settings.motorActive = true;
    settings.heaterState = false;
    settings.humidifierState = false;
    isFirstMotorActivation = true; // İlk dönüşü aktifleştir
    
    // Sonra diğer verileri kaydet
    saveState();
    
    debugPrint("Tavuk kuluçkası başladı. Zaman:", settings.startTime);
    
    // Başlama mesajı göster
    lcd.clearDisplay();
    lcd.setCursor(0,0);
    lcd.println("Tavuk Kuluckasi");
    lcd.setCursor(0,16);
    lcd.println("Baslatildi!");
    lcd.setCursor(0,32);
    
    // Günün ve saatin doğru gösterildiğini kontrol etmek için
    DateTime now = rtc.now();
    sprintf(messageBuffer, "Gun: 1/%d", settings.totalDays);
    lcd.println(messageBuffer);
    
    lcd.setCursor(0,40);
    sprintf(messageBuffer, "Saat: %02d:%02d", now.hour(), now.minute());
    lcd.println(messageBuffer);
    
    lcd.display();
    delay(3000);
}

// GÜNCELLENMİŞ setupGoose
void setupGoose() {
    settings.type = 1;
    settings.targetTemp = 37.7;  // Başlangıç sıcaklığı 37.7°C
    settings.targetHum = 60;     // Başlangıç nemi %60
    settings.totalDays = 30;
    
    // Zamanı al ve güvenli şekilde kaydet
    uint32_t currentTime = getTimeFromRTC();
    settings.startTime = currentTime;
    
    // Hemen kaydet (acil durum için)
    EEPROM.put(EEPROM_TYPE, settings.type);
    delay(5);
    
    // Güvenli zaman kaydı
    saveTimeWithBackup(settings.startTime);
    
    settings.motorActive = true;
    settings.heaterState = false;
    settings.humidifierState = false;
    isFirstMotorActivation = true; // İlk dönüşü aktifleştir
    
    // Sonra diğer verileri kaydet
    saveState();
    
    debugPrint("Kaz kuluçkası başladı. Zaman:", settings.startTime);
    
    // Başlama mesajı göster
    lcd.clearDisplay();
    lcd.setCursor(0,0);
    lcd.println("Kaz Kuluckasi");
    lcd.setCursor(0,16);
    lcd.println("Baslatildi!");
    lcd.setCursor(0,32);
    
    // Günün ve saatin doğru gösterildiğini kontrol etmek için
    DateTime now = rtc.now();
    sprintf(messageBuffer, "Gun: 1/%d", settings.totalDays);
    lcd.println(messageBuffer);
    
    lcd.setCursor(0,40);
    sprintf(messageBuffer, "Saat: %02d:%02d", now.hour(), now.minute());
    lcd.println(messageBuffer);
    
    lcd.display();
    delay(3000);
}

// GÜNCELLENMİŞ setupQuail
void setupQuail() {
    settings.type = 2;
    settings.targetTemp = 37.7;  // Başlangıç sıcaklığı 37.7°C
    settings.targetHum = 65;     // Başlangıç nemi %65
    settings.totalDays = 18;
    
    // Zamanı al ve güvenli şekilde kaydet
    uint32_t currentTime = getTimeFromRTC();
    settings.startTime = currentTime;
    
    // Hemen kaydet (acil durum için)
    EEPROM.put(EEPROM_TYPE, settings.type);
    delay(5);
    
    // Güvenli zaman kaydı
    saveTimeWithBackup(settings.startTime);
    
    settings.motorActive = true;
    settings.heaterState = false;
    settings.humidifierState = false;
    isFirstMotorActivation = true; // İlk dönüşü aktifleştir
    
    // Sonra diğer verileri kaydet
    saveState();
    
    debugPrint("Bıldırcın kuluçkası başladı. Zaman:", settings.startTime);
    
    // Başlama mesajı göster
    lcd.clearDisplay();
    lcd.setCursor(0,0);
    lcd.println("Bildircin Kulucka");
    lcd.setCursor(0,16);
    lcd.println("Baslatildi!");
    lcd.setCursor(0,32);
    
    // Günün ve saatin doğru gösterildiğini kontrol etmek için
    DateTime now = rtc.now();
    sprintf(messageBuffer, "Gun: 1/%d", settings.totalDays);
    lcd.println(messageBuffer);
    
    lcd.setCursor(0,40);
    sprintf(messageBuffer, "Saat: %02d:%02d", now.hour(), now.minute());
    lcd.println(messageBuffer);
    
    lcd.display();
    delay(3000);
}

// GÜNCELLENMİŞ setupManual
void setupManual() {
    settings.type = 3;
    
    lcd.clearDisplay();
    lcd.setCursor(0,0);
    lcd.println("Manuel Ayar");
    lcd.setCursor(0,8);
    lcd.println("Sicaklik (C):");
    lcd.display();
    
    float temp = getNumberInput();
    if(temp < 35.0) temp = 35.0;
    if(temp > 39.0) temp = 39.0;
    settings.targetTemp = temp;
    
    lcd.clearDisplay();
    lcd.setCursor(0,0);
    lcd.println("Nem (%):");
    lcd.display();
    float hum = getNumberInput();
    if(hum < 30) hum = 30;
    if(hum > 85) hum = 85;
    settings.targetHum = hum;
    
    lcd.clearDisplay();
    lcd.setCursor(0,0);
    lcd.println("Gun Sayisi:");
    lcd.display();
    int days = (int)getNumberInput();
    if(days < 1) days = 1;
    if(days > 60) days = 60;
    settings.totalDays = days;
    
    // Zamanı al ve güvenli şekilde kaydet
    uint32_t currentTime = getTimeFromRTC();
    settings.startTime = currentTime;
    
    // Hemen kaydet (acil durum için)
    EEPROM.put(EEPROM_TYPE, settings.type);
    delay(5);
    
    // Güvenli zaman kaydı
    saveTimeWithBackup(settings.startTime);
    
    settings.motorActive = true;
    settings.heaterState = false;
    settings.humidifierState = false;
    isFirstMotorActivation = true; // İlk dönüşü aktifleştir
    
    // Sonra diğer verileri kaydet
    saveState();
    
    debugPrint("Manuel kuluçka başladı. Zaman:", settings.startTime);
    
    // Başlama mesajı göster
    lcd.clearDisplay();
    lcd.setCursor(0,0);
    lcd.println("Manuel Kulucka");
    lcd.setCursor(0,16);
    lcd.println("Baslatildi!");
    lcd.setCursor(0,32);
    
    // Günün ve saatin doğru gösterildiğini kontrol etmek için
    DateTime now = rtc.now();
    sprintf(messageBuffer, "Gun: 1/%d", settings.totalDays);
    lcd.println(messageBuffer);
    
    lcd.setCursor(0,40);
    sprintf(messageBuffer, "Saat: %02d:%02d", now.hour(), now.minute());
    lcd.println(messageBuffer);
    
    lcd.display();
    delay(3000);
}

void resetSystem() {
    settings.type = 4;
    saveState();
    showMainMenu();
}

void askForReset() {
    lcd.clearDisplay();
    lcd.setTextSize(1);
    lcd.setCursor(0,0);
    lcd.println("Sifirlama?");
    lcd.println("#-Evet *-Hayir");
    lcd.display();
    
    while(true) {
        char key = getKey();
        if(key == '#') {
            settings.type = 4;
            saveState();
            showMainMenu();
            currentMenu = MENU_MAIN;
            break;
        }
        else if(key == '*') {
            showSettingsMenu();
            currentMenu = MENU_SETTINGS;
            break;
        }
        
        // Watchdog resetleme
        wdt_reset();
    }
}

void checkAndUpdateSettings(int currentDay) {
    switch(settings.type) {
        case 0: // Tavuk
            if (currentDay >= 19) {
                settings.targetTemp = 37.5;  // Son 3 gün sıcaklık 37.5°C
                settings.targetHum = 75;     // Son 3 gün nem %75
                settings.motorActive = false;
            }
            break;
        case 1: // Kaz
            if (currentDay >= 27) {
                settings.targetTemp = 37.5;  // Son 4 gün sıcaklık 37.5°C
                settings.targetHum = 80;     // Son 4 gün nem %80
                settings.motorActive = false;
            }
            break;
        case 2: // Bıldırcın
            if (currentDay >= 16) {
                settings.targetTemp = 37.5;  // Son 3 gün sıcaklık 37.5°C
                settings.targetHum = 75;     // Son 3 gün nem %75
                settings.motorActive = false;
            }
            break;
    }
}

void controlTemperature(float currentTemp) {
    static float lastTemp = 0;
    static unsigned long lastTime = 0;
    
    unsigned long currentTime = millis();
    float tempRate = 0;
    
    if (lastTime > 0) {
        // Sıcaklık değişim hızı (derece/dakika)
        tempRate = (currentTemp - lastTemp) * 60000 / (currentTime - lastTime);
    }
    
    if(!errorMgr.safeMode) {
        if(currentTemp < (settings.targetTemp - TEMP_HYSTERESIS)) {
            digitalWrite(RELAY1, LOW);   // DEĞİŞTİRİLDİ: HIGH → LOW (Isıtıcıyı aç)
            settings.heaterState = true;
        }
        else if(currentTemp > (settings.targetTemp + TEMP_HYSTERESIS) ||
                (tempRate > 0.5 && currentTemp > settings.targetTemp)) {
            // Sıcaklık çok yüksek VEYA hızla yükseliyor ve hedefin üzerinde
            digitalWrite(RELAY1, HIGH);  // DEĞİŞTİRİLDİ: LOW → HIGH (Isıtıcıyı kapat)
            settings.heaterState = false;
        }
        // Histerezis aralığında durumu değiştirme
    }
    
    lastTemp = currentTemp;
    lastTime = currentTime;
}

void controlHumidity(float currentHum) {
    if(!errorMgr.safeMode) {
        if(currentHum < (settings.targetHum - HUM_HYSTERESIS)) {
            digitalWrite(RELAY2, LOW);   // DEĞİŞTİRİLDİ: HIGH → LOW (Nemlendiricyi aç)
            settings.humidifierState = true;
        }
        else if(currentHum > (settings.targetHum + HUM_HYSTERESIS)) {
            digitalWrite(RELAY2, HIGH);  // DEĞİŞTİRİLDİ: LOW → HIGH (Nemlendiricyi kapat)
            settings.humidifierState = false;
        }
        // Histerezis aralığında durumu değiştirme
    }
}

// GÜNCELLENMİŞ MOTOR KONTROLÜ - Watchdog reset önleme
void controlMotor(uint32_t currentTime) {
    if (!settings.motorActive || errorMgr.safeMode) return;
    
    unsigned long currentMillis = millis();
    
    // İlk açılışta motoru 1 dakika sonra çalıştır
    if (isFirstMotorActivation) {
        // Sistem açıldıktan 1 dakika sonra ilk motor aktivasyonu
        if (currentMillis > 60000) { // 60 saniye
            debugPrint("İlk motor aktivasyonu yapılıyor");
            
            digitalWrite(RELAY4, LOW);  // DEĞİŞTİRİLDİ: HIGH → LOW (Motoru çalıştır)
            
            // Motor çalışma süresi
            lcd.clearDisplay();
            lcd.setCursor(0,0);
            lcd.println("Motor");
            lcd.println("Ilk Donus");
            lcd.println("Yapiliyor...");
            lcd.display();
            
            // Büyük bir delay yerine küçük adımlarla bekle ve watchdog'u sıfırla
            for (unsigned long start = millis(); millis() - start < motorSettings.duration;) {
                delay(100);  // 100ms adımlarla bekle
                wdt_reset(); // Her 100ms'de bir watchdog'u sıfırla
            }
            
            digitalWrite(RELAY4, HIGH);  // DEĞİŞTİRİLDİ: LOW → HIGH (Motoru durdur)
            
            debugPrint("İlk motor aktivasyonu tamamlandı");
            
            previousMillis = currentMillis;
            isFirstMotorActivation = false; // Artık ilk aktivasyon değil
            
            // Kritik verileri hemen EEPROM'a kaydet
            saveTimeWithBackup(settings.startTime);
            delay(20); // EEPROM yazmanın tamamlanması için bekle
            wdt_reset(); // Watchdog'u tekrar sıfırla
        }
    }
    else if (currentMillis - previousMillis >= motorSettings.interval) {
        debugPrint("Periyodik motor dönüşü yapılıyor");
        
        digitalWrite(RELAY4, LOW);  // DEĞİŞTİRİLDİ: HIGH → LOW (Motoru çalıştır)
        
        // Motor çalışma süresi
        lcd.clearDisplay();
        lcd.setCursor(0,0);
        lcd.println("Motor");
        lcd.println("Donduruluyor...");
        lcd.display();
        
        // Büyük bir delay yerine küçük adımlarla bekle ve watchdog'u sıfırla
        for (unsigned long start = millis(); millis() - start < motorSettings.duration;) {
            delay(100);  // 100ms adımlarla bekle
            wdt_reset(); // Her 100ms'de bir watchdog'u sıfırla
        }
        
        digitalWrite(RELAY4, HIGH);  // DEĞİŞTİRİLDİ: LOW → HIGH (Motoru durdur)
        
        debugPrint("Motor dönüşü tamamlandı");
        
        previousMillis = currentMillis;
    }
}

// GÜNCELLENMİŞ TEST MOTOR FONKSİYONU - Watchdog reset önleme
void testMotor() {
    if(errorMgr.safeMode) {
        showMessage("Guvenli Mod!\nMotor Pasif");
        return;
    }
    
    lcd.clearDisplay();
    lcd.setCursor(0,0);
    lcd.println("Motor Test");
    lcd.println("Calistiriliyor...");
    lcd.display();
    
    digitalWrite(RELAY4, LOW);  // DEĞİŞTİRİLDİ: HIGH → LOW (Motoru çalıştır)
    
    // Büyük bir delay yerine küçük adımlarla bekle ve watchdog'u sıfırla
    for (unsigned long start = millis(); millis() - start < 1000;) {
        delay(100);  // 100ms adımlarla bekle
        wdt_reset(); // Her 100ms'de bir watchdog'u sıfırla
    }
    
    digitalWrite(RELAY4, HIGH);  // DEĞİŞTİRİLDİ: LOW → HIGH (Motoru durdur)
    
    showMessage("Motor Testi\nTamamlandi");
}

// SENSÖRLERİ OKUMA - DAHA SAĞLAM OKUMA MEKANİZMASI
SensorData readSHT31_1() {
    SensorData data;
    
    // 3 kez okuma dene
    for (int attempt = 0; attempt < 3; attempt++) {
        data.temp = sht31_1.readTemperature() + settings.tempOffset1;
        data.hum = sht31_1.readHumidity() + settings.humOffset1;
        
        if (!isnan(data.temp) && !isnan(data.hum)) {
            break; // Başarılı okuma, döngüden çık
        }
        delay(100); // Yeniden denemeden önce kısa bekle
        wdt_reset(); // Watchdog'u sıfırla
    }
    
    data.isValid = (!isnan(data.temp) && !isnan(data.hum) &&
                   data.temp > -10 && data.temp < 60 &&
                   data.hum >= 0 && data.hum <= 100);
    return data;
}

SensorData readSHT31_2() {
    SensorData data;
    
    // 3 kez okuma dene
    for (int attempt = 0; attempt < 3; attempt++) {
        data.temp = sht31_2.readTemperature() + settings.tempOffset2;
        data.hum = sht31_2.readHumidity() + settings.humOffset2;
        
        if (!isnan(data.temp) && !isnan(data.hum)) {
            break; // Başarılı okuma, döngüden çık
        }
        delay(100); // Yeniden denemeden önce kısa bekle
        wdt_reset(); // Watchdog'u sıfırla
    }
    
    data.isValid = (!isnan(data.temp) && !isnan(data.hum) &&
                   data.temp > -10 && data.temp < 60 &&
                   data.hum >= 0 && data.hum <= 100);
    return data;
}

int getMotorCountdown() {
    unsigned long timeSinceLastMotor = millis() - previousMillis;
    if(timeSinceLastMotor >= motorSettings.interval) return 0;
    
    return (motorSettings.interval - timeSinceLastMotor) / 60000;
}

// GÜNCELLENMİŞ LOAD STATE - Daha fazla kontrol ve hata önleme
void loadState() {
    // EEPROM'dan veri oku
    uint8_t storedType;
    EEPROM.get(EEPROM_TYPE, storedType); // Önce bir byte olarak oku
    
    debugPrint("EEPROM'dan tip okundu:", (int)storedType);
    
    // EEPROM ilk kez kullanılıyorsa veya geçersiz değer varsa
    if (storedType == 255 || storedType < 0 || storedType > 4) {
        debugPrint("Geçersiz tip, varsayılanlar yükleniyor");
        
        settings.type = 4; // Sıfırlama durumu - kuluçka tipi seçimi
        settings.targetTemp = 37.5; // Varsayılan sıcaklık
        settings.targetHum = 65.0;  // Varsayılan nem
        settings.totalDays = 0;
        settings.startTime = 0;     // Başlangıç zamanı 0 olarak ayarla
        settings.motorActive = false;
        settings.heaterState = false;
        settings.humidifierState = false;
        
        // Her sensör için sıfır offset başlangıç değeri
        settings.tempOffset1 = 0;
        settings.tempOffset2 = 0;
        settings.humOffset1 = 0;
        settings.humOffset2 = 0;
        
        isFirstMotorActivation = false; // İlk açılışta motor aktivasyonu yok
        
        // Varsayılanları EEPROM'a kaydet
        EEPROM.put(EEPROM_TYPE, settings.type);
        delay(5);
        EEPROM.put(EEPROM_START_TIME, settings.startTime);
        delay(5);
        EEPROM.put(EEPROM_TEMP, settings.targetTemp);
        delay(5);
        EEPROM.put(EEPROM_HUM, settings.targetHum);
        delay(5);
        
        // Her sensör için offset değerleri kaydet
        EEPROM.put(EEPROM_TEMP_OFFSET1, settings.tempOffset1);
        delay(5);
        EEPROM.put(EEPROM_HUM_OFFSET1, settings.humOffset1);
        delay(5);
        EEPROM.put(EEPROM_TEMP_OFFSET2, settings.tempOffset2);
        delay(5);
        EEPROM.put(EEPROM_HUM_OFFSET2, settings.humOffset2);
        delay(5);
        
        wdt_reset(); // Watchdog'u sıfırla
        
        return;
    }
    
    // Geçerli bir kuluçka tipi varsa diğer ayarları oku
    settings.type = storedType;
    
    // Geliştirilmiş zaman alma fonksiyonu
    uint32_t storedTime = getStartTimeFromEEPROM();
    settings.startTime = storedTime;
    
    // Debug - zaman kontrolü
    Serial.print("Ana EEPROM'dan okunan zaman: ");
    Serial.println(settings.startTime);
    
    EEPROM.get(EEPROM_TEMP, settings.targetTemp);
    EEPROM.get(EEPROM_HUM, settings.targetHum);
    
    // Her sensör için offset değerlerini oku
    EEPROM.get(EEPROM_TEMP_OFFSET1, tempOffset1);
    EEPROM.get(EEPROM_HUM_OFFSET1, humOffset1);
    EEPROM.get(EEPROM_TEMP_OFFSET2, tempOffset2);
    EEPROM.get(EEPROM_HUM_OFFSET2, humOffset2);
    
    settings.tempOffset1 = tempOffset1;
    settings.humOffset1 = humOffset1;
    settings.tempOffset2 = tempOffset2;
    settings.humOffset2 = humOffset2;
    
    // Tutarlılık kontrolü - değerler mantıklı aralıkta değilse düzelt
    if (settings.targetTemp < 30.0 || settings.targetTemp > 40.0) {
        settings.targetTemp = 37.5; // Varsayılan sıcaklık
    }
    
    if (settings.targetHum < 0.0 || settings.targetHum > 100.0) {
        settings.targetHum = 65.0; // Varsayılan nem
    }
    
    // Zaman kontrolü ve düzeltme
    uint32_t currentTime = getTimeFromRTC();
    
    // Aktif kuluçka var ama zaman geçersiz
    if (settings.type >= 0 && settings.type <= 3) {
        if (settings.startTime == 0 || settings.startTime > currentTime ||
            (currentTime - settings.startTime) > 86400 * 100) { // 100 günden eski ise
            
            Serial.println("UYARI: Geçersiz başlangıç zamanı, şimdiki zamanla ayarlanıyor");
            settings.startTime = currentTime;
            saveTimeWithBackup(settings.startTime);
        }
        
        // Başlangıç zamanı hesaplandıktan sonra gün kontrolü
        int daysPassed = (currentTime - settings.startTime) / 86400 + 1;
        Serial.print("Hesaplanan gün: ");
        Serial.println(daysPassed);
        
        // Toplam gün sayısını ayarla (tip değiştirilmişse)
        switch(settings.type) {
            case 0: settings.totalDays = 21; break; // Tavuk
            case 1: settings.totalDays = 30; break; // Kaz
            case 2: settings.totalDays = 18; break; // Bıldırcın
            case 3: break; // Manuel - değiştirme
        }
    }
    
    // Motor ayarları
    if (settings.type <= 3) { // Aktif bir kuluçka varsa
        settings.motorActive = true;
        
        // Son günlerde motor kontrolünü devre dışı bırak
        uint32_t currentTime = getTimeFromRTC();
        if (settings.startTime > 0 && currentTime > settings.startTime) {
            int currentDay = (currentTime - settings.startTime) / 86400 + 1;
            
            if ((settings.type == 0 && currentDay >= 19) ||  // Tavuk
                (settings.type == 1 && currentDay >= 27) ||  // Kaz
                (settings.type == 2 && currentDay >= 16)) {  // Bıldırcın
                settings.motorActive = false;
            }
        }
    }
    
    // Güç kesintisi tespit edildiğinde ilk motor dönüşünü aktifleştir
    isFirstMotorActivation = true;
    
    debugPrint("Ayarlar yüklendi: Tip:", settings.type);
    debugPrint("Başlangıç zamanı:", settings.startTime);
    debugPrint("Hedef sıcaklık:", settings.targetTemp);
    debugPrint("Hedef nem:", settings.targetHum);
}

void loadMotorSettings() {
    EEPROM.get(EEPROM_MOTOR_DURATION, motorSettings.duration);
    EEPROM.get(EEPROM_MOTOR_INTERVAL, motorSettings.interval);
    
    // Geçersiz değerler için varsayılanları kullan
    if (motorSettings.duration < 1000 || motorSettings.duration > 8000) {
        motorSettings.duration = MOTOR_DURATION_DEFAULT;
    }
    if (motorSettings.interval < 3600000 || motorSettings.interval > 28800000) {
        motorSettings.interval = MOTOR_INTERVAL_DEFAULT;
    }
    
    // Motor süresini watchdog limiti altında tut (güvenlik önlemi)
    if (motorSettings.duration > 7000) {
        motorSettings.duration = 7000; // Maksimum 7 saniye (8 saniye watchdog limiti)
    }
    
    debugPrint("Motor ayarları yüklendi:");
    debugPrint("Süre (ms):", motorSettings.duration);
    debugPrint("Aralık (ms):", motorSettings.interval);
}

// GÜNCELLENMİŞ SAVE STATE - Watchdog reset ile güvenli yazma
void saveState() {
    // Önce kritik verileri kaydet
    EEPROM.put(EEPROM_TYPE, settings.type);
    EEPROM.put(EEPROM_START_TIME, settings.startTime);
    
    // Kısa bir bekleme ile EEPROM'un yazması için zaman tanı
    delay(10);
    wdt_reset(); // Burada da watchdog'u sıfırla
    
    // Sonra diğer verileri kaydet
    EEPROM.put(EEPROM_TEMP, settings.targetTemp);
    EEPROM.put(EEPROM_HUM, settings.targetHum);
    
    // Her sensör için offset değerlerini kaydet
    EEPROM.put(EEPROM_TEMP_OFFSET1, settings.tempOffset1);
    EEPROM.put(EEPROM_HUM_OFFSET1, settings.humOffset1);
    EEPROM.put(EEPROM_TEMP_OFFSET2, settings.tempOffset2);
    EEPROM.put(EEPROM_HUM_OFFSET2, settings.humOffset2);
    
    // Bekle ve watchdog'u sıfırla
    delay(10);
    wdt_reset();
    
    // Checksum hesapla ve kaydet
    uint8_t checksum = calculateChecksum();
    EEPROM.put(EEPROM_CHECKSUM, checksum);
    
    delay(20); // EEPROM yazma işleminin tamamlanması için ek bekleme
    wdt_reset(); // Son bir kez daha watchdog'u sıfırla
    
    debugPrint("Ayarlar EEPROM'a kaydedildi");
}

// Kalıcı durum kaydetme - sadece değişen verileri kaydet
void savePersistentState() {
    static uint8_t lastType = 255;
    static float lastTargetTemp = 0;
    static float lastTargetHum = 0;
    static unsigned long lastSaveTime = 0;
    
    // EEPROM'a çok sık yazma yapmamak için - en fazla 5 dakika arayla
    if (millis() - lastSaveTime < EEPROM_WRITE_INTERVAL) {
        return;
    }
    
    // Sadece değişen değerleri kaydet - EEPROM ömrünü uzatır
    if (settings.type != lastType) {
        EEPROM.put(EEPROM_TYPE, settings.type);
        lastType = settings.type;
    }
    
    if (abs(settings.targetTemp - lastTargetTemp) > 0.1) {
        EEPROM.put(EEPROM_TEMP, settings.targetTemp);
        lastTargetTemp = settings.targetTemp;
    }
    
    if (abs(settings.targetHum - lastTargetHum) > 0.1) {
        EEPROM.put(EEPROM_HUM, settings.targetHum);
        lastTargetHum = settings.targetHum;
    }
    
    // Sadece 6 saatte bir startTime güncelle (çok sık yazma yapma)
    static unsigned long lastTimeUpdate = 0;
    if (millis() - lastTimeUpdate > 21600000) { // 6 saat
        saveTimeWithBackup(settings.startTime);
        lastTimeUpdate = millis();
    }
    
    lastSaveTime = millis();
}

// Checksum hesaplama
uint8_t calculateChecksum() {
    uint8_t checksum = 0;
    
    // settings içindeki kritik değerleri kullanarak basit bir checksum oluştur
    checksum += settings.type;
    checksum += (uint8_t)(settings.targetTemp * 10);
    checksum += (uint8_t)(settings.targetHum * 10);
    checksum += (uint8_t)(settings.totalDays);
    
    // Başlangıç zamanından da bir değer al
    checksum += (uint8_t)(settings.startTime & 0xFF);
    
    return checksum;
}

void showMainMenu() {
    lcd.clearDisplay();
    lcd.setTextSize(1);
    lcd.setCursor(0,0);
    lcd.println("Kulucka Tipi:");
    lcd.setCursor(0,8);
    lcd.println("1-Tavuk");
    lcd.setCursor(0,16);
    lcd.println("2-Kaz");
    lcd.setCursor(0,24);
    lcd.println("3-Bildircin");
    lcd.setCursor(0,32);
    lcd.println("4-Manuel");
    lcd.setCursor(0,40);
    lcd.println("5-Ayarlar");
    lcd.display();
}

void showSettingsMenu() {
    lcd.clearDisplay();
    lcd.setTextSize(1);
    lcd.setCursor(0,0);
    lcd.println("Ayarlar:");
    lcd.setCursor(0,8);
    lcd.println("1-Sicaklik");
    lcd.setCursor(0,16);
    lcd.println("2-Nem");
    lcd.setCursor(0,24);
    lcd.println("3-Motor");
    lcd.setCursor(0,32);
    lcd.println("4-Kalibrasyon");
    lcd.setCursor(0,40);
    lcd.println("5-Sens  6-Reset");
    lcd.display();
}

void showMotorMenu() {
    lcd.clearDisplay();
    lcd.setTextSize(1);
    lcd.setCursor(0,0);
    lcd.println("Motor Ayarlari:");
    lcd.setCursor(0,8);
    lcd.print("Aralik: ");
    lcd.print(motorSettings.interval / 60000);
    lcd.println(" dk");
    lcd.setCursor(0,16);
    lcd.print("Sure: ");
    lcd.print(motorSettings.duration / 1000);
    lcd.println(" sn");
    lcd.setCursor(0,24);
    lcd.println("1-Aralik D.");
    lcd.setCursor(0,32);
    lcd.println("2-Sure D.");
    lcd.display();
}

// HER SENSÖR BİLGİSİNİ AYRI AYRI GÖSTEREN SENSÖR BİLGİLERİ EKRANI
void showSensorInfo() {
    lcd.clearDisplay();
    lcd.setTextSize(1);
    lcd.setCursor(0,0);
    lcd.println("Sensor Bilgileri:");
    
    SensorData sensor1 = readSHT31_1();
    SensorData sensor2 = readSHT31_2();
    
    lcd.setCursor(0,8);
    lcd.print("S1: ");
    if (sensor1.isValid) {
        lcd.print(sensor1.temp, 1);
        lcd.print("C ");
        lcd.print(sensor1.hum, 1);
        lcd.print("%");
    } else {
        lcd.print("Hata!");
    }
    
    lcd.setCursor(0,16);
    lcd.print("S2: ");
    if (sensor2.isValid) {
        lcd.print(sensor2.temp, 1);
        lcd.print("C ");
        lcd.print(sensor2.hum, 1);
        lcd.print("%");
    } else {
        lcd.print("Hata!");
    }
    
    lcd.setCursor(0,24);
    lcd.print("Fark: ");
    if (sensor1.isValid && sensor2.isValid) {
        lcd.print(abs(sensor1.temp - sensor2.temp), 1);
        lcd.print("C ");
        lcd.print(abs(sensor1.hum - sensor2.hum), 1);
        lcd.print("%");
    } else {
        lcd.print("--");
    }
    
    // Offset değerlerini de göster
    lcd.setCursor(0,32);
    lcd.print("OfsT: ");
    lcd.print(settings.tempOffset1, 1);
    lcd.print("/");
    lcd.print(settings.tempOffset2, 1);
    
    lcd.setCursor(0,40);
    lcd.print("OfsH: ");
    lcd.print(settings.humOffset1, 1);
    lcd.print("/");
    lcd.print(settings.humOffset2, 1);
    
    lcd.display();
    
    // Tuş bekle
    while(true) {
        char key = getKey();
        if(key == '*') {
            showSettingsMenu();
            currentMenu = MENU_SETTINGS;
            break;
        }
        wdt_reset(); // Watchdog'u resetle
    }
}

// KALİBRASYON MENÜSÜ - HER SENSÖR İÇİN AYRI AYRI KALİBRASYON
void showCalibrationMenu() {
    lcd.clearDisplay();
    lcd.setTextSize(1);
    lcd.setCursor(0,0);
    lcd.println("Kalibrasyon:");
    
    lcd.setCursor(0,8);
    lcd.println("1-S1 Sicaklik");
    lcd.setCursor(0,16);
    lcd.println("2-S1 Nem");
    lcd.setCursor(0,24);
    lcd.println("3-S2 Sicaklik");
    lcd.setCursor(0,32);
    lcd.println("4-S2 Nem");
    lcd.setCursor(0,40);
    lcd.println("5-Offsetleri Sifirla");
    
    lcd.display();
}

void showMessage(const char* message) {
    lcd.clearDisplay();
    lcd.setTextSize(1);
    lcd.setCursor(0,16);
    lcd.println(message);
    lcd.display();
    
    // Watchdog'u periyodik olarak sıfırlayarak mesaj süresince bekle
    unsigned long startTime = millis();
    while (millis() - startTime < MESSAGE_DURATION) {
        delay(100);
        wdt_reset();
    }
}

void showError(const char* message) {
    lcd.clearDisplay();
    lcd.setTextSize(1);
    lcd.setCursor(0,0);
    lcd.println("HATA!");
    lcd.setCursor(0,16);
    lcd.println(message);
    lcd.display();
}

// GÜNCELLENMİŞ ANA EKRAN - Daha sağlam gün hesaplama
void updateMainDisplay(float temp, float hum, int currentDay) {
    lcd.clearDisplay();
    lcd.setTextSize(1);
    
    // Sıcaklık gösterimi
    lcd.setCursor(0,0);
    lcd.print("S:");
    if (temp < 100 && temp > -40) {
        lcd.print(temp, 1);
        lcd.print(settings.heaterState ? "+" : " ");
    } else {
        lcd.print("--.-");
    }
    lcd.print("/");
    lcd.print(settings.targetTemp, 1);
    lcd.print("C");
    
    // Nem gösterimi
    lcd.setCursor(0,8);
    lcd.print("N:");
    if (hum < 100 && hum >= 0) {
        lcd.print(hum, 1);
        lcd.print(settings.humidifierState ? "+" : " ");
    } else {
        lcd.print("--.-");
    }
    lcd.print("/");
    lcd.print(settings.targetHum, 1);
    lcd.print("%");
    
    // Gün gösterimi - daha güçlü hesaplama
    lcd.setCursor(0,16);
    lcd.print("G:");
    
    // Aktif kuluçka varsa (tip 0-3)
    if (settings.type >= 0 && settings.type <= 3) {
        int dayNum = 1; // Varsayılan olarak 1. gün
        
        // RTCDEN GÜN HESAPLA
        uint32_t currentTime = getTimeFromRTC();
        
        if (settings.startTime > 0 && currentTime >= settings.startTime) {
            dayNum = (currentTime - settings.startTime) / 86400 + 1;
            
            // Makul bir aralık kontrolü
            if (dayNum > settings.totalDays) {
                dayNum = settings.totalDays;
            }
            
            if (dayNum <= 0) {
                dayNum = 1;
            }
        }
        
        lcd.print(dayNum);
        lcd.print("/");
        lcd.print(settings.totalDays);
        
        // Debug - gün hesaplama
        Serial.print("Gün hesaplama: Şimdi=");
        Serial.print(currentTime);
        Serial.print(", Başlangıç=");
        Serial.print(settings.startTime);
        Serial.print(", Fark=");
        Serial.print(currentTime - settings.startTime);
        Serial.print(", Gün=");
        Serial.println(dayNum);
        
        // Kuluçka tipi gösterimi
        lcd.setCursor(0,24);
        lcd.print(typeNames[settings.type]);
        
        // Motor zamanını göster
        if (settings.motorActive) {
            lcd.print(" M:");
            lcd.print(getMotorCountdown());
            lcd.print("dk");
        }
    } else {
        lcd.print("--/--"); // Aktif kuluçka yok
    }
    
    // Saat gösterimi
    DateTime now = rtc.now();
    lcd.setCursor(0,32);
    if (now.hour() < 10) lcd.print("0");
    lcd.print(now.hour());
    lcd.print(":");
    if (now.minute() < 10) lcd.print("0");
    lcd.print(now.minute());

    // Alt bilgi satırı - hangi sensörlerin aktif olduğunu göster
    lcd.setCursor(0,40);
    if (settings.type >= 0 && settings.type <= 3 && settings.startTime > 0) {
        uint32_t currentTime = getTimeFromRTC();
        int dayNum = (currentTime - settings.startTime) / 86400 + 1;
        
        if (dayNum > 0 && dayNum <= settings.totalDays &&
            dayNum >= settings.totalDays - 2) {
            lcd.print("!SON GUNLER!");
        } else if (errorMgr.safeMode) {
            lcd.print("!GUVENLI MOD!");
        } else {
            // Aktif sensörleri göster
            SensorData sensor1 = readSHT31_1();
            SensorData sensor2 = readSHT31_2();
            lcd.print("S:");
            lcd.print(sensor1.isValid ? "1" : "-");
            lcd.print(sensor2.isValid ? "2" : "-");
            lcd.print(" 5-Menu 6-Motor");
        }
    } else {
        lcd.print("S:-- 5-Menu 6-Motor");
    }
    
    // İlerleme çubuğu ekle
    if (settings.type >= 0 && settings.type <= 3 && settings.startTime > 0) {
        uint32_t currentTime = getTimeFromRTC();
        int dayNum = (currentTime - settings.startTime) / 86400 + 1;
        
        if (dayNum > 0 && dayNum <= settings.totalDays) {
            int progress = map(dayNum, 0, settings.totalDays, 0, 80);
            lcd.drawRect(2, 47, 80, 2, BLACK);
            lcd.fillRect(2, 47, progress, 2, BLACK);
        }
    }
    
    lcd.display();
}

void updateBacklight() {
    unsigned long currentTime = millis();
    if (backlightState && (currentTime - lastKeyPressTime >= BACKLIGHT_TIMEOUT)) {
        digitalWrite(BACKLIGHT_PIN, LOW);
        backlightState = false;
    }
}

char getKey() {
    static unsigned long lastDebounceTime = 0;
    static char lastKey = 0;
    const unsigned long debounceDelay = 250; // Tuş sıçraması için daha kısa bekleme süresi
    
    char keys[4][4] = {
        {'1','2','3','A'},
        {'4','5','6','B'},
        {'7','8','9','C'},
        {'*','0','#','D'}
    };
    
    // Geçen son tuş basma süresini kontrol et
    unsigned long currentTime = millis();
    if (currentTime - lastDebounceTime < debounceDelay) {
        return 0; // Debounce süresi dolmadan yeni tuş algılamayı reddet
    }
    
    for(int i = 0; i < 4; i++) {
        digitalWrite(COL1 + i*2, LOW);
        for(int j = 0; j < 4; j++) {
            if(digitalRead(ROW1 + j*2) == LOW) {
                // Tuş basıldığında arka ışığı aç
                lastKeyPressTime = currentTime;
                if (!backlightState) {
                    digitalWrite(BACKLIGHT_PIN, HIGH);
                    backlightState = true;
                }
                
                digitalWrite(COL1 + i*2, HIGH);
                lastDebounceTime = currentTime; // Debounce zamanını güncelle
                return keys[j][i];
            }
        }
        digitalWrite(COL1 + i*2, HIGH);
    }
    return 0;
}

float getNumberInput() {
    String input = "";
    bool hasDecimal = false;
    
    while(true) {
        char key = getKey();
        if(key) {
            if(key >= '0' && key <= '9') {
                if(input.length() < 5) { // Maksimum 5 karakter
                    input += key;
                    lcd.print(key);
                    lcd.display();
                }
            }
            else if(key == '*' && !hasDecimal) {
                if(!input.length()) input = "0";
                input += '.';
                hasDecimal = true;
                lcd.print('.');
                lcd.display();
            }
            else if(key == '#' && input.length() > 0) {
                return input.toFloat();
            }
        }
        
        // Watchdog resetleme
        wdt_reset();
    }
}

// SENSÖR 1 İÇİN SICAKLIK KALİBRASYONU
void calibrateTemperature1() {
    lcd.clearDisplay();
    lcd.setCursor(0,0);
    lcd.println("S1 Sicaklik Kal.:");
    lcd.setCursor(0,8);
    lcd.println("Referans olcum:");
    lcd.display();
    
    float refTemp = getNumberInput();
    
    // Sensör 1'den okuma al
    SensorData sensor1 = readSHT31_1();
    
    if (!sensor1.isValid) {
        showError("Sensor 1\nHatali!");
        delay(2000);
        showCalibrationMenu();
        return;
    }
    
    // Offset hesapla (sadece sensör 1 için)
    float rawTemp = sht31_1.readTemperature(); // Offset olmadan ham değer
    float newOffset = refTemp - rawTemp;
    settings.tempOffset1 = newOffset;
    tempOffset1 = newOffset;
    
    EEPROM.put(EEPROM_TEMP_OFFSET1, tempOffset1);
    
    lcd.clearDisplay();
    lcd.setCursor(0,0);
    lcd.println("S1 Sicaklik");
    lcd.println("Kalibr. Tamam");
    lcd.setCursor(0,16);
    lcd.print("Yeni Offset: ");
    lcd.print(settings.tempOffset1, 1);
    lcd.display();
    delay(2000);
    
    showCalibrationMenu();
}

// SENSÖR 1 İÇİN NEM KALİBRASYONU
void calibrateHumidity1() {
    lcd.clearDisplay();
    lcd.setCursor(0,0);
    lcd.println("S1 Nem Kalibr.:");
    lcd.setCursor(0,8);
    lcd.println("Referans olcum:");
    lcd.display();
    
    float refHum = getNumberInput();
    
    // Sensör 1'den okuma al
    SensorData sensor1 = readSHT31_1();
    
    if (!sensor1.isValid) {
        showError("Sensor 1\nHatali!");
        delay(2000);
        showCalibrationMenu();
        return;
    }
    
    // Offset hesapla (sadece sensör 1 için)
    float rawHum = sht31_1.readHumidity(); // Offset olmadan ham değer
    float newOffset = refHum - rawHum;
    settings.humOffset1 = newOffset;
    humOffset1 = newOffset;
    
    EEPROM.put(EEPROM_HUM_OFFSET1, humOffset1);
    
    lcd.clearDisplay();
    lcd.setCursor(0,0);
    lcd.println("S1 Nem");
    lcd.println("Kalibr. Tamam");
    lcd.setCursor(0,16);
    lcd.print("Yeni Offset: ");
    lcd.print(settings.humOffset1, 1);
    lcd.display();
    delay(2000);
    
    showCalibrationMenu();
}

// SENSÖR 2 İÇİN SICAKLIK KALİBRASYONU
void calibrateTemperature2() {
    lcd.clearDisplay();
    lcd.setCursor(0,0);
    lcd.println("S2 Sicaklik Kal.:");
    lcd.setCursor(0,8);
    lcd.println("Referans olcum:");
    lcd.display();
    
    float refTemp = getNumberInput();
    
    // Sensör 2'den okuma al
    SensorData sensor2 = readSHT31_2();
    
    if (!sensor2.isValid) {
        showError("Sensor 2\nHatali!");
        delay(2000);
        showCalibrationMenu();
        return;
    }
    
    // Offset hesapla (sadece sensör 2 için)
    float rawTemp = sht31_2.readTemperature(); // Offset olmadan ham değer
    float newOffset = refTemp - rawTemp;
    settings.tempOffset2 = newOffset;
    tempOffset2 = newOffset;
    
    EEPROM.put(EEPROM_TEMP_OFFSET2, tempOffset2);
    
    lcd.clearDisplay();
    lcd.setCursor(0,0);
    lcd.println("S2 Sicaklik");
    lcd.println("Kalibr. Tamam");
    lcd.setCursor(0,16);
    lcd.print("Yeni Offset: ");
    lcd.print(settings.tempOffset2, 1);
    lcd.display();
    delay(2000);
    
    showCalibrationMenu();
}

// SENSÖR 2 İÇİN NEM KALİBRASYONU
void calibrateHumidity2() {
    lcd.clearDisplay();
    lcd.setCursor(0,0);
    lcd.println("S2 Nem Kalibr.:");
    lcd.setCursor(0,8);
    lcd.println("Referans olcum:");
    lcd.display();
    
    float refHum = getNumberInput();
    
    // Sensör 2'den okuma al
    SensorData sensor2 = readSHT31_2();
    
    if (!sensor2.isValid) {
        showError("Sensor 2\nHatali!");
        delay(2000);
        showCalibrationMenu();
        return;
    }
    
    // Offset hesapla (sadece sensör 2 için)
    float rawHum = sht31_2.readHumidity(); // Offset olmadan ham değer
    float newOffset = refHum - rawHum;
    settings.humOffset2 = newOffset;
    humOffset2 = newOffset;
    
    EEPROM.put(EEPROM_HUM_OFFSET2, humOffset2);
    
    lcd.clearDisplay();
    lcd.setCursor(0,0);
    lcd.println("S2 Nem");
    lcd.println("Kalibr. Tamam");
    lcd.setCursor(0,16);
    lcd.print("Yeni Offset: ");
    lcd.print(settings.humOffset2, 1);
    lcd.display();
    delay(2000);
    
    showCalibrationMenu();
}

void enterSafeMode(const char* errorMsg) {
    if (!errorMgr.safeMode) {
        errorMgr.safeMode = true;
        
        // Tüm çıkışları güvenli duruma al - DEĞİŞTİRİLDİ: LOW/HIGH tersine çevrildi
        digitalWrite(RELAY1, HIGH);  // Isıtıcıyı kapat
        digitalWrite(RELAY2, HIGH);  // Nemlenidiriciyi kapat
        digitalWrite(RELAY4, HIGH);  // Motoru kapat
        digitalWrite(RELAY3, LOW);   // Fanı çalıştır
        
        // Durumları güncelle
        settings.heaterState = false;
        settings.humidifierState = false;
        
        // Hata mesajını göster ve seri porta yazdır
        showError(errorMsg);
        debugPrint("GÜVENLİ MOD AKTİFLEŞTİRİLDİ:");
        debugPrint(errorMsg);
        
        // Hata durumunu EEPROM'a kaydet
        EEPROM.write(EEPROM_ERROR_FLAG, 1);
    }
}
 

Forum istatistikleri

Konular
7,540
Mesajlar
126,319
Üyeler
3,051
Son üye
kimoz_13

Son kaynaklar

Son profil mesajları

Python Geliştirmeye eklediğim yapay zeka sunucusu, yeni başlayanlar için roket etkisi
Bir insanın zeka seviyesinin en kolay tesbiti, sorduğu sorulardır.
yapay zeka interneti yedi bitirdi, arama motoru kullanan, forumlara yazan kaldı mı ?
Freemont2.0 herbokolog Freemont2.0 wrote on herbokolog's profile.
nick iniz yakıyor
:D
Freemont2.0 posta Freemont2.0 wrote on posta's profile.
Merhabalar :)
Back
Top