Skip to content
All Posts

April 13, 2026

The Moon Wall Lamp: An ESPHome Project Built on Real Astronomy

ESPHomeESP8266WS2812BEmbedded Systems
The Moon Wall Lamp: An ESPHome Project Built on Real Astronomy

My Moon Wall Lamp isn’t your average "night light" — it’s an ESPHome project that simulates the moon’s real phase and its actual tilt in the sky, down to the minute. In this post I’m sharing the hardware, the software architecture, and the math behind it — leaving out personal/security details like WiFi credentials, the API key, and my exact location.

Hardware

  • Wemos D1 Mini V4 (ESP8266) — the brain of the system.
  • 220× WS2812B (NeoPixel) LEDs, arranged in a ring behind the 3D-printed lunar-relief surface.
  • The LED data line runs to the pin ESP8266 normally reserves for serial communication (RX / GPIO3) — made possible by ESPHome’s "esp8266_dma" driver, which uses DMA (Direct Memory Access) to drive 220 LEDs smoothly and without flicker.

Power Wiring and Common Ground

  • The adapter’s +5V output feeds both the LED strip’s VCC and the Wemos’s 5V (Vin) pin — so the lamp runs without needing a USB cable at all. When sizing the adapter, the Wemos’s own ~80mA draw should be factored in too.
  • The Wemos’s 5V pin is used purely as an input (from the adapter to the Wemos); trying to power the LED strip through the Wemos instead will damage the board and the strip won’t run properly.
  • The adapter’s negative (GND) lead has to connect to both the LED strip and the Wemos’s GND pin — otherwise the signal reference is lost and the LEDs light up in random colors.

Software Architecture

The firmware is written entirely in ESPHome (YAML-based). The device integrates with Home Assistant over an encrypted API connection, supports OTA (over-the-air) updates, and falls back to its own access point with a captive portal if it can’t reach the home WiFi — a design that can recover even if it moves house or the network changes.

Automatic Sunrise/Sunset Behavior

ESPHome’s "sun" component calculates the sun’s elevation in real time based on location. Once the sun drops 10° below the horizon, the lamp starts turning on; at -12° in the morning it starts turning off, completing the shutdown at -0.833° — the official sunrise/sunset threshold. Neither transition is abrupt: a 60-step fade script spreads the brightness change over roughly an hour for a smooth effect.

Real Moon-Phase Calculation

The moon phase is computed with simple but accurate modular arithmetic, using a known new-moon reference timestamp and the average synodic month length (29.53058867 days). The result feeds both a percentage sensor and a text sensor that reports one of 8 traditional phase names — New Moon, Waxing Crescent, First Quarter, Waxing Gibbous, Full Moon, Waning Gibbous, Last Quarter, Waning Crescent.

  • 0–3% → New Moon: no light at all, LEDs off.
  • 3–22% → Waxing Crescent: a thin sliver on the right, ~5-50 LEDs lit.
  • 22–28% → First Quarter: right half-circle, ~113 LEDs lit.
  • 28–47% → Waxing Gibbous: right + center, ~150-220 LEDs lit.
  • 47–53% → Full Moon: all 220 LEDs lit.
  • 53–72% → Waning Gibbous: left + center, ~150-220 LEDs lit.
  • 72–78% → Last Quarter: left half-circle, ~113 LEDs lit.
  • 78–97% → Waning Crescent: a thin sliver on the left, ~5-50 LEDs lit.
  • 97–100% → New Moon: no light at all, LEDs off.

Parallactic Tilt: the Hard Part

What makes this lamp unusual is that the LED ring doesn’t just reflect the moon’s phase — it reflects its actual tilt in the sky. The firmware calculates the sun’s ecliptic longitude, the moon’s approximate position, both bodies’ right ascension/declination, the local sidereal time, and the hour angle, to arrive at the "parallactic angle" — the angle that determines whether a crescent looks like a "smile" or stands upright. That angle is applied to each of the 220 LEDs’ positions, drawing a smoothly blended day/night boundary (terminator).

The tilt angle at the same moon phase (First Quarter, 25%) changes with season and time of night — theory vs. a winter evening vs. a summer night.
The tilt angle at the same moon phase (First Quarter, 25%) changes with season and time of night — theory vs. a winter evening vs. a summer night.
The electronics and LED ring during assembly, on the workbench.
The electronics and LED ring during assembly, on the workbench.

LED Strip Direction and Alignment

  • LED 0 sits at the very top of the ring (12 o’clock) — every calculation is anchored to that reference point.
  • The strip is laid out clockwise (12 → 3 → 6 → 9 → 12), with the data input (DIN) starting from that same reference point.
  • A WS2812B strip can only be cut at its marked points (every 3 LEDs) — the cut point has to be planned around the ring’s diameter accordingly.
  • If the strip doesn’t physically start exactly at 12 o’clock, the software alignment (offset) setting described in "Customization" below compensates for it.

Customization

From Home Assistant, I can adjust overall brightness, the bright-side and dark-side (earthshine) colors (RGB), the intensity ratio between the two, and an "alignment" offset that compensates in software for however the LED ring physically ended up mounted — so even if the strip doesn’t start exactly where you want, you can rotate it into place from software.

Bonus Effects

Alongside the realistic simulation, I added a few extra LED effects just for fun: fixed Half Moon and Crescent looks, a plain Night Light mode, a twinkling Starry Night, a flickering orange Solar Eclipse, a green-blue undulating Aurora, a solid-red Blood Moon, an ISS Flyby simulated by a dot sliding around the ring, and — as a personal touch — a red-and-yellow flashing "goal celebration" effect.

The Moon Wall Lamp in a room setting — lit according to the real current moon phase.
The Moon Wall Lamp in a room setting — lit according to the real current moon phase.

Conclusion

This project showed me that real astronomical calculations can run live on a microcontroller — no cloud, no external API, entirely on the device itself. Up next is the automatic plant-watering system I built with the same philosophy; I’ll share that in a separate post soon.