ESP32 Moon Phase Calculator: Build Your Own Lunar Tracker with OLED Display

ESP32 Moon Phase Calculator Build Your Own Lunar Tracker with OLED Display ESP32 Moon Phase Calculator Build Your Own Lunar Tracker with OLED Display

Since childhood, at night we always looked up at the night sky and seen a Moon, and it’s changing face has amazed us sometimes its full and sometime it half. That celestial rhythm is determined with moon phases and guided humanity for centuries. Now, with a little modern magic from an ESP32 microcontroller, you can bring that wonder right to your desk. This guide will show you how to build your own personal moon phase tracker, complete with a bright OLED display that shows the Moon’s current phase in real-time. It’s the perfect hands-on project for any stargazer, tech tinkerer, or anyone who’s ever felt a pull to the cosmos.


Understanding Moon Phases: The Science Behind the Project

The Lunar Cycle Explained

The Moon completes one orbit around Earth approximately every 29.53 days, known as a synodic month. During this cycle, we observe different portions of the Moon’s illuminated surface, creating the familiar phases:

  • New Moon (0% illumination): The Moon is between Earth and Sun
  • Waxing Crescent (1-49% illumination): Increasing visibility after New Moon
  • First Quarter (50% illumination): Half the Moon is visible
  • Waxing Gibbous (51-99% illumination): Growing toward Full Moon
  • Full Moon (100% illumination): Earth is between Moon and Sun
  • Waning Gibbous (99-51% illumination): Decreasing after Full Moon
  • Last Quarter (50% illumination): The other half becomes visible
  • Waning Crescent (49-1% illumination): Diminishing toward New Moon

Astronomical Calculations

Our ESP32 moon phase calculator uses precise astronomical formulas to determine the current lunar phase. The core calculation involves:

  1. Julian Date Calculation: Converting Gregorian calendar dates to Julian dates for astronomical computations
  2. Lunar Cycle Position: Calculating days since the last known New Moon (January 6, 2000)
  3. Phase Determination: Using the synodic month (29.530588 days) to determine current phase

Project Features:

  • Real-time moon phase calculation based on current date
  • Visual moon representation with accurate shading
  • 8 moon phases: New Moon, Waxing Crescent, First Quarter, Waxing Gibbous, Full Moon, Waning Gibbous, Last Quarter, Waning Crescent
  • Displays:
    • Current date and time
    • Moon phase name
    • Illumination percentage
    • Moon age (days into cycle)
    • Graphical moon with proper shadow

Project Components and Hardware Setup

Required Components

  • ESP32 Development Board: Powerful microcontroller with WiFi capability
  • OLED Display (128×64): I2C interface, SSD1306 driver
  • Breadboard and Jumper Wires: For prototyping
  • Micro-USB Cable: For power and programming

Circuit Diagram

OLED display with ESP32 wiring connection diagram

The connections are very simple just connect the I2c OLED display with SDA and SCL and power connections as shown in the above circuit diagram.

OLED Display → ESP32
SDA → GPIO 21
SCL → GPIO 22
VCC → 3.3V
GND → GND

Important Notes:

  • Always use the 3.3V power source for the OLED display
  • Ensure proper grounding between all components
  • Use appropriate pull-up resistors if experiencing I2C communication issues

Illuminate the Night: Build Your ESP32 Moon Phase Calculator with PCBWay

Ever dreamed of tracking lunar cycles from your workspace? Our ESP32 Moon Phase Calculator project combines a powerful microcontroller with a crisp OLED display to show real-time moon phases—a beautiful fusion of astronomy and DIY electronics. But a brilliant prototype deserves a professional foundation, and that’s where PCBWay transforms your vision into reality.

PCBWay offers comprehensive manufacturing services that elevate your project from breadboard to polished gadget. Their PCB fabrication delivers high-quality custom boards, whether you need standard FR4, flexible circuits, or complex rigid-flex designs. For flawless assembly, their SMT and through-hole PCB assembly services handle everything from fine-pitch components to BGA packages, with component sourcing available.

Beyond circuits, PCBWay’s 3D printing (FDM, SLA, SLS, MJF) creates stunning enclosures and custom parts, while CNC machining (3-, 4-, and 5-axis) precision-crafts metal or plastic components. Need robust housings? Their sheet metal fabrication and injection molding services deliver production-grade parts.

PCBWay also provides essential tools like laser-cut SMT stencils and online design tools (Gerber viewer, impedance calculators) to streamline your workflow. With strict quality control and global shipping, they’re the one-stop partner for innovators.

Ready to build your lunar tracker? Trust PCBWay to bring your brightest ideas to life—from PCBs to full product realization only at PCBWAY.COM


Setup and Program Code

After connecting all the required components, we have to upload the program code to ESP32 microcontroller to make it work as ESP32 Moon Phase Calculator using Arduino IDE.

Install Required Libraries (via Arduino IDE Library Manager):

  • Adafruit SSD1306
  • Adafruit GFX Library

After installing the OLED display libraries copy the below code and upload it to ESP32.

Configure the Code:

  • Change YOUR_WIFI_SSID to your WiFi name
  • Change YOUR_WIFI_PASSWORD to your WiFi password
  • Adjust gmtOffset_sec for your timezone (currently set for India GMT+5:30)
/*
 * ESP32 Moon Phase Calculator with OLED Display-CircuitSchools
 * 
 * Hardware Required:
 * - ESP32 Development Board
 * - SSD1306 OLED Display (128x64, I2C)
 * 
 * Wiring (I2C):
 * - OLED SDA -> GPIO 21
 * - OLED SCL -> GPIO 22
 * - OLED VCC -> 3.3V
 * - OLED GND -> GND
 * 
 * Libraries Required:
 * - Adafruit SSD1306
 * - Adafruit GFX Library
 * - WiFi (built-in)
 * - time.h (built-in)
 */

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <WiFi.h>
#include <time.h>

// OLED Display Settings
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
#define SCREEN_ADDRESS 0x3C

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

// WiFi Credentials - CHANGE THESE!
const char* ssid = "YOUR_WIFI_SSID";
const char* password = "YOUR_WIFI_PASSWORD";

// NTP Server Settings
const char* ntpServer = "pool.ntp.org";
const long gmtOffset_sec = 19800;  // GMT+5:30 for India (change as needed)
const int daylightOffset_sec = 0;

// Moon phase names
const char* moonPhaseNames[] = {
  "New Moon",
  "Waxing Crescent",
  "First Quarter",
  "Waxing Gibbous",
  "Full Moon",
  "Waning Gibbous",
  "Last Quarter",
  "Waning Crescent"
};

void setup() {
  Serial.begin(115200);
  
  // Initialize OLED
  if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
    Serial.println(F("SSD1306 allocation failed"));
    for(;;);
  }
  
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(0, 0);
  display.println(F("Moon Phase Calc"));
  display.println(F("Connecting WiFi..."));
  display.display();
  
  // Connect to 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("\nWiFi connected");
    display.clearDisplay();
    display.setCursor(0, 0);
    display.println(F("WiFi Connected!"));
    display.display();
    delay(1000);
    
    // Initialize time
    configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
    delay(2000);
  } else {
    Serial.println("\nWiFi connection failed");
    display.clearDisplay();
    display.setCursor(0, 0);
    display.println(F("WiFi Failed!"));
    display.println(F("Check credentials"));
    display.display();
    delay(3000);
  }
}

void loop() {
  struct tm timeinfo;
  if(!getLocalTime(&timeinfo)){
    display.clearDisplay();
    display.setCursor(0, 0);
    display.println(F("Failed to get time"));
    display.display();
    delay(5000);
    return;
  }
  
  // Calculate moon phase
  float phase = calculateMoonPhase(timeinfo.tm_year + 1900, 
                                   timeinfo.tm_mon + 1, 
                                   timeinfo.tm_mday);
  
  int phaseIndex = (int)((phase / 29.53) * 8) % 8;
  
  // Display moon phase
  displayMoonPhase(phase, phaseIndex, timeinfo);
  
  delay(60000); // Update every minute
}

float calculateMoonPhase(int year, int month, int day) {
  // Julian date calculation
  if (month < 3) {
    year--;
    month += 12;
  }
  
  int a = year / 100;
  int b = a / 4;
  int c = 2 - a + b;
  float e = floor(365.25 * (year + 4716));
  float f = floor(30.6001 * (month + 1));
  float jd = c + day + e + f - 1524.5;
  
  // Days since known new moon (Jan 6, 2000)
  float daysSinceNew = jd - 2451549.5;
  
  // Number of new moons since Jan 6, 2000
  float newMoons = daysSinceNew / 29.53;
  
  // Current phase (0-29.53 days)
  float phase = (newMoons - (int)newMoons) * 29.53;
  
  return phase;
}

void displayMoonPhase(float phase, int phaseIndex, struct tm timeinfo) {
  display.clearDisplay();
  
  // Display date and time
  display.setTextSize(1);
  display.setCursor(0, 0);
  char dateStr[20];
  sprintf(dateStr, "%02d/%02d/%04d", timeinfo.tm_mday, 
          timeinfo.tm_mon + 1, timeinfo.tm_year + 1900);
  display.println(dateStr);
  
  char timeStr[10];
  sprintf(timeStr, "%02d:%02d:%02d", timeinfo.tm_hour, 
          timeinfo.tm_min, timeinfo.tm_sec);
  display.println(timeStr);
  
  // Draw moon
  int centerX = 32;
  int centerY = 42;
  int radius = 15;
  
  // Draw moon circle
  display.fillCircle(centerX, centerY, radius, SSD1306_WHITE);
  
  // Calculate illumination percentage
  float illumination = (1 - cos((phase / 29.53) * 2 * PI)) / 2;
  
  // Draw shadow for moon phase
  if (phase < 14.765) {
    // Waxing - shadow on left
    int shadowWidth = (int)(radius * 2 * (1 - illumination));
    for (int i = -radius; i <= radius; i++) {
      int h = sqrt(radius * radius - i * i);
      for (int j = -h; j < -h + shadowWidth; j++) {
        display.drawPixel(centerX + j, centerY + i, SSD1306_BLACK);
      }
    }
  } else {
    // Waning - shadow on right
    int shadowWidth = (int)(radius * 2 * illumination);
    for (int i = -radius; i <= radius; i++) {
      int h = sqrt(radius * radius - i * i);
      for (int j = h - shadowWidth; j <= h; j++) {
        display.drawPixel(centerX + j, centerY + i, SSD1306_BLACK);
      }
    }
  }
  
  // Display phase name
  display.setCursor(64, 25);
  display.setTextSize(1);
  display.println(moonPhaseNames[phaseIndex]);
  
  // Display illumination percentage
  display.setCursor(64, 38);
  char illumStr[15];
  sprintf(illumStr, "%.1f%% lit", illumination * 100);
  display.println(illumStr);
  
  // Display age
  display.setCursor(64, 50);
  char ageStr[15];
  sprintf(ageStr, "Day %.1f", phase);
  display.println(ageStr);
  
  display.display();
}

How the Code Works – Step by Step

1. Setup Phase

  • Connects to WiFi (so it can get accurate time)
  • Syncs with internet time servers (NTP)
  • Initializes the OLED display

2. The Main Loop

Every minute, the program:

  • Gets the current date and time
  • Calculates the moon’s phase using a mathematical formula
  • Updates the display with new information

3. Moon Phase Calculation

The calculateMoonPhase() function uses Julian Date mathematics to determine where the moon is in its 29.53-day cycle. It calculates how many days have passed since a known new moon (January 6, 2000) and figures out the current position in the lunar month.

4. Visual Display

The displayMoonPhase() function creates a visual representation by:

  • Drawing a white circle for the moon
  • Adding black “shadow” pixels to show the illuminated portion
  • Displaying the phase name (like “Waxing Crescent”)
  • Showing illumination percentage and moon “age” in days

Key Variables

  • phase: Current day in the 29.53-day lunar cycle (0 = New Moon, 14.765 = Full Moon)
  • phaseIndex: Number from 0-7 that picks the correct phase name
  • illumination: Percentage of the moon that’s lit (0% to 100%)

What You’ll See on Screen

  • Current date and time
  • Animated moon graphic showing light/shadow
  • Phase name (e.g., “First Quarter”)
  • Illumination percentage
  • Days since last new moon

Practical Applications

This moon phase calculator has numerous real-world applications:

  1. Astrophotography: Plan photography sessions around moon phases
  2. Gardening: Follow lunar gardening practices
  3. Fishing: Track optimal fishing times based on moon phases
  4. Astronomy Education: Teach lunar cycles in classrooms
  5. Cultural Events: Track holidays based on lunar calendars

Conclusion

Building an ESP32 Moon Phase Calculator is an excellent project that combines astronomy, programming, and electronics. This device provides accurate lunar information with a visually appealing display, making it both educational and practical. The project demonstrates the power of the ESP32 platform for creating Internet-connected devices that interact with real-world phenomena.

By following this guide, you’ve created a functional moon tracker that can be expanded with additional features like weather integration, voice alerts, or remote monitoring through a web interface. The possibilities for enhancement are limited only by your imagination!

Please remember to share your project variations and improvements in the below comments, and happy moon watching!

Add a Comment

Leave a Reply

Your email address will not be published. Required fields are marked *