A következő címkéjű bejegyzések mutatása: esp32. Összes bejegyzés megjelenítése
A következő címkéjű bejegyzések mutatása: esp32. Összes bejegyzés megjelenítése

2025. november 2., vasárnap

BKK Futár - ESP32


#include <WiFi.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>
#include <time.h>

static const char* WIFI_SSID     = "YOUR_WIFI_SSID";
static const char* WIFI_PASSWORD = "YOUR_WIFI_PASSWORD";
static const char* BKK_API_KEY   = "YOUR_BKK_API_KEY";
static const char* LOCAL_TIMEZONE  = "CET-1CEST,M3.5.0/2,M10.5.0/3";
const char* stopId         = "F04166";
const int   minutesAfter = 30;

unsigned long lastApiCall = 0;
const long apiCallInterval = 60000;

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);

  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!");
  }
}

void wifi_disconnect() {
  if (WiFi.status() == WL_CONNECTED) WiFi.disconnect(false);
  WiFi.mode(WIFI_OFF);
  Serial.println("WiFi kapcsolat bontva!");
}

size_t formatLocalHHMM(long epochSec, char* buffer, size_t bufferSize) {
  time_t t = (time_t)epochSec;
  struct tm lt;
  localtime_r(&t, &lt);

  return snprintf(buffer, bufferSize, "%d:%02d", lt.tm_hour, lt.tm_min);
}


void fetchBKKData(const char* stopId);

void setup() {
  Serial.begin(115200);
  delay(500);
  Serial.println("BKK Menetrend Indítása...");

  wifi_connect();
 
  if (WiFi.status() != WL_CONNECTED) {
    Serial.println("Kritikus hiba: Wi-Fi kapcsolat nélkül nem folytatható.");
    while (true) {
      delay(1000);
    }
  }

  setenv("TZ", LOCAL_TIMEZONE, 1);
  tzset();

  fetchBKKData("F04165");
  fetchBKKData(stopId);
}

void loop() {
  if (millis() - lastApiCall > apiCallInterval) {
    lastApiCall = millis();
    Serial.printf("\n--- Frissítés ---\n");
    fetchBKKData(stopId);
  }
}

void parseBKKJson(const String& jsonString,const char* stopId) {
  DynamicJsonDocument doc(24576);
  DeserializationError error = deserializeJson(doc, jsonString);
  if (error) { Serial.print("JSON hiba: "); Serial.println(error.c_str()); return; }

  long long serverTimeMs = doc["currentTime"].as<long long>();
  long serverTimeSec = (long)(serverTimeMs / 1000LL);

  char timeBuffer[6];
  formatLocalHHMM(serverTimeSec, timeBuffer, sizeof(timeBuffer));
  Serial.print("Lekérdezés ideje: ");
  Serial.println(timeBuffer);

  JsonObject routes = doc["data"]["references"]["routes"];
  JsonObject trips  = doc["data"]["references"]["trips"];
  JsonArray stopTimes = doc["data"]["entry"]["stopTimes"];

  Serial.printf("Érkező járatok (Mesgye utca %s):\n",stopId);
  if (stopTimes.size() == 0) { Serial.println("Jelenleg nincsenek érkező járatok."); return; }

  for (JsonObject st : stopTimes) {
    const char* tripId    = st["tripId"];
    const char* routeId   = trips[tripId]["routeId"];
    const char* shortName = routes[routeId]["shortName"];
    const char* headsign  = st["stopHeadsign"];

    long predictedTimeSec = st["predictedDepartureTime"] | 0;
    if (predictedTimeSec == 0) predictedTimeSec = st["departureTime"] | 0;

    long diffSeconds = predictedTimeSec - serverTimeSec;

    long adj = (diffSeconds >= 0) ? (diffSeconds + 30) : (diffSeconds - 30);
    int minutes = (int)(adj / 60);

    char arrivalBuffer[6];
    formatLocalHHMM(predictedTimeSec, arrivalBuffer, sizeof(arrivalBuffer));

    int minutesShown = (minutes < 1) ? 0 : minutes;
    Serial.printf("%5s %2d' %4s %s\n",
      arrivalBuffer,
      minutesShown,
      shortName ? shortName : "?",
      headsign ? headsign : "?"
    );
  }

}

void fetchBKKData(const char* stopId) {
  if (WiFi.status() != WL_CONNECTED) { Serial.println("WiFi kapcsolat megszakadt."); return; }
 
  char urlBuffer[200];

  snprintf(urlBuffer, sizeof(urlBuffer),
    "https://futar.bkk.hu/api/query/v1/ws/otp/api/where/"
"arrivals-and-departures-for-stop.json?"
"key=%s&stopId=BKK_%s&minutesAfter=%d",
    BKK_API_KEY, stopId, minutesAfter);

  HTTPClient http;
  http.begin(urlBuffer);
  int httpCode = http.GET();
 
 
  if (httpCode > 0) {
    if (httpCode == HTTP_CODE_OK) parseBKKJson(http.getString(),stopId);
    else Serial.printf("Hiba a BKK API hívásakor. HTTP kód: %d\n", httpCode);
  } else {
    Serial.printf("HTTP GET hiba: %s\n", http.errorToString(httpCode).c_str());
  }
  http.end();
}

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);
}