LED Straw XMAS Tree

A simple, original and cheap Christmas tree made with LED-illuminated plastic straws that can be controlled over WiFi.

Things used in this project

Hardware components

Arduino MKR1000
Arduino MKR1000
× 1
USB-A to Micro-USB Cable
USB-A to Micro-USB Cable
× 1
LED (generic)
LED (generic)
× 12
Resistor 330 ohm
Resistor 330 ohm
× 12

Software apps and online services

Arduino Web Editor
Arduino Web Editor
Arduino IDE
Arduino IDE

Story

Custom parts and enclosures

KiCad files of MKR1000 LED XMAS tree Shield

– Schematic
– PCB layout

Schematics

Code

The code (more specifically the LED mode) can be modified as you like it and can be optimised.
It should work also with all Arduino WiFi boards/shield.
#include <SPI.h>
#include <WiFi101.h>

char ssid[] = "ssid";   //  your network SSID (name)
char pass[] = "pass";   // your network password
int keyIndex = 0;       // your network key Index number (needed only for WEP)

int status = WL_IDLE_STATUS;
WiFiServer server(80);

// PWM LED pins (from inside to outside the tree)
int red[] = {1,0,8};
int green[] = {4,7,10};
int blue[] = {6,3,5};
int yellow[] = {A3,A4,2};

byte changeMode = 0;   // Mode selected
boolean infoDone = 0;  // Information about current mode

void setup() {
    
    // Initialize LED pins as OUTPUTS
    for(int i = 0; i < 3; i++){
        pinMode(red[i], OUTPUT);
        pinMode(green[i], OUTPUT);
        pinMode(blue[i], OUTPUT);
        pinMode(yellow[i], OUTPUT);
    }
    
    Serial.begin(9600);   // initialize serial communication

    // check for the presence of the shield:
    if (WiFi.status() == WL_NO_SHIELD) {
        Serial.println("WiFi shield not present");
        while (true);   // don't continue
    }
    // attempt to connect to WiFi network:
    while ( status != WL_CONNECTED) {
        Serial.print("Attempting to connect to Network named: ");
        Serial.println(ssid);   // print the network SSID
        status = WiFi.begin(ssid, pass);
        delay(10000);   // wait 10 seconds for connection:
    }
    server.begin();   // start the web server on port 80
    printIPAdress();  // connected, print SSID and IP
    randomSeed(analogRead(A6));
}

void loop() {
    
    WiFiClient client = server.available();   // listen for incoming clients

    if (client) {                       // if you get a client,
        Serial.println("new client");   // print a message out the serial port
        String currentLine = "";        // make a String to hold incoming data from the client
        while (client.connected()) {    // loop while the client's connected
            if (client.available()) {   // if there's bytes to read from the client,
                char c = client.read(); // read a byte, then
                Serial.write(c);        // print it out the serial monitor
                if (c == '\n') {        // if the byte is a newline character
                    // if the current line is blank, you got two newline characters in a row.
                    // that's the end of the client HTTP request, so send a response:
                    if (currentLine.length() == 0) {
                        // HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK)
                        // and a content-type so the client knows what's coming, then a blank line:
                        client.println("HTTP/1.1 200 OK");
                        client.println("Content-type:text/html");
                        client.println();
                        // the content of the HTTP response follows the header:
                        client.print("Click <a href=\"/1\">here</a> to turn mode 1 on (red/blue), (10 min.).<br>");
                        client.print("Click <a href=\"/2\">here</a> to turn mode 2 on (green/yellow), (10 min.).<br>");
                        client.print("Click <a href=\"/3\">here</a> to turn mode 3 on (random), (10-20 min.).<br>");
                        client.print("Click <a href=\"/4\">here</a> to turn mode 4 on (colors), (30 min.).<br>");
                        client.print("Click <a href=\"/0\">here</a> to disconnect.<br>");
                        client.print("Wait until mode X has finished to start a new mode or disconnect.<br>");
                        switch (changeMode){
                            case 1:
                                client.print("(playing mode 1, wait 10 min.).<br>"); infoDone = 1; break;
                            case 2:
                                client.print("(playing mode 2, wait 10 min.).<br>"); infoDone = 1; break;
                            case 3:
                                client.print("(playing mode 3, wait 15 min. aprox.).<br>"); infoDone = 1; break;
                            case 4:
                                client.print("(playing mode 4, wait 30 min.).<br>"); infoDone = 1; break;
                            default:
                                client.print("(not playing any mode)<br>"); infoDone = 0; break;
                        }
                        // The HTTP response ends with another blank line:
                        client.println();
                        // break out of the while loop:
                        break;
                    }
                    else { // if you got a newline, then clear currentLine:
                        currentLine = "";
                    }
                }
                else if (c != '\r') {  // if you got anything else but a carriage return character,
                    currentLine += c;  // add it to the end of the currentLine
                }
                // Check to see what the client request was, and change mode:
                if (currentLine.endsWith("GET /1")) {
                    changeMode = 1;
                }
                if (currentLine.endsWith("GET /2")) {
                    changeMode = 2;
                }
                if (currentLine.endsWith("GET /3")) {
                    changeMode = 3;
                }
                if (currentLine.endsWith("GET /4")) {
                    changeMode = 4;
                }
                if (currentLine.endsWith("GET /0")) {
                    for(int i = 0; i < 3; i++){
                        digitalWrite(red[i], LOW);
                        digitalWrite(green[i], LOW);
                        digitalWrite(blue[i], LOW);
                        digitalWrite(yellow[i], LOW);
                    }
                    break;
                }
                // First we print mode info, then we activate the specific mode
                if(infoDone == 1){
                    switch(changeMode){
                        case 1: mode1(); infoDone = 0; changeMode = 0; break;
                        case 2: mode2(); infoDone = 0; changeMode = 0; break;
                        case 3: mode3(); infoDone = 0; changeMode = 0; break;
                        case 4: mode4(); infoDone = 0; changeMode = 0; break;
                        default: break;
                    }
                }
            }
        }
        // close the connection:
        client.stop();
        Serial.println("client disonnected");
    }

}

/* Mode RED/BLUE (10 min. duration). */
void mode1() {
    for(int t = 0; t < 100; t++){
        for(int i = 0; i < 3; i++){
            fade('r',i,2);
            fade('b',i,2);
        }
    }
}

/* Mode GREEN/YELLOW (10 min. duration). */
void mode2() {
    for(int t = 0; t < 100; t++){
        for(int i = 0; i < 3; i++){
            fade('g',i,2);
            fade('y',i,2);
        }
    }
}

/* Mode RANDOM (10 to 20 min. duration). */
void mode3() {
    for(int t = 0; t < 1200; t++){
        byte rand0 = random(4); // Color: 0, 1, 2 or 3
        byte rand1 = random(3); // Num LED: 0, 1 or 2
        byte rand2 = random(1,3); // Time: 1 to 2
        switch(rand0){
            case 0:
                fade('r',rand1,rand2); break;
            case 1:
                fade('g',rand1,rand2); break;
            case 2:
                fade('b',rand1,rand2); break;
            case 3:
                fade('y',rand1,rand2); break;
        }
    }
}

/* Mode COLORS (30 min. duration). */
void mode4() {
    // (T = 1.2s, loop time = T*500 = 10 min.)
    for(int t = 0; t < 500; t++){
        for(int i = 0; i < 3; i++){
            digitalWrite(red[i], HIGH); delay(50);
            digitalWrite(red[i], LOW); delay(50);
            digitalWrite(green[i], HIGH); delay(50);
            digitalWrite(green[i], LOW); delay(50);
            digitalWrite(blue[i], HIGH); delay(50);
            digitalWrite(blue[i], LOW); delay(50);
            digitalWrite(yellow[i], HIGH); delay(50);
            digitalWrite(yellow[i], LOW); delay(50);
        }
    }
    // (T = 1.5s, loop time = T*400 = 10 min.)
    for(int t = 0; t < 400; t++){
        for(int i = 0; i < 3; i++){
            for(int j = 0; j <= 250; j++){
                analogWrite(red[i],j);
                analogWrite(green[i],j);
                analogWrite(blue[i],j);
                analogWrite(yellow[i],j);
                delay(1);
            }
            for(int j = 250; j >= 0; j--){
                analogWrite(red[i], j);
                analogWrite(green[i], j);
                analogWrite(blue[i], j);
                analogWrite(yellow[i], j);
                delay(1);
            } 
        }
    }
    // (T = 2.5s, loop time = T*240 = 10 min.)
    for(int t = 0; t < 240; t++){
        for(int j = 0; j <= 250; j++){
            analogWrite(red[0], j);
            analogWrite(red[1], j);
            analogWrite(red[2], j);
            delay(1);
        }
        for(int j = 250; j >= 0; j--){
            analogWrite(red[0], j);
            analogWrite(red[1], j);
            analogWrite(red[2], j);
            delay(1);
        }
        for(int j = 0; j <= 250; j++){
            analogWrite(green[0], j);
            analogWrite(green[1], j);
            analogWrite(green[2], j);
            delay(1);
        }
        for(int j = 250; j >= 0; j--){
            analogWrite(green[0], j);
            analogWrite(green[1], j);
            analogWrite(green[2], j);
            delay(1);
        }
        for(int j = 0; j <= 250; j++){
            analogWrite(blue[0], j);
            analogWrite(blue[1], j);
            analogWrite(blue[2], j);
            delay(1);
        }
        for(int j = 250; j >= 0; j--){
            analogWrite(blue[0], j);
            analogWrite(blue[1], j);
            analogWrite(blue[2], j);
            delay(1);
        }
        for(int j = 0; j <= 250; j++){
            analogWrite(yellow[0], j);
            analogWrite(yellow[1], j);
            analogWrite(yellow[2], j);
            delay(1);
        }
        for(int j = 250; j >= 0; j--){
            analogWrite(yellow[0], j);
            analogWrite(yellow[1], j);
            analogWrite(yellow[2], j);
            delay(1);
        }
        for(int j = 0; j <= 250; j++){
            analogWrite(red[0], j);
            analogWrite(red[1], j);
            analogWrite(red[2], j);
            analogWrite(green[0], j);
            analogWrite(green[1], j);
            analogWrite(green[2], j);
            analogWrite(blue[0], j);
            analogWrite(blue[1], j);
            analogWrite(blue[2], j);
            analogWrite(yellow[0], j);
            analogWrite(yellow[1], j);
            analogWrite(yellow[2], j);
            delay(1);
        }
        for(int j = 250; j >= 0; j--){
            analogWrite(red[0], j);
            analogWrite(red[1], j);
            analogWrite(red[2], j);
            analogWrite(green[0], j);
            analogWrite(green[1], j);
            analogWrite(green[2], j);
            analogWrite(blue[0], j);
            analogWrite(blue[1], j);
            analogWrite(blue[2], j);
            analogWrite(yellow[0], j);
            analogWrite(yellow[1], j);
            analogWrite(yellow[2], j);
            delay(1);
        }
    }
}

/* Creates a fading effect (analogWrite, from 0 to 250)
   at the LED specified (color, number, time), for
   example: fade('r', 0, 5); fades red LED number 0 (of 2),
   with 5ms between analog changes.
*/
void fade(char color, byte num, byte t) {
    
    for(int i = 0; i <= 250; i++){
        if(color == 'r'){ analogWrite(red[num], i); }
        else if(color == 'g'){ analogWrite(green[num], i); }
        else if(color == 'b'){ analogWrite(blue[num], i); }
        else if(color == 'y'){ analogWrite(yellow[num], i); }
        delay(t);
    }
    for(int i = 250; i >= 0; i--){
        if(color == 'r'){ analogWrite(red[num], i); }
        else if(color == 'g'){ analogWrite(green[num], i); }
        else if(color == 'b'){ analogWrite(blue[num], i); }
        else if(color == 'y'){ analogWrite(yellow[num], i); }
        delay(t);
    } 
}

/* Prints WiFi SSID where we connected and the local
   IP adress where we can control the LED's.
*/
void printIPAdress() {
    // print the SSID of the network you're attached to:
    Serial.print("SSID: ");
    Serial.println(WiFi.SSID());
    // print your MKR1000 WiFi IP address:
    IPAddress ip = WiFi.localIP();
    Serial.print("IP Address: ");
    Serial.println(ip);
    // IP adress:
    Serial.print("Go to to http://");
    Serial.println(ip);
    Serial.print(" to start straw tree lights!");
}

About The Author

Ibrar Ayyub

I am an experienced technical writer holding a Master's degree in computer science from BZU Multan, Pakistan University. With a background spanning various industries, particularly in home automation and engineering, I have honed my skills in crafting clear and concise content. Proficient in leveraging infographics and diagrams, I strive to simplify complex concepts for readers. My strength lies in thorough research and presenting information in a structured and logical format.

Follow Us:
LinkedinTwitter

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top