GERÇEK ZAMANLI EZAN OKUYAN SAAT

arkadaşlar merhaba ;

🕌 EZAN SAATİ — Teknik Özellikler
Donanım

ESP8266 NodeMCU
MAX7219 4x8x8 LED Matrix (saat gösterimi)
DFPlayer Mini + SD Kart (MP3 ezan çalma)
DS1307 Tiny RTC I2C (internet olmadan saat tutma)

Pin Bağlantıları

MAX7219: DIN=D7, CLK=D5, CS=D8
DFPlayer: RX=D2, TX=D0
RTC: SDA=D3, SCL=D1

Yazılım Özellikleri

WiFi ile internetten otomatik saat senkronizasyonu (NTP)
Aladhan API ile günlük ezan vakitleri çekme (İstanbul koordinatları)
7 günlük vakitler EEPROM’a kaydedilir, internet olmasa da çalışır
Birden fazla kayıtlı WiFi desteği (sırayla dener)
WiFiManager: hiçbir WiFi bulunamazsa “EzanSaati” adlı hotspot açar, şifre: ezan1234, tarayıcıdan 192.168.4.1 ile yeni WiFi girilebilir
5 vakit ezan: Sabah, Öğle, İkindi, Akşam, Yatsı
Her vakit için ayrı MP3 dosyası (SD kartta 1.mp3 → 5.mp3)
Yeni günde vakitler otomatik güncellenir
İnternet yoksa RTC ile saat, EEPROM’dan vakitler kullanılır

Kayıtlı WiFi Ağları

Mim_Online_bilgisayar
KomsuWifi (değiştirilebilir)
IsWifi (değiştirilebilir)

Açılışta bilinen WiFi’leri dener
Hiçbirine bağlanamazsa → “EzanSaati” hotspot’u açar
Telefonu o hotspot’a bağla → tarayıcıdan 192.168.4.1 aç → yeni WiFi gir
Bağlandıktan sonra hotspot kapanır, normal çalışmaya devam eder

Kamp yerinde ise zaten EEPROM’da 7 günlük vakit var, hotspot açmaya bile gerek kalmaz — direkt offline çalışır. Hotspot sadece yeni bir WiFi öğretmek için devreye girer.

Bilinen WiFi’leri sırayla dener
Hiçbiri yoksa “EzanSaati” hotspot’u açar, şifresi ezan1234
Telefon o hotspot’a bağlanıp 192.168.4.1 adresinden yeni WiFi girilir
7 günlük vakitler EEPROM’a kaydedilir
Kamp yerinde internet olmasa bile çalışır

bu projemiz kendim için tasarladığım ve uzun zamandır tasarladığım bir projedir
8×8 dot matrik
esp8266 wifi modülü
rtc gerçek zaman saat modülü
df mini mp3 player modülü
mikro sd kart

#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <WiFiUDP.h>
#include <NTPClient.h>
#include <ArduinoJson.h>
#include <MD_MAX72xx.h>
#include <MD_Parola.h>
#include <SoftwareSerial.h>
#include <DFPlayer_Mini_Mp3.h>
#include <Wire.h>
#include <RTClib.h>
#include <EEPROM.h>
#include <WiFiManager.h>

// --- Bilinen WiFi listesi ---
const char* wifiListesi[][2] = {
  {"Mim_Online_bilgisayar", "Akcakoca81"},
  {"KomsuWifi",             "komsuSifre"},
  {"IsWifi",                "isSifre"},
};
const int wifiSayisi = 3;

#define MAX_DEVICES 4
#define CS_PIN      D8
#define DIN_PIN     D7
#define CLK_PIN     D5
MD_Parola matrix = MD_Parola(MD_MAX72XX::DR1CR0RR0_HW, DIN_PIN, CLK_PIN, CS_PIN, MAX_DEVICES);

SoftwareSerial mp3Serial(D0, D2);

WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "pool.ntp.org", 3 * 3600);

RTC_DS1307 rtc;

#define EEPROM_SIZE     220
#define EEPROM_TARIH    0
#define EEPROM_VAKITLER 4

struct GunVakitleri {
  char vakitler[5][6];
};

GunVakitleri haftaVakitleri[7];
String bugunVakitleri[5];
bool ezanCalindi[5] = {false, false, false, false, false};
int sonGun = -1;

void vakitleriCek();
void eepromKaydet(int g, int a, int y);
bool eepromYukle(int g, int a, int y);
void bugunVakitleriniAyarla(int g, int a, int y);
bool wifiBaglan();

// ===================== SETUP =====================
void setup() {
  Serial.begin(9600);
  delay(3000);
  Serial.println("=== EZAN SAATI BASLIYOR ===");

  EEPROM.begin(EEPROM_SIZE);
  Wire.begin(D3, D1);

  matrix.begin();
  matrix.setIntensity(3);
  matrix.displayReset();
  matrix.setTextAlignment(PA_CENTER);
  matrix.print("...");

  // RTC başlat
  if (!rtc.begin()) {
    Serial.println("RTC bulunamadi!");
  } else {
    Serial.println("RTC OK!");
    if (!rtc.isrunning()) {
      rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
    }
  }

  // WiFi bağlan
  bool baglandi = wifiBaglan();

  DateTime now = rtc.now();

  if (baglandi) {
    // NTP ile RTC senkronize et
    timeClient.begin();
    timeClient.update();
    unsigned long epoch = timeClient.getEpochTime();
    rtc.adjust(DateTime(epoch));
    now = rtc.now();
    Serial.println("RTC NTP ile senkronize edildi!");
    vakitleriCek();
  } else {
    Serial.println("WiFi yok! EEPROM'dan yukleniyor...");
    bool yuklendi = eepromYukle(now.day(), now.month(), now.year());
    if (yuklendi) {
      bugunVakitleriniAyarla(now.day(), now.month(), now.year());
      Serial.println("EEPROM'dan vakitler yuklendi!");
    } else {
      Serial.println("Sabit vakitler kullaniliyor!");
      bugunVakitleri[0] = "05:00";
      bugunVakitleri[1] = "13:10";
      bugunVakitleri[2] = "17:00";
      bugunVakitleri[3] = "20:10";
      bugunVakitleri[4] = "21:45";
    }
  }

  Serial.println("=== BUGUN VAKİTLERİ ===");
  for (int i = 0; i < 5; i++) Serial.println(bugunVakitleri[i]);

  mp3Serial.begin(9600);
  mp3_set_serial(mp3Serial);
  delay(2000);
  mp3_set_volume(25);
  delay(500);
  mp3_stop();
  delay(500);
}

// ===================== LOOP =====================
void loop() {
  DateTime now = rtc.now();

  int saat       = now.hour();
  int dakika     = now.minute();
  int saniye     = now.second();
  int bugunTarih = now.day();

  if (bugunTarih != sonGun) {
    Serial.println("Yeni gun!");
    for (int i = 0; i < 5; i++) ezanCalindi[i] = false;
    sonGun = bugunTarih;

    if (WiFi.status() == WL_CONNECTED) {
      timeClient.update();
      unsigned long epoch = timeClient.getEpochTime();
      rtc.adjust(DateTime(epoch));
      vakitleriCek();
    } else {
      bool yuklendi = eepromYukle(now.day(), now.month(), now.year());
      if (yuklendi) bugunVakitleriniAyarla(now.day(), now.month(), now.year());
    }
  }

  char saatStr[6];
  sprintf(saatStr, "%02d:%02d", saat, dakika);
  if (matrix.displayAnimate()) {
    matrix.displayReset();
    matrix.setTextAlignment(PA_CENTER);
    matrix.print(saatStr);
  }

  if (saniye == 0) {
    Serial.print("Suan: "); Serial.print(saatStr);
    Serial.print(" | ");
    for (int i = 0; i < 5; i++) {
      Serial.print(bugunVakitleri[i]);
      Serial.print(ezanCalindi[i] ? "(OK) " : " ");
    }
    Serial.println();
  }

  if (saniye < 30) {
    String simdi = String(saat < 10 ? "0" : "") + saat + ":" +
                   String(dakika < 10 ? "0" : "") + dakika;
    for (int i = 0; i < 5; i++) {
      if (!ezanCalindi[i] && bugunVakitleri[i] == simdi) {
        Serial.print("!!! EZAN: "); Serial.println(bugunVakitleri[i]);
        ezanCalindi[i] = true;
        mp3_play(i + 1);
        break;
      }
    }
  }

  delay(1000);
}

// ===================== WiFi BAGLAN =====================
bool wifiBaglan() {
  // Önce bilinen ağları dene
  for (int i = 0; i < wifiSayisi; i++) {
    Serial.print("Deneniyor: ");
    Serial.println(wifiListesi[i][0]);

    // Matrix'e göster
    matrix.displayReset();
    matrix.setTextAlignment(PA_CENTER);
    matrix.print("WiFi");

    WiFi.begin(wifiListesi[i][0], wifiListesi[i][1]);
    int deneme = 0;
    while (WiFi.status() != WL_CONNECTED && deneme < 20) {
      delay(500);
      deneme++;
      Serial.print(".");
    }

    if (WiFi.status() == WL_CONNECTED) {
      Serial.println("\nWiFi baglandi: ");
      Serial.println(wifiListesi[i][0]);
      return true;
    } else {
      WiFi.disconnect();
      delay(500);
    }
  }

  // Hiçbiri olmadı — WiFiManager başlat
  Serial.println("Bilinen WiFi bulunamadi, WiFiManager basliyor...");
  Serial.println("Telefondan 'EzanSaati' hotspot'una baglanin!");
  Serial.println("Sonra 192.168.4.1 adresine gidin.");

  matrix.displayReset();
  matrix.setTextAlignment(PA_CENTER);
  matrix.print("AYAR");

  WiFiManager wifiManager;
  wifiManager.setTimeout(180); // 3 dakika bekle, olmazsa devam et
  
  if (wifiManager.autoConnect("EzanSaati", "ezan1234")) {
    Serial.println("WiFiManager ile baglandi!");
    return true;
  } else {
    Serial.println("WiFi baglanamadi, offline devam!");
    return false;
  }
}

// ===================== 7 GÜNLÜK VAKİT ÇEK =====================
void vakitleriCek() {
  DateTime now = rtc.now();
  int baslangicGun = now.day();
  int baslangicAy  = now.month();
  int baslangicYil = now.year();

  Serial.println("7 gunluk vakitler cekiliyor...");

  for (int g = 0; g < 7; g++) {
    DateTime hedef = DateTime(baslangicYil, baslangicAy, baslangicGun) + TimeSpan(g, 0, 0, 0);
    int gun = hedef.day();
    int ay  = hedef.month();
    int yil = hedef.year();

    char tarih[11];
    sprintf(tarih, "%02d-%02d-%04d", gun, ay, yil);

    String url = "http://api.aladhan.com/v1/timings/" + String(tarih) +
                 "?latitude=41.0082&longitude=28.9784&method=13";

    Serial.print("Gun "); Serial.print(g); Serial.print(": "); Serial.println(tarih);

    WiFiClient client;
    HTTPClient http;
    http.begin(client, url);
    http.setTimeout(15000);
    http.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS);

    int httpCode = http.GET();

    if (httpCode == 200) {
      String payload = http.getString();
      DynamicJsonDocument doc(4096);
      DeserializationError hata = deserializeJson(doc, payload);

      if (!hata) {
        String v[5];
        v[0] = doc["data"]["timings"]["Fajr"].as<String>();
        v[1] = doc["data"]["timings"]["Dhuhr"].as<String>();
        v[2] = doc["data"]["timings"]["Asr"].as<String>();
        v[3] = doc["data"]["timings"]["Maghrib"].as<String>();
        v[4] = doc["data"]["timings"]["Isha"].as<String>();

        for (int i = 0; i < 5; i++) {
          if (v[i].length() > 5) v[i] = v[i].substring(0, 5);
          strncpy(haftaVakitleri[g].vakitler[i], v[i].c_str(), 5);
          haftaVakitleri[g].vakitler[i][5] = '\0';
        }

        Serial.print("  "); 
        Serial.print(haftaVakitleri[g].vakitler[0]); Serial.print(" ");
        Serial.print(haftaVakitleri[g].vakitler[1]); Serial.print(" ");
        Serial.print(haftaVakitleri[g].vakitler[2]); Serial.print(" ");
        Serial.print(haftaVakitleri[g].vakitler[3]); Serial.print(" ");
        Serial.println(haftaVakitleri[g].vakitler[4]);
      }
    } else {
      Serial.print("  Hata: "); Serial.println(httpCode);
    }

    http.end();
    delay(500);
  }

  eepromKaydet(baslangicGun, baslangicAy, baslangicYil);
  bugunVakitleriniAyarla(baslangicGun, baslangicAy, baslangicYil);
}

// ===================== EEPROM KAYDET =====================
void eepromKaydet(int g, int a, int y) {
  EEPROM.write(EEPROM_TARIH + 0, g);
  EEPROM.write(EEPROM_TARIH + 1, a);
  EEPROM.write(EEPROM_TARIH + 2, y & 0xFF);
  EEPROM.write(EEPROM_TARIH + 3, (y >> 8) & 0xFF);

  int adres = EEPROM_VAKITLER;
  for (int gun = 0; gun < 7; gun++) {
    for (int v = 0; v < 5; v++) {
      for (int k = 0; k < 6; k++) {
        EEPROM.write(adres++, haftaVakitleri[gun].vakitler[v][k]);
      }
    }
  }
  EEPROM.commit();
  Serial.println("EEPROM kaydedildi!");
}

// ===================== EEPROM YUKLE =====================
bool eepromYukle(int gun, int ay, int yil) {
  int kGun = EEPROM.read(EEPROM_TARIH + 0);
  int kAy  = EEPROM.read(EEPROM_TARIH + 1);
  int kYil = EEPROM.read(EEPROM_TARIH + 2) | (EEPROM.read(EEPROM_TARIH + 3) << 8);

  Serial.print("EEPROM tarihi: ");
  Serial.print(kGun); Serial.print("/"); Serial.print(kAy); Serial.print("/"); Serial.println(kYil);

  if (kYil < 2024 || kYil > 2100) return false;

  DateTime baslangic(kYil, kAy, kGun);
  DateTime bugun(yil, ay, gun);
  int fark = (bugun.unixtime() - baslangic.unixtime()) / 86400;

  Serial.print("Gun farki: "); Serial.println(fark);

  if (fark < 0 || fark >= 7) return false;

  int adres = EEPROM_VAKITLER;
  for (int g = 0; g < 7; g++) {
    for (int v = 0; v < 5; v++) {
      for (int k = 0; k < 6; k++) {
        haftaVakitleri[g].vakitler[v][k] = EEPROM.read(adres++);
      }
    }
  }
  return true;
}

// ===================== BUGÜN VAKİTLERİNİ AYARLA =====================
void bugunVakitleriniAyarla(int gun, int ay, int yil) {
  int kGun = EEPROM.read(EEPROM_TARIH + 0);
  int kAy  = EEPROM.read(EEPROM_TARIH + 1);
  int kYil = EEPROM.read(EEPROM_TARIH + 2) | (EEPROM.read(EEPROM_TARIH + 3) << 8);

  DateTime baslangic(kYil, kAy, kGun);
  DateTime bugun(yil, ay, gun);
  int fark = (bugun.unixtime() - baslangic.unixtime()) / 86400;

  if (fark < 0 || fark >= 7) fark = 0;

  for (int i = 0; i < 5; i++) {
    bugunVakitleri[i] = String(haftaVakitleri[fark].vakitler[i]);
  }
}

mikrosd kart içerisinde mp3 isimli bir klasör oluşturup dosya isimleri 0001.mp3 olarak düzenlenecektir