#include <Wire.h>
#include <RTClib.h>
#include <LiquidCrystal_I2C.h>
#include <EEPROM.h>
#include "Adafruit_SHT31.h"
#include <avr/wdt.h>
#include <Servo.h>
// Pin Tanımları
#define JOY_X A0
#define JOY_Y A2
#define JOY_SW 2
#define FAN_PIN 3
#define MOTOR_PIN 4
#define RELAY_HEAT 11
#define RELAY_HUMID 12
#define RELAY_COOL 13
#define BUZZER_PIN 5
#define SERVO_PIN 6
// EEPROM Adresleri
const int ADDR_VERSION = 0;
const byte PROFILE_VERSION = 10;
const int ADDR_TUR = 4;
const int ADDR_TARIH = 8;
const int ADDR_SON_DONUS = 12;
const int ADDR_PROFIL = 16;
const int ADDR_ISTATISTIK = 200;
// Güvenlik sabitleri
const float MAX_SICAKLIK = 42.0;
const float MIN_SICAKLIK = 35.0;
const float KRITIK_SICAKLIK = 44.0;
const int MAX_SENSOR_HATA = 5;
const unsigned long SENSOR_TIMEOUT = 30000;
// Joystick kalibrasyonu
const int JOY_CENTER_X = 512;
const int JOY_CENTER_Y = 512;
const int JOY_DEADZONE = 100;
const int JOY_THRESHOLD = 200;
int servoAcisi =0;
// Menü yapıları
enum Button { BTN_YOK, BTN_SAG, BTN_YUKARI, BTN_ASAGI, BTN_SOL, BTN_SEC };
enum MenuOgesi { ANA_EKRAN, TUR_SEC, KULUCAKA_S, KULUCAKA_N, TARIH, HATA_MENU, TEST_MODU };
enum HataMenuOgesi { HATA_GENEL, HATA_SENSOR, HATA_SICAKLIK, HATA_NEM, HATA_SISTEM, HATA_ISTATISTIK };
// Yapı tanımları
struct TurProfili {
char isim[12];
int kuluckaGun;
float kuluSicak[2];
float kuluNem[2];
int donusAralik;
int donusSuresi;
};
struct SistemIstatistik {
uint16_t toplamSicakHata;
uint16_t toplamNemHata;
uint16_t toplamAcilDurum;
uint32_t toplamCalismaZamani;
};
struct SistemDurumu {
uint8_t aktifTur;
uint32_t baslangicTarihi;
uint32_t sonDonus;
uint32_t donusBaslangic;
bool donuyor;
bool isitici;
bool nemlendirici;
bool sogutma;
bool alarm;
MenuOgesi menu;
HataMenuOgesi hataMenu;
bool testModuAktif;
byte testSecim;
byte testTipi;
byte testAsama;
unsigned long testZamani;
byte sicakSecim;
byte nemSecim;
bool ilkOkuma;
unsigned long snoozeTime;
int sicaklikHata;
int nemHata;
unsigned long sonSensorOkuma;
bool guvenliMod;
unsigned long sistemBaslangic;
bool lcdDirty;
byte tarihSecimi;
SistemIstatistik istatistik;
};
// Global değişkenler
TurProfili TURLAR[4] = {
{"Tavuk",21,{37.5,38.0},{55,65},3,5},
{"Hindi",28,{37.3,37.6},{60,70},4,7},
{"Bldrcn",17,{37.7,38.0},{60,65},2,3},
{"Kaz",30,{37.3,37.6},{65,75},6,10}
};
SistemDurumu durum;
Adafruit_SHT31 sht31;
LiquidCrystal_I2C lcd(0x27, 16, 2);
RTC_DS3231 rtc;
Servo nemServo;
// Sensor verileri
float sicakBuffer[5], nemBuffer[5];
byte sicakIndex = 0, nemIndex = 0;
float sicaklik = 37.5, nem = 60;
float sonGecerliSicaklik = 37.5, sonGecerliNem = 60;
// Zamanlayıcılar
unsigned long sensorTimer = 0;
unsigned long kontrolTimer = 0;
unsigned long ekranTimer = 0;
unsigned long buttonTimer = 0;
unsigned long saglikTimer = 0;
unsigned long donusTimer = 0;
unsigned long alarmTimer = 0;
unsigned long watchdogTimer = 0;
// Button debounce
Button sonButton = BTN_YOK;
unsigned long sonButtonZaman = 0;
// Fonksiyon prototipler
void bekle(unsigned long ms);
void donanimiBaslat();
void ayarlariYukle();
void ayarlariKaydet();
void fabrikaAyarlari();
Button tusOku();
void sensorOku();
float ortalamaHesapla(float arr[], int n);
void profilGuvenlik();
void sicaklikNemKontrol();
int hesaplaFanHiz(float mevcut, float min, float max);
void acilDurumProtokolu();
void yumurtaCevir();
bool kuluckaDonemindeMi();
void alarmKontrol(Button btn);
void snoozeAlarm();
void sistemSaglikKontrol();
void anaEkranButonlar(Button btn);
void menuIslem(Button btn);
void turSecMenu(Button btn);
void sicaklikMenu(Button btn);
void nemMenu(Button btn);
void tarihDuzenle(Button btn);
void hataMenu(Button btn);
void testModuIslem(Button btn);
void testIslemleri();
void ekranGuncelle();
void anaEkranGoster();
void turSecEkran();
void sicaklikEkran();
void nemEkran();
void tarihEkran();
void hataEkran();
void testModuEkran();
void setup() {
Serial.begin(9600);
// Watchdog başlat
wdt_disable();
wdt_enable(WDTO_8S);
nemServo.attach(SERVO_PIN);
// Sistem durumunu başlat
memset(&durum, 0, sizeof(durum));
durum.aktifTur = 0;
durum.menu = ANA_EKRAN;
durum.hataMenu = HATA_GENEL;
durum.lcdDirty = true;
durum.ilkOkuma = true;
// LCD başlat
Wire.begin();
lcd.init();
lcd.backlight();
lcd.clear();
lcd.print("Sistem Baslat...");
// Donanım başlat
donanimiBaslat();
// Güvenli başlangıç için bekle
bekle(1000);
// Sensör başlat
if (!sht31.begin(0x44)) {
lcd.clear();
lcd.print("Sensor Hata!");
lcd.setCursor(0, 1);
lcd.print("Guvenli Mod");
durum.guvenliMod = true;
bekle(2000);
}
// RTC başlat
if (!rtc.begin()) {
lcd.clear();
lcd.print("RTC Hata!");
bekle(2000);
} else if (rtc.lostPower()) {
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
}
// Ayarları yükle
ayarlariYukle();
// Sensor buffer'ını başlat
for (int i = 0; i < 5; i++) {
sicakBuffer[i] = 37.5;
nemBuffer[i] = 60;
}
durum.sistemBaslangic = millis();
durum.sonSensorOkuma = millis();
// Zamanlayıcıları başlat
unsigned long now = millis();
sensorTimer = now;
kontrolTimer = now;
ekranTimer = now;
buttonTimer = now;
saglikTimer = now;
donusTimer = now;
alarmTimer = now;
watchdogTimer = now;
lcd.clear();
lcd.print("Sistem Hazir!");
bekle(1000);
wdt_reset();
}
void loop() {
unsigned long currentTime = millis();
// Watchdog reset
if (currentTime - watchdogTimer >= 1000) {
wdt_reset();
watchdogTimer = currentTime;
}
// Ana döngü frekans kontrolü
static unsigned long lastMainLoop = 0;
if (currentTime - lastMainLoop < 50) {
delay(10);
return;
}
lastMainLoop = currentTime;
// Buton okuma
Button btn = BTN_YOK;
if (currentTime - buttonTimer >= 200) {
btn = tusOku();
if (btn != BTN_YOK && btn != sonButton) {
buttonTimer = currentTime;
sonButton = btn;
durum.lcdDirty = true;
} else if (btn == BTN_YOK) {
sonButton = BTN_YOK;
}
}
// Profil güvenlik kontrolü
profilGuvenlik();
// Test modu kontrolü
if (durum.testModuAktif) {
testIslemleri();
}
// Menü işlemleri
if (durum.menu != ANA_EKRAN) {
menuIslem(btn);
} else {
anaEkranButonlar(btn);
}
// Sensor okuma
if (currentTime - sensorTimer >= 3000) {
sensorOku();
sensorTimer = currentTime;
}
// Normal kontrol işlemleri (test modunda değilse)
if (!durum.testModuAktif) {
if (currentTime - kontrolTimer >= 5000) {
sicaklikNemKontrol();
kontrolTimer = currentTime;
}
}
// Yumurta çevirme
if (currentTime - donusTimer >= 30000) {
yumurtaCevir();
donusTimer = currentTime;
}
// Alarm kontrolü
if (currentTime - alarmTimer >= 2000) {
alarmKontrol(btn);
alarmTimer = currentTime;
}
// Ekran güncelleme
if (currentTime - ekranTimer >= 1000 || durum.lcdDirty) {
ekranGuncelle();
ekranTimer = currentTime;
durum.lcdDirty = false;
}
// Sistem sağlık kontrolü
if (currentTime - saglikTimer >= 60000) {
sistemSaglikKontrol();
saglikTimer = currentTime;
}
delay(10);
}
void testIslemleri() {
unsigned long simdi = millis();
switch (durum.testTipi) {
case 1: // Röle Testi
switch (durum.testAsama) {
case 0:
digitalWrite(RELAY_HEAT, LOW);
lcd.clear();
lcd.print("ISITICI ACIK");
durum.testAsama++;
durum.testZamani = simdi;
break;
case 1:
if (simdi - durum.testZamani > 2000) {
digitalWrite(RELAY_HEAT, HIGH);
digitalWrite(RELAY_HUMID, LOW);
lcd.clear();
lcd.print("NEM ACIK");
durum.testAsama++;
durum.testZamani = simdi;
}
break;
case 2:
if (simdi - durum.testZamani > 2000) {
digitalWrite(RELAY_HUMID, HIGH);
digitalWrite(RELAY_COOL, LOW);
lcd.clear();
lcd.print("SOGUTMA ACIK");
durum.testAsama++;
durum.testZamani = simdi;
}
break;
case 3:
if (simdi - durum.testZamani > 2000) {
digitalWrite(RELAY_COOL, HIGH);
durum.testModuAktif = false;
durum.menu = ANA_EKRAN;
durum.lcdDirty = true;
}
break;
}
break;
case 2: // Motor Testi
switch (durum.testAsama) {
case 0:
digitalWrite(MOTOR_PIN, LOW);
lcd.clear();
lcd.print("MOTOR CALISIYOR");
durum.testAsama++;
durum.testZamani = simdi;
break;
case 1:
if (simdi - durum.testZamani > 3000) {
digitalWrite(MOTOR_PIN, HIGH);
durum.testModuAktif = false;
durum.menu = ANA_EKRAN;
durum.lcdDirty = true;
}
break;
}
break;
case 3: // Fan Testi
switch (durum.testAsama) {
case 0:
analogWrite(FAN_PIN, 255);
lcd.clear();
lcd.print("FAN MAX HIZ");
durum.testAsama++;
durum.testZamani = simdi;
break;
case 1:
if (simdi - durum.testZamani > 3000) {
analogWrite(FAN_PIN, 0);
durum.testModuAktif = false;
durum.menu = ANA_EKRAN;
durum.lcdDirty = true;
}
break;
}
break;
case 4: // Buzzer Testi
switch (durum.testAsama) {
case 0:
tone(BUZZER_PIN, 1000, 500);
lcd.clear();
lcd.print("BUZZER TEST");
durum.testAsama++;
durum.testZamani = simdi;
break;
case 1:
if (simdi - durum.testZamani > 1000) {
noTone(BUZZER_PIN);
durum.testModuAktif = false;
durum.menu = ANA_EKRAN;
durum.lcdDirty = true;
}
break;
}
break;
case 5: // Sensor Testi
lcd.clear();
lcd.print("S:");
lcd.print(sicaklik, 1);
lcd.print("C N:");
lcd.print(nem, 0);
lcd.print("%");
lcd.setCursor(0, 1);
lcd.print("Hata S:");
lcd.print(durum.sicaklikHata);
lcd.print(" N:");
lcd.print(durum.nemHata);
if (simdi - durum.testZamani > 5000) {
durum.testModuAktif = false;
durum.menu = ANA_EKRAN;
durum.lcdDirty = true;
}
break;
case 6: // Çıkış
durum.testModuAktif = false;
durum.menu = ANA_EKRAN;
durum.lcdDirty = true;
break;
}
}
void bekle(unsigned long ms) {
unsigned long startTime = millis();
while (millis() - startTime < ms) {
wdt_reset();
delay(10);
}
}
void donanimiBaslat() {
// Pin modları
pinMode(JOY_SW, INPUT_PULLUP);
pinMode(FAN_PIN, OUTPUT);
pinMode(MOTOR_PIN, OUTPUT);
pinMode(RELAY_HEAT, OUTPUT);
pinMode(RELAY_HUMID, OUTPUT);
pinMode(RELAY_COOL, OUTPUT);
pinMode(BUZZER_PIN, OUTPUT);
// Güvenli başlangıç - tüm röleleri kapat
digitalWrite(RELAY_HEAT, HIGH);
digitalWrite(RELAY_HUMID, HIGH);
digitalWrite(RELAY_COOL, HIGH);
digitalWrite(MOTOR_PIN, HIGH);
analogWrite(FAN_PIN, 0);
// Başlangıç sesi
tone(BUZZER_PIN, 1000, 200);
delay(300);
tone(BUZZER_PIN, 1500, 200);
delay(300);
noTone(BUZZER_PIN);
}
void ayarlariYukle() {
byte storedVersion = EEPROM.read(ADDR_VERSION);
if (storedVersion != PROFILE_VERSION) {
fabrikaAyarlari();
return;
}
// Ayarları yükle
EEPROM.get(ADDR_TUR, durum.aktifTur);
EEPROM.get(ADDR_TARIH, durum.baslangicTarihi);
EEPROM.get(ADDR_SON_DONUS, durum.sonDonus);
EEPROM.get(ADDR_ISTATISTIK, durum.istatistik);
// Güvenlik kontrolü
durum.aktifTur = constrain(durum.aktifTur, 0, 3);
// Geçersiz tarih kontrolü
if (durum.baslangicTarihi == 0 || durum.baslangicTarihi == 0xFFFFFFFF) {
DateTime now = rtc.now();
durum.baslangicTarihi = now.unixtime();
}
if (durum.sonDonus == 0 || durum.sonDonus == 0xFFFFFFFF) {
durum.sonDonus = durum.baslangicTarihi;
}
}
void ayarlariKaydet() {
EEPROM.put(ADDR_TUR, durum.aktifTur);
EEPROM.put(ADDR_TARIH, durum.baslangicTarihi);
EEPROM.put(ADDR_SON_DONUS, durum.sonDonus);
EEPROM.put(ADDR_ISTATISTIK, durum.istatistik);
}
void fabrikaAyarlari() {
EEPROM.write(ADDR_VERSION, PROFILE_VERSION);
durum.aktifTur = 0;
DateTime now = rtc.now();
durum.baslangicTarihi = now.unixtime();
durum.sonDonus = now.unixtime();
durum.sicaklikHata = 0;
durum.nemHata = 0;
durum.guvenliMod = false;
// İstatistikleri sıfırla
memset(&durum.istatistik, 0, sizeof(SistemIstatistik));
ayarlariKaydet();
lcd.clear();
lcd.print("Fabrika Ayarlari");
lcd.setCursor(0, 1);
lcd.print("Yuklendi!");
bekle(2000);
durum.lcdDirty = true;
}
Button tusOku() {
int joyX = analogRead(JOY_X);
int joyY = analogRead(JOY_Y);
bool sw = !digitalRead(JOY_SW);
// Joystick kalibrasyonu
int deltaX = joyX - JOY_CENTER_X;
int deltaY = joyY - JOY_CENTER_Y;
// Dead zone kontrolü
if (abs(deltaX) < JOY_DEADZONE) deltaX = 0;
if (abs(deltaY) < JOY_DEADZONE) deltaY = 0;
// Button mapping
if (sw) return BTN_SEC;
if (deltaX > JOY_THRESHOLD) return BTN_SAG;
if (deltaX < -JOY_THRESHOLD) return BTN_SOL;
if (deltaY > JOY_THRESHOLD) return BTN_ASAGI;
if (deltaY < -JOY_THRESHOLD) return BTN_YUKARI;
return BTN_YOK;
}
void sensorOku() {
if (durum.guvenliMod) {
sicaklik = sonGecerliSicaklik;
nem = sonGecerliNem;
return;
}
float nt = sht31.readTemperature();
float nh = sht31.readHumidity();
// İlk okuma için buffer doldur
if (durum.ilkOkuma) {
float defaultTemp = (isnan(nt) || nt < 10 || nt > 60) ? 37.5 : nt;
float defaultHum = (isnan(nh) || nh < 0 || nh > 100) ? 60 : nh;
for (int i = 0; i < 5; i++) {
sicakBuffer[i] = defaultTemp;
nemBuffer[i] = defaultHum;
}
durum.ilkOkuma = false;
sicaklik = defaultTemp;
nem = defaultHum;
sonGecerliSicaklik = sicaklik;
sonGecerliNem = nem;
durum.sonSensorOkuma = millis();
return;
}
// Sıcaklık okuma kontrolü
if (!isnan(nt) && nt > 10 && nt < 60) {
sicakBuffer[sicakIndex] = nt;
sicakIndex = (sicakIndex + 1) % 5;
durum.sicaklikHata = 0;
durum.sonSensorOkuma = millis();
sicaklik = ortalamaHesapla(sicakBuffer, 5);
sonGecerliSicaklik = sicaklik;
} else {
durum.sicaklikHata++;
durum.istatistik.toplamSicakHata++;
if (durum.sicaklikHata > MAX_SENSOR_HATA) {
durum.guvenliMod = true;
durum.lcdDirty = true;
}
sicaklik = sonGecerliSicaklik;
}
// Nem okuma kontrolü
if (!isnan(nh) && nh >= 0 && nh <= 100) {
nemBuffer[nemIndex] = nh;
nemIndex = (nemIndex + 1) % 5;
durum.nemHata = 0;
nem = ortalamaHesapla(nemBuffer, 5);
sonGecerliNem = nem;
} else {
durum.nemHata++;
durum.istatistik.toplamNemHata++;
if (durum.nemHata > MAX_SENSOR_HATA) {
durum.guvenliMod = true;
durum.lcdDirty = true;
}
nem = sonGecerliNem;
}
}
float ortalamaHesapla(float arr[], int n) {
if (n <= 0) return 0;
float toplam = 0;
for (int i = 0; i < n; i++) {
toplam += arr[i];
}
return toplam / n;
}
void profilGuvenlik() {
for (int i = 0; i < 4; i++) {
TurProfili &t = TURLAR[i];
// Sıcaklık sınırları
t.kuluSicak[0] = constrain(t.kuluSicak[0], MIN_SICAKLIK, MAX_SICAKLIK - 0.5);
t.kuluSicak[1] = constrain(t.kuluSicak[1], t.kuluSicak[0] + 0.5, MAX_SICAKLIK);
// Nem sınırları
t.kuluNem[0] = constrain(t.kuluNem[0], 30.0, 95.0);
t.kuluNem[1] = constrain(t.kuluNem[1], t.kuluNem[0] + 5, 95.0);
// Çevirme parametreleri
t.donusAralik = constrain(t.donusAralik, 1, 24);
t.donusSuresi = constrain(t.donusSuresi, 1, 30);
// Kuluçka günü
t.kuluckaGun = constrain(t.kuluckaGun, 10, 40);
}
}
void sicaklikNemKontrol() {
if (durum.aktifTur >= 4) return;
TurProfili &t = TURLAR[durum.aktifTur];
// KRİTİK DURUM KONTROLÜ
if (sicaklik > KRITIK_SICAKLIK) {
acilDurumProtokolu();
return;
}
float hedefSicaklik = (t.kuluSicak[0] + t.kuluSicak[1]) / 2.0;
float hedefNem = (t.kuluNem[0] + t.kuluNem[1]) / 2.0;
float nmFark = hedefNem - nem; // Hedef nem ile mevcut nem farkı
servoAcisi = nmFark * 1.8; // 1.8 katsayısı ile açıya çevir
servoAcisi = constrain(servoAcisi, 0, 180); // Negatif değerleri 0 yap
nemServo.write(servoAcisi); // Servo pozisyonunu güncelle
// Sıcaklık kontrolü
float sicaklikFark = sicaklik - hedefSicaklik;
if (sicaklikFark < -0.5) {
digitalWrite(RELAY_HEAT, LOW);
durum.isitici = true;
} else if (sicaklikFark > 0.5) {
digitalWrite(RELAY_HEAT, HIGH);
durum.isitici = false;
}
// Nem kontrolü
float nemFark = nem - hedefNem;
if (nemFark < -5) {
digitalWrite(RELAY_HUMID, LOW);
durum.nemlendirici = true;
} else if (nemFark > 5) {
digitalWrite(RELAY_HUMID, HIGH);
durum.nemlendirici = false;
}
// Fan kontrolü
int fanHiz = hesaplaFanHiz(sicaklik, t.kuluSicak[0], t.kuluSicak[1]);
analogWrite(FAN_PIN, fanHiz);
// Soğutucu kontrolü
if (sicaklikFark > 1.5) {
digitalWrite(RELAY_COOL, LOW);
durum.sogutma = true;
} else if (sicaklikFark < 0.5) {
digitalWrite(RELAY_COOL, HIGH);
durum.sogutma = false;
}
}
int hesaplaFanHiz(float mevcut, float min, float max) {
if (max <= min) return 100;
float oran = (mevcut - min) / (max - min);
oran = constrain(oran, 0.0, 1.0);
int minHiz = 80;
int maxHiz = 255;
return constrain((int)(minHiz + oran * (maxHiz - minHiz)), minHiz, maxHiz);
}
void acilDurumProtokolu() {
durum.istatistik.toplamAcilDurum++;
// Güvenlik önlemleri
digitalWrite(RELAY_HEAT, HIGH);
digitalWrite(RELAY_HUMID, HIGH);
digitalWrite(RELAY_COOL, LOW);
analogWrite(FAN_PIN, 255);
// Alarm sesi
for (int i = 0; i < 5; i++) {
tone(BUZZER_PIN, 1000, 300);
bekle(400);
noTone(BUZZER_PIN);
bekle(100);
}
lcd.clear();
lcd.print("ACIL DURUM!");
lcd.setCursor(0, 1);
lcd.print("Sicak: ");
lcd.print(sicaklik, 1);
lcd.print("C");
bekle(3000);
durum.lcdDirty = true;
}
void yumurtaCevir() {
if (!kuluckaDonemindeMi()) {
digitalWrite(MOTOR_PIN, HIGH);
durum.donuyor = false;
return;
}
DateTime now = rtc.now();
TurProfili &t = TURLAR[durum.aktifTur];
if (!durum.donuyor) {
uint32_t gecenSaniye = now.unixtime() - durum.sonDonus;
if (gecenSaniye >= (unsigned long)t.donusAralik * 3600) {
durum.donuyor = true;
durum.donusBaslangic = now.unixtime();
digitalWrite(MOTOR_PIN, LOW);
durum.lcdDirty = true;
// Çevirme başlangıç sesi
tone(BUZZER_PIN, 500, 200);
delay(250);
noTone(BUZZER_PIN);
}
} else {
// Çevirme işlemi devam ediyor
uint32_t gecenSaniye = now.unixtime() - durum.donusBaslangic;
if (gecenSaniye >= (unsigned long)t.donusSuresi) {
// Çevirme tamamlandı
durum.donuyor = false;
durum.sonDonus = now.unixtime();
digitalWrite(MOTOR_PIN, HIGH);
durum.lcdDirty = true;
// Çevirme bitiş sesi
tone(BUZZER_PIN, 800, 200);
delay(250);
noTone(BUZZER_PIN);
// Ayarları kaydet
ayarlariKaydet();
}
}
}
bool kuluckaDonemindeMi() {
if (durum.aktifTur >= 4) return false;
DateTime now = rtc.now();
uint32_t gecenGun = (now.unixtime() - durum.baslangicTarihi) / 86400;
TurProfili &t = TURLAR[durum.aktifTur];
return gecenGun < (uint32_t)t.kuluckaGun - 3; // Son 3 gün çevirme yapma
}
void alarmKontrol(Button btn) {
bool alarmDurumu = false;
// Alarm koşulları
if (durum.guvenliMod) alarmDurumu = true;
if (sicaklik > MAX_SICAKLIK || sicaklik < MIN_SICAKLIK) alarmDurumu = true;
if (durum.sicaklikHata > MAX_SENSOR_HATA) alarmDurumu = true;
if (durum.nemHata > MAX_SENSOR_HATA) alarmDurumu = true;
// Snooze kontrolü
if (durum.snoozeTime > 0 && millis() - durum.snoozeTime < 300000) { // 5 dakika snooze
alarmDurumu = false;
}
if (alarmDurumu && !durum.alarm) {
durum.alarm = true;
durum.lcdDirty = true;
} else if (!alarmDurumu && durum.alarm) {
durum.alarm = false;
durum.lcdDirty = true;
noTone(BUZZER_PIN);
}
// Alarm sesi
if (durum.alarm) {
static unsigned long lastAlarmSound = 0;
if (millis() - lastAlarmSound > 2000) {
tone(BUZZER_PIN, 1000, 500);
lastAlarmSound = millis();
}
// Snooze butonu
if (btn == BTN_SEC) {
snoozeAlarm();
}
}
}
void snoozeAlarm() {
durum.snoozeTime = millis();
durum.alarm = false;
noTone(BUZZER_PIN);
durum.lcdDirty = true;
lcd.clear();
lcd.print("Alarm Ertelendi");
lcd.setCursor(0, 1);
lcd.print("5 dakika");
bekle(1500);
}
void sistemSaglikKontrol() {
// Çalışma süresi güncelle
durum.istatistik.toplamCalismaZamani = (millis() - durum.sistemBaslangic) / 1000;
// Sensor timeout kontrolü
if (millis() - durum.sonSensorOkuma > SENSOR_TIMEOUT) {
durum.guvenliMod = true;
durum.lcdDirty = true;
}
// İstatistikleri kaydet
ayarlariKaydet();
// Bellek kontrolü
extern int __heap_start, *__brkval;
int v;
int freeMemory = (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
if (freeMemory < 200) { // 200 byte altında RAM kaldıysa
lcd.clear();
lcd.print("DUSUK RAM!");
lcd.setCursor(0, 1);
lcd.print("Yeniden Baslat");
bekle(3000);
// Sistem yeniden başlatma
wdt_enable(WDTO_15MS);
while(1) {}
}
}
void anaEkranButonlar(Button btn) {
switch (btn) {
case BTN_YUKARI:
durum.menu = TUR_SEC;
durum.lcdDirty = true;
break;
case BTN_ASAGI:
durum.menu = HATA_MENU;
durum.lcdDirty = true;
break;
case BTN_SAG:
durum.menu = KULUCAKA_S;
durum.sicakSecim = 0;
durum.lcdDirty = true;
break;
case BTN_SOL:
durum.menu = KULUCAKA_N;
durum.nemSecim = 0;
durum.lcdDirty = true;
break;
case BTN_SEC:
durum.menu = TEST_MODU;
durum.testSecim = 1;
durum.lcdDirty = true;
break;
default:
break;
}
}
void menuIslem(Button btn) {
switch (durum.menu) {
case TUR_SEC:
turSecMenu(btn);
break;
case KULUCAKA_S:
sicaklikMenu(btn);
break;
case KULUCAKA_N:
nemMenu(btn);
break;
case TARIH:
tarihDuzenle(btn);
break;
case HATA_MENU:
hataMenu(btn);
break;
case TEST_MODU:
testModuIslem(btn);
break;
default:
break;
}
}
void turSecMenu(Button btn) {
switch (btn) {
case BTN_YUKARI:
if (durum.aktifTur > 0) {
durum.aktifTur--;
durum.lcdDirty = true;
}
break;
case BTN_ASAGI:
if (durum.aktifTur < 3) {
durum.aktifTur++;
durum.lcdDirty = true;
}
break;
case BTN_SEC:
ayarlariKaydet();
durum.menu = ANA_EKRAN;
durum.lcdDirty = true;
// Onay sesi
tone(BUZZER_PIN, 1200, 200);
delay(250);
noTone(BUZZER_PIN);
break;
case BTN_SOL:
durum.menu = ANA_EKRAN;
durum.lcdDirty = true;
break;
case BTN_SAG:
durum.menu = TARIH;
durum.tarihSecimi = 0;
durum.lcdDirty = true;
break;
default:
break;
}
}
void sicaklikMenu(Button btn) {
TurProfili &t = TURLAR[durum.aktifTur];
switch (btn) {
case BTN_YUKARI:
if (durum.sicakSecim == 0) {
t.kuluSicak[0] += 0.1;
if (t.kuluSicak[0] > t.kuluSicak[1] - 0.5) {
t.kuluSicak[0] = t.kuluSicak[1] - 0.5;
}
} else {
t.kuluSicak[1] += 0.1;
}
t.kuluSicak[0] = constrain(t.kuluSicak[0], MIN_SICAKLIK, MAX_SICAKLIK);
t.kuluSicak[1] = constrain(t.kuluSicak[1], MIN_SICAKLIK, MAX_SICAKLIK);
durum.lcdDirty = true;
break;
case BTN_ASAGI:
if (durum.sicakSecim == 0) {
t.kuluSicak[0] -= 0.1;
} else {
t.kuluSicak[1] -= 0.1;
if (t.kuluSicak[1] < t.kuluSicak[0] + 0.5) {
t.kuluSicak[1] = t.kuluSicak[0] + 0.5;
}
}
t.kuluSicak[0] = constrain(t.kuluSicak[0], MIN_SICAKLIK, MAX_SICAKLIK);
t.kuluSicak[1] = constrain(t.kuluSicak[1], MIN_SICAKLIK, MAX_SICAKLIK);
durum.lcdDirty = true;
break;
case BTN_SAG:
durum.sicakSecim = (durum.sicakSecim + 1) % 2;
durum.lcdDirty = true;
break;
case BTN_SEC:
ayarlariKaydet();
durum.menu = ANA_EKRAN;
durum.lcdDirty = true;
// Onay sesi
tone(BUZZER_PIN, 1200, 200);
delay(250);
noTone(BUZZER_PIN);
break;
case BTN_SOL:
durum.menu = ANA_EKRAN;
durum.lcdDirty = true;
break;
default:
break;
}
}
void nemMenu(Button btn) {
TurProfili &t = TURLAR[durum.aktifTur];
switch (btn) {
case BTN_YUKARI:
if (durum.nemSecim == 0) {
t.kuluNem[0] += 1;
if (t.kuluNem[0] > t.kuluNem[1] - 5) {
t.kuluNem[0] = t.kuluNem[1] - 5;
}
} else {
t.kuluNem[1] += 1;
}
t.kuluNem[0] = constrain(t.kuluNem[0], 30, 95);
t.kuluNem[1] = constrain(t.kuluNem[1], 35, 95);
durum.lcdDirty = true;
break;
case BTN_ASAGI:
if (durum.nemSecim == 0) {
t.kuluNem[0] -= 1;
} else {
t.kuluNem[1] -= 1;
if (t.kuluNem[1] < t.kuluNem[0] + 5) {
t.kuluNem[1] = t.kuluNem[0] + 5;
}
}
t.kuluNem[0] = constrain(t.kuluNem[0], 30, 95);
t.kuluNem[1] = constrain(t.kuluNem[1], 35, 95);
durum.lcdDirty = true;
break;
case BTN_SAG:
durum.nemSecim = (durum.nemSecim + 1) % 2;
durum.lcdDirty = true;
break;
case BTN_SEC:
ayarlariKaydet();
durum.menu = ANA_EKRAN;
durum.lcdDirty = true;
// Onay sesi
tone(BUZZER_PIN, 1200, 200);
delay(250);
noTone(BUZZER_PIN);
break;
case BTN_SOL:
durum.menu = ANA_EKRAN;
durum.lcdDirty = true;
break;
default:
break;
}
}
void tarihDuzenle(Button btn) {
DateTime now = rtc.now();
switch (btn) {
case BTN_SEC:
durum.baslangicTarihi = now.unixtime();
durum.sonDonus = now.unixtime();
ayarlariKaydet();
durum.menu = ANA_EKRAN;
durum.lcdDirty = true;
// Onay sesi
tone(BUZZER_PIN, 1200, 200);
delay(250);
noTone(BUZZER_PIN);
break;
case BTN_SOL:
durum.menu = TUR_SEC;
durum.lcdDirty = true;
break;
default:
break;
}
}
void hataMenu(Button btn) {
switch (btn) {
case BTN_YUKARI:
if (durum.hataMenu > HATA_GENEL) {
durum.hataMenu = (HataMenuOgesi)((int)durum.hataMenu - 1);
durum.lcdDirty = true;
}
break;
case BTN_ASAGI:
if (durum.hataMenu < HATA_ISTATISTIK) {
durum.hataMenu = (HataMenuOgesi)((int)durum.hataMenu + 1);
durum.lcdDirty = true;
}
break;
case BTN_SEC:
if (durum.hataMenu == HATA_SISTEM) {
fabrikaAyarlari(); // Fabrika ayarlarına dön
}
durum.lcdDirty = true;
break;
case BTN_SOL:
durum.menu = ANA_EKRAN;
durum.lcdDirty = true;
break;
default:
break;
}
}
void testModuIslem(Button btn) {
switch (btn) {
case BTN_YUKARI:
if (durum.testSecim > 1) {
durum.testSecim--;
durum.lcdDirty = true;
}
break;
case BTN_ASAGI:
if (durum.testSecim < 6) {
durum.testSecim++;
durum.lcdDirty = true;
}
break;
case BTN_SEC:
if (durum.testSecim == 6) {
durum.menu = ANA_EKRAN;
durum.lcdDirty = true;
} else {
durum.testModuAktif = true;
durum.testTipi = durum.testSecim;
durum.testAsama = 0;
durum.testZamani = millis();
durum.lcdDirty = true;
}
break;
case BTN_SOL:
durum.menu = ANA_EKRAN;
durum.lcdDirty = true;
break;
default:
break;
}
}
void ekranGuncelle() {
switch (durum.menu) {
case ANA_EKRAN:
anaEkranGoster();
break;
case TUR_SEC:
turSecEkran();
break;
case KULUCAKA_S:
sicaklikEkran();
break;
case KULUCAKA_N:
nemEkran();
break;
case TARIH:
tarihEkran();
break;
case HATA_MENU:
hataEkran();
break;
case TEST_MODU:
testModuEkran();
break;
default:
break;
}
}
void anaEkranGoster() {
lcd.clear();
// İlk satır: Tür ve gün bilgisi
TurProfili &t = TURLAR[durum.aktifTur];
lcd.print(t.isim);
DateTime now = rtc.now();
uint32_t gecenGun = (now.unixtime() - durum.baslangicTarihi) / 86400;
lcd.print(" G:");
lcd.print(gecenGun);
lcd.print("/");
lcd.print(t.kuluckaGun);
// İkinci satır: Sıcaklık ve nem
lcd.setCursor(0, 1);
lcd.print(sicaklik, 1);
lcd.print("C ");
lcd.print(nem, 0);
lcd.print("% O");
lcd.print(servoAcisi);
// Durum göstergeleri
if (durum.alarm) {
lcd.setCursor(15, 0);
lcd.print("!");
}
if (durum.guvenliMod) {
lcd.setCursor(14, 0);
lcd.print("G");
}
if (durum.donuyor) {
lcd.setCursor(13, 0);
lcd.print("D");
}
// Aktif sistemler göstergesi
if (durum.isitici || durum.nemlendirici || durum.sogutma) {
lcd.setCursor(15, 1);
if (durum.isitici) lcd.print("I");
else if (durum.sogutma) lcd.print("S");
else if (durum.nemlendirici) lcd.print("N");
}
}
void turSecEkran() {
lcd.clear();
lcd.print("TUR SECIMI");
lcd.setCursor(0, 1);
lcd.print(">");
lcd.print(TURLAR[durum.aktifTur].isim);
lcd.print(" ");
lcd.print(TURLAR[durum.aktifTur].kuluckaGun);
lcd.print("gun");
}
void sicaklikEkran() {
lcd.clear();
lcd.print("SICAKLIK AYARI");
lcd.setCursor(0, 1);
TurProfili &t = TURLAR[durum.aktifTur];
if (durum.sicakSecim == 0) {
lcd.print(">");
} else {
lcd.print(" ");
}
lcd.print(t.kuluSicak[0], 1);
lcd.print("C-");
if (durum.sicakSecim == 1) {
lcd.print(">");
}
lcd.print(t.kuluSicak[1], 1);
lcd.print("C");
}
void nemEkran() {
lcd.clear();
lcd.print("NEM AYARI");
lcd.setCursor(0, 1);
TurProfili &t = TURLAR[durum.aktifTur];
if (durum.nemSecim == 0) {
lcd.print(">");
} else {
lcd.print(" ");
}
lcd.print((int)t.kuluNem[0]);
lcd.print("%-");
if (durum.nemSecim == 1) {
lcd.print(">");
}
lcd.print((int)t.kuluNem[1]);
lcd.print("%");
}
void tarihEkran() {
lcd.clear();
lcd.print("TARIH SIFIRLAMA");
lcd.setCursor(0, 1);
lcd.print("SEC:Sifirla");
}
void hataEkran() {
lcd.clear();
switch (durum.hataMenu) {
case HATA_GENEL:
lcd.print("GENEL DURUM");
lcd.setCursor(0, 1);
if (durum.guvenliMod) {
lcd.print("Guvenli Mod");
} else {
lcd.print("Normal");
}
break;
case HATA_SENSOR:
lcd.print("SENSOR HATALARI");
lcd.setCursor(0, 1);
lcd.print("S:");
lcd.print(durum.sicaklikHata);
lcd.print(" N:");
lcd.print(durum.nemHata);
break;
case HATA_SICAKLIK:
lcd.print("SICAKLIK");
lcd.setCursor(0, 1);
lcd.print("Mevcut:");
lcd.print(sicaklik, 1);
lcd.print("C");
break;
case HATA_NEM:
lcd.print("NEM");
lcd.setCursor(0, 1);
lcd.print("Mevcut:");
lcd.print(nem, 0);
lcd.print("%");
break;
case HATA_SISTEM:
lcd.print("SISTEM SIFIRLAMA");
lcd.setCursor(0, 1);
lcd.print("SEC:Fabrika Ayr");
break;
case HATA_ISTATISTIK:
lcd.print("ISTATISTIKLER");
lcd.setCursor(0, 1);
lcd.print("Hata S:");
lcd.print(durum.istatistik.toplamSicakHata);
lcd.print(" N:");
lcd.print(durum.istatistik.toplamNemHata);
break;
}
}
void testModuEkran() {
lcd.clear();
lcd.print("TEST MODU");
lcd.setCursor(0, 1);
lcd.print(">");
switch (durum.testSecim) {
case 1:
lcd.print("Role Testi");
break;
case 2:
lcd.print("Motor Testi");
break;
case 3:
lcd.print("Fan Testi");
break;
case 4:
lcd.print("Buzzer Testi");
break;
case 5:
lcd.print("Sensor Testi");
break;
case 6:
lcd.print("Cikis");
break;
}
}