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.

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.
| Kavram | Değer / açıklama |
|---|---|
| Protokol ve port | SNTP, UDP 123 |
| Zaman damgası | 1900'den beri geçen saniye (ESP32 bunu 1970 tabanlı Unix zamanına çevirir) |
| Tipik doğruluk | Ev internetinde 10–50 ms |
| Yeniden eşitleme | Arduino ESP32'de varsayılan 3 saat, sntp_set_sync_interval() ile değişir (en az 15 sn) |
| En fazla sunucu | 3 (configTzTime'a verilen sunucu adları) |
| İnternet trafiği | İstek ve yanıt 48 baytlık birer NTP paketi; günde birkaç kilobayt bile etmez |
| Gerekenler | ESP32, 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ölge | TZ metni (configTzTime) | configTime karşılığı |
|---|---|---|
| Türkiye (yıl boyu UTC+3) | <+03>-3 | configTime(10800, 0, ...) |
| Almanya, Fransa, İtalya, İspanya | CET-1CEST,M3.5.0,M10.5.0/3 | Uygun değil, configTzTime kullan |
| İngiltere, Portekiz | GMT0BST,M3.5.0/1,M10.5.0 | Uygun değil, configTzTime kullan |
| ABD doğu (New York) | EST5EDT,M3.2.0,M11.1.0 | Uygun değil, configTzTime kullan |
| Azerbaycan, Gürcistan (UTC+4) | <+04>-4 | configTime(14400, 0, ...) |
| UTC (zaman damgası için) | UTC0 | configTime(0, 0, ...) |
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 pini | ESP32 | Raspberry Pi Pico W | Not |
|---|---|---|---|
| OLED / DS3231 VCC | 3V3 | 3V3 (OUT) | İkisi de 3,3 V ile çalışır |
| OLED / DS3231 GND | GND | GND | Ortak toprak |
| OLED / DS3231 SDA | GPIO 21 | GP4 | I2C veri hattı |
| OLED / DS3231 SCL | GPIO 22 | GP5 | I2C saat hattı |
| Röle modülü IN | GPIO 26 | GP15 | Zamanlı görev örneği |
| Röle modülü VCC | 5V (VIN) | VBUS | Çoğu röle bobini 5 V ister |
Adım adım ilk ESP32 NTP kodu
- 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.
- Ek kütüphane gerekmez: WiFi.h ve time.h ESP32 çekirdeğiyle gelir.
- Koddaki WIFI_SSID ve WIFI_PASS değerlerini kendi ağınla değiştir.
- Kodu yükle, Seri Monitör'ü 115200 baud hızında aç.
- Önce Wi-Fi noktaları, birkaç saniye sonra her saniye güncellenen tarih ve saat görünmelidir.
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ır | Ne 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.
| Alan | Aralık | Örnek (16 Kasım 2026, 14:05:09, Pazartesi) |
|---|---|---|
| tm_sec | 0–59 (artık saniyede 60) | 9 |
| tm_min | 0–59 | 5 |
| tm_hour | 0–23 | 14 |
| tm_mday | 1–31 | 16 |
| tm_mon | 0–11 (0 = Ocak) | 10 |
| tm_year | 1900'den beri geçen yıl | 126 (1900 + 126 = 2026) |
| tm_wday | 0–6 (0 = Pazar) | 1 |
| tm_yday | 0–365 (yılın kaçıncı günü, 0'dan) | 319 |
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:
| Kod | Anlamı | Örnek çıktı |
|---|---|---|
| %H / %M / %S | Saat (00–23) / dakika / saniye | 14 / 05 / 09 |
| %I ve %p | 12 saatlik saat ve AM/PM | 02 PM |
| %d / %m / %Y | Gün / ay (01–12) / dört haneli yıl | 16 / 11 / 2026 |
| %y | İki haneli yıl | 26 |
| %A / %a | Gün adı, uzun / kısa (İngilizce) | Monday / Mon |
| %B / %b | Ay adı, uzun / kısa (İngilizce) | November / Nov |
| %j | Yılın günü (001–366) | 320 |
| %F / %T | %Y-%m-%d / %H:%M:%S kısayolları | 2026-11-16 / 14:05:09 |
| %Z | Saat 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.
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}
34OLED 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.
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}
66Kodda 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.
| Durum | Saat korunur mu? | Ne yapmalı? |
|---|---|---|
| Wi-Fi bir süre kesildi | Evet, ESP32 saymaya devam eder | Hiçbir şey; Wi-Fi gelince NTP düzeltir |
| Deep sleep (derin uyku) | Evet, RTC zamanlayıcısı sayar | Uyku uzunsa uyanınca ara sıra NTP ile eşitle |
| Elektrik kesildi ya da EN düğmesi | Hayır, saat 1970'e döner | DS3231 gibi pilli bir RTC modülü ekle |
| İnternet hiç yok (tarla, depo) | NTP hiç gelmez | Saati 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.

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.
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}
53Her 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.
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.
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.
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}
22Hangi 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 | Özellik | Not |
|---|---|---|
| pool.ntp.org | Gönüllü havuz, en yakın sunucu | Genel kullanım için ilk tercih |
| tr.pool.ntp.org / europe.pool.ntp.org | Ülke ya da kıta havuzu | Gecikme biraz daha düşük |
| time.cloudflare.com | Büyük şirket altyapısı | Yedek sunucu olarak iyi |
| time.google.com | Artık saniyeyi yayarak uygular (leap smear) | Diğer sunucularla karıştırma |
| Modemin IP adresi | Bazı modemler yerel NTP sunar | İnternetsiz yerel ağda işe yarar |
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.
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)
36MicroPython'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
| Belirti | Olası neden | Çözüm |
|---|---|---|
| Saat 1970 ya da hiç gelmiyor | Wi-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 geride | Saat dilimi verilmemiş, UTC gösteriliyor | configTzTime("<+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 126 | tm_mon 0'dan, tm_year 1900'den sayılır | tm_mon + 1, tm_year + 1900 ya da strftime kullan |
| Görev aynı dakikada defalarca çalışıyor | Tekrar koruması yok | Çalıştığı günü (tm_yday) saklayıp kontrol et |
| Döngü her turda 5 saniye takılıyor | Saat yokken getLocalTime() varsayılan olarak 5000 ms bekler | loop() içinde getLocalTime(&t, 0) kullan |
| OLED'de gün adında garip simgeler | Yazı tipinde Türkçe harf yok | Gün adlarını ASCII yaz ya da U8g2 kütüphanesine geç |
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.
Bu yazıdan sonra yapabileceğin projeler
Tüm projeleri gör
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

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.

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.

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

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

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

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,

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).
Diğer yazılar
BlueGrays uygulaması
Bu devreyi telefonunda adım adım kur
Devre şeması, kod ve parça listesi tek ekranda. 200'den fazla Arduino, ESP32 ve Pico projesi seni bekliyor.
Telefonunla tara
Kamerayı koda tut; telefonunun uygulama mağazası açılır.
ya da mağazada aç

