
RGB WEDDING DECOR
BACKGROUND
With planning a wedding being as hectic as it is (especially a South Asian one), the thought may come to mind as to why I would want to make my own decor.
My brother got married a couple of months before I did but was too busy finishing up his residency to plan his Valima (a party that is thrown by the groom's party after the wedding), so I took over. The problem was that any decor that I liked and thought was elegant was not really for him; he said that he would be happy if we just 3D printed some boxes and put RGB LED strips in them... I refused to give him that, but then made it my mission to use my engineering background to make some truly elegant and unique wedding centerpieces that my LED loving brother would be happy with it. That was when the fun began :)
DECORATIONS PIECES CREATED
RGB Wedding Centerpieces Part 1:
For this piece, I went off of my brother's idea of having a 3D printed box and instead found some cubical mirror vases. To fulfill my brother's request of a centerpiece with RGB LEDs, I put a strip of LEDs along the inner wall of the vase, near the top and programmed the LEDs to have a fade sequence from white to red throughout the event.
There were two fun, surprise elements:
When my brother and his wife entered the reception hall, I had all of the centerpieces turn off and had a friend stand on the other side of the room and turn on groups of the centerpieces in sequence in line with them as they and walked down the aisle
We served dinner buffet-style and informed guests that it was their table's turn to go get dinner by turning their lights on in a "rainbow chase" sequence. We like to think this made the wait a little more fun while also keeping things organized :)
To add some elegance, I purchased some Manzanita branches in bulk and spray painted them rose gold, with some red ombre glitter fading into the gold from the base to the top. I hung crystal garlands with orchids at the end and dispersed those throughout
RGB Wedding Sign:
I was riding home on the train from work trying to figure out what sort of wedding welcome sign to get for my brother's event and how I could make it unique. I then came up with the idea of getting an acrylic sign laser-etched and aligning a strip of RGB LEDs with the bottom end of it so that the light could reflect through and highlight the etched portion. I found one Etsy store that made laser etched signs on a type of acrylic that had the properties of total internal reflection (lucite) and started from there. The circuitry and code was pretty much the same as the centerpieces (the color sequence was different as I wanted it to go through the the entire spectrum), so the main difference was in how the assembly happened. This was such a success that I made one for myself and was requested by my best friend to make one for her wedding as well
RGB Wedding Centerpieces Part 2:
Inspired by the success of my brother's event decor, I wanted to make some unique (and elegant) centerpieces of my own, so I came up with a different design, but similar concept as his. I instead had a little orchid candle holder at the base of the centerpiece that housed an RGB LED strip and lit up according to my wedding color scheme. I also had the LED effect set to rainbow as tables were called for dinner
RGB Tiki Torches:
One of our wedding events took place in a tent outside and I wanted to make sure that the path to the tent was lit up for the guests throughout the night. Solution? RGB LEDs of course! Since I was on my RGB LED kick, I wondered what would happen if we made some color-changing tiki torches. Again, the code was pretty much the same, but there were some differences in the assembly
TECHNICAL DETAILS
The code from the centerpiece is below as an example- more details to come:
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>
#include <WiFiUdp.h>
#include <ArduinoOTA.h>
#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
#include <avr/power.h>
#endif
//DEFINE WIFI LOGIN + IP ADDRESS
#ifndef STASSID
#define STASSID "lightcontrol" //Insert your WiFi Network Name Here
#define STAPSK "lightcontrol" //Insert your WiFi Password Here
#endif
IPAddress ip(192, 168, 1, 116); //Insert desired IP here
IPAddress gateway(192, 168, 1, 1);
IPAddress subnet(255, 255, 255, 0);
const char* ssid = STASSID;
const char* password = STAPSK;
//DEFINE NEOPIXEL OBJECT
#define PIN 4 //PIN you are using (although its PIN 4 it maps to D2 on the D1 Mini)
#define NUMstrip 30 //Number of strip
Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUMstrip, PIN, NEO_GRB + NEO_KHZ800);
//Initiating Other Variables
int color_R = 0;
int color_G = 0;
int color_B = 0;
int change_made = 0;
int breathe = 20;
int chase = 50;
int meteor = 30;
int heart = 60;
int delayval = 50;
int main = 150;
int circle = 50;
int brightness = 100;
int tmpR, tmpG, tmpB;
int extra = 14;
int speed; int color_R1; int color_G1; int color_B1; int d_R; int d_G; int d_B;
uint32_t color; uint32_t color2;
double redVal; double greenVal; double blueVal;
String curr_comm = "main";
ESP8266WebServer server(80);
void handleRoot() {
server.send(200, "text/plain", " Available for Commands" + WiFi.localIP());
}
void handleNotFound() {
String message = "File Not Found\n\n";
message += "URI: ";
message += server.uri();
message += "\nMethod: ";
message += (server.method() == HTTP_GET) ? "GET" : "POST";
message += "\nArguments: ";
message += server.args();
message += "\n";
for (uint8_t i = 0; i < server.args(); i++) {
message += " " + server.argName(i) + ": " + server.arg(i) + "\n";
}
server.send(404, "text/plain", message);
}
void setup(void) {
strip.begin();
RGB(20, 20, 20);
Serial.begin(115200);
WiFi.mode(WIFI_STA);
WiFi.config(ip, gateway, subnet);
RGB(0, 0, 0);
WiFi.begin(ssid, password);
Serial.println("");
// Wait for connection
while (WiFi.status() != WL_CONNECTED) {
fade2other(100, 100, 100, main);
if (WiFi.status() == WL_CONNECTED) break;
fade2other(255, 80, 80, main);
if (WiFi.status() == WL_CONNECTED) break;
fade2other(255, 0, 250, main);
if (WiFi.status() == WL_CONNECTED) break;
Serial.print(".");
}
Serial.println("");
Serial.print("Connected to ");
Serial.println(ssid);
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
if (MDNS.begin("esp8266")) {
Serial.println("MDNS responder started");
}
server.on("/", handleRoot);
server.on("/inline", []() {
server.send(200, "text/plain", "Hello!");
});
server.onNotFound(handleNotFound);
server.begin();
Serial.println("HTTP server started");
// Web Management Cases
server.on("/switch", handle_switch);
//Arduino OTA Code
ArduinoOTA.onStart([]() {
String type;
if (ArduinoOTA.getCommand() == U_FLASH) {
type = "sketch";
} else { // U_SPIFFS
type = "filesystem";
}
RGB(0, 0, 20);
// NOTE: if updating SPIFFS this would be the place to unmount SPIFFS using SPIFFS.end()
Serial.println("Start updating " + type);
});
ArduinoOTA.onEnd([]() {
Serial.println("\nEnd");
});
ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
});
ArduinoOTA.onError([](ota_error_t error) {
Serial.printf("Error[%u]: ", error);
if (error == OTA_AUTH_ERROR) {
Serial.println("Auth Failed");
} else if (error == OTA_BEGIN_ERROR) {
Serial.println("Begin Failed");
} else if (error == OTA_CONNECT_ERROR) {
Serial.println("Connect Failed");
} else if (error == OTA_RECEIVE_ERROR) {
Serial.println("Receive Failed");
} else if (error == OTA_END_ERROR) {
Serial.println("End Failed");
}
});
ArduinoOTA.begin();
Serial.println("Ready");
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
//NeoPixel Initiation
RGB(20, 20, 20);
delay(500);
RGB(0, 0, 0);
delay(500);
RGB(20, 20, 20);
delay(500);
RGB(0, 0, 0);
change_made = 1;
}
void loop(void) {
check_for_updates();
handle_current();
}
void check_for_updates() {
server.handleClient();
ArduinoOTA.handle();
}
void handle_switch() { //This is the main sever handling segment in this example
change_made = 1; //to allow for break out of loops (see below)
delay(0);
yield();
if (server.hasArg("R") && server.hasArg("G") && server.hasArg("B")) {
color_R = server.arg("R").toInt();
color_G = server.arg("G").toInt();
color_B = server.arg("B").toInt();
if (server.hasArg("breathe")) //Breathing Effect
{
breathe = server.arg("breathe").toInt();
curr_comm = "breatheRGB";
// breatheRGB(color_R, color_G, color_B, breathe);
}
else if (server.hasArg("chase")) //TheaterChase Effect
{
chase = server.arg("chase").toInt();
curr_comm = "chaseRGB";
// chaseRGB(color_R, color_G, color_B, chase);
}
else if (server.hasArg("meteor")) //Meteor Effect
{
meteor = server.arg("meteor").toInt();
curr_comm = "meteorRGB";
// meteorRain(color_R, color_G, color_B, 10, 64, false, meteor);
}
else if (server.hasArg("circle")) //Circle Effect
{
circle = server.arg("circle").toInt();
curr_comm = "circleRGB";
// circleRGB(color_R, color_G, color_B, circle);
}
else if (server.hasArg("heart")) //Heart Beat
{
heart = server.arg("heart").toInt();
curr_comm = "heartRGB";
// heartRGB(color_R, color_G, color_B, heart);
}
else
{ //Basic RGB
curr_comm = "RGB";
fade2other(color_R, color_G, color_B, 50);
}
}
if (server.hasArg("R1")) {
delayval = server.arg("R1").toInt();
curr_comm = "rainbow1";
// rainbow(delayval); //1st rainbow effect
}
if (server.hasArg("R2")) {
delayval = server.arg("R2").toInt();
curr_comm = "rainbowchase";
// rainbowCycle(delayval); //2nd rainbow effect
}
if (server.hasArg("bright")) {
brightness = server.arg("bright").toInt();
server.send(200, "text/plain", "Brightness Changed!");
// changeBrightness(brightness); //adjust brightness
}
if (server.hasArg("main")) {
main = server.arg("main").toInt();
curr_comm = "main";
// main_effect(main);
}
if (server.hasArg("off")) {
server.send(200, "text/plain", "Off");
curr_comm = "off";
}
delay(0);
yield();
return;
}
void handle_current() {
// Serial.println("Handling Command");
if (change_made == 1)
{
Serial.println("Change Made");
if (curr_comm == "RGB") fade2other(color_R, color_G, color_B, 50);
if (curr_comm == "breatheRGB") breatheRGB(color_R, color_G, color_B, breathe);
if (curr_comm == "chaseRGB") chaseRGB(color_R, color_G, color_B, chase);
if (curr_comm == "circleRGB") circleRGB(color_R, color_G, color_B, circle);
if (curr_comm == "meteorRGB") meteorRain(color_R, color_G, color_B, 10, 64, false, meteor);
if (curr_comm == "main") main_effect(main);
if (curr_comm == "heartRGB") heartRGB(color_R, color_G, color_B, heart);
if (curr_comm == "rainbow1") rainbow(delayval);
if (curr_comm == "rainbowchase") rainbowCycle(delayval);
if (curr_comm == "off") chase2color(0, 0, 0);
}
check_for_updates();
}
void rainbowCycle(uint8_t wait) { //2nd rainbow effect
server.send(200, "text/plain", "Rainbow 2!");
change_made = 0;
uint16_t i, j;
while (curr_comm == "rainbowchase") {
for (j = 0; j < 256 * 5; j++) { // 5 cycles of all colors on wheel
for (i = 0; i < strip.numPixels(); i++) {
strip.setPixelColor(i, Wheel(((i * 256 / strip.numPixels()) + j) & 255));
}
strip.show();
check_for_updates();
if (change_made == 1) return;
delay(wait);
}
}
}
void rainbow(uint8_t wait) { //1st rainbow effect
server.send(200, "text/plain", "Rainbow 1!");
change_made = 0;
uint16_t i, j;
while (curr_comm == "rainbow1") {
for (j = 0; j < 256; j++) {
for (i = 0; i < strip.numPixels(); i++) {
strip.setPixelColor(i, Wheel((i + j) & 255));
}
strip.show();
check_for_updates();
if (change_made == 1) return;
delay(wait);
}
}
}
void changeBrightness(uint8_t brightness) {
strip.setBrightness(brightness);
}
uint32_t Wheel(byte WheelPos) { //this is used for one of the rainbow effects
WheelPos = 255 - WheelPos;
if (WheelPos < 85) {
return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
}
if (WheelPos < 170) {
WheelPos -= 85;
return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
}
WheelPos -= 170;
return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
}
void main_effect(int main)
{
server.send(200, "text/plain", "Main Effect");
change_made = 0;
while (curr_comm == "main")
{
check_for_updates();
if (change_made == 1) return;
Serial.println("Running Main Effect");
fade2other(100, 100, 80, 100);
if (change_made == 1) return;
fade2other(255, 40, 40, 100);
if (change_made == 1) return;
fade2other(200, 20, 200, 100);
if (change_made == 1) return;
}
}
void heartRGB(int color_R, int color_G, int color_B, int heartRate) {
int time_beat = 60000 / heartRate;
change_made = 0;
int interval = time_beat / 3;
curr_comm = "heartRGB";
server.send(200, "text/plain", "Heart Beat");
RGB(0, 0, 0);
while (curr_comm == "heartRGB")
{
rapidblink(color_R, color_G, color_B);
check_for_updates();
delay(interval);
Serial.println("Systole");
rapidblink(color_R, color_G, color_B);
check_for_updates;
delay(interval * 2);
Serial.println("Diastole");
check_for_updates;
if (change_made == 1) return;
}
}
void rapidblink(int color_R, int color_G, int color_B) {
RGB(color_R * 0.30, color_G * 0.30, color_B * 0.30);
delay(20);
RGB(color_R * 0.60, color_G * 0.60, color_B * 0.60);
delay(20);
RGB(color_R, color_G, color_B);
delay(20);
RGB(color_R * 0.60, color_G * 0.60, color_B * 0.60);
delay(20);
RGB(color_R * 0.30, color_G * 0.30, color_B * 0.30);
delay(20);
RGB(color_R * 0.05, color_G * 0.05, color_B * 0.05);
}
void breatheRGB(int color_R, int color_G, int color_B, int breathe_speed) //Breathe RGB Effect
{
change_made = 0;
server.send(200, "text/plain", "Breathing RGB");
fade2other(color_R, color_B, color_B, 50);
fade2other(0, 0, 0, 50);
double numb_steps = 200;
while (curr_comm == "breatheRGB")
{
for (double i = 0; i < numb_steps; i++)
{
double perc = sin((i / numb_steps) * PI);
long redVal = round(color_R * perc);
long greenVal = round(color_G * perc);
long blueVal = round(color_B * perc);
for (int j = 0; j < strip.numPixels(); j++)
{
strip.setPixelColor(j, strip.Color(redVal, greenVal, blueVal));
}
strip.show();
check_for_updates();
if (change_made == 1) return;
delay(breathe_speed);
}
RGB(0, 0, 0);
delay(breathe_speed * 10);
}
}
void circleRGB(int color_R, int color_G, int color_B, int speed) {
server.send(200, "text/plain", "RGB Circle");
Serial.println("Circle RGB Started");
change_made = 0;
fade2other(0, 0, 0, 50);
while (curr_comm == "circleRGB")
{
Serial.println("Circle RGB Running");
for (int i = 0; i < strip.numPixels(); i++)
{
strip.setPixelColor(i, color_R, color_G, color_B);
for (int s = 1; s < extra + 1; s++)
{
tmpR = (color_R * (extra - s)) / extra; // Multiply first to avoid truncation errors
tmpG = (color_G * (extra - s)) / extra;
tmpB = (color_B * (extra - s)) / extra;
strip.setPixelColor((i + s) % strip.numPixels(), tmpR, tmpG, tmpB);
strip.setPixelColor((i + strip.numPixels() - s) % strip.numPixels(), tmpR, tmpG, tmpB);
}
strip.show();
check_for_updates();
if (change_made == 1) return;
delay(speed);
}
}
}
void chaseRGB(int color_R, int color_G, int color_B, int chase_speed) //Chase RGB Effect
{
server.send(200, "text/plain", "Chase RGB");
change_made = 0;
fade2other(0, 0, 0, 50);
while (curr_comm == "chaseRGB")
{
for (int q = 0; q < 3; q++) {
for (int i = 0; i < strip.numPixels(); i = i + 3) {
strip.setPixelColor(i + q, color_R, color_G, color_B); //turn every third pixel on
}
strip.show();
check_for_updates();
if (change_made == 1) return;
delay(chase_speed);
for (int i = 0; i < strip.numPixels(); i = i + 3) {
strip.setPixelColor(i + q, 0, 0, 0); //turn every third pixel off
}
}
}
}
//Meteor RGB Effect
void meteorRain(byte red, byte green, byte blue, byte meteorSize, byte meteorTrailDecay, boolean meteorRandomDecay, int SpeedDelay) {
change_made = 0;
fade2other(0, 0, 0, 50);
while (curr_comm == "meteorRGB")
{
for (int i = 0; i < strip.numPixels() + strip.numPixels(); i++) {
// fade brightness all LEDs one step
for (int j = 0; j < strip.numPixels(); j++) {
if ( (!meteorRandomDecay) || (random(10) > 5) ) {
fadeToBlack(j, meteorTrailDecay );
}
}
// draw meteor
for (int j = 0; j < meteorSize; j++) {
if ( ( i - j < strip.numPixels()) && (i - j >= 0) ) {
strip.setPixelColor(i - j, red, green, blue);
}
}
strip.show();
check_for_updates();
delay(SpeedDelay);
}
if (change_made == 1) return;
}
}
void fadeToBlack(int ledNo, byte fadeValue) {
#ifdef ADAFRUIT_NEOPIXEL_H
// NeoPixel
uint32_t oldColor;
uint8_t r, g, b;
int value;
oldColor = strip.getPixelColor(ledNo);
// r = (oldColor & 0x00ff0000UL) >> 16;
// g = (oldColor & 0x0000ff00UL) >> 8;
// b = (oldColor & 0x000000ffUL);
r = (oldColor >> 16) & 255;
g = (oldColor >> 8) & 255;
b = oldColor & 255;
r = (r <= 10) ? 0 : (int) r - (r * fadeValue / 256);
g = (g <= 10) ? 0 : (int) g - (g * fadeValue / 256);
b = (b <= 10) ? 0 : (int) b - (b * fadeValue / 256);
strip.setPixelColor(ledNo, r, g, b);
#endif
#ifndef ADAFRUIT_NEOPIXEL_H
// FastLED
leds[ledNo].fadeToBlackBy( fadeValue );
#endif
}
void RGB(int color_R, int color_G, int color_B) {
for (int i = 0; i < strip.numPixels(); i++) {
strip.setPixelColor(i, strip.Color(color_R, color_G, color_B));
}
strip.show();
}
void chase2color(int color_R, int color_G, int color_B) {
change_made = 0;
for (int j = 0; j < strip.numPixels(); j++) {
strip.setPixelColor(j, color_R, color_G, color_B);
strip.show();
delay(10);
}
}
void fade2other(int color_R2, int color_G2, int color_B2, double numb_steps) {
server.send(200, "text/plain", "Fading 2 Other");
Serial.println("Fading 2 Other");
change_made = 0;
// double numb_steps = 50;
speed = 20;
color = strip.getPixelColor(1);
color2 = strip.getPixelColor(5);
color_R1 = (color >> 16) & 255;
color_G1 = (color >> 8) & 255;
color_B1 = color & 255;
if (color != color2) {
chase2color(color_R1, color_G1, color_B1);
}
else {
RGB(color_R1, color_G1, color_B1);
}
check_for_updates();
if (change_made == 1) return;
d_R = color_R2 - color_R1;
d_G = color_G2 - color_G1;
d_B = color_B2 - color_B1;
d_R = abs(d_R);
d_G = abs(d_G);
d_B = abs(d_B);
redVal = color_R1;
greenVal = color_G1;
blueVal = color_B1;
for (double i = 1; i <= numb_steps; i++) {
// Serial.println("Calculating and doing fade");
if (color_R2 > color_R1) {
redVal = round(color_R1 + ((i / numb_steps) * d_R));
}
else if (color_R2 < color_R1) {
redVal = round(color_R1 - ((i / numb_steps) * d_R));
}
else redVal = color_R1;
if (color_G2 > color_G1) {
greenVal = round(color_G1 + ((i / numb_steps) * d_G));
}
else if (color_G2 < color_G1) {
greenVal = round(color_G1 - ((i / numb_steps) * d_G));
}
else greenVal = color_G1;
if (color_B2 > color_B1) {
blueVal = round(color_B1 + ((i / numb_steps) * d_B));
}
else if (color_B2 < color_B1) {
blueVal = round(color_B1 - ((i / numb_steps) * d_B));
}
else blueVal = color_B1;
check_for_updates();
if (change_made == 1) return;
RGB(redVal, greenVal, blueVal);
delay(speed);
}
RGB(color_R2, color_G2, color_B2);
check_for_updates();
return;
}
FINAL THOUGHTS
Pictures of these pieces can be seen below. After my brother's wedding event and my multiple wedding events, our decorator loved the pieces so much that she purchased them from us, so the pieces will live on :)


