#include "AstroCalc.h"
#include <WiFi.h>
#include <NTPClient.h>
#include <WiFiUdp.h>
#include <RTClib.h>
// KONFIGURACJA
const char* ssid = "Wokwi-GUEST";
const char* password = "";
// NTP
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "pool.ntp.org", 3600, 60000);
// RTC
RTC_DS3231 rtc;
// AstroCalc
double observer_lat = 45.613418;
double observer_lon = 10.312439;
double observer_h_m = 385.0;
AstroCalc::AstroCalc astro(observer_lat, observer_lon);
// ZMIENNE
bool timeSynced = false;
unsigned long lastAstroUpdate = 0;
const unsigned long ASTRO_UPDATE_INTERVAL = 3600000;
// FUNKCJE POMOCNICZE
void printMemoryInfo(const char* label) {
Serial.printf("[%s] Pamięć: wolna=%luB, max_alloc=%luB\n", label, ESP.getFreeHeap(), ESP.getMaxAllocHeap());
}
String formatTime(unsigned long secondsSinceMidnight) {
char buffer[9];
sprintf(buffer, "%02lu:%02lu:%02lu", secondsSinceMidnight / 3600, (secondsSinceMidnight % 3600) / 60, secondsSinceMidnight % 60);
return String(buffer);
}
String formatDateTime(unsigned long unixTime) {
time_t t = unixTime;
struct tm *tm = localtime(&t);
char buffer[20];
strftime(buffer, sizeof(buffer), "%Y.%m.%d %H:%M:%S", tm);
return String(buffer);
}
// SYNCHRONIZACJA CZASU
bool syncTimeWithNTP() {
Serial.println("Łączenie z WiFi...");
WiFi.begin(ssid, password);
int attempts = 0;
while (WiFi.status() != WL_CONNECTED && attempts < 20) {
delay(500);
Serial.print(".");
attempts++;
}
if (WiFi.status() != WL_CONNECTED) {
Serial.println("\nBrak połączenia WiFi!");
return false;
}
Serial.println("\nPołączono z WiFi!");
printMemoryInfo("Po WiFi");
// Synchronizacja NTP
Serial.println("Synchronizacja czasu NTP...");
timeClient.begin();
if (!timeClient.update()) {
timeClient.forceUpdate();
}
unsigned long epochTime = timeClient.getEpochTime();
Serial.printf("Czas UTC z NTP: %s\n", formatDateTime(epochTime).c_str());
// Ustawienie RTC
if (rtc.begin()) {
rtc.adjust(DateTime(epochTime));
Serial.println("RTC zsynchronizowane z NTP");
}
// Rozłączenie WiFi
WiFi.disconnect(true);
WiFi.mode(WIFI_OFF);
delay(100);
Serial.println("WiFi rozłączone");
printMemoryInfo("Po rozłączeniu WiFi");
return true;
}
// WYŚWIETLENIE PEŁNYCH DANYCH
void displayFullAstroData(unsigned long unixTime) {
printMemoryInfo("Przed obliczeniami");
Serial.println("\n==================================================================================");
Serial.println("PEŁNE DANE ASTRONOMICZNE - ASTROCALC");
Serial.println("==================================================================================");
// Oblicz dane
AstroCalc::AstronomicalData data = astro.calculate(unixTime);
// Konwersja na czas lokalny
time_t localTime = unixTime + 3600;
// CZAS I LOKALIZACJA
Serial.println("PARAMETR . . . . . . UTC . . . . . LOCAL . . . . WARTOŚĆ");
Serial.println("----------------------------------------------------------------------------------");
Serial.printf("Data/Czas . . . %s %s %.4f°/%.4f°\n", formatDateTime(unixTime).c_str(), formatDateTime(localTime).c_str(), observer_lat, observer_lon);
// SŁOŃCE - WSPÓŁRZĘDNE
Serial.println("----------------------------------------------------------------------------------");
Serial.printf("Słońce - Azymut . . . . . . . . . %.2f°\n", data.sunPosition.azimuth * (180.0 / M_PI));
Serial.printf("Słońce - Wysokość . . . . . . . . %.2f°\n", data.sunPosition.elevation * (180.0 / M_PI));
Serial.printf("Słońce - Rektascensja . . . . . . . %.4f°\n", data.sunPosition.rightAscension * (180.0 / M_PI));
Serial.printf("Słońce - Deklinacja . . . . . . . . %.4f°\n", data.sunPosition.declination * (180.0 / M_PI));
Serial.printf("Słońce - Dł. ekliptyczna . . . . . . %.2f°\n", data.sunPosition.eclipticLongitude);
// zodiak Słońca
Serial.printf("Słońce - Zodiak . . . . . . . . . %s\n", data.sunPosition.zodiacSunSign);
Serial.printf("Słońce - Odległość . . . . . . . . %.6f AU\n", data.sunPosition.distanceAU);
Serial.printf("Słońce - Odległość (km) . . . . . . %.0f km\n", data.sunPosition.distance);
// SŁOŃCE - CZASY
Serial.println("----------------------------------------------------------------------------------");
Serial.printf("Wschód słońca . . . . %s . . . %s\n", formatTime(data.sunTimes.rise).c_str(), formatTime(data.sunTimes.rise + 3600).c_str());
Serial.printf("Górowanie słońca . . . %s . . . %s . . . . %.1f°\n", formatTime(data.sunTimes.transit).c_str(), formatTime(data.sunTimes.transit + 3600).c_str(), data.sunTimes.transitElevation);
Serial.printf("Zachód słońca . . . . %s . . . %s\n", formatTime(data.sunTimes.set).c_str(), formatTime(data.sunTimes.set + 3600).c_str());
// ZMIERZCHI
Serial.println("----------------------------------------------------------------------------------");
Serial.printf("Świt cywilny . . . . %s . . . %s\n", formatTime(data.sunTimes.civilDawn).c_str(), formatTime(data.sunTimes.civilDawn + 3600).c_str());
Serial.printf("Świt żeglarski . . . . %s . . . %s\n", formatTime(data.sunTimes.nauticalDawn).c_str(), formatTime(data.sunTimes.nauticalDawn + 3600).c_str());
Serial.printf("Świt astronomiczny . . %s . . . %s\n", formatTime(data.sunTimes.astronomicalDawn).c_str(), formatTime(data.sunTimes.astronomicalDawn + 3600).c_str());
Serial.printf("Zmierzch cywilny . . . %s . . . %s\n", formatTime(data.sunTimes.civilDusk).c_str(), formatTime(data.sunTimes.civilDusk + 3600).c_str());
Serial.printf("Zmierzch żeglarski . . %s . . . %s\n", formatTime(data.sunTimes.nauticalDusk).c_str(), formatTime(data.sunTimes.nauticalDusk + 3600).c_str());
Serial.printf("Zmierzch astronomiczny . %s . . . %s\n", formatTime(data.sunTimes.astronomicalDusk).c_str(), formatTime(data.sunTimes.astronomicalDusk + 3600).c_str());
// KSIĘŻYC - WSPÓŁRZĘDNE
Serial.println("----------------------------------------------------------------------------------");
Serial.printf("Księżyc - Azymut . . . . . . . . . %.2f°\n", data.moonPosition.azimuth * (180.0 / M_PI));
Serial.printf("Księżyc - Wysokość . . . . . . . . %.2f°\n", data.moonPosition.elevation * (180.0 / M_PI));
Serial.printf("Księżyc - Rektascensja . . . . . . . %.4f°\n", data.moonPosition.rightAscension * (180.0 / M_PI));
Serial.printf("Księżyc - Deklinacja . . . . . . . %.4f°\n", data.moonPosition.declination * (180.0 / M_PI));
// POPRAWIONA LINIA (112): używamy .phase.name, który jest teraz const char*
Serial.printf("Księżyc - Faza . . . . . . . . . %s (%.1f%%)\n", data.moonData.phase.name, data.moonData.phase.fraction * 100.0);
Serial.printf("Księżyc - Oświetlenie . . . . . . . %.3f\n", data.moonPosition.illumination);
Serial.printf("Księżyc - Wiek . . . . . . . . . %.2f dni\n", data.moonData.phase.age);
Serial.printf("Księżyc - Dł. ekliptyczna . . . . . . %.2f°\n", data.moonData.eclipticLongitude);
Serial.printf("Księżyc - Sz. ekliptyczna . . . . . . %.2f°\n", data.moonData.eclipticLatitude);
Serial.printf("Księżyc - Zodiak . . . . . . . . . %s\n", data.moonData.zodiacMoonSign);
Serial.printf("Księżyc - Odległość . . . . . . . . %.0f km\n", data.moonPosition.distance);
Serial.printf("Księżyc - Elongacja . . . . . . . . %.2f°\n", data.moonPosition.elongation);
Serial.printf("Księżyc - Kąt paralaktyczny . . . . . %.2f°\n", data.moonPosition.parallacticAngle * (180.0 / M_PI));
// KSIĘŻYC - CZASY
Serial.println("----------------------------------------------------------------------------------");
Serial.printf("Wschód księżyca . . . %s . . . %s\n", formatTime(data.moonTimes.rise).c_str(), formatTime(data.moonTimes.rise + 3600).c_str());
Serial.printf("Górowanie księżyca . . %s . . . %s . . . . %.1f°\n", formatTime(data.moonTimes.transit).c_str(), formatTime(data.moonTimes.transit + 3600).c_str(), data.moonTimes.transitElevation);
Serial.printf("Zachód księżyca . . . %s . . . %s\n", formatTime(data.moonTimes.set).c_str(), formatTime(data.moonTimes.set + 3600).c_str());
// LIBRACJA I KĄTY
Serial.println("----------------------------------------------------------------------------------");
Serial.printf("Libracja - dł. selenogr . . . . . . . %.2f°\n", data.libration.selenographicLongitude);
Serial.printf("Libracja - sz. selenogr . . . . . . . %.2f°\n", data.libration.selenographicLatitude);
Serial.printf("Kąt - jasny brzeg . . . . . . . . %.1f°\n", data.positionAngles.brightLimb);
Serial.printf("Kąt - biegun . . . . . . . . . . %.1f°\n", data.positionAngles.pole);
Serial.printf("Kąt - oś . . . . . . . . . . . %.1f°\n", data.positionAngles.axis);
// CZAS GWIEZDNY
Serial.println("----------------------------------------------------------------------------------");
double jd = AstroCalc::AstroCalc::julianDate(unixTime);
double lst = AstroCalc::AstroCalc::getLocalSiderealTime(jd, observer_lon);
Serial.printf("Czas gwiazdowy lokalny . . . . . . . %.4f° (%.4fh)\n", lst * (180.0 / M_PI), lst * (180.0 / M_PI) / 15.0);
Serial.println("==================================================================================");
printMemoryInfo("Po wyświetleniu danych");
}
// SETUP
void setup() {
Serial.begin(115200);
delay(1000);
Serial.println("\n=== INICJALIZACJA ASTROCALC ===");
printMemoryInfo("Start");
// Ustaw wysokość obserwatora
astro.setObserverHeight(observer_h_m);
// Sprawdzenie RTC
if (!rtc.begin()) {
Serial.println("RTC nie działa! Wymagana synchronizacja.");
timeSynced = syncTimeWithNTP();
} else {
DateTime now = rtc.now();
if (now.year() < 2024) {
Serial.println("RTC ma nieprawidłowy czas. Synchronizacja...");
timeSynced = syncTimeWithNTP();
} else {
Serial.printf("RTC OK: %s\n", formatDateTime(now.unixtime()).c_str());
timeSynced = true;
}
}
if (timeSynced) {
DateTime now = rtc.now();
unsigned long currentTime = now.unixtime();
// Pierwsze obliczenia i wyświetlenie
displayFullAstroData(currentTime);
lastAstroUpdate = millis();
}
printMemoryInfo("Koniec setup");
}
// LOOP
void loop() {
static unsigned long lastDisplay = 0;
const unsigned long DISPLAY_INTERVAL = 60000;
if (!rtc.begin() || !timeSynced) {
delay(5000);
return;
}
DateTime now = rtc.now();
unsigned long currentTime = now.unixtime();
// Automatyczne odświeżanie danych co godzinę
if (millis() - lastAstroUpdate > ASTRO_UPDATE_INTERVAL) {
displayFullAstroData(currentTime);
lastAstroUpdate = millis();
}
// Wyświetlanie statusu co minutę
if (millis() - lastDisplay > DISPLAY_INTERVAL) {
Serial.printf("\n[%s] RTC=%s, Odśw.=%.1fh temu\n", formatTime(currentTime % 86400).c_str(), timeSynced ? "OK" : "BRAK", (millis() - lastAstroUpdate) / 3600000.0);
lastDisplay = millis();
}
// Sprawdzenie utraty zasilania RTC
static bool rtcLostPower = false;
if (rtc.lostPower()) {
if (!rtcLostPower) {
Serial.println("\n[ALERT] RTC straciło zasilanie! Resynchronizacja...");
rtcLostPower = true;
timeSynced = syncTimeWithNTP();
if (timeSynced) {
DateTime newNow = rtc.now();
displayFullAstroData(newNow.unixtime());
lastAstroUpdate = millis();
}
}
} else {
rtcLostPower = false;
}
delay(1000);
}