2025. október 19., vasárnap

Pontos idő - ESP32

// --- Hálózat / Internet ---
#include <WiFi.h>
#include <WiFiUdp.h>
#include <WiFiClientSecure.h>
#include <HTTPClient.h>

// --- Időkezelés ---
#include <NTPClient.h>
#include <time.h>
#include <sys/time.h>

// --- JSON feldolgozás ---
#include <ArduinoJson.h>

// Wi-Fi és API adatok
static const char* WIFI_SSID       = "YOUR_WIFI_SSID";
static const char* WIFI_PASSWORD   = "YOUR_WIFI_PASSWORD";
static const char* NTP_SERVER      = "pool.ntp.org";
static const char* WEATHER_API_URL = "https://api.openweathermap.org/data/2.5/weather?";
static const char* API_KEY         = "YOUR_API_KEY";
static const char* LATITUDE        = "47.4979";
static const char* LONGITUDE       = "19.0402";
static const char* LOCAL_TIMEZONE  = "CET-1CEST,M3.5.0/2,M10.5.0/3";

// Csak egyszer frissítünk naponta
bool synced_today = false;

// Legutóbb letöltött napkelte/napnyugta idő
static struct tm sunrise_local_tm = {};
static struct tm sunset_local_tm  = {};

WiFiUDP ntpUDP;
NTPClient utc(ntpUDP, NTP_SERVER);

// Kiírja az aktuális UTC és helyi időt
void printNowBoth() {
  time_t now_utc = time(nullptr);
  struct tm lt, gt;
  localtime_r(&now_utc, &lt);
  gmtime_r(&now_utc, &gt);

  Serial.printf(
    "UTC idő: %02d:%02d:%02d | Helyi idő: %02d:%02d:%02d\n",
    gt.tm_hour, gt.tm_min, gt.tm_sec,
    lt.tm_hour, lt.tm_min, lt.tm_sec
  );
}

// Wi-Fi csatlakozás
void wifi_connect() {
  if (WiFi.status() == WL_CONNECTED) return;

  Serial.printf("Kapcsolódás a WiFihez (%s)...", WIFI_SSID);
  WiFi.mode(WIFI_STA);
  WiFi.disconnect();
  WiFi.setAutoReconnect(true);
  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);

  // Timeout 10 másodperc
  unsigned long start = millis();
  while (WiFi.status() != WL_CONNECTED && millis() - start < 10000) {
    delay(250);
    Serial.print(".");
    yield();
  }

  if (WiFi.status() == WL_CONNECTED) {
    Serial.println(" SIKERES!");
    Serial.print("IP cím: ");
    Serial.println(WiFi.localIP());
  } else {
    Serial.println(" SIKERTELEN!");
  }
}

// Wi-Fi bontás energiatakarékossághoz
void wifi_disconnect() {
  if (WiFi.status() == WL_CONNECTED) WiFi.disconnect(false);
  WiFi.mode(WIFI_OFF);
  Serial.println("WiFi kapcsolat bontva!");
}

// Rendszeridő beállítása UTC epoch szerint
void setSystemTimeUTC(uint32_t epoch_utc) {
  struct timeval tv { (time_t)epoch_utc, 0 };
  settimeofday(&tv, nullptr);
}

// NTP-ről pontos idő frissítése
bool syncTimeWithNTP() {
  Serial.print("NTP frissítés...");
  utc.begin();
  bool ok = utc.forceUpdate();
  Serial.println(ok ? " SIKERES!" : " SIKERTELEN!");
  if (ok) setSystemTimeUTC(utc.getEpochTime());
  utc.end();
  return ok;
}

// Napkelte/napnyugta letöltése az internetről és helyi idővé konvertálás
bool updateSunriseSunset() {
  // Napló kedvéért aktuális dátum kiírása
  time_t now_utc = time(nullptr);
  struct tm lt_now;
  localtime_r(&now_utc, &lt_now);
  Serial.printf("Dátum: %04d-%02d-%02d\n",
                lt_now.tm_year + 1900, lt_now.tm_mon + 1, lt_now.tm_mday);

  WiFiClientSecure client;
  client.setInsecure(); // Nem ellenőrizzük a tanúsítványt (egyszerűbb)

  HTTPClient http;
  String url = String(WEATHER_API_URL) +
               "lat=" + LATITUDE +
               "&lon=" + LONGITUDE +
               "&units=metric&appid=" + API_KEY;

  http.setTimeout(8000);
  http.begin(client, url);
  int httpCode = http.GET();

  if (httpCode == HTTP_CODE_OK) {
    // JSON válasz beolvasása
    String body = http.getString();
    DynamicJsonDocument doc(4096);

    // JSON pars-olása
    DeserializationError err = deserializeJson(doc, body);
    if (err) {
      Serial.printf("JSON parse hiba: %s\n", err.f_str());
      http.end();
      return false;
    }

    // Mezők ellenőrzése
    if (!doc.containsKey("sys") || !doc["sys"].containsKey("sunrise")) {
      Serial.println("JSON parse hiba: hiányzó sunrise mező.");
      http.end();
      return false;
    }
    if (!doc["sys"].containsKey("sunset")) {
      Serial.println("JSON parse hiba: hiányzó sunset mező.");
      http.end();
      return false;
    }

    // Epoch → helyi idő konverzió
    time_t sr_utc = doc["sys"]["sunrise"].as<long>();
    time_t ss_utc = doc["sys"]["sunset"].as<long>();

    localtime_r(&sr_utc, &sunrise_local_tm);
    localtime_r(&ss_utc, &sunset_local_tm);

    Serial.printf("Napkelte: %02d:%02d\n", sunrise_local_tm.tm_hour, sunrise_local_tm.tm_min);
    Serial.printf("Napnyugta: %02d:%02d\n", sunset_local_tm.tm_hour, sunset_local_tm.tm_min);

    http.end();
    return true;
  }

  // Ha a HTTP nem OK
  Serial.printf("HTTP hiba: %d\n", httpCode);
  http.end();
  return false;
}

// Mindent egyszer frissít: NTP + napkelte/napnyugta
void synchronization() {
  wifi_connect();
  if (WiFi.status() != WL_CONNECTED) { wifi_disconnect(); return; }

  bool ntp_ok = syncTimeWithNTP();
  bool wx_ok  = updateSunriseSunset();

  synced_today = ntp_ok && wx_ok;
  wifi_disconnect();
}

void setup() {
  Serial.begin(115200);

  // Helyi időzóna beállítása az RTC-nek
  setenv("TZ", LOCAL_TIMEZONE, 1);
  tzset();

  // Induláskor idő + napkelte/nyugta frissítés
  synchronization();
}

void loop() {
  time_t now_utc = time(nullptr);
  struct tm gt;
  gmtime_r(&now_utc, &gt);

  // Naponta egyszer 01:00 után frissítünk
  if ((gt.tm_hour == 0) && synced_today) synced_today = false;
  if ((gt.tm_hour == 1) && (gt.tm_min == 0) &&
      (gt.tm_sec > 29) && !synced_today) synchronization();

  printNowBoth(); // Debug: kiírás minden mp-ben
  delay(1000);
}

Nincsenek megjegyzések:

Megjegyzés küldése