RGB Lighting Reactive to Music, Wifi Controlled and Ambilight (Google Assistant Compatible)

Introduction: RGB Lighting Reactive to Music, Wifi Controlled and Ambilight (Google Assistant Compatible)

I've been working on this for a couple of months now and I'm constantly adding new functions and features, but since I haven't seen anything quite like this on the Internet yet, I'd like to share it with you guys...

Addressable RGB Strips have been gaining traction as of late. And why shouldn't they? LEDs look fantastic, they're super efficient and since they're RGB you can customize them as much as you want! But actual finished products like Philips HUE are still quite expensive and are lacking many features in my oppinion.

The DIY community has shown time and time again that it's possible to create whole room

addressable RGB lighting for under 50$, by using the popular WS2811 strips and an Arduino to control them, but usually you're stuck with button controls and a couple of effects. That's why I tried to create my own solution, that can be controlled over Wifi, aswell as cellular if you're not at home, doesn't rely on your PC as a power source and since I love ambilights for your monitor, I also wanted to incorporate that into the project, to sync your whole room to whatever is onscreen when that mode is active.

I won't cover the basics, like installing Arduino IDE or how to get the librarys you need, but if youre interested, simply message me and I'll try to help :P

Stuff you'll need:

  • Some wires
  • Arduino UNO or nano, basically anything with I2C support that has a Serial Port
  • Lolin Board/NODE MCU Dev Board (something with internet and I2C)
  • lots of LEDs... i got 5m WS2811 30/m and another 60/m strip
  • 100-1000mF electrolytic capacitor
  • Google Home device (optional, you can simply use your phone instead)
  • 3.3v to 5v bidirectional converter (if you wanna keep your esp8266 safe, usually you can connect tit directly to 5v)
  • 3h of your life
  • 12v 5A PSU (if your using 12v LEDs)

Step 1: Test the LEDs

The first thing you should do after you've gotten your LEDs is connecting them to the PSU to check if they work. Those Strips from China that you find on eBay are usually fine, but some might have defective parts, and it would be a shame if they didn't work and you figured it out after you installed them. DON'T PLUG IN THE PSU UNTIL EVERYTHING IS CONNECTED!!!
To test them, you have to connect the 12V pin (or 5V on some Strips) to the +12V connector of your power supply and the GND pin to ground (the - connector, usually black).
To control them, we're gonna use the Arduino. Connect the ground of the Arduino to the PSU ground and the DIN (data) pin of the LEDs to D3 on the Arduino. You can choose any other digital pin as well, but you're gonna have to change the code accordingly.

Install the FastLED library to your Arduino IDE and upload the DemoReel100 code, from the FastLED examples.

If you're seeing the LEDs light up, you're good to go.

Step 2: Installing the LEDs

To install the LEDs I used simple double-sided tape that I cut into short strips.

I'd recommend planning where you wanna install everything beforehand since the LED strips can only pass data in one direction, so they have to be oriented away from your Arduino/NODE MCU. You can always cut the strips to your liking and connect them separately to your Arduino (I'm using 3 separate Strips for my Bed, Table, and PC, but have the Table strip divided into 2 zones, one for the table and one for my Ambilight).

You should probably check everything for shorts before proceeding to the next step, but you can also skip this if you like living dangerously.

Step 3: Connecting Arduin and NODE MCU

Some of you might wonder, why you need both Arduino and NODE MCU for this project...

The NODE MCU is controlling the LEDs and communicating with the App as well as the IFTTT service for google home. This is enough to control all the Effects and colors remotely... But since I wanted this to be able to connect to my Ambilight, I needed a Serial connection to my PC to get the On-screen data. That's where the Arduino comes into play. Its only job is to get the On-screen data, store it, pass it on to the NODE MCU board when needed.

Why didn't I simply use the Serial connection of the NODE MCU?
Well, for some reason every f***ing time I tried, the Serial data would get corrupted, and I would receive total jibberish... I guess it has to do with FastLED disabling interrupts, to get the LED timings right, but I'm not quite sure... If anyone has an idea how to fix it, I'd love to hear it.

Skip to here, if you just wanna know what to do

To connect the Arduino to the NODE MCU, we're gonna use the pins D3 and D4 on the Lolin Board and the A4 and A5 pins on the Arduino. Since the ESP8266 (the heart of the NODE MCU board) officially only supports up to 3.3V, you might want to add the bidirectional voltage converter in between. Additionally, you have to connect the grounds of the boards, by using a jumper between two of their GND pins.

Since the ESP8266 uses quite a lot of power on startup, connect a capacitor to its VU (the voltage from the USB port) and ground pin, to prevent random resets.

Step 4: Uploading Software

the Arduino code, to get all the values from your PC:

#include "Wire.h"<br>int reqLed = 0; //the led thats being requested<br><br>// Baudrate, higher rate allows faster refresh rate and more LEDs (defined in /etc/boblight.conf) #define serialRate 115200 #define NUM_LEDS 33<br>// Adalight sends a "Magic Word" (defined in /etc/boblight.conf) before sending the pixel data uint8_t prefix[] = {'A', 'd', 'a'}, hi, lo, chk, i;<br><br>// Initialise LED-array uint8_t leds[NUM_LEDS][3]; uint8_t ledsfull[NUM_LEDS][3];<br><br>void setup() {<br>Wire.begin(8);                // join i2c bus with address #8   Wire.onRequest(requestEvent); // register event   Wire.onReceive(receiveEvent); // register event     Serial.begin(serialRate);   // Send "Magic Word" string to host   Serial.print("Ada\n");<br>pinMode(13, OUTPUT);<br><br>for(;;) {   // Wait for first byte of Magic Word   for (i = 0; i < sizeof prefix; ++i) {   waitLoop: while (!Serial.available()) ;;     // Check next byte in Magic Word     if (prefix[i] == Serial.read()) continue;     // otherwise, start over     i = 0;     goto waitLoop;   }   // Hi, Lo, Checksum   while (!Serial.available()) ;;   hi = Serial.read();   while (!Serial.available()) ;;   lo = Serial.read();   while (!Serial.available()) ;;   chk = Serial.read();<br><br>// If checksum does not match go back to wait   if (chk != (hi ^ lo ^ 0x55)) {     i = 0;     goto waitLoop;   }<br><br>memset(leds, 0, 3 * NUM_LEDS * sizeof(uint8_t));   // Read the transmission data and set LED values   for (uint8_t i = 0; i < NUM_LEDS; i++) {     byte r, g, b;     while (!Serial.available());     r = Serial.read();     while (!Serial.available());     g = Serial.read();     while (!Serial.available());     b = Serial.read();     leds[i][0] = r;     leds[i][1] = g;     leds[i][2] = b;   }<br>  for(int i =0; i<NUM_LEDS; i++)<br>{<br>ledsfull[i][0] = leds[i][0];<br>ledsfull[i][1] = leds[i][1];<br>ledsfull[i][2] = leds[i][2];<br>}<br>}<br>}<br>// function that executes whenever data is requested by master // this function is registered as an event, see setup() void requestEvent() {     uint8_t col[3];     col[0] = ledsfull[reqLed][0];     col[1] = ledsfull[reqLed][1];     col[2] = ledsfull[reqLed][2];     //col[0]=255;     //col[1]=0;     //col[2]=255;     Wire.write(col, 3);<br>reqLed++; }<br>void receiveEvent(int l) {  while (1 < Wire.available()) { // loop through all but the last     char c = Wire.read();    // print the character   }   int x = Wire.read();   reqLed = 0;   digitalWrite(13, !digitalRead(13)); }

The code for the NODE MCU board, the pins for the LEDs are 4, 5, and 14, therefore, you have to use pins D1, D2, D5 (look at the picture for reference)

#define FASTLED_ESP8266_RAW_PIN_ORDER<br>#include 
"FastLED.h"<br>FASTLED_USING_NAMESPACE<br><br>#if defined(FASTLED_VERSION) && (FASTLED_VERSION < 3001000)
#warning "Requires FastLED 3.1 or later; check github for latest code."
#endif<br>#include "Wire.h"<br>#define BLYNK_PRINT Serial<br><br>#include "ESP8266WiFi.h"<br>#include "BlynkSimpleEsp8266.h"<br>#include 
"SimpleTimer.h"<br>SimpleTimer timer;<br>/*********************************** FastLED Defintions ********************************/<br>#define NUM_LEDSB    28<br>#define NUM_LEDSA    33<br>#define NUM_LEDST    19<br>#define NUM_LEDSC    9
#define NUM_LEDS    (NUM_LEDSB + NUM_LEDST + NUM_LEDSC)<br>#define DATA_PIN    5
#define COLOR_ORDER BRG
#define SLAVE_ADDRESS 8
#define NUM_DATA 8<br>/********************************GLOBAL SETTINGS**********************************/struct CRGB leds [NUM_LEDS];
struct CRGB ledsT[NUM_LEDST];
struct CRGB ledsB[NUM_LEDSB];
struct CRGB ledsC[NUM_LEDSC];
int mode = 2;<br>const int allEffects = 15;<br>int newMode;<br>bool ambi = false;<br>int music = 0;
int brightness = 255;
struct CRGB color;
int speed = 100;
/**********************************************BLYNK*************************************************/r auth[] = "bff47b8282bf4e129226fe8ab96460b2";
char ssid[] = "WLAN-DC2A79";
char pass[] = "7190774630806407";<br>BLYNK_WRITE(V1){brightness = param.asInt(); delay(10);}<br>

BLYNK_WRITE(V0){if(param.asInt()==0)
{
      if (mode != -1) {change(-1);}
    }
  else{
    Blynk.syncVirtual(V3);
  }
}

BLYNK_WRITE(V6) { // when Button Widget or Web API called
  if (param.asInt() == 1) {
    digitalWrite(15, HIGH);
    timer.setTimeout(200L, []() {  // reset pin in 200ms
    digitalWrite(15, LOW);
    });
  }
}

BLYNK_WRITE(V2)
{
  speed = param.asInt();
}

BLYNK_WRITE(V3)
{
  int in = param.asInt();
  if(in!=mode)
  {
    change(in);
  }
}
BLYNK_WRITE(V4)
{
  ambi = param.asInt() == 1;
}
BLYNK_WRITE(V5)
{
  music = (param.asInt()-1) % 5 ;
}

BLYNK_WRITE(V10)
{
  color.r = param[0].asInt();
  color.g = param[1].asInt();
  color.b = param[2].asInt();

if(14!=mode)
  {
    change(14);
  }
}
/******************************** GLOBALS for fade *******************************/

CRGB oldLeds[NUM_LEDS];
const int fadeTime = 1200;
unsigned long fadeStart = 0;
bool fading = true;
const bool directFade = false;

/********************************** GLOBALS for EFFECTS ******************************/
//RAINBOW
uint8_t thishue = 0;                                          // Starting hue value.
uint8_t deltahue = 10;

//CANDYCANE
CRGBPalette16 currentPalettestriped;

//NOISE
static uint16_t dist;         // A random number for our noise generator.
const uint16_t scale = 30;          // Wouldn't recommend changing this on the fly, or the animation will be really blocky.
const uint8_t maxChanges = 38;      // Value for blending between palettes.
CRGBPalette16 targetPalette(OceanColors_p);
CRGBPalette16 currentPalette(CRGB::Black);

//TWINKLE
#define DENSITY     80
int twinklecounter = 0;

//RIPPLE
uint8_t colour;                                               // Ripple colour is randomized.
int center = 0;                                               // Center of the current ripple.
int step = -1;                                                // -1 is the initializing step.
uint8_t myfade = 255;                                         // Starting brightness.
#define maxsteps 16                                           // Case statement wouldn't allow a variable.
uint8_t bgcol = 0;                                            // Background colour rotates.
int thisdelay = 20;                                           // Standard delay value.
int rippleFramerate = 40;

//LIGHTNING
uint8_t frequency = 50;                                       // controls the interval between strikes
uint8_t flashes = 8;                                          //the upper limit of flashes per strike
unsigned int dimmer = 1;
uint8_t ledstart;                                             // Starting location of a flash
uint8_t ledlen;
int lightningcounter = 0;

//FUNKBOX
int idex = 0;                //-LED INDEX (0 to NUM_LEDS-1
int TOP_INDEX = int(NUM_LEDS / 2);
int thissat = 255;           //-FX LOOPS DELAY VAR
uint8_t thishuepolice = 0;
int antipodal_index(int i) {
  int iN = i + TOP_INDEX;
  if (i >= TOP_INDEX) {
    iN = ( i + TOP_INDEX ) % NUM_LEDS;
  }
  return iN;
}

//FIRE
#define COOLING  60
#define SPARKING 128
const bool gReverseDirection = true;
CRGBPalette16 gPal = HeatColors_p; //gPal = CRGBPalette16( CRGB::Black, CRGB::Blue, CRGB::Aqua,  CRGB::White); // for blue flames
bool advancedFire = false;
const uint8_t fireFramerate = 40;

//BPM
uint8_t gHue = 0;
uint8_t beatsPerMinute = 48;

//POLICE
int policeFramerate = 55;

//CONFETTI
int confettiFramerate = 60;

/**********************************************MUSIC************************************/
uint8_t volume = 0;   //Holds the volume level read from the sound detector.
uint8_t last = 0;
float avgBump = 0;    //Holds the "average" volume-change to trigger a "bump."
float avgVol = 0;
bool bump = false;
float avgTime = 0;
float maxVol = 15;
float timeBump = 0;

int table[] = {0, 0, 0}; //the data will be transmited via table as to allow different data to be transfer.

BLYNK_CONNECTED()
{
  Blynk.syncVirtual(V0);
  Blynk.syncVirtual(V1);
  Blynk.syncVirtual(V2);
  Blynk.syncVirtual(V3); 
  Blynk.syncVirtual(V10);

Serial.println("successfully connected, values are up to date");
}

void setup() {
  Wire.begin (D3, D4);

  FastLED.addLeds(ledsB, NUM_LEDSB).setCorrection(TypicalLEDStrip);
  FastLED.addLeds(ledsT, NUM_LEDST).setCorrection(TypicalLEDStrip);
  FastLED.addLeds(ledsC, NUM_LEDSC).setCorrection(TypicalLEDStrip);
  FastLED.setBrightness(255);

setupStripedPalette( CRGB::Red, CRGB::Red, CRGB::White, CRGB::White); //for CANDY CANE

fill_rainbow(ledsB, NUM_LEDSB, 0, 10);
  FastLED.show();
  delay(1000);
  LEDS.showColor(CRGB(0, 0, 0));

Serial.begin(115200);
  delay(20);
  Blynk.begin(auth, ssid, pass);
  Serial.println("exiting setup");
}

void loop() {
  Blynk.run();

if (!ambi)
  {
    FastLED.setBrightness(brightness);
    random16_add_entropy(rand());

/*EVERY_N_SECONDS(20) {
      if (mode != -1)
        change(mode + 1);
      }*/

switch (mode)
    {
      default: FastLED.showColor(CRGB(255, 255, 255)); break;
      case -1: memset(leds, 0, 3 * NUM_LEDS * sizeof(uint8_t)); break;
      case 0: fire(); advancedFire = false; break;
      case 1: fire(); advancedFire = true; break;
      case 2: bpm(); break;
      case 3: policeAll(); break;
      case 4: rainbowSwitchUpdate(); EVERY_N_SECONDS(2) {
          RainbowSwitch();
        } break;
      case 5: rainbow(); break;
      case 6: sinelon(); break;
      case 7: confetti(); break;
      case 8: cyclonRainbow(); break;
      case 9: ripple(); break;
      case 10: noise(); break;
      case 11: lightning(); break;
      case 12: candyCane(); break;
      case 13: policeOne(); break;
      case 14: fill_solid(leds, NUM_LEDS, color); break;
    }
    showLeds();
  }
  else {
    FastLED.setBrightness(255);
    EVERY_N_MILLISECONDS(5) {
      getAmbilightValues();
      switch (music) {
        default: showLeds(); break;
        case 0: showLeds(); break;
        case 1: adjustForMusic(); break;
        case 2: getBpm(); break;
        case 3: averageMusic(); break;
        case 4: importedMusic(); break;
      }
    }
  }
  EVERY_N_MILLISECONDS( 35 ) {
    gHue++;
  }
}

//*********************************ChangeEffect***************************************

void change(int in)
{
  fading = true;
  fadeStart = millis();
  for (int i = 0; i < NUM_LEDS; i++)
  {
    oldLeds[i] = leds[i];
  }

mode = in % allEffects;
}

//*********************************FADE***********************************************

void showLeds()
{
  //CRGB tmpLeds[NUM_LEDS];
  if (fading)
  {
    unsigned long currentMillis = millis();
    unsigned int diff = currentMillis - fadeStart;

float fraction = (float)diff / (float)fadeTime;
    uint8_t amountOfFade = fraction * 255;

if (directFade) {
      for (int i = 0; i < NUM_LEDS; i++)
      {
        leds[i] = blend(oldLeds[i], leds[i], amountOfFade);
        //leds[i] = CRGB(amountOfFade, amountOfFade, amountOfFade);
      }
    }
    else {
      if (amountOfFade < 85) {
        for (int i = 0; i < NUM_LEDS; i++)
        {
          leds[i] = blend(oldLeds[i], CRGB(0, 0, 0), amountOfFade * 3);
        }
      }
      else if (amountOfFade < 128) {
        memset(leds, 0, 3 * NUM_LEDS * sizeof(uint8_t));
      }
      else {
        for (int i = 0; i < NUM_LEDS; i++)
        {
          leds[i] = blend(CRGB(0, 0, 0), leds[i], amountOfFade * 2 - 256);
        }
      }
    }

 if (diff >= fadeTime)
    {
      fading = false;
      twinklecounter = 0;
    }
  }

/*********************************set the independent led arrays, get the order right******************************/
  for (int i = 0; i < NUM_LEDST; i++)
  {
    ledsT[i] = leds[NUM_LEDSB - 1 + i];
  }
  for (int i = 0; i < NUM_LEDSB; i++)
  {
    ledsB[i] = leds[NUM_LEDSB - 1 - i];
  }
  for (int i = 0; i < NUM_LEDSC; i++)
  {
    ledsC[i] = leds[NUM_LEDSB + NUM_LEDST - 1 + i];
  }

  FastLED.show();
}
//*********************************EFFECTS*********************************************

void fire()
{
  EVERY_N_MILLISECONDS( 1000 / fireFramerate ) {
    if (advancedFire)
    { static uint8_t hue = 0;
      hue++;
      CRGB darkcolor  = CHSV(hue, 255, 192); // pure hue, three-quarters brightness
      CRGB lightcolor = CHSV(hue, 128, 255); // half 'whitened', full brightness
      gPal = CRGBPalette16( CRGB::Black, darkcolor, lightcolor, CRGB::White); \
    }

static byte heat[NUM_LEDS];

// Step 1.  Cool down every cell a little
    for ( int i = 0; i < NUM_LEDS; i++) {
      heat[i] = qsub8( heat[i],  random8(0, ((COOLING * 10) / NUM_LEDS) + 2));
    }

 // Step 2.  Heat from each cell drifts 'up' and diffuses a little
    for ( int k = NUM_LEDS - 1; k >= 2; k--) {
      heat[k] = (heat[k - 1] + heat[k - 2] + heat[k - 2] ) / 3;
    }

    // Step 3.  Randomly ignite new 'sparks' of heat near the bottom
    if ( random8() < SPARKING ) {
      int y = random8(7);
      heat[y] = qadd8( heat[y], random8(160, 255) );
    }

    // Step 4.  Map from heat cells to LED colors
    for ( int j = 0; j < NUM_LEDS; j++) {
      // Scale the heat value from 0-255 down to 0-240
      // for best results with color palettes.
      byte colorindex = scale8( heat[j], 240);
      CRGB color = ColorFromPalette( gPal, colorindex);
      int pixelnumber;
      if ( gReverseDirection ) {
        pixelnumber = (NUM_LEDS - 1) - j;
      } else {
        pixelnumber = j;
      }
      leds[pixelnumber] = color;
    }

    //FastLED.delay(1000/fireFramerate);
  }
}

void bpm()
{
  CRGBPalette16 palette = PartyColors_p;
  uint8_t beat = beatsin8(beatsPerMinute, 64, 255);
  for ( int i = 0; i < NUM_LEDS; i++) { //9948
    leds[i] = ColorFromPalette(palette, gHue + (i * 2), beat - gHue + (i * 10));
  }
}

void policeAll()
{
  EVERY_N_MILLISECONDS(1000 / policeFramerate) {
    idex++;
    if (idex >= NUM_LEDS) {
      idex = 0;
    }
    int idexR = idex;
    int idexB = antipodal_index(idexR);
    int thathue = (thishuepolice + 160) % 255;
    leds[idexR] = CHSV(thishuepolice, thissat, 255);
    leds[idexB] = CHSV(thathue, thissat, 255);
  }
}

void policeOne()
  {
  EVERY_N_MILLISECONDS(1000 / policeFramerate) {
    idex++;
    if (idex >= NUM_LEDS) {
      idex = 0;
    }
    int idexR = idex;
    int idexB = antipodal_index(idexR);
    int thathue = (thishuepolice + 160) % 255;
    for (int i = 0; i < NUM_LEDS; i++ ) {
      if (i == idexR) {
        leds[i] = CHSV(thishuepolice, thissat, 255);
      }
      else if (i == idexB) {
        leds[i] = CHSV(thathue, thissat, 255);
      }
      else {
        leds[i] = CHSV(0, 0, 0);
      }
    }
  }
  }

void rainbow()
{
  EVERY_N_MILLISECONDS(speed) {
    thishue++;
  }
  fill_rainbow(leds, NUM_LEDS, thishue, deltahue);
}

void sinelon()
{
  fadeToBlackBy( leds, NUM_LEDS, 2);
  int pos = beatsin16((15 * speed) / 100, 0, NUM_LEDS - 1);
  leds[pos] += CHSV( gHue, 255, 255);
}

void confetti()
{
  EVERY_N_MILLISECONDS(1000 / confettiFramerate) {
    fadeToBlackBy( leds, NUM_LEDS, 10);
    int pos = random16(NUM_LEDS);
    leds[pos] += CHSV( gHue + random8(64), 200, 255);
  }
}

void cyclonRainbow()
{
  static uint8_t hue = 0;
  // First slide the led in one direction
  for (int i = 0; i < NUM_LEDS; i++) {
    // Set the i'th led to red
    leds[i] = CHSV(hue++, 255, 255);
    // Show the leds
    showLeds();
    // now that we've shown the leds, reset the i'th led to black
    // leds[i] = CRGB::Black;
    fadeall();
    // Wait a little bit before we loop around and do it again
    delay(10);
  }
  for (int i = (NUM_LEDS) - 1; i >= 0; i--) {
    // Set the i'th led to red
    leds[i] = CHSV(hue++, 255, 255);
    // Show the leds
    showLeds();
    // now that we've shown the leds, reset the i'th led to black
    // leds[i] = CRGB::Black;
    fadeall();
    // Wait a little bit before we loop around and do it again
    delay(10);
  }
}

void fadeall() {
  for (int i = 0; i < NUM_LEDS; i++) {
    leds[i].nscale8(250);  //for CYCLon
  }
}

void ripple()
{
  EVERY_N_MILLISECONDS(1000 / rippleFramerate) {
    for (int i = 0; i < NUM_LEDS; i++) leds[i] = CHSV(bgcol++, 255, 15);  // Rotate background colour.
    switch (step) {
      case -1:                                                          // Initialize ripple variables.
        center = random(NUM_LEDS);
        colour = random8();
        step = 0;
        break;
      case 0:
        leds[center] = CHSV(colour, 255, 255);                          // Display the first pixel of the ripple.
        step ++;
        break;
      case maxsteps:                                                    // At the end of the ripples.
        step = -1;
        break;
      default:                                                             // Middle of the ripples.
        leds[(center + step + NUM_LEDS) % NUM_LEDS] += CHSV(colour, 255, myfade / step * 2);   // Simple wrap from Marc Miller
        leds[(center - step + NUM_LEDS) % NUM_LEDS] += CHSV(colour, 255, myfade / step * 2);
        step ++;                                                         // Next step.
        break;
    }
  }
}

void noise()
{
  for (int i = 0; i < NUM_LEDS; i++) {                                     // Just onE loop to fill up the LED array as all of the pixels change.
    uint8_t index = inoise8(i * scale, dist + i * scale) % 255;            // Get a value from the noise function. I'm using both x and y axis.
    leds[i] = ColorFromPalette(currentPalette, index, 255, LINEARBLEND);   // With that value, look up the 8 bit colour palette value and assign it to the current LED.
  }
  dist += beatsin8(10, 1, 4);

EVERY_N_MILLISECONDS(10) {
    nblendPaletteTowardPalette(currentPalette, targetPalette, maxChanges);  // FOR NOISE ANIMATIon
    {
      gHue++;
    }
  }
  EVERY_N_SECONDS(5) {
    targetPalette = CRGBPalette16(CHSV(random8(), 255, random8(128, 255)), CHSV(random8(), 255, random8(128, 255)), CHSV(random8(), 192, random8(128, 255)), CHSV(random8(), 255, random8(128, 255)));
  }
}

void lightning()
{
  twinklecounter++;                     //Resets strip if previous animation was running
  if (twinklecounter <= 2) {
    FastLED.clear();
    FastLED.showColor(CRGB(0, 0, 0));
    FastLED.show();
  }
  ledstart = random8(NUM_LEDS - 1);         // Determine starting location of flash
  ledlen = random8(NUM_LEDS - ledstart);  // Determine length of flash (not to go beyond NUM_LEDS-1)
  for (int flashCounter = 0; flashCounter < random8(3, flashes); flashCounter++) {
    if (flashCounter == 0) dimmer = 5;    // the brightness of the leader is scaled down by a factor of 5
    else dimmer = random8(1, 3);          // return strokes are brighter than the leader
    fill_solid(leds + ledstart, ledlen, CHSV(255, 0, 255 / dimmer));
    showLeds();    // Show a section of LED's
    delay(random8(4, 10));                // each flash only lasts 4-10 milliseconds
    fill_solid(leds + ledstart, ledlen, CHSV(255, 0, 0)); // Clear the section of LED's
    showLeds();
    if (flashCounter == 0) delay (130);   // longer delay until next flash after the leader
    delay(50 + random8(100));             // shorter delay between strokes
  }
  delay(random8(frequency) * 100);
}

void candyCane()
{
  static uint8_t startIndex = 0;
  startIndex = startIndex + 1; /* higher = faster motion */
  fill_palette( leds, NUM_LEDS,
                startIndex, 16, /* higher = narrower stripes */
                currentPalettestriped, 255, LINEARBLEND);
}

void RainbowSwitch()
{
  leds[0] = ColorFromPalette(RainbowStripeColors_p, 50, 255, LINEARBLEND);
}

void rainbowSwitchUpdate()
{
  for (int i = 0; i < NUM_LEDS - 1; i++)
  {
    leds[i + 1] = leds[i];
  }
}
/**************************** START STRIPLED PALETTE *****************************************/
void setupStripedPalette( CRGB A, CRGB AB, CRGB B, CRGB BA) {
  currentPalettestriped = CRGBPalette16(
                            A, A, A, A, A, A, A, A, B, B, B, B, B, B, B, B
                            //    A, A, A, A, A, A, A, A, B, B, B, B, B, B, B, B
                          );
}

/**************************** AMBILIGHT **********************************************/
void getAmbilightValues()
{
  Wire.beginTransmission(8); // transmit to device #8
  Wire.write("x5");      // restarts the transmission loop
  Wire.endTransmission();

 for (int i = 0; i < NUM_LEDSA; i++)
  {
    Wire.requestFrom(SLAVE_ADDRESS, 3);// request 3 bytes from slave device #8
    for (int i = 0; i < 3; i++) //organizes the data from the slave in the table
    {
      int c = Wire.read(); // receive a byte as an int
      table[i] = c;
    }
    if (i < NUM_LEDSA)
    {
      leds[i].r = table[0];
      leds[i].g = table[1];
      leds[i].b = table[2];
    }
  }
}

void adjustForMusic()
{
  static int TmpValues[NUM_LEDS];
  static CRGB TmpLeds[NUM_LEDS];

//create black  and white values/int from colors
  for (int i = 0; i < NUM_LEDS; i++) {
    TmpLeds[i] = leds[i];
    //TmpValues[i] = max(leds[i].r, TmpValues[i]);//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  }
  //shift the hue for rainbow effect************
  for (int i = 0; i < NUM_LEDS; i++) {
    leds[i] = CHSV((gHue + 4 * i) % 255, 255, TmpValues[i]);
  }
  //smooth out with neighbouring cells**********
  for (int i = 0; i < NUM_LEDS; i++) {
    //TmpValues[max(i - 1, 0)] += TmpValues[i] * 0.2;//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    //TmpValues[min(NUM_LEDS, i + 1)] += TmpValues[i] * 0.2;//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  }
  // fade the leds and values*******************
  for (int i = 0; i < NUM_LEDS; i++) {
    TmpValues[i] -= 3;
  }
  fadeToBlackBy( TmpLeds, NUM_LEDS, 10);

showLeds();
  //reset the leds to normal********************
  for (int i = 0; i < NUM_LEDS; i++) {
    leds[i] = TmpLeds[i];
  }
}

void getBpm()
{/*
  static int TmpValues[NUM_LEDS];
  for (int i = 0; i < NUM_LEDS; i++) {
    TmpValues[i] = leds[i].r;
  }

static int averageEnergyL;
  long averageL;
  static long lastBeat = 0;

for (int i = 6; i >= 2; i--)
  {
    averageL += TmpValues[i];
  }
  averageL = averageL / 4;

  averageEnergyL += (int)(averageL * 0.05);
  averageEnergyL = averageEnergyL * 0.95;

  static CRGB ileds[NUM_LEDS];
  for (int i = 1; i < NUM_LEDS; i++)
  {
    ileds[i - 1] = ileds[i];
  }
  if (averageL > 12 + averageEnergyL)
  {
    int value = (int)(averageL * 1.2) ^ 2;
    if (value > 90)
    {
      lastBeat = millis();
    }
    value = (int)(((int)(log(averageL / 5) * 65)) + 2 * (int)(averageL * 1.2) ^ 2) / 3;
    ileds[NUM_LEDS - 1] = CHSV(gHue, 255, min(255, value));
  }

  if ((millis() - lastBeat) > 2000)
  {
    static int averageEnergyH;
    long averageH = 0;
    for (int i = 25; i >= 10; i--)
    {
      averageH += TmpValues[i];
    }
    averageH = min(255, averageH / 10);
    averageEnergyH += (int)(averageH * 0.05);
    averageEnergyH = averageEnergyH * 0.95;

   int a = min(255, (log(averageEnergyH / 2)) * 55);

    for (int i = 0; i < NUM_LEDS; i++)
    {
      ileds[i] = CRGB(a, a, a * 0.9);
    }
  }

  //add to original led array
  for (int i = 0; i < NUM_LEDS; i++)
  {
    leds[i] = ileds[i];
  }

  showLeds();*/
}

void averageMusic()
{
  static int TmpValues[NUM_LEDSA];
  long avg = 0;
  for (int i = 0; i < NUM_LEDSA; i++) {
    TmpValues[i] = leds[i].r;
    avg += TmpValues[i];
  }
  avg = avg / NUM_LEDSA;
  avg = log(avg / 4) * 50;
  for (int i = 0; i < NUM_LEDS; i++)
  {
    leds[i] = CHSV(gHue + 2 * i, 160, avg);
  }
  showLeds();
}

void importedMusic()
{

  static int TmpValues[NUM_LEDSA];
    long avg = 0;
    for (int i = 0; i < NUM_LEDSA; i++) {
    TmpValues[i] = leds[i].r;
    avg += TmpValues[i];
    }
    avg = avg / NUM_LEDSA;
  
  EVERY_N_MILLISECONDS(30) {
    volume = avg;
    
    if (volume < avgVol / 2.0 || volume < 15) volume = 0;
    else avgVol = (avgVol + volume) / 2.0; //If non-zeo, take an "average" of volumes.
    if (volume > maxVol) maxVol = volume;

   if (volume - last > 10) avgBump = (avgBump + (volume - last)) / 2.0;
    bump = (volume - last > avgBump * .9);

   //If a "bump" is triggered, average the time between bumps
    if (bump) {
      avgTime = (((millis() / 1000.0) - timeBump) + avgTime) / 2.0;
      timeBump = millis() / 1000.0;
    }
    last = volume;
  }
  if (volume > 0) {
    Visualize();
  }
  fadeall();
  showLeds();
}

void Visualize() {
  CRGBPalette16 palette = PartyColors_p;
  //uint8_t beat = beatsin8(max(120 / avgTime, 1), 64, 255);//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  for ( int i = 0; i < NUM_LEDS; i++) { //9948
    //leds[i] = CHSV(64, min(255,avgTime*255), beat - gHue + (i * 10));//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  }
}

The code is far from clean, and a lot of effects are still missing, but I had to make a new version since the last one was too unstable... I'll be updating this mess, but it works so...

The Program you need running on your PC is called Prismatik

https://www.reddit.com/r/Lightpack/comments/448w8m/prismatik_as_it_should_have_been_windows/

to connect, select the COM port of the ARDUINO, not the NODE MCU.


IMPORTANT

The music modes use the Music detection of Prismatik, not a microphone! For proper function, set the mode in Prismatik to music reactive and the colors to black and full red!!!

Step 5: Finishing Up

now that everything is connected and set up, you can go ahead, and download the Blynk app to your phone and create this project:

tinyurl.com/y dbbn94x

To add Google Assistant support, you need an IFTTT account and the IP address of the BLYNK server in your region. To find the IP, simply type: ping blynk-cloud.com into the CMD window on your PC.

Create a new IFTTT Applet, add the google assistant command as if and webhook as then.

In the webhook tab, set the URL to:

http://IP_OF_THE_SERVER/YOUR_AUTH_KEY/pin/THE_PIN_TO_CHANGE

the pins are:

  • V0 for on/off
  • V1 for brightness
  • V2 for speed
  • V3 for the LED effect
  • V4 to toggle the ambilightmode
  • V5 to change the music mode

the method has to be set to PUT, the content to application.json

the value has to be written in square brackets and quotation marks, e.g.: ["0"] for off and ["1"] for on

That's it! You did it!

If anyone actually does this project, please let me know... I'd love to hear your feedback/suggestions/thoughts, since this is my first instructable. :D

Hope you had fun!

Share

    Recommendations

    • Tiny Home Contest

      Tiny Home Contest
    • Fix It! Contest

      Fix It! Contest
    • Water Contest

      Water Contest

    4 Discussions

    That looks neat! Do you have any progress photos from when you were setting it up?

    3 replies

    But I can add shots of some details if you want, like the Arduino part and stuff :-P

    Sure, that would be really helpful to those that want to replicate the project :)

    I'm afraid no... Didn't ever expect it to turn out that well, so I never thought about documenting it properly