Device Output.
A standalone desk globe that shows Earth from space in real time—live day/night, NASA clouds, and city lights—on a 1.75" round AMOLED.
The Weather Globe is a standalone, internet-connected desk display built on an ESP32-S3 microcontroller. Utilizing a 1.75" round AMOLED screen, the device acts as a live window onto Earth and the solar system. Its primary feature is a real-time, sun-synchronous rendering of Earth, complete with accurate day/night shadow lines, live cloud cover pulled from NASA VIIRS satellites and refreshed in the background, and illuminated city lights on the night side.
Operating entirely on the device without the need for companion mobile apps or cloud accounts, it features a built-in captive portal for WiFi configuration and a web-based settings dashboard.
Calculates the real-time position of the sun to accurately drape a soft twilight terminator (day/night line) across the globe.
Automatically fetches and maps live cloud cover from NASA's VIIRS satellites, layering it over the base map.
Renders NASA "Black Marble" city lights exclusively on the shadowed hemisphere of the Earth.
Allows users to switch the view to any of 10 celestial bodies: Earth, Mercury, Venus, Mars, Jupiter, Saturn, Uranus, Neptune, the Moon, and the Sun.
On a user-defined schedule, the globe smoothly transitions to a full-screen, data-rich card displaying local time, date, temperature, "feels like" temperature, humidity, and wind speed.
Hosts a local web server (accessible via the device's IP) to adjust motion speed (true 24-hour rotation vs. smooth time-lapse), brightness, camera tilt, screen rotation, and weather card cadence.
Most "Earth globe" gadgets use static textures spinning on a timer. This project calculates the true subsolar point (NOAA solar position) for the current UTC, downloads NASA VIIRS daily cloud mosaics, and additively blends NASA Black Marble city lights on the night side.
A precomputed lookup table maps every pixel on the round display to a geographic normal. The rendering thread shades day to night using a smootherstep terminator with 8×8 Bayer dithering to prevent RGB565 color banding.
A dedicated RTOS task fetches a NASA VIIRS true-color snapshot from the EarthData WVS snapshot API, decodes the JPEG in memory into a 1024×512 buffer, feathers the dateline seam, and publishes the new texture atomically via pointer-swap. It re-fetches roughly every 3 hours once online (and retries within ~10 minutes after a failed download).
Because AMOLED screens can't easily be screenshotted, the firmware rendering engine has a Python replica on the desktop. Visual changes are previewed against the replica before being flashed.
The fiddliest piece. A freshly-built daily mosaic has missing satellite swaths, so the firmware judges completeness by counting no-data pixels only in the mid-latitude band (≈±45°) — polar night is legitimately black and must not count as a gap. If that band exceeds ~5% missing the day is rejected and the task steps back day-by-day (up to 7 days) to the most recent fully-assembled mosaic. Any remaining no-data pixels are filled from a Blue Marble base image, so the globe never shows a black void — or an invented cloud — as it spins.
Honest figures, read straight from the repository — a small, single-purpose firmware plus the host tooling that feeds it.
The entire device program in one file, firmware/src/main.cpp (C++ / Arduino), backed by ~3,500 lines of Python host tooling in backend/.
12 LittleFS binaries — eleven 1 MB RGB565 body textures plus a packed font/icon atlas — in a ~14 MB filesystem partition on the 16 MB flash.
Earth plus the eight other planets, the Moon and the Sun, all sun-shaded; targeting the LilyGo T-Display-S3 AMOLED (ESP32-S3, 8 MB PSRAM) via PlatformIO.
The real story of embedded systems lies in the hardware edge cases. Here are three critical bugs resolved during field-testing:
Text rendered perfectly on the host replica but garbled randomly on the physical panel. Root cause: the CO5300 display driver passes raw x/y/w/h coordinates without rounding. Any partial SPI write with an odd dimension shifts and corrupts the hardware buffer. The fix involved strict even-padding on every text blit.
During time-lapse animations, the globe would hold still for 30 frames then awkwardly lurch forward. The underlying NTP clock was bound to time(nullptr), which is whole-second granular. The fix derived a sub-second fractional offset using millis(), re-anchoring on every RTC tick to prevent wrapping, so the spin advances smoothly between whole-second clock ticks. (The render loop is unbounded — it yields once per frame and simply runs as fast as the panel allows; frame rate is measured in the serial heartbeat, not capped at a target.)
When the globe was moved to a new house, the captive portal refused to load on 192.168.4.1. The ESP32's SoftAP channel strictly follows the Station radio. The radio kept hunting for the old home network saved deep in the driver, dragging the hotspot off-channel. The fix: explicitly wipe the persistent driver credentials and serve the portal in pure WIFI_AP mode.