Batman – Lampe

Die „Batman“ Lampe ist eine selbst entwickelte RGB-LED-Lampe auf Basis eines Wemos D1 Mini und 37x WS2812 LEDs.
Das Gehäuse wurde vollständig für den 3D-Druck konstruiert und besteht aus PETG in Schwarz und Weiß.

Die Steuerung erfolgt über einen einzelnen Drucktaster mit mehreren Funktionen wie Programmwechsel und Helligkeitssteuerung.

Bilder

Front


Front (ausgeschaltet)

Die Vorderseite der Batman-Lampe wurde mit einer nur 0,2 mm starken schwarzen Schicht gedruckt, wodurch das markante Batman-Logo auch im ausgeschalteten Zustand klar sichtbar ist. Dahinter sorgen zwei weiße Schichten für zusätzliche Stabilität und dienen gleichzeitig als Lichtdiffusor. Zwar wird das Licht durch die schwarze Front leicht gedämpft, doch genau dieser Aufbau erzeugt im eingeschalteten Zustand den beeindruckenden Leuchteffekt, der auf dem Bild darüber zu sehen ist.


Maßgeschneiderte LED-Einheit

Die LEDs wurden auf einer Trägerplatte in Form des Batman-Logos positioniert, aufgeklebt und anschließend sorgfältig miteinander verlötet. (Aufmerksame Betrachter entdecken an einer Stelle unterschiedliche Kabelfarben – dort musste ich improvisieren, weil das passende Material ausgegangen war.)

Die komplette LED-Einheit wird von hinten in das Frontgehäuse eingesetzt und verschraubt. Dadurch befindet sich keine Elektronik vor den LEDs, was für eine gleichmäßige Ausleuchtung des Logos sorgt. Im hinteren Gehäusedeckel sind anschließend der Taster sowie der Wemos-Controller untergebracht.


Funktionen

  • verschiedene programmierte Lichtmodi
  • Statische Farben
  • Farbwechsel
  • Sanfte RGB-Übergänge
  • Dynamische Animationen
  • 5 Dimmstufen
  • Speicherung der letzten Einstellungen
  • Steuerung über einen einzelnen Taster

Bedienung

AktionFunktion
Kurz drückenLichtprogramm wechseln
Lange drückenHelligkeit dimmen

Die zuletzt verwendete Programmnummer sowie die eingestellte Helligkeit werden automatisch gespeichert und nach dem Einschalten wieder geladen.


Elektronik

Die Lampe verwendet:

  • Wemos D1 Mini
  • 37x WS2812 RGB LEDs
  • Drucktaster (Der Drucktaster ist auf einer 20 × 20 mm großen Lochrasterplatine verlötet.)
  • 10kΩ Widerstand

Der Drucktaster ist als Pullup-Schaltung aufgebaut:

  • GPIO5 → 10kΩ → 3,3V
  • GPIO5 → Taster → GND

Schrauben

MengeTypVerwendung
2xM2 x 5mmTasterplatine
8xM3 x 8mmGehäusedeckel / LED Halter

Fazit

Mit dem Endergebnis bin ich mehr als zufrieden. Die Lampe wirkt schlicht und elegant, und gerade der Kontrast zwischen dem komplett schwarzen Batman-Logo im ausgeschalteten Zustand und dem eindrucksvollen Leuchteffekt nach dem Einschalten macht für mich den besonderen Reiz aus.

Auch im Inneren überzeugt das Design: Die gesamte Elektronik findet sauber und platzsparend ihren Platz, sodass alles ordentlich verstaut ist und die Ausleuchtung nicht beeinträchtigt wird.

Ich hoffe, euch gefällt die Batman-Lampe genauso gut wie mir und wünsche euch viel Spaß beim Nachbauen!

Arduino Quellcode anzeigen

// Beispiel Arduino Code

#include 
#include 
// by DL4KER www.dl4ker.de
// ================= EINSTELLUNGEN =================
#define LED_PIN       2
#define BUTTON_PIN    5
#define NUM_LEDS      37
#define NUM_PROGRAMS  8
#define NUM_DIM_LEVELS 5

#define LED_TYPE      WS2812B
#define COLOR_ORDER   GRB

CRGB leds[NUM_LEDS];

// 5 Dimmstufen: 20%, 40%, 60%, 80%, 100%
const uint8_t dimLevel[NUM_DIM_LEVELS] = {
  51, 102, 153, 204, 255
};

// ================= SPEICHER =================
uint8_t program;
uint8_t dim;

#define EE_PROGRAM 0
#define EE_DIM     1

// ================= TASTER =================
bool buttonState = HIGH;
bool lastButtonState = HIGH;
bool longDone = false;

unsigned long buttonTime = 0;
unsigned long debounceTime = 0;

#define DEBOUNCE 40
#define LONG_PRESS 700

// ================= ANIMATION =================
unsigned long animTime = 0;

// =================================================
// SETUP
// =================================================
void setup() {

  pinMode(BUTTON_PIN, INPUT_PULLUP);

  EEPROM.begin(8);

  program = EEPROM.read(EE_PROGRAM);
  dim     = EEPROM.read(EE_DIM);

  if (program >= NUM_PROGRAMS) program = 0;
  if (dim >= NUM_DIM_LEVELS) dim = NUM_DIM_LEVELS - 1;

  FastLED.addLeds(
    leds, NUM_LEDS
  );

  FastLED.setBrightness(dimLevel[dim]);
  FastLED.clear();
  FastLED.show();

  randomSeed(analogRead(A0));

  animTime = millis();
}

// =================================================
// LOOP
// =================================================
void loop() {

  handleButton();

  switch (program) {

    case 0: randomProgram(); break;
    case 1: colorPulse();    break;
    case 2: fixedColor(CRGB::Blue);   break;
    case 3: fixedColor(CRGB::Red);    break;
    case 4: fixedColor(CRGB::Green);  break;
    case 5: fixedColor(CRGB::White);  break;
    case 6: fixedColor(CRGB::Yellow); break;
    case 7: whitePulse();    break;
  }
}

// =================================================
// TASTER
// =================================================
void handleButton() {

  bool reading = digitalRead(BUTTON_PIN);

  if (reading != lastButtonState)
    debounceTime = millis();

  if (millis() - debounceTime > DEBOUNCE) {

    if (reading != buttonState) {

      buttonState = reading;

      // gedrückt
      if (buttonState == LOW) {
        buttonTime = millis();
        longDone = false;
      }

      // losgelassen
      else {

        // kurzer Druck
        if (!longDone &&
            millis() - buttonTime < LONG_PRESS) {

          nextProgram();
        }
      }
    }
  }

  // langer Druck
  if (buttonState == LOW &&
      !longDone &&
      millis() - buttonTime >= LONG_PRESS) {

    nextDim();
    longDone = true;
  }

  lastButtonState = reading;
}

// =================================================
// NÄCHSTES PROGRAMM
// =================================================
void nextProgram() {

  program++;

  if (program >= NUM_PROGRAMS)
    program = 0;

  saveSettings();

  animTime = millis();

  // Anzeige kurz zurücksetzen
  fill_solid(leds, NUM_LEDS, CRGB::Black);
  FastLED.show();
}

// =================================================
// NÄCHSTE DIMMSTUFE
// =================================================
void nextDim() {

  dim++;

  if (dim >= NUM_DIM_LEVELS)
    dim = 0;

  // Helligkeit SOFORT ändern
  FastLED.setBrightness(dimLevel[dim]);

  saveSettings();

  // sofort neu anzeigen
  FastLED.show();
}

// =================================================
// SPEICHERN
// =================================================
void saveSettings() {

  EEPROM.write(EE_PROGRAM, program);
  EEPROM.write(EE_DIM, dim);
  EEPROM.commit();
}

// =================================================
// PROGRAMM 1
// JEDE ZWEITE LED / ZUFALLSFARBEN
// =================================================
void randomProgram() {

  if (millis() - animTime < 1500)
    return;

  animTime = millis();

  static bool phase = false;
  phase = !phase;

  for (uint8_t i = 0; i < NUM_LEDS; i++) {

    if ((i & 1) == phase)
      leds[i] = CHSV(random8(), 255, 255);
    else
      leds[i] = CRGB::Black;
  }

  FastLED.show();
}

// =================================================
// PROGRAMM 2
// WEISS -> GRÜN -> GELB -> ROT
// 60 SEKUNDEN
// =================================================
void colorPulse() {

  uint32_t t = (millis() - animTime) % 60000UL;

  CRGB c;

  if (t < 15000) {

    // Weiß -> Grün
    uint8_t x = map(t, 0, 15000, 0, 255);

    c.r = 255 - x;
    c.g = 255;
    c.b = 255 - x;

  } else if (t < 30000) {

    // Grün -> Gelb
    uint8_t x = map(t, 15000, 30000, 0, 255);

    c.r = x;
    c.g = 255;
    c.b = 0;

  } else {

    // Gelb -> Rot
    uint8_t x = map(t, 30000, 60000, 255, 0);

    c.r = 255;
    c.g = x;
    c.b = 0;
  }

  fill_solid(leds, NUM_LEDS, c);

  FastLED.show();
}

// =================================================
// FESTE FARBE
// =================================================
void fixedColor(CRGB color) {

  static uint8_t lastProgram = 255;

  if (lastProgram != program) {

    fill_solid(leds, NUM_LEDS, color);
    FastLED.show();

    lastProgram = program;
  }
}

// =================================================
// WEISS PULSIEREND
// =================================================
void whitePulse() {

  uint16_t t = millis() % 4000;

  uint8_t b;

  if (t < 2000)
    b = map(t, 0, 2000, 5, 255);
  else
    b = map(t, 2000, 4000, 255, 5);

  // Dimmstufe berücksichtigen
  b = ((uint16_t)b * dimLevel[dim]) / 255;

  fill_solid(leds, NUM_LEDS, CRGB(b, b, b));

  FastLED.show();
}