Owen Hollingsworth

All projects

ThermoLamp

A weather forecast you can read from across the room. ThermoLamp is a desk lamp built like an old mercury thermometer: its LED column rises and changes color with the outside temperature, and a round touchscreen in the bulb fills in the details.

Status
Working prototype
Size
444 mm (17.5 in) tall, with a 124 mm (4.9 in) globe
Controller
Waveshare ESP32-S3-Touch-LCD-2.8C, a 480×480 round touchscreen
Light
18 WS2812B LEDs in two offset columns
Data
Open-Meteo weather and air quality over Wi-Fi, NTP time
Firmware
Arduino (ESP32 core 3.x), LVGL 8.3, ArduinoJson
Enclosure
8 printed parts of my own design, no soldering
Parts cost
About $93, plus filament
Skills
Embedded C++ (ESP32), LVGL touch UI, REST APIs and JSON, Wi-Fi reliability, AI-assisted development, CAD and 3D printing, technical documentation

The goal

I wanted to check the weather at a glance without adding another boring rectangular screen to my desk. Going from a boring rectangle to a boring circle wasn't much better, and LEDs on their own only give a rough idea of the temperature.

So I combined the two in a retro design that looks like an old mercury glass thermometer. The glowing column gives you the reading from across the room, and the screen fills in the details up close.

How it works

The mercury column

Eighteen LEDs sit in two columns of nine, with the second column shifted half a step higher, so together they make 18 evenly spaced levels. They face backward into a white reflector, so the stem glows softly around an engraved scale. Each level is 5 °F: 20 °F lights two levels, 60 °F lights ten, and 100 °F lights all 18.

The color follows the temperature on a smooth gradient borrowed from Apple Weather's forecast bars, from deep blue below 0 °F to red-orange above 100 °F. The weather adds effects on top:

  • Rain, drizzle or snow: one lit LED in eight turns white, and those white "drops" fall down the column.
  • Thunderstorm: the whole lit column turns white.
  • Extreme heat or cold (above 100 °F or below 20 °F): the column slowly breathes.
Four renders of the lamp side by side: 31 degrees with four icy blue levels lit, 72 degrees with twelve yellow levels, 104 degrees with the full column red, and 52 degrees in teal with white raindrops.
Renders of the four main looks: cold, mild, hot and rain.

The screen

The touch UI shows the city, local time, temperature, humidity, air quality and a 3-day forecast, ringed by an arc in the same colors as the LEDs. You can swipe between up to eight cities or let them rotate, tap the forecast for the next 24 hours, and run a timer or Pomodoro, during which the LED column drains as time runs out. Night mode dims or darkens everything between sunset and sunrise. Everything is set up on the screen itself: no app and no account.

Four round screens: Chicago at 72 degrees with humidity, air quality and a 3-day forecast; a 24-hour temperature line over rain-chance bars; a Pomodoro countdown at 18:41; and a Settings page with toggles and a brightness slider.
Four of the screens, rendered from the real firmware: a city page, the 24-hour forecast, the Pomodoro timer and Settings.

Under the hood

Weather and air quality come from the Open-Meteo API over Wi-Fi every 10 minutes, and the clock syncs over NTP. There's no local sensor. The firmware is Arduino on the ESP32 core 3.x, with LVGL 8.3 for the UI and ArduinoJson for the API responses. The LEDs are driven straight from the ESP32's RMT peripheral rather than through a NeoPixel library, and the firmware caps them at about 500 mA, so one USB-C cable powers the whole lamp with room to spare.

I built the firmware, and the code behind the CAD model and renders, with Claude as a coding partner.

Key decisions

  • CAD as code. Every dimension lives in one parametric model, so changing something like the screen tilt or the screw type regenerates every part to match. Both the heat-set and self-tapping versions come out of the same model.
  • Two offset strips for twice the resolution. A standard 30-LED/m strip spaces its LEDs 33.3 mm apart, which is too coarse for a thermometer. Two strips offset by half a step give 18 levels just 16.7 mm apart.
  • No soldering. A factory lead, a press-on clip and lever connectors join the LED strips to the board. The parts also come in two versions: one with heat-set inserts, and one with self-tapping screws for builders without a soldering iron.
  • Open-Meteo for the weather. It needs no API key, so the lamp works out of the box without anyone signing up for anything.
  • Plain HTTP first, HTTPS as a fallback. Each HTTPS request takes about 40 KB of the ESP32's scarce internal RAM, so the lamp asks for weather over HTTP first and switches to HTTPS only if HTTP is blocked.
  • A heavy base. At 444 mm, the lamp is top-heavy, so a sealed compartment in the globe holds about 200 g of steel BBs to keep it upright.
Exploded view of the lamp: top cap and cap plug, stem reflector, engraved LED spine, front shell holding the round touchscreen and TPU gasket, rear shell with the ballast compartment and USB-C port, and a snap-on ballast lid.
Exploded view of the eight printed parts.

Problems and fixes

  • The screen glitched whenever Wi-Fi was busy. Thin horizontal lines and flicker showed up during every weather update. The fix was the Arduino-ESP32 3.0.2 core with its XIP libraries and the PSRAM set to OPI mode. I also learned that giving the display's bounce buffer more than 30 lines starved Wi-Fi of RAM and knocked the lamp offline.
  • Weather updates quietly stopped. The ESP32 was running out of internal RAM. I gave LVGL its own reserved block of memory and moved requests to HTTP first. Then I made the lamp heal itself: it rejoins Wi-Fi after 3 minutes of failed updates, restarts if that doesn't work, and a watchdog restarts it if the network task stalls. Settings shows when the last update happened and why the last try failed.
  • The screen's glass bound in its pocket. Printed base-down, the round screen pocket sagged at the top. Printing the front shell screen-face-down, with supports, keeps the pocket perfectly round.

Where it is now

The prototype is built and running, and the full build guide is written: parts list, printing, wiring, flashing and troubleshooting. I'm releasing the design for free soon, with paid tiers for commercial use.

What's next

  • A web flasher. Builders will be able to install the firmware straight from a browser, with no Arduino IDE or PlatformIO setup.
  • A wall mount. For anyone who'd rather hang their thermometer than give it desk space.
  • ThermoLamp Mini. A smaller version is in active development. Its screen (non-touch) and a single LED already work, but it still takes a lot of soldering and fiddling with parts, so there's work to do before anyone else can build one.