Leon – RGB 3D Printed Lamp


Individually Designed LED Lamp Made with 3D Printing

The “Leon” lamp is a self-developed RGB LED lamp based on a Wemos D1 Mini and 11 WS2812 LEDs.
The housing was fully designed for 3D printing and is made from PETG in red, white, and black.

Control is handled via a single push button with multiple functions such as program switching and brightness control.


Images

Front view


Rear CAD view


Installed electronics

The two small covers for wall mounting are attached using a small amount of super glue.

The Wemos D1 Mini is fixed at the corners using UV epoxy resin (this has proven reliable for simple DIY projects).


Features

  • 9 programmed lighting modes
  • Static colors
  • Color transitions
  • Smooth RGB fades
  • Dynamic animations
  • 5 brightness levels
  • Saves last settings automatically
  • Controlled via a single button

Operation

ActionFunction
Short pressSwitch lighting program
Long pressAdjust brightness

The last used program number and brightness level are automatically saved and restored after power-up.geladen.


Electronics

The lamp uses:

  • Wemos D1 Mini
  • 11× WS2812 RGB LEDs
  • Push button
  • 10kΩ resistor

The button is wired as a pull-up configuration:

  • GPIO5 → 10kΩ → 3.3V
  • GPIO5 → Button → GND

The button PCB measures 25 × 25 mm.


Materials

ComponentMaterial
HousingPETG Red
DiffuserPETG White
LogoPETG Black

3D Printing Settings

My 3D prints are typically produced using the following standard settings:

  • Nozzle: 0.4 mm
  • Layer height: 0.2 mm

This setup provides a good balance between detail quality, mechanical strength, and print time, making it ideal for both technical parts and decorative prints.


Screws

QuantityTypeUse
M2 × 5 mmButton PCB
M3 × 12 mmHousing cover

Bill of Materials

QuantityType
1xWemos D1 Mini
11xWS2812 RGB LEDs
1xPush button
1x10kΩ resistor
2xM2 x 5 mm screws
4xM3 x 12 mm screws
  • 1× Wemos D1 Mini
  • 11× WS2812 RGB LEDs
  • 1× Push button
  • 1× 10kΩ resistor
  • 2× M2 × 5 mm screws
  • 4× M3 × 12 mm screws

Conclusion

The lamp works very well technically and fulfills all planned functions. Visually, the red housing looks generally consistent during operation.

However, testing showed that with a 2 mm wall thickness in red PETG, too much unwanted light shines through, reducing contrast and overall lighting quality.

For better light control, two options are reasonable:

  • Thicker wall design (simple but material-heavy)
  • Dual-color housing with a black inner layer (recommended)

Due to multi-material printing capabilities, the dual-color version is the cleanest solution and will be preferred for the next iteration.

Downloads

Show Arduino code

#include <FastLED.h>
#include <EEPROM.h>

// by DL4KER www.dl4ker.de 
#define LED_PIN     2       // GPIO2 / D4
#define BUTTON_PIN  5       // GPIO5 / D1
#define NUM_LEDS    11
#define LED_TYPE    WS2812B
#define COLOR_ORDER GRB

CRGB leds[NUM_LEDS];

// ------------------------------------------------
// Helligkeitsstufen
// ------------------------------------------------
const uint8_t brightnessLevels[5] = {40, 80, 130, 190, 255};
uint8_t brightnessIndex = 2;

// ------------------------------------------------
// Programme
// ------------------------------------------------
uint8_t currentProgram = 0;
const uint8_t totalPrograms = 9;

// ------------------------------------------------
// Taster
// ------------------------------------------------
bool lastButtonState = HIGH;
unsigned long pressStart = 0;
bool longPressHandled = false;

const unsigned long longPressTime = 700;

// ------------------------------------------------
// Timing
// ------------------------------------------------
unsigned long lastUpdate = 0;

// ------------------------------------------------
// EEPROM
// ------------------------------------------------
#define EEPROM_PROGRAM_ADDR   0
#define EEPROM_BRIGHT_ADDR    1

// ================================================================
// Einstellungen speichern
// ================================================================
void saveSettings() {
  EEPROM.write(EEPROM_PROGRAM_ADDR, currentProgram);
  EEPROM.write(EEPROM_BRIGHT_ADDR, brightnessIndex);
  EEPROM.commit();
}

// ================================================================
// Einstellungen laden
// ================================================================
void loadSettings() {

  currentProgram = EEPROM.read(EEPROM_PROGRAM_ADDR);
  brightnessIndex = EEPROM.read(EEPROM_BRIGHT_ADDR);

  if (currentProgram >= totalPrograms)
    currentProgram = 0;

  if (brightnessIndex >= 5)
    brightnessIndex = 2;
}

// ================================================================
// Setup
// ================================================================
void setup() {

  pinMode(BUTTON_PIN, INPUT_PULLUP);

  EEPROM.begin(10);

  loadSettings();

  FastLED.addLeds(leds, NUM_LEDS);

  FastLED.setBrightness(brightnessLevels[brightnessIndex]);

  FastLED.clear();
  FastLED.show();

  randomSeed(analogRead(A0));
}

// ================================================================
// Hauptloop
// ================================================================
void loop() {

  handleButton();

  runProgram();
}

// ================================================================
// Taster auswerten
// ================================================================
void handleButton() {

  bool buttonState = digitalRead(BUTTON_PIN);

  // Taste gedrückt
  if (lastButtonState == HIGH && buttonState == LOW) {
    pressStart = millis();
    longPressHandled = false;
  }

  // Lange gedrückt
  if (buttonState == LOW &&
      !longPressHandled &&
      millis() - pressStart > longPressTime) {

    longPressHandled = true;

    brightnessIndex++;

    if (brightnessIndex >= 5)
      brightnessIndex = 0;

    FastLED.setBrightness(brightnessLevels[brightnessIndex]);

    saveSettings();
  }

  // Taste losgelassen
  if (lastButtonState == LOW && buttonState == HIGH) {

    // kurzer Druck
    if (!longPressHandled) {

      currentProgram++;

      if (currentProgram >= totalPrograms)
        currentProgram = 0;

      saveSettings();
    }
  }

  lastButtonState = buttonState;
}

// ================================================================
// Programme
// ================================================================
void runProgram() {

  switch (currentProgram) {

    // ------------------------------------------------
    // Programm 1 - Blau
    // ------------------------------------------------
    case 0:
      fill_solid(leds, NUM_LEDS, CRGB::Blue);
      FastLED.show();
      delay(20);
      break;

    // ------------------------------------------------
    // Programm 2 - Zufällige Farben
    // ------------------------------------------------
    case 1:

      if (millis() - lastUpdate > 1500) {

        lastUpdate = millis();

        for (int i = 0; i < NUM_LEDS; i++) {
          leds[i] = CHSV(random8(), 255, 255);
        }

        FastLED.show();
      }

      break;

    // ------------------------------------------------
    // Programm 3 - Regenbogen
    // ------------------------------------------------
    case 2: {

      static uint8_t hue = 0;

      fill_rainbow(leds, NUM_LEDS, hue, 10);

      FastLED.show();

      hue++;

      delay(30);

      break;
    }

    // ------------------------------------------------
    // Programm 4 - Weicher Farbwechsel
    // ------------------------------------------------
    case 3: {

      static uint8_t fadeHue = 0;

      fill_solid(leds, NUM_LEDS, CHSV(fadeHue, 255, 255));

      FastLED.show();

      fadeHue++;

      delay(40);

      break;
    }

    // ------------------------------------------------
    // Programm 5 - Grün
    // ------------------------------------------------
    case 4:
      fill_solid(leds, NUM_LEDS, CRGB::Green);
      FastLED.show();
      delay(20);
      break;

    // ------------------------------------------------
    // Programm 6 - Orange
    // ------------------------------------------------
    case 5:
      fill_solid(leds, NUM_LEDS, CRGB::Orange);
      FastLED.show();
      delay(20);
      break;

    // ------------------------------------------------
    // Programm 7 - Rot
    // ------------------------------------------------
    case 6:
      fill_solid(leds, NUM_LEDS, CRGB::Red);
      FastLED.show();
      delay(20);
      break;

    // ------------------------------------------------
    // Programm 8 - Lila
    // ------------------------------------------------
    case 7:
      fill_solid(leds, NUM_LEDS, CRGB::Purple);
      FastLED.show();
      delay(20);
      break;

    // ------------------------------------------------
    // Programm 9 - Gelb
    // ------------------------------------------------
    case 8:
      fill_solid(leds, NUM_LEDS, CRGB::Yellow);
      FastLED.show();
      delay(20);
      break;
  }
}