Rehberler · 11 dk okuma

ESP32 NTP ile İnternetten Saat: Saat Dilimi, OLED ve RTC Yedeği

ESP32 NTP ile saat nasıl alınır? configTzTime ve Türkiye saat dilimi, getLocalTime, strftime, OLED saat, DS3231 yedeği, her gün zamanlı görev ve Pico W ntptime.

ESP32 NTP ile saat almak, kartı internetteki zaman sunucularına bağlayıp tarihi ve saati hiçbir saat modülü kullanmadan, birkaç on milisaniye doğrulukla öğrenmek demektir. ESP32 Wi-Fi'ye bağlandıktan sonra tek bir configTzTime() çağrısıyla saati alır, saat dilimini uygular ve ardından saati kendi içinde saymaya devam eder. Masa saati, zamanlı sulama, veri kaydında zaman damgası, her sabah çalan alarm ya da belirli saatte açılan aydınlatma gibi projelerde ayrı bir RTC modülüne gerek kalmaz.

Bu rehberde NTP'nin nasıl çalıştığını, Türkiye için doğru saat dilimi ayarını (UTC+3), getLocalTime ve strftime ile tarihi istediğin biçimde yazmayı, saati OLED ekranda göstermeyi, Wi-Fi kesildiğinde ya da elektrik gidip geldiğinde saati DS3231 modülüyle korumayı ve her gün belirli bir saatte görev çalıştırmayı adım adım kuracağız. Son bölümde aynı işi Raspberry Pi Pico W'de MicroPython'un ntptime modülüyle yapacağız.

ESP32 geliştirme kartı
ESP32 DevKit: dahili Wi-Fi sayesinde NTP sunucularından saati alır ve ayrı bir saat modülü olmadan tarih ile saati tutar.

NTP nedir, ESP32 saati nasıl alır?

NTP (Network Time Protocol), bilgisayarların ve cihazların saatlerini internet üzerinden eşitlemek için kullanılan, 1980'lerden beri çalışan bir protokoldür. Sunucular katmanlar (stratum) hâlinde dizilir: stratum 1 sunucular doğrudan atom saatine ya da GPS'e bağlıdır, stratum 2 sunucular onlardan saat alır ve bu böyle devam eder. ESP32 saati UDP 123 portundan küçük bir paketle ister; sunucu 1900'den beri geçen saniyeyi ve saniyenin kesirini içeren bir zaman damgası döndürür. ESP32 paketin gidip gelme süresini hesaba katarak kendi saatini ayarlar. Ev internetinde bu yöntemle elde edilen doğruluk genellikle 10–50 milisaniye arasındadır; bir saat projesi için fazlasıyla yeterlidir.

ESP32'nin içindeki lwIP ağ yığını NTP'nin basitleştirilmiş sürümü olan SNTP'yi kullanır. Saat bir kez alındıktan sonra ESP32 onu sistem saati olarak tutar ve kristalden türetilen bir sayaçla saymaya devam eder; her saniye internete gitmez. Arka planda belirli aralıklarla (Arduino ESP32 çekirdeğinde varsayılan olarak 3 saatte bir) sunucuya yeniden sorup küçük kaymaları düzeltir. Sistem saati UTC olarak tutulur; senin gördüğün yerel saat, buna saat dilimi kuralı uygulanarak hesaplanır.

KavramDeğer / açıklama
Protokol ve portSNTP, UDP 123
Zaman damgası1900'den beri geçen saniye (ESP32 bunu 1970 tabanlı Unix zamanına çevirir)
Tipik doğrulukEv internetinde 10–50 ms
Yeniden eşitlemeArduino ESP32'de varsayılan 3 saat, sntp_set_sync_interval() ile değişir (en az 15 sn)
En fazla sunucu3 (configTzTime'a verilen sunucu adları)
İnternet trafiğiİstek ve yanıt 48 baytlık birer NTP paketi; günde birkaç kilobayt bile etmez
GerekenlerESP32, 2,4 GHz Wi-Fi ağı ve internet bağlantısı

configTime ve configTzTime: Türkiye saat dilimi (UTC+3)

Arduino ESP32 çekirdeğinde NTP'yi başlatmanın iki yolu vardır. configTime(gmtOffset_sec, daylightOffset_sec, sunucu1, sunucu2, sunucu3) UTC farkını ve yaz saati farkını saniye olarak alır: Türkiye için configTime(10800, 0, "pool.ntp.org") yazarsın, çünkü 3 saat 10.800 saniyedir ve Türkiye 2016'dan beri yaz saati uygulamadan yıl boyu UTC+3'te kalır. Bu yöntem basittir ama bölgenin yaz saatine geçiş tarihlerini bilmez; Avrupa gibi yaz saati uygulanan bir yerde geçişler yanlış günde olur, bu yüzden orada configTzTime kullanmalısın.

Daha doğru yol configTzTime(TZ, sunucu1, sunucu2, sunucu3) fonksiyonudur. Bu fonksiyon POSIX biçiminde bir saat dilimi metni alır ve yaz saatine geçiş kurallarını da içerir; ESP32 her yıl geçişi kendisi yapar. Türkiye için metin "<+03>-3" şeklindedir: köşeli parantez içindeki +03 ekranda görünecek kısaltma, -3 ise UTC'ye ulaşmak için yerel saatten 3 saat çıkarılması gerektiği anlamına gelir. Aşağıdaki tabloda sık kullanılan bölgelerin metinleri var.

BölgeTZ metni (configTzTime)configTime karşılığı
Türkiye (yıl boyu UTC+3)<+03>-3configTime(10800, 0, ...)
Almanya, Fransa, İtalya, İspanyaCET-1CEST,M3.5.0,M10.5.0/3Uygun değil, configTzTime kullan
İngiltere, PortekizGMT0BST,M3.5.0/1,M10.5.0Uygun değil, configTzTime kullan
ABD doğu (New York)EST5EDT,M3.2.0,M11.1.0Uygun değil, configTzTime kullan
Azerbaycan, Gürcistan (UTC+4)<+04>-4configTime(14400, 0, ...)
UTC (zaman damgası için)UTC0configTime(0, 0, ...)
POSIX saat dilimi metninde işaret terstir: Türkiye için "UTC+3" ya da "GMT+3" yazarsan ESP32 bunu "UTC'nin 3 saat gerisi" olarak yorumlar ve saat 6 saat yanlış çıkar. Doğru metin "<+03>-3" ya da "UTC-3"tür. Saatin tam 3 ya da 6 saat kaydığını görüyorsan sorun hemen her zaman bu işarettir.

Gerekenler ve bağlantılar

Yalnızca saati Seri Monitör'de görmek için ESP32 ve bir Wi-Fi ağı yeterlidir. Rehberin ilerleyen bölümlerinde saati göstermek için 0,96 inç SSD1306 OLED ekran, saati elektrik kesintisinde korumak için DS3231 RTC modülü ve zamanlı görev örneğinde bir röle modülü kullanıyoruz. OLED ile DS3231 aynı I2C hattını paylaşır, yani ikisi de aynı iki pine bağlanır. ESP32'nin pin dizilimine Pinout aracından bakabilirsin.

Parça piniESP32Raspberry Pi Pico WNot
OLED / DS3231 VCC3V33V3 (OUT)İkisi de 3,3 V ile çalışır
OLED / DS3231 GNDGNDGNDOrtak toprak
OLED / DS3231 SDAGPIO 21GP4I2C veri hattı
OLED / DS3231 SCLGPIO 22GP5I2C saat hattı
Röle modülü INGPIO 26GP15Zamanlı görev örneği
Röle modülü VCC5V (VIN)VBUSÇoğu röle bobini 5 V ister
ESP32 yalnızca 2,4 GHz Wi-Fi ağlarına bağlanır. Modem 5 GHz ve 2,4 GHz için aynı adı kullanıyorsa ya da ağın adında Türkçe karakter varsa bağlantı kurulamayabilir. Saat hiç gelmiyorsa önce Seri Monitör'de Wi-Fi'nin bağlandığından emin ol; NTP ancak Wi-Fi bağlandıktan sonra çalışır.

Adım adım ilk ESP32 NTP kodu

  1. Arduino IDE'de ESP32 kart paketinin kurulu olduğundan emin ol ve Araçlar menüsünden ESP32 Dev Module kartını seç. Kurulumu bilmiyorsan ESP32 Nedir yazısına bakabilirsin.
  2. Ek kütüphane gerekmez: WiFi.h ve time.h ESP32 çekirdeğiyle gelir.
  3. Koddaki WIFI_SSID ve WIFI_PASS değerlerini kendi ağınla değiştir.
  4. Kodu yükle, Seri Monitör'ü 115200 baud hızında aç.
  5. Önce Wi-Fi noktaları, birkaç saniye sonra her saniye güncellenen tarih ve saat görünmelidir.
C++ (Arduino IDE)
1#include <WiFi.h>
2#include <time.h>
3
4const char* WIFI_SSID = "AgAdi";       // Wi-Fi adı / Wi-Fi name
5const char* WIFI_PASS = "Sifre123";    // Wi-Fi şifresi / Wi-Fi password
6const char* TZ_INFO   = "<+03>-3";     // Türkiye: UTC+3, yaz saati yok / Turkey: UTC+3, no DST
7
8void setup() {
9  Serial.begin(115200);
10  WiFi.begin(WIFI_SSID, WIFI_PASS);
11  Serial.print("Wi-Fi");
12  while (WiFi.status() != WL_CONNECTED) {    // bağlanana kadar bekle / wait until connected
13    delay(500);
14    Serial.print(".");
15  }
16  Serial.println(" OK");
17
18  // NTP sunucuları + saat dilimi / NTP servers + time zone
19  configTzTime(TZ_INFO, "pool.ntp.org", "time.cloudflare.com");
20
21  struct tm t;
22  while (!getLocalTime(&t)) {                // ilk eşitlemeyi bekle (5 sn deneme) / wait for the first sync (5 s per try)
23    Serial.println("NTP bekleniyor / waiting for NTP");
24  }
25  Serial.println("Saat alindi / time received");
26}
27
28void loop() {
29  struct tm t;
30  if (getLocalTime(&t)) {
31    Serial.println(&t, "%d.%m.%Y %H:%M:%S");  // ör. 16.11.2026 14:05:09 / e.g. 16.11.2026 14:05:09
32  }
33  delay(1000);
34}
35
SatırNe yapar?
configTzTime(TZ_INFO, ...)SNTP istemcisini başlatır, sunucuları ve saat dilimini ayarlar; hemen döner, saat arka planda gelir
getLocalTime(&t)Yerel saati struct tm yapısına doldurur; saat yoksa en fazla 5 saniye bekleyip false döner
Serial.println(&t, "...")ESP32'nin Print sınıfı struct tm'yi doğrudan strftime biçimiyle yazdırabilir
time(nullptr)1970'ten beri geçen saniyeyi (Unix zamanı, UTC) verir

Burada önemli bir ayrıntı var: getLocalTime() saatin "geçerli" olup olmadığını yıla bakarak anlar. ESP32 ilk açıldığında sistem saati 1 Ocak 1970'tedir ve fonksiyon yıl 2016'dan büyük olana kadar false döndürür. Bu yüzden NTP gelmeden çalışan bir görev ya da kayıt kodu, yanlışlıkla 1970 tarihli veriler üretmez; tabii dönüş değerini kontrol edersen. Fonksiyonun ikinci parametresi bekleme süresidir (milisaniye); loop() içinde kodu bekletmek istemiyorsan getLocalTime(&t, 0) yazarak yalnızca bir kez denemesini sağlayabilirsin.

struct tm: saatin parçaları

getLocalTime() saati bir struct tm yapısına parçalayarak yazar. Bu alanlarla saat, gün ya da ay karşılaştırması yaparak zamanlı görevler kurarsın. Yapının iki alanı yeni başlayanları sık yanıltır: ay 0'dan, yıl ise 1900'den başlayarak sayılır.

AlanAralıkÖrnek (16 Kasım 2026, 14:05:09, Pazartesi)
tm_sec0–59 (artık saniyede 60)9
tm_min0–595
tm_hour0–2314
tm_mday1–3116
tm_mon0–11 (0 = Ocak)10
tm_year1900'den beri geçen yıl126 (1900 + 126 = 2026)
tm_wday0–6 (0 = Pazar)1
tm_yday0–365 (yılın kaçıncı günü, 0'dan)319
Ekrana "16.10.2026" yazıyorsa ama bugün Kasım'daysa tm_mon değerine 1 eklemeyi unutmuşsundur. Yılı 126 görüyorsan da tm_year + 1900 yazman gerekir. strftime kullanırsan bu dönüşümleri senin yerine yapar.

strftime ile tarih ve saati biçimlendirmek

strftime(), struct tm içindeki saati istediğin kalıba göre bir karakter dizisine yazar. Kalıp içindeki yüzde işaretli kodlar ilgili değerle değiştirilir, geri kalan karakterler aynen kalır. Dizinin boyutunu en uzun çıktı artı bir (sondaki sıfır karakteri) olacak şekilde ayırmalısın: "14:05:09" 8 karakterdir, bu yüzden dizi en az 9 bayt olmalıdır. Sık kullanılan kodlar:

KodAnlamıÖrnek çıktı
%H / %M / %SSaat (00–23) / dakika / saniye14 / 05 / 09
%I ve %p12 saatlik saat ve AM/PM02 PM
%d / %m / %YGün / ay (01–12) / dört haneli yıl16 / 11 / 2026
%yİki haneli yıl26
%A / %aGün adı, uzun / kısa (İngilizce)Monday / Mon
%B / %bAy adı, uzun / kısa (İngilizce)November / Nov
%jYılın günü (001–366)320
%F / %T%Y-%m-%d / %H:%M:%S kısayolları2026-11-16 / 14:05:09
%ZSaat dilimi kısaltması+03

ESP32'deki C kütüphanesi yalnızca İngilizce gün ve ay adlarını bilir; %A her zaman "Monday" yazar. Türkçe tarih için gün ve ay adlarını kendi dizinde tutup tm_wday ve tm_mon değerlerini dizi indisi olarak kullanırsın. Seri Monitör UTF-8 desteklediği için Türkçe harfler orada düzgün görünür. Aşağıdaki kod hem "16 Kasım 2026 Pazartesi" gibi okunaklı bir tarih hem de veri kaydı için sıralanabilir ISO biçimini (2026-11-16 14:05:09) üretir.

C++ (Arduino IDE)
1#include <WiFi.h>
2#include <time.h>
3
4const char* WIFI_SSID = "AgAdi";
5const char* WIFI_PASS = "Sifre123";
6const char* TZ_INFO   = "<+03>-3";
7
8// tm_wday: 0 = Pazar ... 6 = Cumartesi / 0 = Sunday ... 6 = Saturday
9const char* GUNLER[] = {"Pazar", "Pazartesi", "Salı", "Çarşamba", "Perşembe", "Cuma", "Cumartesi"};
10const char* AYLAR[]  = {"Ocak", "Şubat", "Mart", "Nisan", "Mayıs", "Haziran",
11                        "Temmuz", "Ağustos", "Eylül", "Ekim", "Kasım", "Aralık"};
12
13void setup() {
14  Serial.begin(115200);
15  WiFi.begin(WIFI_SSID, WIFI_PASS);
16  while (WiFi.status() != WL_CONNECTED) delay(500);
17  configTzTime(TZ_INFO, "pool.ntp.org");
18}
19
20void loop() {
21  struct tm t;
22  if (!getLocalTime(&t)) return;             // saat henüz yok / time not set yet
23
24  char saat[9];                              // "HH:MM:SS" + '\0'
25  char iso[20];                              // "YYYY-MM-DD HH:MM:SS" + '\0'
26  strftime(saat, sizeof(saat), "%H:%M:%S", &t);
27  strftime(iso, sizeof(iso), "%Y-%m-%d %H:%M:%S", &t);
28
29  // Türkçe tarih: 16 Kasım 2026 Pazartesi / Turkish date
30  Serial.printf("%d %s %d %s  %s\n", t.tm_mday, AYLAR[t.tm_mon], t.tm_year + 1900, GUNLER[t.tm_wday], saat);
31  Serial.printf("Kayit / log: %s  epoch: %ld\n", iso, (long)time(nullptr));
32  delay(1000);
33}
34
Veri kaydederken (SD kart, Google Sheets, sunucu) tarihi her zaman %Y-%m-%d %H:%M:%S biçiminde ya da doğrudan Unix zamanı olarak yaz. Bu biçim alfabetik sıralandığında kronolojik de sıralanır; Excel ve veritabanları da onu tarih olarak tanır. Ekranda gösterirken Türkçe biçimi kullanabilirsin.

OLED ekranda saat ve tarih göstermek

Saati Seri Monitör'den çıkarıp gerçek bir masa saatine dönüştürmek için 0,96 inç SSD1306 OLED ekran idealdir: ucuzdur, iki kabloyla bağlanır ve büyük rakamları keskin gösterir. Aşağıdaki kod üstte gün adını ve tarihi, ortada büyük punto ile saati, altta da Wi-Fi durumunu gösterir. Ekranı her döngüde değil, yalnızca saniye değiştiğinde yeniden çizdiği için I2C hattını boşuna meşgul etmez. Adafruit SSD1306 ve Adafruit GFX kütüphanelerini Kütüphane Yöneticisi'nden kurman gerekir; ekranın ayrıntıları OLED Ekran (SSD1306) yazısında.

C++ (Arduino IDE)
1#include <WiFi.h>
2#include <Wire.h>
3#include <Adafruit_GFX.h>
4#include <Adafruit_SSD1306.h>
5#include <time.h>
6
7const char* WIFI_SSID = "AgAdi";
8const char* WIFI_PASS = "Sifre123";
9const char* TZ_INFO   = "<+03>-3";
10// OLED yazı tipinde Türkçe harf yok / the OLED font has no Turkish letters
11const char* GUNLER[] = {"Pazar", "Pazartesi", "Sali", "Carsamba", "Persembe", "Cuma", "Cumartesi"};
12
13Adafruit_SSD1306 display(128, 64, &Wire, -1);
14int sonSaniye = -1;                          // son çizilen saniye / last drawn second
15
16void yaz(const char* mesaj) {                // ekrana tek satır / one line on screen
17  display.clearDisplay();
18  display.setTextSize(1);
19  display.setCursor(0, 0);
20  display.print(mesaj);
21  display.display();
22}
23
24void setup() {
25  Wire.begin(21, 22);                        // SDA = 21, SCL = 22
26  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
27  display.setTextColor(SSD1306_WHITE);
28  yaz("Wi-Fi baglaniyor...");
29
30  WiFi.begin(WIFI_SSID, WIFI_PASS);
31  while (WiFi.status() != WL_CONNECTED) delay(300);
32  configTzTime(TZ_INFO, "pool.ntp.org", "time.cloudflare.com");
33  yaz("NTP bekleniyor...");
34}
35
36void loop() {
37  struct tm t;
38  if (!getLocalTime(&t, 0)) {                // 0 = beklemeden dene / try without waiting
39    delay(200);
40    return;
41  }
42  if (t.tm_sec == sonSaniye) {               // saniye değişmediyse çizme / redraw only on a new second
43    delay(20);
44    return;
45  }
46  sonSaniye = t.tm_sec;
47
48  char saat[9], tarih[11];
49  strftime(saat, sizeof(saat), "%H:%M:%S", &t);
50  strftime(tarih, sizeof(tarih), "%d.%m.%Y", &t);
51
52  display.clearDisplay();
53  display.setTextSize(1);
54  display.setCursor(0, 0);
55  display.print(GUNLER[t.tm_wday]);          // gün adı / day name
56  display.setCursor(68, 0);
57  display.print(tarih);                      // 10 karakter = 60 piksel / 10 chars = 60 px
58  display.setTextSize(2);
59  display.setCursor(16, 26);
60  display.print(saat);                       // 8 x 12 = 96 piksel genişlik / 96 px wide
61  display.setTextSize(1);
62  display.setCursor(0, 56);
63  display.print(WiFi.status() == WL_CONNECTED ? "Wi-Fi: var" : "Wi-Fi: yok");
64  display.display();
65}
66

Kodda gün adlarının Türkçe harfsiz yazıldığına dikkat et: Adafruit GFX'in varsayılan yazı tipinde ş, ç ve ı gibi harfler yoktur ve yerlerine anlamsız simgeler çıkar. Yazı boyutu 2 olduğunda her karakter 12 piksel genişliğindedir; 8 karakterlik "14:05:09" 96 piksel tutar, 16. pikselden başlatınca 128 piksellik ekranda tam ortalanır. 16x2 karakter LCD kullanmak istersen aynı strftime çıktılarını lcd.print() ile yazman yeterli; bağlantısı I2C LCD Ekran yazısında anlatılıyor.

Wi-Fi kesilince saat ne olur? DS3231 ile RTC yedeği

En sık sorulan soru şudur: Wi-Fi giderse saat de gider mi? Hayır. ESP32 saati bir kez aldıktan sonra kendi sayacıyla saymaya devam eder; Wi-Fi'nin kopması saati durdurmaz. Bu sayaç 40 MHz kristalden beslendiği için kayması günde yaklaşık bir iki saniye kadardır ve Wi-Fi geri geldiğinde bir sonraki eşitlemede düzeltilir. Asıl sorun elektrik kesintisi ya da EN düğmesiyle yeniden başlatmadır: bu durumda sistem saati 1970'e döner ve Wi-Fi yoksa ESP32 saati bilemez.

DurumSaat korunur mu?Ne yapmalı?
Wi-Fi bir süre kesildiEvet, ESP32 saymaya devam ederHiçbir şey; Wi-Fi gelince NTP düzeltir
Deep sleep (derin uyku)Evet, RTC zamanlayıcısı sayarUyku uzunsa uyanınca ara sıra NTP ile eşitle
Elektrik kesildi ya da EN düğmesiHayır, saat 1970'e dönerDS3231 gibi pilli bir RTC modülü ekle
İnternet hiç yok (tarla, depo)NTP hiç gelmezSaati yalnızca RTC modülünden al

Derin uyku sırasında saat ana kristal yerine yonganın içindeki daha az hassas RC osilatörle sayılır. Bu osilatör sıcaklıktan etkilendiği için uzun uykularda saat birkaç saniye, hatta daha fazla kayabilir; bu yüzden pille çalışan ve saatlerce uyuyan projelerde birkaç uyanmada bir NTP eşitlemesi yapmak iyi bir alışkanlıktır. Ayrıntılar ESP32 Deep Sleep yazısında.

RTC saat modülü
Pilli RTC modülü: ESP32'nin elektriği kesildiğinde bile saati saymaya devam eder; Wi-Fi gelene kadar saati buradan alırsın.

Kesintiye dayanıklı bir saat için en iyi yöntem ikisini birleştirmektir: açılışta saati hemen DS3231 modülünden al, Wi-Fi geldiğinde NTP ile düzelt ve her NTP eşitlemesinde DS3231'i de güncelle. Aşağıdaki kodda DS3231'e yerel saat yerine UTC yazılır; böylece saat dilimi kuralı tek bir yerde (TZ metninde) kalır ve yaz saati geçişleri RTC'yi bozmaz. NTP eşitlemesini yakalamak için sntp_set_time_sync_notification_cb() ile bir geri çağırma fonksiyonu tanımlanır. Bu fonksiyon ağ görevi içinde çalıştığı için I2C işi orada yapılmaz; yalnızca bir bayrak kaldırılır ve DS3231'e yazma işini loop() üstlenir. Kod RTClib kütüphanesini kullanır.

C++ (Arduino IDE)
1#include <WiFi.h>
2#include <Wire.h>
3#include <RTClib.h>
4#include <sys/time.h>
5#include "esp_sntp.h"
6
7const char* WIFI_SSID = "AgAdi";
8const char* WIFI_PASS = "Sifre123";
9const char* TZ_INFO   = "<+03>-3";
10
11RTC_DS3231 rtc;
12volatile bool ntpGeldi = false;              // NTP eşitlemesi oldu mu? / did an NTP sync happen?
13
14void ntpCallback(struct timeval* tv) {       // her NTP eşitlemesinde çağrılır / called on every NTP sync
15  ntpGeldi = true;                           // I2C işini loop() yapsın / let loop() do the I2C work
16}
17
18void setup() {
19  Serial.begin(115200);
20  Wire.begin(21, 22);
21  setenv("TZ", TZ_INFO, 1);                  // NTP gelmese de saat dilimi geçerli / TZ valid even without NTP
22  tzset();
23
24  // 1) Sistem saatini önce DS3231'den kur (DS3231'de UTC saklanır) / set system time from the DS3231 (stores UTC)
25  if (rtc.begin() && !rtc.lostPower()) {
26    struct timeval tv = { (time_t)rtc.now().unixtime(), 0 };
27    settimeofday(&tv, nullptr);
28    Serial.println("Saat DS3231'den / time from DS3231");
29  }
30
31  // 2) Wi-Fi gelince NTP saati düzeltir; bağlantı sonra gelse de SNTP yeniden dener
32  //    NTP corrects the clock once Wi-Fi is up; SNTP keeps retrying if the link comes later
33  sntp_set_time_sync_notification_cb(ntpCallback);
34  WiFi.begin(WIFI_SSID, WIFI_PASS);
35  configTzTime(TZ_INFO, "pool.ntp.org", "time.cloudflare.com");
36}
37
38void loop() {
39  if (ntpGeldi) {
40    ntpGeldi = false;
41    rtc.adjust(DateTime((uint32_t)time(nullptr)));   // DS3231'e UTC yaz / write UTC to the DS3231
42    Serial.println("DS3231 NTP ile guncellendi / DS3231 updated from NTP");
43  }
44
45  struct tm t;
46  if (getLocalTime(&t, 0)) {
47    Serial.println(&t, "%d.%m.%Y %H:%M:%S");
48  } else {
49    Serial.println("Saat yok: NTP ve DS3231 bekleniyor / no time yet");
50  }
51  delay(1000);
52}
53
DS1307 de aynı kodla çalışır (RTC_DS1307 yaz, lostPower yerine isrunning kullan), ama ayda bir iki dakika kayabilir. DS3231 sıcaklık dengeli kristali sayesinde yılda yaklaşık bir dakika içinde kalır. Modüller arasındaki farklar ve pil şarj devresi tuzağı için Arduino RTC Modülü yazısına göz at.

Her gün belirli saatte görev çalıştırmak

NTP saatiyle en çok yapılan şey zamanlı görevdir: sabah 07:30'da sulama pompasını 10 dakika çalıştırmak, akşam 19:00'da bahçe ışıklarını yakmak, her saat başı bir ölçüm göndermek. Yöntem basittir: loop() içinde saati oku, saat ve dakika hedefle eşleşiyorsa görevi başlat. Asıl incelik görevin aynı dakika içinde yüzlerce kez tetiklenmesini önlemektir. Bunun için görevin çalıştığı günü (tm_yday) bir değişkende saklarsın; aynı gün ikinci kez çalışmaz. Aşağıdaki kod hafta içi her sabah 07:30'da GPIO 26'daki röleyi 10 dakika açar; süreyi millis() ile ölçtüğü için kod hiçbir yerde bloke olmaz.

C++ (Arduino IDE)
1#include <WiFi.h>
2#include <time.h>
3
4const char* WIFI_SSID = "AgAdi";
5const char* WIFI_PASS = "Sifre123";
6const char* TZ_INFO   = "<+03>-3";
7
8const int ROLE_PIN = 26;                     // röle modülü IN / relay module IN
9const int GOREV_SAAT = 7;                    // her gün 07:30 / every day at 07:30
10const int GOREV_DAKIKA = 30;
11const unsigned long SURE_MS = 10UL * 60 * 1000;   // 10 dakika çalış / run for 10 minutes
12
13int sonGun = -1;                             // görevin çalıştığı son gün (tm_yday) / last day the task ran
14bool roleAcik = false;
15unsigned long acilisMs = 0;
16
17void setup() {
18  Serial.begin(115200);
19  pinMode(ROLE_PIN, OUTPUT);
20  digitalWrite(ROLE_PIN, LOW);
21  WiFi.begin(WIFI_SSID, WIFI_PASS);
22  while (WiFi.status() != WL_CONNECTED) delay(500);
23  configTzTime(TZ_INFO, "pool.ntp.org");
24}
25
26void loop() {
27  struct tm t;
28  if (getLocalTime(&t, 0)) {                 // saat geçerliyse / only when the time is valid
29    bool haftaici = (t.tm_wday >= 1 && t.tm_wday <= 5);   // Pzt-Cuma / Mon-Fri
30    if (haftaici && t.tm_hour == GOREV_SAAT && t.tm_min == GOREV_DAKIKA && t.tm_yday != sonGun) {
31      sonGun = t.tm_yday;                    // bugün bir kez / once per day
32      digitalWrite(ROLE_PIN, HIGH);
33      roleAcik = true;
34      acilisMs = millis();
35      Serial.println(&t, "%H:%M gorev basladi / task started");
36    }
37  }
38  if (roleAcik && millis() - acilisMs >= SURE_MS) {   // süre dolunca kapat / switch off after the period
39    digitalWrite(ROLE_PIN, LOW);
40    roleAcik = false;
41    Serial.println("Gorev bitti / task finished");
42  }
43  delay(200);
44}
45
  • Saniyeye eşitlik arama: t.tm_sec == 0 gibi bir koşul, döngü o saniyeyi kaçırırsa (Wi-Fi yeniden bağlanırken, uzun bir delay sırasında) görevi atlar. Dakika ve gün kontrolü daha güvenlidir.
  • Geçerli saat kontrolü: getLocalTime() false dönerken görev çalıştırma; aksi hâlde açılışta 1970 tarihine göre yanlış kararlar verilir.
  • Kaçırılan görev: Elektrik 07:29'da gidip 07:35'te gelirse görev o gün çalışmaz. Önemliyse koşulu "saat 07:30'u geçti ve bugün çalışmadı" şeklinde kur ve sonGun değerini Preferences ile kalıcı belleğe yaz.
  • Birden fazla görev: Saat, dakika ve süreyi bir dizi içinde tut; her görev için ayrı bir sonGun değişkeni kullan.
  • Yüksek akımlı yük: Pompa ya da lambayı doğrudan pinden değil, röle modülü ya da MOSFET üzerinden sür.
ESP32'nin GPIO pinleri 3,3 V verir ve yalnızca birkaç on miliamper akım sağlayabilir. Röle modülünün IN girişi çoğu zaman 3,3 V ile tetiklenir, ama bazı 5 V röle kartları güvenilir çekmeyebilir; bu durumda 3,3 V tetiklemeli bir kart ya da transistörlü sürücü kullan. 220 V tarafında çalışırken devre fişe takılıyken kablolara dokunma.

Eşitleme aralığını değiştirmek ve NTP'yi izlemek

Varsayılan 3 saatlik eşitleme aralığı çoğu proje için uygundur. Daha sık eşitlemek (ör. sıcaklık değişimi yüksek bir dış ortamda) ya da trafiği azaltmak için sntp_set_sync_interval() fonksiyonuna milisaniye cinsinden yeni aralığı verirsin. Bu çağrıyı configTzTime()'dan önce yapmalısın; çünkü yeni aralık bir sonraki başlatmada ya da mevcut aralık dolduğunda geçerli olur. Protokol kuralları gereği aralık 15 saniyeden kısa olamaz. sntp_get_sync_status() bir eşitleme tamamlandığında bir kez SNTP_SYNC_STATUS_COMPLETED döndürür, sonra kendini sıfırlar; böylece her yeni eşitlemeyi yakalayabilirsin.

C++ (Arduino IDE)
1#include <WiFi.h>
2#include <time.h>
3#include "esp_sntp.h"
4
5const char* TZ_INFO = "<+03>-3";
6
7void setup() {
8  Serial.begin(115200);
9  WiFi.begin("AgAdi", "Sifre123");
10  while (WiFi.status() != WL_CONNECTED) delay(500);
11
12  sntp_set_sync_interval(6UL * 60 * 60 * 1000);   // 6 saatte bir eşitle (en az 15 sn) / sync every 6 hours (min 15 s)
13  configTzTime(TZ_INFO, "pool.ntp.org");          // ayar sntp_init() öncesi verilir / set before sntp_init()
14}
15
16void loop() {
17  if (sntp_get_sync_status() == SNTP_SYNC_STATUS_COMPLETED) {
18    Serial.println("Yeni NTP esitlemesi / new NTP sync");
19  }
20  delay(1000);
21}
22

Hangi NTP sunucusunu kullanmalı?

En yaygın seçim pool.ntp.org'dur: dünya çapında gönüllüler tarafından işletilen binlerce sunucudan oluşan bir havuzdur ve her istekte sana yakın bir sunucunun adresini verir. Ülke alt alan adları (tr.pool.ntp.org, de.pool.ntp.org) sunucuyu daha da yakına çeker. configTzTime() en fazla üç sunucu adı kabul eder; ilki yanıt vermezse sıradakine geçer.

SunucuÖzellikNot
pool.ntp.orgGönüllü havuz, en yakın sunucuGenel kullanım için ilk tercih
tr.pool.ntp.org / europe.pool.ntp.orgÜlke ya da kıta havuzuGecikme biraz daha düşük
time.cloudflare.comBüyük şirket altyapısıYedek sunucu olarak iyi
time.google.comArtık saniyeyi yayarak uygular (leap smear)Diğer sunucularla karıştırma
Modemin IP adresiBazı modemler yerel NTP sunarİnternetsiz yerel ağda işe yarar
Kendi ürününü yüzlerce cihaza dağıtacaksan pool.ntp.org yerine kendi alan adınla bir havuz (vendor zone) almak ya da cihazların açılış saatini rastgele dağıtmak iyi bir davranıştır. Aynı saniyede binlerce cihazın sunucuya gitmesi gönüllü sunucuları zorlar.

Raspberry Pi Pico W ile NTP: ntptime

Raspberry Pi Pico W'de (ve Pico 2 W'de) aynı iş MicroPython'un ntptime modülüyle yapılır. ntptime.settime() NTP sunucusuna sorar ve Pico'nun dahili RTC'sini UTC'ye ayarlar. MicroPython'da ESP32'deki gibi bir saat dilimi metni yoktur; Türkiye saati için UTC'ye 3 × 3600 saniye eklersin. ntptime yalnızca bir kez saat alır, otomatik yeniden eşitleme yapmaz; uzun süre çalışan projelerde settime() çağrısını günde bir iki kez tekrarlamak kaymayı giderir. Pico W'nin RTC'si de elektrik kesilince sıfırlanır, bu yüzden aynı DS3231 yedeği burada da geçerlidir. Pico W ile Wi-Fi'ye bağlanmanın ayrıntıları Pico W Wi-Fi ve Web Sunucu yazısında.

Python
1import network
2import ntptime
3import time
4
5SSID = "AgAdi"
6PASS = "Sifre123"
7UTC_OFFSET = 3 * 3600          # Türkiye UTC+3 / Turkey UTC+3
8# localtime(): 0 = Pazartesi / 0 = Monday
9GUNLER = ("Pazartesi", "Sali", "Carsamba", "Persembe", "Cuma", "Cumartesi", "Pazar")
10
11wlan = network.WLAN(network.STA_IF)
12wlan.active(True)
13wlan.connect(SSID, PASS)
14while not wlan.isconnected():  # bağlanana kadar bekle / wait until connected
15    time.sleep(0.5)
16
17ntptime.host = "pool.ntp.org"
18for deneme in range(5):        # NTP bazen zaman aşımına uğrar / NTP may time out
19    try:
20        ntptime.settime()      # dahili RTC'yi UTC'ye ayarlar / sets the internal RTC to UTC
21        break
22    except OSError:
23        time.sleep(2)
24
25def yerel_saat():              # UTC + 3 saat / UTC + 3 hours
26    return time.localtime(time.time() + UTC_OFFSET)
27
28son_gun = -1
29while True:
30    yil, ay, gun, saat, dk, sn, hgun, ygun = yerel_saat()
31    print("{:02d}.{:02d}.{} {} {:02d}:{:02d}:{:02d}".format(gun, ay, yil, GUNLER[hgun], saat, dk, sn))
32    if saat == 7 and dk == 30 and ygun != son_gun:   # her gün 07:30'da bir kez / once a day at 07:30
33        son_gun = ygun
34        print("Gorev calisti / task ran")
35    time.sleep(1)
36

MicroPython'daki time.localtime() sekiz elemanlı bir demet döndürür: yıl, ay (1–12), gün, saat, dakika, saniye, haftanın günü ve yılın günü. ESP32'deki struct tm'den iki farkı vardır: ay 1'den başlar ve haftanın günü 0 = Pazartesi olarak sayılır. ntptime.settime() ağ zaman aşımına uğradığında OSError fırlatır; koddaki beş denemelik döngü bu yüzden vardır.

ESP32 NTP saat ile proje fikirleri

  • Wi-Fi masa saati: Saati, tarihi ve iç ortam sıcaklığını tek bir OLED ekranda göster; gece belirli saatte parlaklığı düşür.
  • Dev LED saat: NTP saatini MAX7219 LED matris üzerinde kayan yazıyla göster.
  • Zamanlı bitki sulama: Her sabah toprak nemine bakıp gerekirse mini su pompasını belirli bir süre çalıştır.
  • Zaman damgalı veri kaydı: Sensör ölçümlerini ISO tarih biçimiyle SD karta yaz.
  • Hava durumlu saat: Saatin yanına internetten çekilen hava durumunu ekle; ESP32 hava durumu yazısı bunun devamı.
  • Sabah raporu: Her gün 08:00'de ev sıcaklığını ve gece boyunca algılanan hareketleri Telegram ile telefonuna gönder.

Sık yapılan hatalar ve çözümleri

BelirtiOlası nedenÇözüm
Saat 1970 ya da hiç gelmiyorWi-Fi bağlı değil ya da NTP portu (UDP 123) engelliÖnce WiFi.status() kontrolü; okul ve iş ağlarında başka ağ ya da telefon hotspotu dene
Saat tam 3 saat gerideSaat dilimi verilmemiş, UTC gösteriliyorconfigTzTime("<+03>-3", ...) ya da configTime(10800, 0, ...)
Saat 6 saat yanlışTZ metninde işaret ters ("UTC+3")Türkiye için "<+03>-3" ya da "UTC-3" yaz
Ay bir eksik, yıl 126tm_mon 0'dan, tm_year 1900'den sayılırtm_mon + 1, tm_year + 1900 ya da strftime kullan
Görev aynı dakikada defalarca çalışıyorTekrar koruması yokÇalıştığı günü (tm_yday) saklayıp kontrol et
Döngü her turda 5 saniye takılıyorSaat yokken getLocalTime() varsayılan olarak 5000 ms beklerloop() içinde getLocalTime(&t, 0) kullan
OLED'de gün adında garip simgelerYazı tipinde Türkçe harf yokGün adlarını ASCII yaz ya da U8g2 kütüphanesine geç
Bir sorunu ayırmak için önce yalnızca Seri Monitör'e saat yazan ilk kodu çalıştır. Orada saat doğruysa sorun ekran, RTC ya da görev mantığındadır; orada da yanlışsa Wi-Fi ve saat dilimi ayarına bak.

ESP32 NTP, bir projeye doğru saati eklemenin en ucuz ve en zahmetsiz yoludur: birkaç satır kodla saniyesi saniyesine saat alır, saat dilimini ve yaz saatini kendisi yönetir; bir DS3231 ekleyerek elektrik kesintilerine de dayanıklı hâle gelir. BlueGrays uygulamasında ESP32 NTP ile internetten gerçek zaman, DS1307 RTC'li dijital saat, OLED ekranlı hava durumu ve zaman damgalı sıcaklık kaydedici projelerini adım adım devre şemaları ve kodlarıyla bulabilirsin.

Sıkça sorulan sorular

ESP32 internet olmadan saati tutabilir mi?

Saati bir kez NTP'den aldıktan sonra evet: ESP32 sistem saatini kendi sayacıyla saymaya devam eder ve Wi-Fi'nin kesilmesi saati durdurmaz. Ancak elektrik kesilir ya da kart yeniden başlarsa saat 1970'e döner. İnternetin hiç olmadığı yerlerde ya da kesintiye dayanıklı bir saat için DS3231 gibi pilli bir RTC modülü ekle.

ESP32 NTP saati neden 3 saat geri gösteriyor?

Saat dilimi ayarlanmadığında ESP32 saati UTC olarak gösterir ve Türkiye UTC+3 olduğu için saat tam 3 saat geride çıkar. configTzTime("<+03>-3", "pool.ntp.org") ya da configTime(10800, 0, "pool.ntp.org") kullan. TZ metnine "UTC+3" yazmak ise işaret ters yorumlandığı için saati 6 saat kaydırır.

Türkiye için configTime değerleri nedir?

Türkiye 2016'dan beri yıl boyu UTC+3'te kalır ve yaz saati uygulamaz. Bu yüzden configTime(10800, 0, "pool.ntp.org") yazarsın: 10800 saniye 3 saattir, yaz saati farkı 0'dır. Aynı ayar configTzTime ile "<+03>-3" metniyle yapılır.

ESP32 NTP ne sıklıkla senkronize olur?

Arduino ESP32 çekirdeğinde SNTP varsayılan olarak 3 saatte bir sunucuya yeniden sorar; aradaki sürede saati kendi sayacıyla tutar. Aralığı sntp_set_sync_interval() fonksiyonuyla milisaniye cinsinden değiştirebilirsin, ancak protokol gereği 15 saniyeden kısa olamaz.

ESP32 kullanırken RTC modülüne gerek var mı?

Cihaz sürekli elektrikliyse ve Wi-Fi'ye bağlanabiliyorsa gerek yoktur; NTP daha doğru saat verir. Elektrik kesintisinden sonra internet gelmeden doğru saat gerekiyorsa ya da cihaz internetsiz bir yerde çalışacaksa DS3231 gibi pilli bir RTC modülü eklemek gerekir.

Raspberry Pi Pico W ile NTP saati nasıl alınır?

MicroPython'da Wi-Fi'ye bağlandıktan sonra import ntptime ve ntptime.settime() yazman yeterlidir; bu komut Pico'nun dahili RTC'sini UTC'ye ayarlar. Türkiye saati için time.localtime(time.time() + 10800) kullanırsın. ntptime otomatik yeniden eşitleme yapmadığı için settime() çağrısını günde bir iki kez tekrarlamak iyi olur.

Tüm projeleri gör
ESP32 NTP ile İnternetten Gerçek Zaman
#128İleri
Premium

ESP32 NTP ile İnternetten Gerçek Zaman

ESP32, Wi-Fi'a bağlanıp NTP (Network Time Protocol) sunucularından milisaniye hassasiyetiyle gerçek zamanı çeker. configTzTime() fonksiyonu sayesinde Türkiye saat dilimi (TRT, UTC+3) otomatik uygulanır ve yaz/kış saati uygulayan ülkelerde DST geçişi POSIX TZ string'i ile otomatik yönetilir. Saat hem Serial Monitor'e hem de opsiyonel I2C LCD'ye yazdırılır. configTzTime() SNTP hizmetini başlatır; ağ erişimi varken periyodik yeniden senkronizasyon yapılır ve iki senkronizasyon arasında sistem s

4.5(13)
21
ESP32 RTC DS1307 ile Dijital Saat (I2C + LCD)
#120Orta
Premium

ESP32 RTC DS1307 ile Dijital Saat (I2C + LCD)

Bu projede DS1307 gerçek zaman saati (RTC) modülü ile 16x2 I2C LCD ekrana saat ve tarih bilgisi yansıtıyoruz. DS1307 pil destekli bir RTC'dir; ESP32 kapansa bile zamanı korur. Her iki modül de aynı I2C hattını (SDA/SCL) paylaşır, böylece sadece iki sinyal kablosu ile çoklu cihaz kontrolü öğrenmiş oluruz. Bu proje sayesinde I2C haberleşme protokolünü, RTC modüllerinin çalışma prensibini ve LCD ekranda dinamik veri gösterimini pratik bir şekilde öğreneceksiniz.

4.6(26)
40
ESP32 Wi-Fi STA Bağlantısı (LCD Ekranlı)
#127İleri

ESP32 Wi-Fi STA Bağlantısı (LCD Ekranlı)

Bu projede ESP32'yi Station (STA) modunda evdeki Wi-Fi ağına güvenli ve hata toleranslı şekilde bağlıyoruz. SSID/şifreyi secrets.h dosyasına ayırarak Git'e sızmasını önlüyor, otomatik yeniden bağlanma mekanizması kuruyor, RSSI sinyal seviyesini ve IP adresini I2C LCD ekranda gösteriyoruz. Dahili LED durum göstergesi olarak çalışır. Üretim seviyesi bir bağlantı yöneticisidir.

4.4(21)
34
ESP32 HTTPClient + Hava Durumu API (SSD1306 OLED Ekranlı)
#134İleri
Premium

ESP32 HTTPClient + Hava Durumu API (SSD1306 OLED Ekranlı)

Bu projede ESP32 ile internet üzerinden hava durumu API'sine (wttr.in) HTTPClient.h kullanarak REST API çağrısı yapıyoruz. Bir önceki I2C LCD versiyonundan farklı olarak burada SSD1306 OLED (128×64) ekran kullanıyoruz — büyük font, vector ikonlar ve tek ekranda zengin görsel sunum mümkün oluyor. Hava durumu için 7 farklı vector ikon (güneşli, parçalı bulutlu, bulutlu, yağmurlu, karlı, fırtınalı, sisli) runtime'da çiziliyor (bitmap dosyası gerektirmez). Sıcaklık 3x büyük fontla ortada, hava dur

4.3(10)
19
ESP32 HTTPClient + Hava Durumu API (LCD Ekranlı)
#133İleri
Premium

ESP32 HTTPClient + Hava Durumu API (LCD Ekranlı)

Bu projede ESP32 ile internet üzerinden hava durumu API'sine (wttr.in) HTTPClient.h kullanarak REST API çağrısı yapıyoruz. ArduinoJson v7 ile dönen JSON cevabını parse edip şehir, sıcaklık, nem, hava durumu ve rüzgar bilgilerini I2C LCD ekranda hem Türkçe hem İngilizce gösteriyoruz. wttr.in ücretsizdir, API key gerektirmez — herhangi bir şehir ismini yazarak o şehrin anlık hava durumunu çekebilirsiniz. 30 dakikada bir otomatik güncelleme, LED ile her ekran için farklı görsel feedback ve eksiks

4.7(13)
20
ESP32 Deep Sleep — Pil Tasarrufu (OLED + RTC RAM Sayaç)
#135İleri
Premium

ESP32 Deep Sleep — Pil Tasarrufu (OLED + RTC RAM Sayaç)

ESP32'nin Deep Sleep modu, CPU ve çoğu çevre birimini kapatarak akım tüketimini ~10µA seviyesine düşürür ve pille çalışan IoT cihazları için kritik öneme sahiptir. Bu projede üç farklı uyandırma kaynağını kullanıyoruz: zamanlayıcı (timer, 15sn), harici pin (EXT0 — buton GPIO 33) ve touch (T0/GPIO 4). RTC_DATA_ATTR ile işaretlenen değişkenler deep sleep boyunca korunur — boot sayacı, timer wake sayacı ve buton wake sayacı kalıcı olarak izlenir. SSD1306 OLED ekranda her uyanışta wake reason, say

4.3(10)
16
ESP32 Sıcaklık Loglayıcı (DHT22 + DS1307 RTC + microSD + OLED)
#144İleri
Premium

ESP32 Sıcaklık Loglayıcı (DHT22 + DS1307 RTC + microSD + OLED)

ESP32 ile zamanlı sıcaklık ve nem kayıt sistemi kur! Bu projede DHT22 sensörü ile dakikada bir sıcaklık/nem okuyup DS1307 RTC modülünden aldığın gerçek zaman etiketiyle microSD karta CSV formatında kaydediyoruz. OLED ekranda büyük font ile son sıcaklık değeri, nem yüzdesi, timestamp ve toplam kayıt sayısı canlı gösterilir. SD kart üzerindeki /temp_log.csv dosyası Excel/Google Sheets/Python pandas ile açılıp analiz edilebilir — sera monitörü, ev/oda sıcaklık takibi, laboratuvar veri toplama,

4.7(7)
12
ESP32 I2C LCD Ekran (16x2)
#119Orta
Premium

ESP32 I2C LCD Ekran (16x2)

Bu projede 16x2 karakter LCD ekranı I2C protokolü üzerinden ESP32'ye bağlayarak metin görüntülüyoruz. I2C sayesinde sadece 2 data pini (SDA ve SCL) ile ekranı kontrol edebiliyoruz; klasik paralel bağlantıdaki 6+ pin israfı ortadan kalkıyor. Kod ilk satıra sabit bir mesaj, ikinci satıra ise her saniye artan bir sayaç yazdırıyor. Ayrıca başlangıçta I2C tarayıcı çalıştırarak ekranın adresini Serial Monitor'a yazdırıyoruz (genelde 0x27 veya 0x3F).

4.9(23)
40