// Kitaplık Yöneticisi'nden kurulacak:
// "LiquidCrystal I2C"
// Kart: "ESP32 Dev Module"
#include <WiFi.h>
#include <WiFiClientSecure.h>
#include <HTTPClient.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
// Evdeki Wi-Fi ağının adı ve şifresi
const char* WIFI_NAME = "Wokwi-GUEST";
const char* WIFI_PASSWORD = "";
// Merkez Bankası'nın günlük kur listesi
const char* RATES_URL = "https://www.tcmb.gov.tr/kurlar/today.xml";
// Kurlar iş günleri 15.30'da açıklanır;
// yarım saatte bir bakmak yeter (ms)
const unsigned long FETCH_EVERY = 30UL * 60 * 1000;
// Alınamazsa bu kadar sonra yine dene
const unsigned long RETRY_AFTER = 60000;
// Ekran sayfaları arası süre (ms)
const unsigned long PAGE_EVERY = 4000;
// ESP32'nin I2C pinleri
const int SDA_PIN = 21;
const int SCL_PIN = 22;
// Bu süreden sonra şifreyi sor (ms)
const unsigned long WIFI_HINT_AFTER = 15000;
// I2C adresi çoğunda 0x27, bazısında 0x3F
LiquidCrystal_I2C lcd(0x27, 16, 2);
// Son okunan satış kurları; 0: henüz yok
float usd = 0;
float eur = 0;
float gbp = 0;
// Kurların tarihi, ör. "30.10.2026"
String rateDate = "";
unsigned long nextFetch = 0;
unsigned long lastPage = 0;
int page = 0;
// Bir satırı yazar, kalanını boşlukla
// siler (ekran titremez)
void printLine(int row, const String& text) {
lcd.setCursor(0, row);
lcd.print(text);
for (int n = text.length(); n < 16; n++) {
lcd.print(' ');
}
}
// Bir paranın satış kurunu bulur
// (ForexSelling); bulamazsa 0
float sellingRate(const String& xml, const char* code) {
int at = xml.indexOf(String("CurrencyCode=\"") + code + "\"");
if (at < 0) return 0;
int start = xml.indexOf("<ForexSelling>", at);
if (start < 0) return 0;
start += 14;
int end = xml.indexOf('<', start);
return xml.substring(start, end).toFloat();
}
// Listeyi indirir; olmazsa ekrandaki
// eski kurlar kalır
bool fetchRates() {
WiFiClientSecure client;
// Sertifikaya bakılmaz: yalnızca
// herkese açık bir liste okunuyor
client.setInsecure();
HTTPClient http;
http.begin(client, RATES_URL);
// Sıkıştırmasız iste: ESP32'nin olağan
// isteğine TCMB gzip ile cevap veriyor
http.setAcceptEncoding("identity");
int status = http.GET();
if (status != 200) {
Serial.print("Kurlar alınamadı, HTTP ");
Serial.println(status);
http.end();
return false;
}
String xml = http.getString();
http.end();
// Liste en başta tarihini söyler:
// Tarih="30.10.2026"
int at = xml.indexOf("Tarih=\"");
if (at >= 0) {
int end = xml.indexOf('"', at + 7);
rateDate = xml.substring(at + 7, end);
}
float newUsd = sellingRate(xml, "USD");
if (newUsd == 0) {
// Gelen şey kur listesi değil: başını
// göster, nedeni oradan anlaşılır
Serial.print("Beklenmeyen yanıt (");
Serial.print(xml.length());
Serial.print(" bayt): ");
Serial.println(xml.substring(0, 160));
return false;
}
usd = newUsd;
eur = sellingRate(xml, "EUR");
gbp = sellingRate(xml, "GBP");
Serial.print(rateDate);
Serial.print(" USD ");
Serial.print(usd, 4);
Serial.print(" EUR ");
Serial.print(eur, 4);
Serial.print(" GBP ");
Serial.println(gbp, 4);
return usd > 0;
}
// "USD/TL 49.8644": tam 16 karakter
String rateLine(const char* code, float rate) {
char text[17];
snprintf(text, sizeof text, "%s/TL %8.4f", code, rate);
return String(text);
}
void showPage() {
if (usd == 0) {
printLine(0, "Kur alinamadi");
printLine(1, "Yine denenecek");
return;
}
if (page == 0) {
printLine(0, rateLine("USD", usd));
printLine(1, rateLine("EUR", eur));
} else {
printLine(0, rateLine("GBP", gbp));
printLine(1, "TCMB " + rateDate);
}
}
void setup() {
Serial.begin(115200);
Wire.begin(SDA_PIN, SCL_PIN);
lcd.init();
lcd.backlight();
lcd.print("Wi-Fi bekleniyor");
Serial.print("Bağlanılıyor: ");
Serial.println(WIFI_NAME);
WiFi.begin(WIFI_NAME, WIFI_PASSWORD);
unsigned long start = millis();
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
if (millis() - start > WIFI_HINT_AFTER) {
// Bağlanamadı: ad ya da şifre?
lcd.setCursor(0, 1);
lcd.print("Ad/sifre dogru?");
}
}
Serial.println();
Serial.println("Bağlandı");
printLine(0, "Kurlar aliniyor");
printLine(1, "");
}
void loop() {
// İlk açılışta, sonra yarım saatte bir
if ((long)(millis() - nextFetch) >= 0) {
bool ok = fetchRates();
nextFetch = millis() + (ok ? FETCH_EVERY : RETRY_AFTER);
showPage();
}
// İki sayfa sırayla: USD ve EUR, sonra
// GBP ve kurların tarihi
if (millis() - lastPage > PAGE_EVERY) {
lastPage = millis();
page = 1 - page;
showPage();
}
}