Transformers: LED-Umbau einer Tischlampe

Es war einmal ein Geschenk:
Eine weiß leuchtende Transformers-Lampe (für'n Tisch). Meine Freundin schenkte sie mir Ende 2015. Die Lampe gefiel mir wirklich gut, allerdings fand ich es langweilig, dass sie nur weiß leuchtete und ziemlich beschissen, dass es keine Möglichkeit gab, eben diese an die Wand zu hängen.

Also beschloss ich die Lampe anzupassen:
Sie sollte am Besten in ALLEN Farben leuchten können und vorallem an die Wand zu schrauben sein.

Die Idee war simpel:
Die bisherigen LEDs sollten raus und gegen RGB-LEDs ausgetauscht werden, zusätzlich war der Plan die Strombuchse von hinten nach unten zu verlegen, um die Lampe später an die Wand hängen zu können.
Nach einem bisschen Schrauben, Dremeln und Bohren war das Gehäuse schonmal leer, das neue Loch für die untere Buchse gebohrt und auch alle alten Halterungen im Inneren entfernt.

Hier eine Liste der benötigten Teile:

UPDATE:
Mittlerweile existieren schon zwei dieser Lampen:
Vor ein paar Wochen war mein Patenkind zu Besuch: Jasper ist fast drei Jahre alt und war von der Lampe, welche mittlerweile im Wohzimmer hängt, sehr angetan. Welches er mit den Worten "Auch haben!" zum Ausdruck brachte. Ich versprach ihm also, ihm auch so eine zu bauen. Deswegen gibt es im Text immer mal wieder die Bezeichnungen "erste/zweite" Lampe. Klar soweit?

Die Lampe wird auf der Rückseite durch sechs Schrauben zusammen gehalten: Entfernt man die, kann man das Gehäuse einfach auseinander ziehen. Die originalen LEDs werden durch kleine "Plastiknöpsel" gehalten, welche ich mit'm Dremel weggeschnitten habe, da ich an genau diese Stellen jeweils zwei RGB-LEDs geklebt habe. Die LEDs werden in Reihe verschaltet und haben drei Anschlüsse:

  • 5V
  • Data
  • GND

Die erste Lampe mit eigenen Breakoutboards an jeder LED. Bei der zweiten Lampe sind die LEDs einfach mit Heißkleber fixiert. Geht auch. LEDs aus der Nähe.

Die 5V sollten möglichst direkt am Netzteil abgenommen werden und nicht über den Arduino, da die 8 LEDs doch ein bisschen "Saft" brauchen. Für den "Datapin" nimmt man sich irgendeinen Ausgang am Board: Ich wählte D6. Der Taster wird mittels Pull-Up-Widerstand (~4,7 kOhm) auf einen Eingang des Boards gelegt (D4 beispielsweise). Das Ganze sieht im Schema dann ungefähr so aus:

Schema der Schaltung im Inneren der Lampe

Den Taster und den Wippschalter habe ich seitlich aus dem Gehäuse geführt. Kleiner Tipp: Wer absolut keine Lust hat, sich den Verstand "wegzufeilen", um ein rechteckiges Loch in das Plastik zu bekommen, der kann sich auch stumpf einen Schalter direkt an's Kabel machen. Das tat ich bei der ersten Lampe, allerdings weiß ich nicht, wo später bei Jasper die Lampe stehen wird und ob/wie man dort gut an das Kabel kommt.

Die neue Strombuchse kommt nun "unten" aus dem Gehäuse. Die alte Stromaufnahme, auf der Rückseite, habe ich ebenfalls durch eine neue, größere Buchse ersetzt. So kann man die Lampe entweder hinstellen, oder an die Wand hängen. Natürlich sollte man nicht beide Aufnahmen gleichzeitig "befeuern", das wird lustige Effekte geben...

Beim Schreiben des Codes fiel mir auf, dass einzelne Farben zwar ganz nett aussehen, ich es aber noch viel geiler finde, wenn die Farben sich langsam ändern, das hat etwas beruhigendes. Mag ich gut leiden.
Dazu benutze ich im Code eine Library namens FastLED. Dort gibt es eine fertige Funktion namens "Rainbow" die meinen Wünschen sehr nahe kommt.
Die Lampe kann nun vier verschiedene Modi:

  1. Regenbogen (Langsame Farbwechsel)
  2. Weiß leuchten
  3. Blau leuchten
  4. FEUER!!!! (Das war eher ein Test, geht aber auch. Vielleicht während man Techno hört)

Achso, ja der Code. Hier:

/*
Hacky hacky code for Transformer-RGB Lamp
with some colors and animations:
Colors:
 - White
 - Blue
Animations:
 - Rainbow
 - Fire
*/

#include "FastLED.h"
#define NUM_LEDS 8 //Count of LEDs
#define CHIPSET WS2812B
#define FRAMES_PER_SECOND  120

#define DATA_PIN 6 //Data pin
#define BTN_PIN 4 // Button to change color

int colors[] = {10000, CRGB::White, CRGB::MediumBlue, 10001}; //Color patterns
int brightness[] = {0, 150, 250}; //Brightness patterns

//Used for fire-animation
#define COOLING  50
#define SPARKING 120
#define ANTIBEAT 100

CRGB leds[NUM_LEDS];
uint8_t gHue = 0;
bool gReverseDirection = false;

int current = 0; // Current pattern to start with
int state = 0; //Startvalue of button
int antibeatCnt = 0;

void setup() {
  delay(1000); // sanity check delay - allows reprogramming if accidently blowing power w/leds
  pinMode(BTN_PIN, INPUT); //set buttonmode
  FastLED.addLeds<CHIPSET,DATA_PIN,RGB>(leds, NUM_LEDS).setCorrection( TypicalLEDStrip );
  setColor();
}

void loop() {
  animate();
  if(button()) {
    handleCurrent();
    setColor();
  } 
}

void handleCurrent() {
  current++;
    if(current > sizeof(colors) / sizeof(int)-1){
      current = 0;
    }
}

void setColor() {
  int color = colors[current];
  FastLED.setBrightness(brightness[current]);
  for(int led = 0; led < NUM_LEDS; led = led + 1) {
      leds[led] = colors[current];
  }
  FastLED.show();
}

boolean button() {
    if(antibeatCnt > 0) {
      delay(1);
      antibeatCnt--;
      return false;
    }
    if(digitalRead(BTN_PIN) == state) return false;
    state = digitalRead(BTN_PIN);
    if(state == LOW) {
      antibeatCnt = ANTIBEAT;
      return true;
    }
    return false;
}


boolean animate() {
  if(millis() % 2) {
    return false;
  }
  int color = colors[current];
  if(color > 9999 && color < 10003) {
    FastLED.delay(1000/FRAMES_PER_SECOND); 
    switch(color) {
      case 10000:
        EVERY_N_MILLISECONDS( 130 ) { gHue++; }
        FastLED.setBrightness(250);
        fill_rainbow( leds, NUM_LEDS, gHue, 7);
      break;
      
      case 10001:
        EVERY_N_MILLISECONDS( 20 ) { gHue++; }
        random16_add_entropy( random());
        FastLED.setBrightness(110);
        fire2012();
      break;
      
      default: 
      break;
    }
    FastLED.show(); 
    return true;
  }
  return false;
}

void fire2012()
{
  static byte heat[NUM_LEDS];

  for( int i = 0; i < NUM_LEDS; i++) {
    heat[i] = qsub8( heat[i],  random8(0, ((COOLING * 10) / NUM_LEDS) + 2));
  }

  for( int k= NUM_LEDS - 1; k >= 2; k--) {
    heat[k] = (heat[k - 1] + heat[k - 2] + heat[k - 2] ) / 3;
  }

  if( random8() < SPARKING ) {
    int y = random8(7);
    heat[y] = qadd8( heat[y], random8(160,255) );
  }

  for( int j = 0; j < NUM_LEDS; j++) {
    CRGB color = HeatColor( heat[j]);
    // guck mal mami, ohne temp-variable! (mrks sagt das)
    color.g = color.r ^ color.g;
    color.r = color.r ^ color.g;
    color.g = color.r ^ color.g;
    int pixelnumber;
    if( gReverseDirection ) {
      pixelnumber = (NUM_LEDS-1) - j;
    } else {
      pixelnumber = j;
    }
    leds[pixelnumber] = color;
  }
}

Das Innenleben der ersten Lampe Das Board der zweiten Lampe klebt am Rand Grün. Weiß. Blau-Lila. Pink.

Das folgende Video "dokumentiert", wie der Bau der zweiten Lampe so gelaufen ist: