Last active
January 5, 2018 13:49
-
-
Save yeutterg/2909ab05c726c4f8a4ab3f417c720d17 to your computer and use it in GitHub Desktop.
Arduino Code for the NYC Window Display
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Arduino Code for the 2017 NYC Holiday Window Display | |
// More info about this project: https://yeutterg.github.io/nyc-display-2017 | |
#include "FastLED.h" | |
#define BRIGHTNESS 255 | |
#define NUM_LEDS_PER_STRIP 100 | |
#define NUM_STRIPS 4 | |
#define NUM_LEDS NUM_STRIPS * NUM_LEDS_PER_STRIP | |
#define LED_START_PIN 30 | |
#define UPDATES_PER_SECOND 100 | |
//#define LED_PIN 30 | |
#define SNOW_SPEED 20 | |
//#define SNOW_DELAY 50 // runs between snowfall | |
CRGB leds[NUM_LEDS]; | |
bool SNOWFALL = true; | |
// some nice reference colors for the Green Wire WS2811 pixels | |
CHSV r(0, 255, 255); // red | |
CHSV o(15, 255, 255); // orange | |
CHSV y(30, 255, 255); // yellow | |
CHSV g(92, 255, 255); // green | |
CHSV t(120, 255, 255); // teal | |
CHSV b(160, 255, 255); // blue | |
CHSV p(195, 255, 255); // purple | |
CHSV k(240, 255, 255); // pink | |
CRGB c = CRGB::Black; // off | |
CRGB w = CRGB::White; // cool white | |
CRGB x = CRGB::LightSalmon; // warm white | |
CRGBPalette16 palette_off = CRGBPalette16( c,c,c,c, c,c,c,c, c,c,c,c, c,c,c,c); | |
CRGBPalette16 palette_twinkle = CRGBPalette16( c,c,c,w, c,c,c,c, c,c,c,w, c,c,c,w); | |
CRGBPalette16 palette_red = CRGBPalette16( r,r,r,r, r,r,r,r, r,r,r,r, r,r,r,w); | |
CRGBPalette16 palette_orange = CRGBPalette16( o,o,o,o, o,o,o,o, o,o,o,o, o,o,o,w); | |
CRGBPalette16 palette_yellow = CRGBPalette16( y,y,y,y, y,y,y,y, y,y,y,y, y,y,y,w); | |
CRGBPalette16 palette_green = CRGBPalette16( g,g,g,g, g,g,g,g, g,g,g,g, g,g,g,w); | |
CRGBPalette16 palette_blue = CRGBPalette16( b,b,b,b, b,b,b,b, b,b,b,b, b,b,b,w); | |
CRGBPalette16 palette_teal = CRGBPalette16( t,t,t,t, t,t,t,t, t,t,t,t, t,t,t,w); | |
CRGBPalette16 palette_purple = CRGBPalette16( p,p,p,p, p,p,p,p, p,p,p,p, p,p,p,w); | |
CRGBPalette16 palette_pink = CRGBPalette16( k,k,k,k, k,k,k,k, k,k,k,k, k,k,k,w); | |
//CRGBPalette16 palette_multi = CRGBPalette16( k,y,t,r, b,o,p,w, k,y,t,r, b,o,p,w); | |
CRGBPalette16 palette_multi = CRGBPalette16(0xFF0000, 0xD52A00, 0xAB5500, 0xAB7F00, | |
0xABAB00, 0x56D500, 0x00FF00, 0x00D52A, | |
0x00AB55, 0x0056AA, 0x0000FF, 0x2A00D5, | |
0x5500AB, 0x7F0081, 0xAB0055, w); | |
CRGBPalette16 palette_ww = CRGBPalette16( x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,w); | |
CRGBPalette16 palette_cw = CRGBPalette16( w,w,w,w, w,w,w,w, w,w,w,w, w,w,w,t); | |
CRGBPalette16 palette_snow = CRGBPalette16( w,w,w,w, w,w,w,w, w,w,w,w, w,w,w,w); | |
// Start by fading on to rainbow | |
CRGBPalette16 currentPalette( CRGB::Black); | |
CRGBPalette16 currentSnowPalette = currentPalette; | |
//CRGBPalette16 targetPalette( RainbowColors_p ); | |
CRGBPalette16 targetPalette = palette_yellow; | |
// Vertical map for snowfall effect | |
int verticalMap[][2] = { | |
{0, 74}, | |
{75, 149}, | |
{150, 224}, | |
{225, 299}, | |
{300, 374}, | |
{375, 449}, | |
{450, 524}, | |
{525, 599} | |
}; | |
int numVerticalRows = sizeof(verticalMap)/sizeof(*verticalMap); | |
byte currentSnowRow = 0; | |
int currentSnowTimestep = 0; | |
int currentSnowDelay = 0; | |
//boolean snowOn = true; | |
void setup() { | |
delay(1000); // power-up safety delay | |
Serial.begin(9600); | |
// Add all the LED strips | |
// WS2811_PORTA: 69,68,61,60,59,100,58,31 (note: pin 100 only available on the digix) | |
// WS2811_PORTB: 90,91,92,93,94,95,96,97 (note: only available on the digix) | |
// WS2811_PORTD: 25,26,27,28,14,15,29,11 | |
FastLED.addLeds<WS2811_PORTD, NUM_STRIPS, RGB>(leds, NUM_LEDS_PER_STRIP); | |
// FastLED.addLeds<WS2811_PORTA, 31>(leds, NUM_LEDS_PER_STRIP, NUM_LEDS_PER_STRIP); | |
// FastLED.addLeds<WS2811_PORTB, 27>(leds, 2*NUM_LEDS_PER_STRIP, NUM_LEDS_PER_STRIP); | |
// FastLED.addLeds<WS2811, LED_START_PIN+3>(leds, 3*NUM_LEDS_PER_STRIP, NUM_LEDS_PER_STRIP); | |
// FastLED.addLeds<WS2811, LED_START_PIN+4>(leds, 4*NUM_LEDS_PER_STRIP, NUM_LEDS_PER_STRIP); | |
// FastLED.addLeds<WS2811, LED_START_PIN+5>(leds, 5*NUM_LEDS_PER_STRIP, NUM_LEDS_PER_STRIP); | |
// FastLED.addLeds<WS2811, LED_START_PIN+6>(leds, 6*NUM_LEDS_PER_STRIP, NUM_LEDS_PER_STRIP); | |
// FastLED.addLeds<WS2811, LED_START_PIN+7>(leds, 7*NUM_LEDS_PER_STRIP, NUM_LEDS_PER_STRIP); | |
FastLED.setBrightness(BRIGHTNESS); | |
} | |
void loop() { | |
uint8_t maxChanges = 24; // Min 1 (slowest), max 48 - speed of palette crossfade | |
nblendPaletteTowardPalette(currentPalette, targetPalette, maxChanges); | |
static uint8_t startIndex = 0; | |
startIndex = startIndex + 1; /* motion speed */ | |
FillLEDsFromPaletteColors(startIndex); | |
FastLED.show(); | |
FastLED.delay(1000 / UPDATES_PER_SECOND); | |
if (Serial.available() > 0) { | |
// read the incoming byte: | |
char serialChar = Serial.read(); | |
Serial.print(serialChar); | |
switch(serialChar) { | |
case 'r': | |
targetPalette = palette_red; | |
SNOWFALL = true; | |
break; | |
case 'g': | |
targetPalette = palette_green; | |
SNOWFALL = true; | |
break; | |
case 'b': | |
targetPalette = palette_blue; | |
SNOWFALL = true; | |
break; | |
case 'y': | |
targetPalette = palette_yellow; | |
SNOWFALL = true; | |
break; | |
case 'p': | |
targetPalette = palette_purple; | |
SNOWFALL = true; | |
break; | |
case 'o': | |
targetPalette = palette_orange; | |
SNOWFALL = true; | |
break; | |
case 'q': | |
targetPalette = palette_pink; | |
SNOWFALL = true; | |
break; | |
case 't': | |
targetPalette = palette_teal; | |
SNOWFALL = true; | |
break; | |
case 'm': | |
targetPalette = palette_multi; | |
SNOWFALL = true; | |
break; | |
case 'w': | |
targetPalette = palette_cw; | |
SNOWFALL = true; | |
break; | |
case 'x': | |
targetPalette = palette_ww; | |
SNOWFALL = true; | |
break; | |
case 'c': | |
targetPalette = palette_off; | |
SNOWFALL = false; | |
break; | |
case 'a': | |
// TODO random | |
targetPalette = palette_purple; | |
SNOWFALL = true; | |
break; | |
case 'n': | |
targetPalette = palette_multi; | |
SNOWFALL = true; | |
break; | |
} | |
} | |
} | |
void rainbowAll(int delayVal) { | |
for (byte i = 0; i < 255; i++) { | |
setAllHue(i); | |
Serial.println(i); | |
FastLED.delay(delayVal); | |
} | |
} | |
void multiAll() { | |
for (int i = 0; i < NUM_LEDS; i += 8) { | |
setColor(i, g); | |
setColor(i+1, k); | |
setColor(i+2, y); | |
setColor(i+3, t); | |
setColor(i+4, r); | |
setColor(i+5, b); | |
setColor(i+6, o); | |
setColor(i+7, p); | |
} | |
FastLED.show(); | |
} | |
void setAllHue(byte hue) { | |
for (int i = 0; i < NUM_LEDS; i++) { | |
setHue(i, hue); | |
} | |
FastLED.show(); | |
} | |
void setHue(int led, byte hue) { | |
setHSV(led, hue, 255, 255); | |
} | |
void setHSV(int led, byte hue, byte sat, byte val) { | |
if (led < NUM_LEDS) { | |
leds[led] = CHSV(hue, sat, val); | |
} | |
} | |
void setAllColor(CRGB color) { | |
for (int i = 0; i < NUM_LEDS; i++) { | |
setColor(i, color); | |
} | |
FastLED.show(); | |
} | |
void setColor(int led, CRGB color) { | |
if (led < NUM_LEDS) { | |
leds[led] = color; | |
} | |
} | |
void setAllColor(CHSV color) { | |
for (int i = 0; i < NUM_LEDS; i++) { | |
setColor(i, color); | |
} | |
FastLED.show(); | |
} | |
void setColor(int led, CHSV color) { | |
if (led < NUM_LEDS) { | |
leds[led] = color; | |
} | |
} | |
void FillLEDsFromPaletteColors(uint8_t colorIndex) { | |
uint8_t brightness = 255; | |
if (!SNOWFALL) { | |
// Just apply the color palette, no snowfall | |
for( int i = 0; i < NUM_LEDS; i++) { | |
CRGB paletteValue = ColorFromPalette(currentPalette, colorIndex + sin8(i*16), brightness); | |
leds[i] = paletteValue; | |
} | |
} else { | |
// Snowfall overlay | |
// Note this only works with 1 row right now! | |
byte rowsFullOn = 1; // 1 row fading on, rowsFullOn full on, 1 row fading off | |
// Get the current LEDs that should be white | |
int (&rowFadeOff)[2] = verticalMap[currentSnowRow]; | |
int rowFullOn[2] = {0, 0}; | |
for (int i = 0; i < rowsFullOn; i++) { | |
int (&thisRow)[2] = verticalMap[(currentSnowRow + i + 1) % numVerticalRows]; | |
if (i == 0) { | |
// Get initial position | |
rowFullOn[0] = thisRow[0]; | |
} | |
if (i == (rowsFullOn - 1)) { | |
// Get final position | |
rowFullOn[1] = thisRow[1]; | |
} | |
} | |
int (&rowFadeOn)[2] = verticalMap[(currentSnowRow + rowsFullOn + 1) % numVerticalRows]; | |
for( int i = 0; i < NUM_LEDS; i++) { | |
CRGB paletteValue = ColorFromPalette(currentPalette, colorIndex + sin8(i*16), brightness); | |
uint8_t snowBlendVal = (float)currentSnowTimestep / (float)SNOW_SPEED * 255; | |
uint8_t negSnowBlendVal = 255 - snowBlendVal; | |
CRGB snowValue = ColorFromPalette(palette_snow, colorIndex + sin8(i*16), brightness); | |
if (i >= rowFadeOn[0] && i <= rowFadeOn[1]) { | |
leds[i] = nblend(paletteValue, snowValue, snowBlendVal); | |
} else if (i >= rowFadeOff[0] && i <= rowFadeOff[1]) { | |
leds[i] = nblend(paletteValue, snowValue, negSnowBlendVal); | |
} else if (i >= rowFullOn[0] && i <= rowFullOn[1]) { | |
leds[i] = snowValue; | |
} else { | |
leds[i] = paletteValue; | |
} | |
colorIndex += 3; | |
} | |
// Iterate the timestep | |
currentSnowTimestep++; | |
if (currentSnowTimestep > SNOW_SPEED) { | |
currentSnowTimestep = 0; | |
// Reset the snow palette | |
currentSnowPalette = currentPalette; | |
// Iterate the snow row | |
currentSnowRow++; | |
if (currentSnowRow >= numVerticalRows) { | |
currentSnowRow = 0; | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment