// ESP32 HTTPClient + Weather API (wttr.in) + I2C LCD
// LED: GPIO 5 (220 ohm) | LCD: SDA=21 SCL=22 VCC=VIN
// Bilingual TR/EN display
// API: wttr.in (key gerektirmez / no key required)
#include <WiFi.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
// Wi-Fi credentials — Wokwi default
const char* WIFI_SSID = "Wokwi-GUEST";
const char* WIFI_PASS = "";
// Sehir adi — kendi sehrinizle degistirin / Your city
const char* CITY = "Istanbul";
// API call interval — 30 dakika / 30 minutes
const unsigned long FETCH_INTERVAL_MS = 30UL * 60UL * 1000UL;
#define LED_PIN 5
#define I2C_SDA 21
#define I2C_SCL 22
LiquidCrystal_I2C lcd(0x27, 16, 2);
struct WeatherData {
String city;
String tempC;
String humidity;
String descEn;
String descTr;
String windKmh;
unsigned long lastFetchMs;
bool valid;
};
WeatherData weather = {"", "", "", "", "", "", 0, false};
bool wifiOk = false;
// ============================================================
// LCD helpers
// ============================================================
void lcdLine(uint8_t row, const String &text) {
lcd.setCursor(0, row);
String t = text;
while (t.length() < 16) t += " ";
lcd.print(t.substring(0, 16));
}
void showScreen(const String &tr, const String &en) {
lcdLine(0, tr);
lcdLine(1, en);
}
// ============================================================
// Hava durumu EN -> TR cevirisi / Weather EN -> TR mapping
// ============================================================
String translateWeather(const String &en) {
String e = en;
e.toLowerCase();
if (e.indexOf("partly cloudy") >= 0) return "Parcali bulut";
if (e.indexOf("sunny") >= 0) return "Gunesli";
if (e.indexOf("clear") >= 0) return "Acik";
if (e.indexOf("overcast") >= 0) return "Kapali";
if (e.indexOf("cloudy") >= 0) return "Bulutlu";
if (e.indexOf("mist") >= 0) return "Sisli";
if (e.indexOf("fog") >= 0) return "Sis";
if (e.indexOf("light rain") >= 0) return "Hafif yagmur";
if (e.indexOf("heavy rain") >= 0) return "Siddetli yagmur";
if (e.indexOf("rain") >= 0) return "Yagmurlu";
if (e.indexOf("drizzle") >= 0) return "Cisenti";
if (e.indexOf("snow") >= 0) return "Karli";
if (e.indexOf("thunder") >= 0) return "Firtinali";
if (e.indexOf("hail") >= 0) return "Doluli";
return en;
}
// ============================================================
// LED yardimcisi / LED helper
// ============================================================
void blink(uint8_t times, uint16_t onMs = 100, uint16_t offMs = 120) {
for (uint8_t i = 0; i < times; i++) {
digitalWrite(LED_PIN, HIGH); delay(onMs);
digitalWrite(LED_PIN, LOW); delay(offMs);
}
}
// ============================================================
// API'den veri cek / Fetch from API
// ============================================================
bool fetchWeather() {
if (!wifiOk) return false;
showScreen("API cagriliyor", "Fetching data..");
digitalWrite(LED_PIN, HIGH);
HTTPClient http;
String url = String("http://wttr.in/") + CITY + "?format=j1";
http.setTimeout(10000);
http.begin(url);
http.addHeader("User-Agent", "BlueGrays-ESP32/1.0");
int code = http.GET();
bool ok = false;
if (code == 200) {
String body = http.getString();
JsonDocument doc;
DeserializationError err = deserializeJson(doc, body);
if (!err) {
JsonObject cur = doc["current_condition"][0];
weather.city = String(CITY);
weather.tempC = cur["temp_C"].as<String>();
weather.humidity = cur["humidity"].as<String>();
weather.descEn = cur["weatherDesc"][0]["value"].as<String>();
weather.descTr = translateWeather(weather.descEn);
weather.windKmh = cur["windspeedKmph"].as<String>();
weather.lastFetchMs = millis();
weather.valid = true;
ok = true;
}
}
http.end();
if (ok) {
showScreen("Veri alindi!", "Data received!");
digitalWrite(LED_PIN, HIGH);
delay(2000);
digitalWrite(LED_PIN, LOW);
} else {
showScreen("HATA: HTTP " + String(code), "Error: HTTP " + String(code));
digitalWrite(LED_PIN, LOW);
blink(3, 150, 150);
delay(1500);
}
return ok;
}
// ============================================================
// Veri ekranlarini sirayla goster + LED davranisi
// ============================================================
void showWeatherScreens() {
if (!weather.valid) {
showScreen("Veri yok", "No data yet");
delay(2500);
return;
}
// Sehir / City — 1 kirpis
showScreen("Sehir: " + weather.city, "City: " + weather.city);
blink(1);
delay(2780);
// Sicaklik / Temperature — 2 kirpis
showScreen("Sicaklik: " + weather.tempC + " C", "Temp: " + weather.tempC + " C");
blink(2);
delay(2560);
// Nem / Humidity — 3 kirpis
showScreen("Nem: %" + weather.humidity, "Humidity: " + weather.humidity + "%");
blink(3);
delay(2340);
// Hava / Weather — uzun 1sn yanik
showScreen("Hava: " + weather.descTr, "Weather: " + weather.descEn);
digitalWrite(LED_PIN, HIGH);
delay(1000);
digitalWrite(LED_PIN, LOW);
delay(2000);
// Ruzgar / Wind — 4 hizli kirpis
showScreen("Ruzgar: " + weather.windKmh + "km/h", "Wind: " + weather.windKmh + " km/h");
blink(4, 80, 100);
delay(2280);
// Son guncelleme / Last update — yavas heartbeat
unsigned long elapsedSec = (millis() - weather.lastFetchMs) / 1000;
unsigned long elapsedMin = elapsedSec / 60;
String trAge = elapsedMin > 0 ? String(elapsedMin) + " dk once" : String(elapsedSec) + " sn once";
String enAge = elapsedMin > 0 ? String(elapsedMin) + " min ago" : String(elapsedSec) + " sec ago";
showScreen("Guncel: " + trAge, "Updated: " + enAge);
blink(1, 60, 940);
blink(1, 60, 940);
}
// ============================================================
// SETUP
// ============================================================
void setup() {
pinMode(LED_PIN, OUTPUT);
digitalWrite(LED_PIN, LOW);
// LCD ilk basta / Init LCD first
Wire.begin(I2C_SDA, I2C_SCL);
lcd.init();
lcd.backlight();
// Splash 3sn
showScreen(" BlueGrays", " Weather v1.0");
delay(3000);
// WiFi — 20sn timeout
showScreen("WiFi baglaniyor", "Connecting WiFi");
WiFi.mode(WIFI_STA);
WiFi.begin(WIFI_SSID, WIFI_PASS);
unsigned long startWifi = millis();
while (WiFi.status() != WL_CONNECTED && millis() - startWifi < 20000) {
delay(400);
}
if (WiFi.status() == WL_CONNECTED) {
wifiOk = true;
showScreen("WiFi baglandi", "WiFi connected");
delay(2000);
showScreen("IP adresi:", WiFi.localIP().toString());
delay(2000);
// Ilk API cagrisi / First API call
fetchWeather();
} else {
showScreen("WiFi baglanmadi", "WiFi failed");
delay(2000);
showScreen("Offline modu", "Offline mode");
delay(2500);
}
}
// ============================================================
// LOOP
// ============================================================
void loop() {
// 30 dakikada bir API tekrar cagir
if (wifiOk && millis() - weather.lastFetchMs > FETCH_INTERVAL_MS) {
fetchWeather();
}
// Veri ekranlarini sirayla goster (LED davranisi ile birlikte)
showWeatherScreens();
}