Panduan · 12 mnt baca

Waktu NTP ESP32: jam internet dengan zona waktu, OLED, dan cadangan RTC

Cara mendapatkan waktu NTP di ESP32: configTzTime dan zona waktu, getLocalTime, strftime, jam OLED, cadangan DS3231, tugas harian terjadwal, dan ntptime Pico W.

Mengambil waktu dengan ESP32 NTP berarti menghubungkan board ke server waktu di internet dan memperoleh tanggal serta waktu dengan akurasi beberapa puluh milidetik, tanpa modul jam apa pun. Setelah ESP32 terhubung ke Wi-Fi, satu panggilan configTzTime() mengambil waktu, menerapkan zona waktumu, lalu board terus menghitung waktu sendiri. Jam meja, penyiraman terjadwal, cap waktu untuk pencatatan data, alarm pagi, atau lampu yang menyala pada waktu tertentu tidak lagi memerlukan modul RTC terpisah.

Dalam panduan ini kita akan membahas langkah demi langkah cara kerja NTP, pengaturan zona waktu yang benar, penulisan tanggal dalam format apa pun dengan getLocalTime dan strftime, penampilan waktu pada layar OLED, pemeliharaan waktu dengan modul DS3231 ketika Wi-Fi terputus atau daya hilang, serta menjalankan tugas pada waktu tertentu setiap hari. Pada bagian terakhir kita akan melakukan hal yang sama di Raspberry Pi Pico W dengan modul ntptime MicroPython.

Board pengembangan ESP32
ESP32 DevKit: Wi-Fi bawaannya memungkinkan board mengambil waktu dari server NTP dan menyimpan tanggal serta waktu tanpa modul jam terpisah.

Apa itu NTP dan bagaimana ESP32 mendapatkan waktu?

NTP (Network Time Protocol) adalah protokol yang digunakan sejak 1980-an untuk menyinkronkan jam komputer dan perangkat melalui internet. Server disusun dalam lapisan yang disebut strata: server stratum 1 terhubung langsung ke jam atom atau GPS, server stratum 2 mengambil waktu dari server tersebut, dan seterusnya. ESP32 meminta waktu melalui paket kecil pada port UDP 123; server membalas dengan cap waktu berisi detik sejak 1900 beserta pecahan detiknya. ESP32 memperhitungkan waktu perjalanan pulang-pergi paket dan mengatur jamnya sendiri. Pada koneksi internet rumah, akurasi yang diperoleh biasanya antara 10 dan 50 milidetik, lebih dari cukup untuk proyek jam.

Stack jaringan lwIP di dalam ESP32 memakai SNTP, versi sederhana dari NTP. Setelah menerima waktu, ESP32 menyimpannya sebagai waktu sistem dan terus menghitung dengan timer yang bersumber dari kristalnya; board tidak mengakses internet setiap detik. Di latar belakang, board meminta waktu lagi ke server secara berkala (secara default setiap 3 jam pada core Arduino ESP32) dan mengoreksi pergeseran kecil. Waktu sistem disimpan dalam UTC; waktu lokal yang kamu lihat dihitung dengan menerapkan aturan zona waktu.

KonsepNilai / penjelasan
Protokol dan portSNTP, UDP 123
Cap waktuDetik sejak 1900 (ESP32 mengubahnya menjadi waktu Unix berbasis 1970)
Akurasi tipikal10–50 ms pada koneksi internet rumah
Sinkronisasi ulangDefault 3 jam pada Arduino ESP32, diubah dengan sntp_set_sync_interval() (minimum 15 dtk)
Jumlah maksimum server3 (nama server yang diteruskan ke configTzTime)
Lalu lintas internetRequest dan respons masing-masing berupa paket NTP 48 byte; paling banyak beberapa kilobyte per hari
Yang dibutuhkanESP32, jaringan Wi-Fi 2,4 GHz, dan koneksi internet

configTime dan configTzTime: mengatur zona waktu

Ada dua cara memulai NTP pada core Arduino ESP32. configTime(gmtOffset_sec, daylightOffset_sec, server1, server2, server3) menerima selisih terhadap UTC dan selisih waktu musim panas dalam detik. Untuk Turki, misalnya, kamu menulis configTime(10800, 0, "pool.ntp.org"), karena 3 jam sama dengan 10.800 detik dan Turki tetap menggunakan UTC+3 sepanjang tahun tanpa waktu musim panas sejak 2016. Cara ini sederhana, tetapi tidak mengetahui tanggal pergantian waktu musim panas di wilayahmu; di tempat yang menerapkan DST, seperti Eropa atau AS, pergantian terjadi pada hari yang salah, jadi gunakan configTzTime di sana.

Cara yang lebih baik adalah configTzTime(TZ, server1, server2, server3). Fungsi ini menerima string zona waktu dalam format POSIX yang juga memuat aturan waktu musim panas, lalu ESP32 menangani pergantiannya sendiri setiap tahun. Untuk Turki, string-nya adalah "<+03>-3": +03 di dalam kurung sudut merupakan singkatan yang tampil di layar, sedangkan -3 berarti kamu mengurangi waktu lokal sebanyak 3 jam untuk mendapatkan UTC. Tabel berikut mencantumkan string untuk wilayah yang umum digunakan.

WilayahString TZ (configTzTime)Padanan configTime
Turki (UTC+3 sepanjang tahun)<+03>-3configTime(10800, 0, ...)
Jerman, Prancis, Italia, SpanyolCET-1CEST,M3.5.0,M10.5.0/3Tidak cocok, gunakan configTzTime
Britania Raya, PortugalGMT0BST,M3.5.0/1,M10.5.0Tidak cocok, gunakan configTzTime
AS bagian timur (New York)EST5EDT,M3.2.0,M11.1.0Tidak cocok, gunakan configTzTime
Azerbaijan, Georgia (UTC+4)<+04>-4configTime(14400, 0, ...)
UTC (untuk cap waktu)UTC0configTime(0, 0, ...)
Tanda dalam string zona waktu POSIX terbalik: jika kamu menulis "UTC+3" atau "GMT+3" untuk zona UTC+3, ESP32 membacanya sebagai “3 jam di belakang UTC” dan jam akhirnya meleset 6 jam. String yang benar adalah "<+03>-3" atau "UTC-3". Demikian pula, Eropa Tengah menggunakan "CET-1...", bukan "CET+1". Jika jammu meleset tepat 3 atau 6 jam, hampir selalu tanda inilah penyebabnya.

Kebutuhan dan pengkabelan

Untuk melihat waktu di Serial Monitor, kamu hanya membutuhkan ESP32 dan jaringan Wi-Fi. Pada bagian berikutnya kita memakai layar OLED SSD1306 0,96 inci untuk menampilkan waktu, modul RTC DS3231 untuk mempertahankannya ketika listrik padam, dan modul relay untuk contoh tugas terjadwal. OLED dan DS3231 berbagi bus I2C yang sama, sehingga keduanya terhubung ke dua pin yang sama. Kamu bisa melihat pinout ESP32 dengan alat Pinout.

Pin komponenESP32Raspberry Pi Pico WCatatan
OLED / DS3231 VCC3V33V3 (OUT)Keduanya bekerja pada 3,3 V
OLED / DS3231 GNDGNDGNDGround bersama
OLED / DS3231 SDAGPIO 21GP4Jalur data I2C
OLED / DS3231 SCLGPIO 22GP5Jalur clock I2C
IN modul relayGPIO 26GP15Contoh tugas terjadwal
VCC modul relay5V (VIN)VBUSSebagian besar kumparan relay membutuhkan 5 V
ESP32 hanya terhubung ke jaringan Wi-Fi 2,4 GHz. Jika router-mu memakai nama yang sama untuk 5 GHz dan 2,4 GHz, atau nama jaringan mengandung karakter khusus, koneksi bisa gagal. Jika waktu tidak pernah diterima, pastikan dahulu di Serial Monitor bahwa Wi-Fi sudah terhubung; NTP hanya bekerja setelah Wi-Fi aktif.

Langkah demi langkah: sketch NTP ESP32 pertamamu

  1. Pastikan paket board ESP32 sudah terinstal di Arduino IDE dan pilih ESP32 Dev Module di Tools. Jika kamu belum tahu caranya, lihat artikel Apa Itu ESP32?.
  2. Tidak perlu library tambahan: WiFi.h dan time.h sudah disertakan dalam core ESP32.
  3. Ganti nilai WIFI_SSID dan WIFI_PASS dengan detail jaringanmu, serta TZ_INFO dengan zona waktumu dari tabel di atas.
  4. Upload sketch dan buka Serial Monitor pada 115200 baud.
  5. Mula-mula kamu akan melihat titik-titik Wi-Fi, lalu setelah beberapa detik tanggal dan waktu diperbarui setiap detik.
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
BarisApa fungsinya?
configTzTime(TZ_INFO, ...)Memulai klien SNTP serta mengatur server dan zona waktu; langsung kembali, waktu diterima di latar belakang
getLocalTime(&t)Mengisi struct tm dengan waktu lokal; jika waktu belum tersedia, menunggu hingga 5 detik dan mengembalikan false
Serial.println(&t, "...")Kelas Print ESP32 dapat mencetak struct tm langsung dengan format strftime
time(nullptr)Mengembalikan detik sejak 1970 (waktu Unix, UTC)

Ada detail penting di sini: getLocalTime() menentukan apakah waktu “valid” dengan memeriksa tahunnya. Ketika ESP32 melakukan boot, waktu sistem adalah 1 Januari 1970, dan fungsi mengembalikan false hingga tahunnya lebih besar dari 2016. Jadi, kode yang mencatat data atau menjalankan tugas sebelum waktu NTP diterima tidak akan tanpa sengaja menghasilkan entri bertanggal 1970, asalkan kamu memeriksa nilai kembaliannya. Parameter kedua adalah batas waktu dalam milidetik; jika kamu tidak ingin memblokir di dalam loop(), tulis getLocalTime(&t, 0) agar hanya mencoba sekali.

struct tm: bagian-bagian waktu

getLocalTime() menuliskan waktu ke dalam struct tm, yang terbagi menjadi beberapa bagian. Kamu memakai field ini untuk membandingkan jam, hari, atau bulan ketika membuat tugas terjadwal. Dua field sering membingungkan pemula: bulan dihitung mulai dari 0 dan tahun dihitung sejak 1900.

FieldRentangContoh (Senin 16 November 2026, 14.05.09)
tm_sec0–59 (60 pada detik kabisat)9
tm_min0–595
tm_hour0–2314
tm_mday1–3116
tm_mon0–11 (0 = Januari)10
tm_yearTahun sejak 1900126 (1900 + 126 = 2026)
tm_wday0–6 (0 = Minggu)1
tm_yday0–365 (hari dalam setahun, mulai dari 0)319
Jika layar menampilkan “16.10.2026” padahal bulannya November, kamu lupa menambahkan 1 ke tm_mon. Jika tahun terlihat sebagai 126, kamu membutuhkan tm_year + 1900. Jika memakai strftime, konversi ini dilakukan untukmu.

Memformat tanggal dan waktu dengan strftime

strftime() menuliskan waktu dari struct tm ke array karakter sesuai pola. Kode persen dalam pola diganti dengan nilai yang sesuai, dan semua karakter lainnya tetap apa adanya. Tentukan ukuran array sebesar keluaran terpanjang ditambah satu (untuk nol penutup): “14:05:09” terdiri dari 8 karakter, jadi array harus berukuran minimal 9 byte. Kode yang paling umum:

KodeArtiContoh keluaran
%H / %M / %SJam (00–23) / menit / detik14 / 05 / 09
%I dan %pFormat 12 jam dan AM/PM02 PM
%d / %m / %YHari / bulan (01–12) / tahun empat digit16 / 11 / 2026
%yTahun dua digit26
%A / %aNama hari, panjang / pendek (bahasa Inggris)Monday / Mon
%B / %bNama bulan, panjang / pendek (bahasa Inggris)November / Nov
%jHari dalam setahun (001–366)320
%F / %TSingkatan untuk %Y-%m-%d / %H:%M:%S2026-11-16 / 14:05:09
%ZSingkatan zona waktu+03

Library C pada ESP32 hanya mengenal nama hari dan bulan bahasa Inggris; %A selalu mencetak “Monday”. Untuk tanggal dalam bahasa lain, simpan nama hari dan bulan dalam array-mu sendiri lalu gunakan tm_wday dan tm_mon sebagai indeks array. Contoh berikut memakai nama bahasa Turki; cukup ganti dengan bahasamu. Karena Serial Monitor mendukung UTF-8, huruf beraksen tampil dengan benar di sana. Sketch menghasilkan tanggal yang mudah dibaca sekaligus format ISO yang dapat diurutkan (2026-11-16 14:05:09) untuk pencatatan.

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
Ketika mencatat data (kartu SD, Google Sheets, server), selalu tuliskan tanggal sebagai %Y-%m-%d %H:%M:%S atau sebagai waktu Unix mentah. Format ini tersusun secara kronologis jika diurutkan secara alfabetis, dan Excel serta basis data mengenalinya sebagai tanggal. Kamu tetap bisa memakai format lokal di layar.

Menampilkan waktu dan tanggal pada layar OLED

Untuk mengubah keluaran Serial Monitor menjadi jam meja sungguhan, layar OLED SSD1306 0,96 inci sangat cocok: murah, terhubung dengan dua kabel, dan menampilkan angka besar dengan tajam. Sketch berikut menampilkan hari dan tanggal di bagian atas, waktu dengan font besar di tengah, serta status Wi-Fi di bawah. Karena layar digambar ulang hanya ketika detik berubah, bukan pada setiap perulangan, bus I2C tidak terus sibuk tanpa perlu. Instal library Adafruit SSD1306 dan Adafruit GFX melalui Library Manager; layarnya sendiri dibahas dalam artikel layar OLED (SSD1306).

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

Perhatikan bahwa nama hari ditulis tanpa huruf beraksen: font default Adafruit GFX tidak memiliki karakter seperti ş, ç, atau é dan menampilkan simbol tak bermakna sebagai gantinya. Pada ukuran teks 2, setiap karakter lebarnya 12 piksel; “14:05:09” yang terdiri dari 8 karakter memerlukan 96 piksel, jadi mulai dari piksel 16 membuatnya tepat di tengah layar 128 piksel. Jika kamu lebih suka LCD karakter 16x2, cukup cetak keluaran strftime yang sama dengan lcd.print(); pengkabelannya dijelaskan dalam artikel layar LCD I2C.

Apa yang terjadi pada waktu ketika Wi-Fi terputus? Cadangan RTC DS3231

Pertanyaan yang paling umum: jika Wi-Fi hilang, apakah waktunya ikut hilang? Tidak. Setelah ESP32 mendapatkan waktu dari NTP, board terus menghitung dengan timer-nya sendiri; kehilangan Wi-Fi tidak menghentikan jam. Karena timer ini bersumber dari kristal 40 MHz, waktunya bergeser sekitar satu atau dua detik per hari, dan sinkronisasi berikutnya mengoreksinya ketika Wi-Fi kembali. Masalah sebenarnya adalah daya terputus atau mulai ulang dengan tombol EN: waktu sistem kembali ke 1970, dan tanpa Wi-Fi ESP32 tidak bisa mengetahui waktu.

SituasiApakah waktu dipertahankan?Yang perlu dilakukan
Wi-Fi terputus sementaraYa, ESP32 terus menghitungTidak perlu tindakan; NTP mengoreksinya ketika Wi-Fi kembali
Deep sleepYa, timer RTC terus menghitungUntuk sleep yang lama, sinkronkan ulang dengan NTP pada beberapa siklus bangun
Daya terputus atau tombol ENTidak, jam kembali ke 1970Tambahkan modul RTC dengan baterai cadangan seperti DS3231
Tidak ada internet sama sekali (lapangan, gudang)Waktu NTP tidak pernah diterimaAmbil waktu hanya dari modul RTC

Selama deep sleep, waktu tidak dihitung oleh kristal utama, melainkan oleh osilator RC di dalam chip yang kurang presisi. Osilator ini dipengaruhi suhu, sehingga selama sleep yang lama jam bisa bergeser beberapa detik atau lebih; pada proyek bertenaga baterai yang sleep berjam-jam, sebaiknya lakukan sinkronisasi NTP setiap beberapa kali bangun. Detailnya ada dalam artikel deep sleep ESP32.

Modul jam RTC
Modul RTC dengan baterai cadangan: terus menghitung meskipun ESP32 kehilangan daya, sehingga kamu bisa mengambil waktu darinya hingga Wi-Fi kembali.

Cara terbaik membuat jam yang tetap berjalan ketika listrik padam adalah menggabungkan keduanya: ketika boot, segera ambil waktu dari modul DS3231, koreksi dengan NTP setelah Wi-Fi aktif, lalu perbarui DS3231 pada setiap sinkronisasi NTP. Dalam sketch berikut, DS3231 menyimpan UTC, bukan waktu lokal; dengan begitu aturan zona waktu berada di satu tempat (string TZ) dan pergantian waktu musim panas tidak pernah mengacaukan RTC. Untuk mendeteksi sinkronisasi NTP, callback didaftarkan dengan sntp_set_time_sync_notification_cb(). Karena callback ini berjalan di dalam tugas jaringan, tidak ada operasi I2C di sana; callback hanya mengaktifkan flag, dan loop() menangani penulisan ke DS3231. Sketch memakai library RTClib.

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 bekerja dengan kode yang sama (tulis RTC_DS1307 dan gunakan isrunning sebagai pengganti lostPower), tetapi waktunya bisa bergeser satu atau dua menit per bulan. Berkat kristal dengan kompensasi suhu, pergeseran DS3231 tetap sekitar satu menit per tahun. Untuk perbedaan antarmodul dan jebakan rangkaian pengisian baterai, lihat artikel modul jam RTC Arduino.

Menjalankan tugas pada waktu tertentu setiap hari

Penggunaan waktu NTP yang paling umum adalah tugas terjadwal: menjalankan pompa penyiraman selama 10 menit pada pukul 07.30, menyalakan lampu taman pada pukul 19.00, mengirim pembacaan tepat setiap pergantian jam. Caranya sederhana: baca waktu di loop() dan mulai tugas ketika jam serta menit sesuai dengan target. Detail yang perlu diperhatikan adalah mencegah tugas terpicu ratusan kali dalam menit yang sama. Untuk itu, simpan hari pelaksanaan tugas (tm_yday) dalam variabel agar tugas tidak pernah berjalan dua kali pada hari yang sama. Sketch berikut menyalakan relay pada GPIO 26 selama 10 menit setiap pagi pada hari kerja pukul 07.30; karena mengukur durasi dengan millis(), kode tidak pernah memblokir.

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
  • Mencocokkan detik: kondisi seperti t.tm_sec == 0 melewatkan tugas jika perulangan melewatkan detik tersebut (ketika Wi-Fi menghubungkan ulang atau selama delay yang panjang). Memeriksa menit dan hari lebih aman.
  • Memeriksa validitas waktu: jangan jalankan tugas selama getLocalTime() mengembalikan false, atau kamu akan membuat keputusan yang salah berdasarkan tahun 1970 tepat setelah boot.
  • Tugas terlewat: jika listrik padam pukul 07.29 dan kembali pukul 07.35, tugas tidak berjalan hari itu. Jika ini penting, tulis kondisi sebagai “sudah lewat pukul 07.30 dan belum berjalan hari ini” lalu simpan sonGun ke flash dengan Preferences.
  • Beberapa tugas: simpan jam, menit, dan durasi dalam array serta gunakan variabel hari pelaksanaan terakhir yang terpisah untuk setiap tugas.
  • Beban berarus tinggi: kendalikan pompa atau lampu melalui modul relay atau MOSFET, jangan pernah langsung dari pin.
Pin GPIO ESP32 menghasilkan 3,3 V dan hanya dapat memasok beberapa puluh miliampere. Input IN modul relay biasanya terpicu pada 3,3 V, tetapi sebagian board relay 5 V mungkin tidak beralih dengan andal; dalam kasus itu gunakan board dengan pemicu 3,3 V atau driver transistor. Ketika bekerja pada sisi listrik PLN, jangan pernah menyentuh pengkabelan selama rangkaian masih terhubung ke listrik.

Mengubah interval sinkronisasi dan memantau NTP

Interval sinkronisasi default 3 jam cocok untuk sebagian besar proyek. Untuk menyinkronkan lebih sering (misalnya di luar ruangan dengan perubahan suhu besar) atau mengurangi lalu lintas, teruskan interval baru dalam milidetik ke sntp_set_sync_interval(). Panggil sebelum configTzTime(), karena interval baru berlaku pada permulaan berikutnya atau ketika interval sekarang berakhir. Menurut aturan protokol, interval tidak boleh lebih pendek dari 15 detik. sntp_get_sync_status() mengembalikan SNTP_SYNC_STATUS_COMPLETED sekali setelah sinkronisasi selesai lalu mereset dirinya, sehingga kamu bisa mendeteksi setiap sinkronisasi baru.

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

Server NTP mana yang sebaiknya digunakan?

Pilihan paling umum adalah pool.ntp.org: kumpulan ribuan server yang dijalankan sukarelawan di seluruh dunia dan memberikan alamat server terdekat pada setiap request. Subdomain negara (uk.pool.ntp.org, de.pool.ntp.org) memberikan server yang lebih dekat lagi. configTzTime() menerima hingga tiga nama server; jika server pertama tidak menjawab, fungsi beralih ke server berikutnya.

ServerFiturCatatan
pool.ntp.org (alamat server NTP)Kumpulan server sukarelawan, server terdekatPilihan pertama untuk penggunaan umum
uk.pool.ntp.org / europe.pool.ntp.org (alamat server NTP per negara atau benua)Kumpulan server negara atau benuaLatensi sedikit lebih rendah
time.cloudflare.com (server NTP Cloudflare)Infrastruktur perusahaan besarBagus sebagai server cadangan
time.google.com (server NTP Google)Menyebarkan detik kabisat secara bertahap (leap smear)Jangan campurkan dengan server lain
Alamat IP router-muSebagian router menyediakan NTP lokalBerguna pada jaringan lokal tanpa internet
Jika kamu akan mendistribusikan produkmu sendiri ke ratusan perangkat, sebaiknya dapatkan kumpulan server atas namamu sendiri (vendor zone) sebagai pengganti pool.ntp.org, atau acak waktu mulai perangkat. Ribuan perangkat yang mengakses server pada detik yang sama membebani server sukarelawan.

NTP di Raspberry Pi Pico W: ntptime

Di Raspberry Pi Pico W (dan Pico 2 W), pekerjaan yang sama dilakukan dengan modul ntptime MicroPython. ntptime.settime() meminta waktu ke server NTP dan mengatur RTC internal Pico ke UTC. MicroPython tidak memiliki string zona waktu seperti ESP32; untuk waktu lokal, tambahkan selisih waktumu dalam detik ke UTC (3 × 3600 untuk UTC+3 dalam contoh). ntptime hanya mengambil waktu sekali dan tidak menyinkronkan ulang secara otomatis; pada proyek yang berjalan lama, memanggil settime() sekali atau dua kali sehari menghilangkan pergeseran. RTC Pico W juga direset ketika daya hilang, jadi cadangan DS3231 yang sama berlaku di sini. Menghubungkan Pico W ke Wi-Fi dibahas secara terperinci dalam artikel web server Pico W dan Wi-Fi.

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

Dalam MicroPython, time.localtime() mengembalikan tuple delapan elemen: tahun, bulan (1–12), hari, jam, menit, detik, hari dalam minggu, dan hari dalam setahun. Ada dua perbedaan dari struct tm ESP32: bulan dimulai dari 1 dan hari dalam minggu dihitung dengan 0 = Senin. ntptime.settime() memunculkan OSError ketika jaringan melewati batas waktu, itulah sebabnya sketch memiliki perulangan lima kali percobaan.

Ide proyek jam NTP ESP32

  • Jam meja Wi-Fi: tampilkan waktu, tanggal, dan suhu ruangan pada satu layar OLED, lalu redupkan pada malam hari.
  • Jam LED raksasa: tampilkan waktu NTP sebagai teks berjalan pada matriks LED MAX7219.
  • Penyiraman tanaman terjadwal: periksa kelembapan tanah setiap pagi dan jalankan pompa air mini selama waktu tertentu jika diperlukan.
  • Pencatatan data dengan cap waktu: tuliskan pembacaan sensor dengan tanggal ISO ke kartu SD.
  • Jam cuaca: tambahkan informasi cuaca dari internet di samping waktu; artikel cuaca ESP32 melanjutkan pembahasan ini.
  • Laporan pagi: setiap hari pukul 08.00, kirim suhu rumah dan gerakan yang terdeteksi semalaman ke ponselmu melalui Telegram.

Kesalahan umum dan solusinya

GejalaKemungkinan penyebabSolusi
Waktu menampilkan 1970 atau tidak pernah diterimaWi-Fi belum terhubung atau port NTP (UDP 123) diblokirPeriksa WiFi.status() dahulu; pada jaringan sekolah dan kantor, coba jaringan lain atau hotspot ponsel
Waktu meleset tepat sebesar selisih UTC-muZona waktu belum diatur, yang ditampilkan adalah UTCconfigTzTime("<+03>-3", ...) atau string untuk zona waktumu
Waktu meleset sebesar dua kali selisihnyaTanda terbalik dalam string TZ ("UTC+3")Gunakan "<+03>-3" atau "UTC-3" untuk UTC+3
Bulan kurang satu, tahun menunjukkan 126tm_mon dihitung mulai dari 0, tm_year sejak 1900Gunakan tm_mon + 1, tm_year + 1900, atau strftime
Tugas terpicu berkali-kali dalam menit yang samaTidak ada pencegah pengulanganSimpan hari pelaksanaannya (tm_yday) dan periksa
Perulangan terhenti selama 5 detik setiap kali berjalanTanpa waktu yang valid, getLocalTime() secara default menunggu 5000 msGunakan getLocalTime(&t, 0) di dalam loop()
Simbol aneh pada nama hari di OLEDFont tidak memiliki huruf beraksenTulis nama hari dalam ASCII biasa atau beralih ke library U8g2
Untuk mengisolasi masalah, jalankan dahulu sketch pertama yang hanya mencetak waktu ke Serial Monitor. Jika waktu di sana benar, masalahnya ada pada layar, RTC, atau logika tugas; jika di sana juga salah, periksa Wi-Fi dan pengaturan zona waktu.

NTP ESP32 adalah cara termurah dan paling praktis untuk menambahkan waktu yang akurat ke proyek: dengan beberapa baris kode, board mendapatkan waktu yang tepat hingga detik, menangani zona waktu dan waktu musim panas sendiri, serta tetap mempertahankan waktu ketika listrik padam jika ditambahkan DS3231. Di aplikasi BlueGrays kamu akan menemukan proyek langkah demi langkah lengkap dengan skema rangkaian dan kode untuk jam waktu nyata melalui NTP ESP32, jam digital dengan RTC DS1307, tampilan cuaca di OLED, dan pencatat suhu dengan cap waktu.

Pertanyaan umum

Bisakah ESP32 mempertahankan waktu tanpa internet?

Bisa, setelah menerima waktu dari NTP: ESP32 terus menghitung waktu sistem dengan timer-nya sendiri, dan kehilangan Wi-Fi tidak menghentikan jam. Namun, jika daya hilang atau board mulai ulang, waktu kembali ke 1970. Di tempat tanpa internet, atau untuk jam yang tetap mempertahankan waktu ketika listrik padam, tambahkan modul RTC dengan baterai cadangan seperti DS3231.

Mengapa waktu NTP ESP32-ku meleset beberapa jam?

Jika zona waktu belum diatur, ESP32 menampilkan UTC, sehingga jam meleset tepat sebesar selisih UTC-mu. Gunakan configTzTime dengan string POSIX yang benar, misalnya "CET-1CEST,M3.5.0,M10.5.0/3" untuk Eropa Tengah atau "GMT0BST,M3.5.0/1,M10.5.0" untuk Britania Raya. Jika meleset sebesar dua kali selisihnya, tanda dalam string TZ-mu terbalik.

Apa perbedaan configTime dan configTzTime?

configTime menerima selisih UTC dan selisih waktu musim panas dalam detik, tetapi tidak mengetahui kapan DST dimulai dan berakhir di wilayahmu. configTzTime menerima string zona waktu POSIX yang mencakup aturan DST, sehingga ESP32 beralih antara waktu musim panas dan musim dingin secara otomatis. Untuk wilayah mana pun yang menerapkan waktu musim panas, configTzTime adalah pilihan yang tepat.

Seberapa sering ESP32 menyinkronkan waktu dengan NTP?

Pada core Arduino ESP32, SNTP secara default meminta waktu lagi ke server setiap 3 jam dan mempertahankan waktu dengan timer-nya sendiri di antaranya. Kamu bisa mengubah interval dalam milidetik dengan sntp_set_sync_interval(), tetapi menurut aturan protokol interval tidak boleh lebih pendek dari 15 detik.

Apakah ESP32 membutuhkan modul RTC?

Tidak jika perangkat selalu mendapat daya dan dapat mengakses Wi-Fi; NTP memberikan waktu yang lebih akurat. Jika kamu membutuhkan waktu yang benar setelah listrik padam sebelum internet kembali, atau perangkat akan berjalan di tempat tanpa internet, tambahkan modul RTC dengan baterai cadangan seperti DS3231.

Bagaimana cara mendapatkan waktu NTP di Raspberry Pi Pico W?

Dalam MicroPython, setelah terhubung ke Wi-Fi, cukup jalankan import ntptime dan ntptime.settime(); ini mengatur RTC internal Pico ke UTC. Untuk waktu lokal, tambahkan selisih waktumu dalam detik, misalnya time.localtime(time.time() + 3600) untuk UTC+1. ntptime tidak menyinkronkan ulang secara otomatis, jadi panggil settime() lagi sekali atau dua kali sehari.

Lihat semua proyek
Jam Real-Time dari Internet lewat NTP ESP32
#128Mahir
Premium

Jam Real-Time dari Internet lewat NTP ESP32

ESP32 tersambung ke Wi-Fi dan mengambil waktu nyata dengan presisi milidetik dari server NTP (Network Time Protocol). Berkat fungsi configTzTime(), zona waktu Turki (TRT, UTC+3) otomatis diterapkan, dan pergantian DST di negara yang memakai waktu musim panas otomatis diatur dengan string POSIX TZ. Waktunya ditampilkan di Serial Monitor sekaligus di LCD I2C opsional. configTzTime() memulai layanan SNTP; sinkronisasi ulang berkala terjadi selama koneksi tersedia.

4.5(13)
21
Jam Digital dengan ESP32 dan RTC DS1307 (I2C + LCD)
#120Menengah
Premium

Jam Digital dengan ESP32 dan RTC DS1307 (I2C + LCD)

Di proyek ini, kita menampilkan waktu dan tanggal di layar LCD I2C 16x2 memakai modul jam real-time (RTC) DS1307. DS1307 adalah RTC berbaterai cadangan yang tetap menjaga waktu meskipun ESP32 dimatikan. Kedua modul berbagi bus I2C yang sama (SDA/SCL), sehingga kita belajar mengendalikan beberapa perangkat hanya dengan dua kabel sinyal. Lewat proyek ini kamu mendapat pengetahuan praktis tentang protokol komunikasi I2C, cara kerja modul RTC, dan tampilan data dinamis di LCD.

4.6(26)
40
Koneksi Wi-Fi STA ESP32 (dengan Layar LCD)
#127Mahir

Koneksi Wi-Fi STA ESP32 (dengan Layar LCD)

Di proyek ini, kita menyambungkan ESP32 ke jaringan Wi-Fi rumah dalam mode Station (STA) dengan cara yang aman dan tahan gangguan. Kita menyimpan SSID dan kata sandi di file secrets.h terpisah agar tidak bocor ke Git, menyiapkan mekanisme sambung ulang otomatis, dan menampilkan tingkat sinyal RSSI dan alamat IP di layar LCD I2C. LED bawaan bekerja sebagai indikator status. Ini adalah pengelola koneksi kelas produksi.

4.4(21)
34
HTTPClient + API Cuaca ESP32 (dengan Layar OLED SSD1306)
#134Mahir
Premium

HTTPClient + API Cuaca ESP32 (dengan Layar OLED SSD1306)

Di proyek ini, kita memakai ESP32 untuk melakukan panggilan REST API ke API cuaca (wttr.in) lewat internet dengan HTTPClient.h. Berbeda dengan versi LCD I2C sebelumnya, di sini kita memakai layar OLED SSD1306 (128×64), yang memungkinkan font besar, ikon vektor, dan tampilan visual yang kaya di satu layar. Tujuh ikon vektor untuk kondisi cuaca (cerah, berawan sebagian, berawan, hujan, salju, badai, berkabut) digambar ketika program berjalan (tanpa file bitmap).

4.3(10)
19
HTTPClient + API Cuaca ESP32 (dengan Layar LCD)
#133Mahir
Premium

HTTPClient + API Cuaca ESP32 (dengan Layar LCD)

Di proyek ini, kita memakai ESP32 untuk melakukan panggilan REST API ke API cuaca (wttr.in) lewat internet dengan HTTPClient.h. Kita mengurai respons JSON yang diterima dengan ArduinoJson v7 dan menampilkan kota, suhu, kelembapan, cuaca, dan informasi angin di layar LCD I2C dalam bahasa Turki dan Inggris. wttr.in gratis dan tidak butuh kunci API; kamu cukup memasukkan nama kota apa pun untuk mengambil kondisi cuaca terkini kota itu. Data diperbarui otomatis setiap 30 menit.

4.7(13)
20
Deep Sleep ESP32: Hemat Baterai (OLED + Penghitung RTC RAM)
#135Mahir
Premium

Deep Sleep ESP32: Hemat Baterai (OLED + Penghitung RTC RAM)

Mode Deep Sleep ESP32 menurunkan konsumsi arus hingga ~10 µA dengan mematikan CPU dan sebagian besar periferal, sehingga sangat penting untuk perangkat IoT bertenaga baterai. Di proyek ini, kita memakai tiga sumber bangun yang berbeda: timer (15 detik), pin eksternal (EXT0, tombol GPIO 33), dan sentuhan (T0/GPIO 4). Variabel yang ditandai RTC_DATA_ATTR dipertahankan selama deep sleep; penghitung boot, penghitung bangun karena timer, dan penghitung bangun karena tombol terus dilacak.

4.3(10)
16
Pencatat Data Suhu ESP32 (DHT22 + RTC DS1307 + microSD + OLED)
#144Mahir
Premium

Pencatat Data Suhu ESP32 (DHT22 + RTC DS1307 + microSD + OLED)

Buat pencatat suhu bercap waktu dengan ESP32! Baca suhu/kelembapan DHT22 setiap menit, ambil waktu sebenarnya dari RTC DS1307, dan catat ke kartu microSD sebagai CSV. OLED menampilkan suhu langsung (font besar), kelembapan, cap waktu, dan penghitung catatan. File /temp_log.csv bisa dibuka di Excel, Google Sheets, atau Python pandas; cocok untuk rumah kaca, suhu kamar, data laboratorium, penyimpanan makanan, atau sarang lebah.

4.7(7)
12
Layar LCD I2C ESP32 (16x2)
#119Menengah
Premium

Layar LCD I2C ESP32 (16x2)

Di proyek ini, kita menampilkan teks dengan menyambungkan layar LCD karakter 16x2 ke ESP32 lewat protokol I2C. Berkat I2C, kita bisa mengendalikan layar hanya dengan dua pin data (SDA dan SCL), sehingga tidak perlu memboroskan 6+ pin seperti pada sambungan paralel klasik. Kode mencetak pesan tetap di baris pertama dan penghitung yang naik setiap detik di baris kedua. Selain itu, kita menjalankan pemindai I2C di awal untuk mencetak alamat layar ke Serial Monitor (biasanya 0x27).

4.9(23)
40