#include <MoonPhase.h>
#include <Wire.h>
#include "RTClib.h"
#include <math.h>
RTC_DS3231 rtc;
MoonPhase m;
// FUNCTION DECLARATIONS
void showTimeRTC();
void calculateMoonPhase();
void setTimeRTC(int year, int month, int day, int hour, int minute, int second);
void calculateShadowCenter();
// Shadow center structure
struct ShadowCenter {
double x;
double y;
double radius;
};
void setup() {
Serial.begin(9600);
delay(1000);
// Initialize I2C and RTC
Wire.begin();
if (!rtc.begin()) {
Serial.println("Nie znaleziono modułu RTC DS3231!");
while (1);
}
Serial.println("RTC DS3231 zainicjalizowany!");
// Check if RTC lost power and set compilation time
if (rtc.lostPower()) {
Serial.println("RTC stracił zasilanie - ustawiam czas kompilacji!");
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
}
// Display current time from RTC
showTimeRTC();
// Calculate and display moon phase
calculateMoonPhase();
// Calculate shadow center
calculateShadowCenter();
}
void loop() {
static unsigned long lastTime = 0;
unsigned long currentTime = millis();
// Refresh every 5 minutes (300000 ms)
if (currentTime - lastTime >= 300000) {
lastTime = currentTime;
showTimeRTC();
calculateMoonPhase();
calculateShadowCenter();
Serial.println("------------------------");
}
delay(1000); // Small delay for stability
}
void calculateShadowCenter() {
DateTime now = rtc.now();
time_t t = now.unixtime();
m.calculate(t);
// Moon dimensions
const int moonWidth = 240;
const int moonHeight = 240;
const int moonRadius = 120;
const int centerX = moonWidth / 2;
const int centerY = moonHeight / 2;
// Calculate shadow center based on moon phase
ShadowCenter shadow;
// Calculate shadow radius based on illumination (in pixels)
shadow.radius = (1.0 - m.fraction) * moonRadius;
// Calculate shadow center coordinates in pixels
// X coordinate varies with phase (left to right)
shadow.x = centerX + (moonRadius * 0.8) * cos(m.phase * 2 * M_PI);
// Y coordinate varies with libration/declination
shadow.y = centerY + (moonRadius * 0.6) * sin(m.phase * 4 * M_PI);
// Clamp values to stay within moon circle
double distanceFromCenter = sqrt(pow(shadow.x - centerX, 2) + pow(shadow.y - centerY, 2));
double maxAllowedRadius = moonRadius - shadow.radius;
if (distanceFromCenter + shadow.radius > moonRadius) {
// Adjust position to keep shadow inside moon
double scale = maxAllowedRadius / distanceFromCenter;
shadow.x = centerX + (shadow.x - centerX) * scale;
shadow.y = centerY + (shadow.y - centerY) * scale;
}
// Ensure radius is reasonable
shadow.radius = fmax(0.0, fmin(moonRadius, shadow.radius));
Serial.println("\n=== ŚRODEK CIENIA ===");
Serial.print("Wymiary księżyca:\t");
Serial.print(moonWidth);
Serial.print("x");
Serial.print(moonHeight);
Serial.print("px, promień: ");
Serial.print(moonRadius);
Serial.println("px");
Serial.print("Współrzędna X:\t");
Serial.print(shadow.x, 1);
Serial.println(" px");
Serial.print("Współrzędna Y:\t");
Serial.print(shadow.y, 1);
Serial.println(" px");
Serial.print("Promień cienia:\t");
Serial.print(shadow.radius, 1);
Serial.println(" px");
Serial.print("Oświetlenie:\t");
Serial.print(m.fraction * 100, 1);
Serial.println("%");
// Visual representation (simplified)
Serial.println("Pozycja cienia:");
Serial.print("Środek księżyca: (");
Serial.print(centerX);
Serial.print(", ");
Serial.print(centerY);
Serial.println(")");
Serial.print("Środek cienia: (");
Serial.print((int)shadow.x);
Serial.print(", ");
Serial.print((int)shadow.y);
Serial.print("), R=");
Serial.print((int)shadow.radius);
Serial.println(")");
// Simple ASCII visualization
Serial.println("Schemat (przybliżony):");
for (int i = 0; i < 12; i++) {
for (int j = 0; j < 12; j++) {
int visX = j * 20;
int visY = i * 20;
double distToCenter = sqrt(pow(visX - centerX, 2) + pow(visY - centerY, 2));
double distToShadow = sqrt(pow(visX - shadow.x, 2) + pow(visY - shadow.y, 2));
if (distToCenter > moonRadius + 10) {
Serial.print(" "); // Outside moon
} else if (distToShadow <= shadow.radius) {
Serial.print("██"); // Shadow area
} else if (distToCenter <= moonRadius) {
Serial.print("░░"); // Illuminated moon area
} else {
Serial.print(" "); // Outside
}
}
Serial.println();
}
Serial.println("======================");
}
void calculateMoonPhase() {
DateTime now = rtc.now();
time_t t = now.unixtime();
// Calculate moon phase
m.calculate(t);
// Display data
Serial.println("\n=== FAZA KSIĘŻYCA ===");
Serial.print("Dzień Juliański:\t");
Serial.println(m.jDate, 6);
Serial.print("Faza (0-1):\t\t");
Serial.println(m.phase, 4);
Serial.print("Wiek księżyca:\t\t");
Serial.print(m.age, 2);
Serial.println(" dni");
Serial.print("Oświetlenie:\t\t");
Serial.print(m.fraction * 100, 1);
Serial.println("%");
Serial.print("Odległość:\t\t");
Serial.print(m.distance, 2);
Serial.println(" promieni Ziemi");
Serial.print("Szer. ekliptyczna:\t");
Serial.print(m.latitude, 2);
Serial.println("°");
Serial.print("Dł. ekliptyczna:\t");
Serial.print(m.longitude, 2);
Serial.println("°");
Serial.print("Faza księżyca:\t\t");
Serial.println(m.phaseName);
Serial.print("Znak zodiaku:\t\t");
Serial.println(m.zodiacName);
// Additional information based on phase
Serial.print("Stan:\t\t\t");
if (m.phase < 0.03 || m.phase > 0.97) {
Serial.println("🌑 NOW");
} else if (m.phase < 0.22) {
Serial.println("🌒 Pierwsza kwadra");
} else if (m.phase < 0.28) {
Serial.println("🌓 Pełnia rosnąca");
} else if (m.phase < 0.47) {
Serial.println("🌔 Oświetlona");
} else if (m.phase < 0.53) {
Serial.println("🌕 PEŁNIA");
} else if (m.phase < 0.72) {
Serial.println("🌖 Ubywająca");
} else if (m.phase < 0.78) {
Serial.println("🌗 Ostatnia kwadra");
} else {
Serial.println("🌘 Ciemniejąca");
}
Serial.println("======================");
}
void showTimeRTC() {
DateTime now = rtc.now();
Serial.println("\n=== CZAS RTC ===");
Serial.print("Data: ");
Serial.print(now.day());
Serial.print(".");
Serial.print(now.month());
Serial.print(".");
Serial.println(now.year());
Serial.print("Czas: ");
if (now.hour() < 10)
Serial.print("0");
Serial.print(now.hour());
Serial.print(":");
if (now.minute() < 10)
Serial.print("0");
Serial.print(now.minute());
Serial.print(":");
if (now.second() < 10)
Serial.print("0");
Serial.println(now.second());
Serial.print("Temperatura RTC: ");
Serial.print(rtc.getTemperature());
Serial.println("°C");
Serial.println("=================");
}
// Function for manual time correction (can be called via Serial)
void setTimeRTC(int year, int month, int day, int hour, int minute, int second) {
DateTime dt(year, month, day, hour, minute, second);
rtc.adjust(dt);
Serial.println("Czas RTC zaktualizowany!");
}