Project tutorial
Christmas Tree with 150 Digital LED Pixels

Christmas Tree with 150 Digital LED Pixels © GPL3+

Arduino-controlled Christmas Tree lit by 150 digital RGB LED pixels. The RTC chip switches on and off the tree at the planned hours!

  • 5,185 views
  • 0 comments
  • 11 respects

Components and supplies

Christmas Tree
×1
Ardgen mega
Arduino Mega 2560 & Genuino Mega 2560
For this project, MEGA is better than UNO, because it has more memory.
×1
12mm Diffused Thin Digital RGB LED Pixels WS2801 (Strand of 50)
I saw them here: https://www.adafruit.com/product/322 But I bought them here: https://4tronix.co.uk/store/index.php?rt=product/product&product_id=214
×3
Adafruit Real Time Clock (RTC) DS3231
I bought this on Amazon. My chip is not made by Adafruit.
×1
Adafruit DC Power supply - 5V 10A
×1
Adafruit Female DC Power adapter - 2.1mm jack to screw terminal block
×1
Half-size Breadboard
×1
Jumper Wires
×1
Electronic Wire (20AWG)
×1
Insulating tape
×1
(External) Junction Box
Choose the box you prefer to put in the Arduino and the Power Supply.
×1

Necessary tools and machines

09507 01
Soldering iron (generic)
You can also connect the wires without soldering them...

Apps and online services

About this project

0. The Project

One day I decided to change the light bulbs on my Christmas Tree to customize the colors of the bulbs and create my own animations!

On the Adafruit website, I have found out that the 12mm diffused thin digital RGB LED pixels WS2801 are addressable (you can tell to every single LED what to do and when!) and can be controlled by an Arduino MEGA 2560 rev3 board (I have bought the LEDs from a reseller).

I've added to my project a Real Time Clock (RTC) chip, in order to give to Arduino the real time. The strand is always plugged to the power outlet, but the tree is on just from 5 pm to 8 am!

Adafruit has helped me make my project with the dedicated WS2801 LEDs tutorial! Check it out for further details and more accurate information!

If you are using different models of LEDs, please refer to their guide/instruction for wiring and coding. If they are compatible with FastLED, the code will need minor changes!

1. Assembling and wiring

I suggest you to test the project before putting the LEDs on the tree!

Connect the strands of LEDs to each other with their connectors. The 4 inputs on the strip should be:

  • RED -> 5V
  • WHITE -> GND
  • BLUE -> DATA
  • GREEN -> CLOCK

Connect the strand DATA pin to Arduino PIN 2; and CLOCK pin to Arduino PIN 3. (Note: data and clock color might be inverted, look for the mark on every led chip).

The Real Time Clock (RTC) DS3231 allows Arduino to get the real time, because the on-board chips are not accurate enough to keep the time for hours and days. Connect the SDA pin to Arduino PIN 20 and SCL pin to Arduino PIN 21.

2. Power

The 5V 10A power supply is adapted for 150 LEDs. Each WS2801 LED requests 60mA, so 50 LEDs need 3A; 150 LEDs need 9A.

Connect the power supply 2.1mm jack to the female adapter ("2.1mm to screw/terminal block"). Connect 6 wires to the adapter (OR USE THE BREADBOARD TO SPLIT THE POWER in an easier way):

  • 2 (1 5V and 1 GND) for the first 75 LEDs -> between LEDs 50 and 51, there should be a pair of power wires. Otherwise, connect them in the strand connectors;
  • 2 (1 5V and 1 GND) for the last 75 LEDs -> plug between LEDs 100 and 101;
  • 2 (1 5V and 1 GND) to the BREADBOARD, to power up Arduino and RTC.

Note: Be sure to connect the (+) positive pole to 5V and the (-) negative pole to GND. Wires can be soldered, especially in case of permanent/outdoor projects. You can use a Header Pin Housing Kit to create your own jumper wires! Clock and data wires must be connected only at the beginning of the strand. Power should be split throughout the whole strand in at least 2 points. In this way each LED has enough power!

With the BREADBOARD, connect the power wires to other jumper wires to Arduino (5V pin and GND pin) and to the RTC (5V and GND pins).

3. Code

To make the code running properly, you have to install on your computer the following libraries:

  • FastLED by FastLED (click Clone or download then Download ZIP)

3.1 Setting the time

Upload on Arduino the Example file TimeRTCSet (File -> Examples -> Time -> TimeRTCSet) or dowload and run the RTC_set.ino (see the Code section). Then open the Serial Monitor (Tools -> Serial monitor). It will copy your computer's time on the RTC. You need do this process just once.

Note: There will be a little error of a pair of seconds in the RTC time due to the synchronization between the PC and the board. Also, I suggest you to use this code, it's the easiest that I've found on the Internet. Instead you can use the examples that are included in the libraries.

You can check the time stored by running the RTC_read.ino (dowload it at the end of this page).

3.2 Coding the animations

Now you can download the file Christmas_tree.ino (this is the main code) and upload it on Arduino. It is ready to use, but you can customize it! Colors are set via named HTML web colors.

There are 3 animations (I think the best is the Adafruit's rainbow). I have created the other two animations: every 300 ms (= 0,3 s) an LED on the tree changes its color to red, orange, yellow, green, blue, etc. I prefer a tree with quite slow animations; every second that you watch the Christmas Tree, some lights have different colors than before, but you are not blinded by flashing lights.

The code will switch on the LEDs at 5 pm and it will switch them off at 8 am in the morning. During the day, Arduino will check the time every 10 minutes to see if it is 5 o' clock! (It is the best solution to bypass the lack of a relay).

I wrote an updated version of the code, Christmas_tree_UPDATED.ino. There are the same animations and functions, but colors are more calibrated because they are set via the HSV method (Hue, Saturation, Value). If you are not an expert user, check out the FastLED Pixel Reference guide!

4. Ready to be lit!

The strand is now ready to be put on the tree! And your Christmas tree is ready!

If you have enjoyed this tutorial, please post in the comments photos of your project! Feedback and improvement suggestions are welcome!

5. Next...

I am currently adding 50 LEDs to reach the 200 (I have to add a second power supply though).

I am also working on the code to make the tree look better; I am correcting the color encoding (to make them more calibrated) and adding new animations!

Latest major update of this tutorial: 31 October 2017

DISCLAIMER: I am NOT responsible for any damage to things or people that might occur while replicating this project. This script is a simplified recap of what I have created. If you are not sure of what you are doing, please leave a comment below or look for competent help on the web.

Code

Christmas_treeArduino
This is the MAIN CODE of your project. It is ready-to-use!
/*  ================= CHRISTMAS_TREE ===================
 *  Code for 150 WS2801 Digital RGB leds.
 *  Written by MARTINO GHISLENI.
 *  Based on the FASTLED library.
 *  September 2016 - September 2017
 *
 *  NOTE: COLORS ARE SET VIA THE NAMED HTML WEB COLORS
 *  ====================================================
 */

#include <FastLED.h>
#define NUM_LEDS 150
#define DATA_PIN 2        // BLUE
#define CLOCK_PIN 3       // GREEN
CRGBArray<NUM_LEDS> leds;
#include <Wire.h>
#include <TimeLib.h>
#include <DS1307RTC.h>


void setup() {
  FastLED.addLeds<WS2801, DATA_PIN, CLOCK_PIN, RGB>(leds, NUM_LEDS);
}


void loop() {
  tmElements_t tm;
  RTC.read(tm);
  
  int timeSinceMidnight;
  int Blocco17 = 1020;  //17:00   -> 17 * 60 = 1020 minutes from midnight
  int Blocco24 = 1439;  //23:59
  int Blocco00 = 0;     //00:00
  int Blocco08 = 480;   //08:00
  int Blocco16 = 1005;  //16:45
  
  timeSinceMidnight = (tm.Hour * 60) + tm.Minute;

  //SWITCHING ON and from 17:00 to 24:00
  if ( (timeSinceMidnight >= Blocco17) && (timeSinceMidnight <= Blocco24) ) {
    Animazione1();
    Animazione2();
    Animazione1();
    Animazione3();
  }
  
  //From MIDNIGHT to MORNING (00:00-08:00)
  if ( (timeSinceMidnight >= Blocco00) && (timeSinceMidnight < Blocco08) ) {
    Animazione1();
    Animazione2();
    Animazione1();
    Animazione3();
  }
  
  //SWITCHING OFF and from 08:00 to 16:45    =check every 10'=
  if ( (timeSinceMidnight >= Blocco08) && (timeSinceMidnight < Blocco16) ) {
    Spegnimento();
    delay(600000);
  }
  
  //WAITING FOR 5PM from 16:45 to 17:00   =check every 1'=
  if ( (timeSinceMidnight >= Blocco16) && (timeSinceMidnight < Blocco17) ) {
    delay(60000);
  }
}


/*  ===================  Animations ===================
 *  Rainbow (1);
 *  Red-Orange-Yellow-Green-Blue (2);
 *  Rainbow (1 again);
 *  Purple-Blue-LightBLue-Green-Yellow-Orange-Red (3).
 *  ===================================================
 */

//==1== RAINBOW
void Animazione1()  {
  static uint8_t hue=0;
  for(int i = 0; i < NUM_LEDS; i++) {
  leds(0,i).fill_rainbow(hue++);
  FastLED.show();
  delay(300);      //0,3 seconds
  }
  delay(10000);    //10 seconds
}
  
//==2== LED RED-ORANGE-YELLOW-GREEN-BLUE
void Animazione2()  {
  for(int q = 0; q < NUM_LEDS; q=q+5) {
  leds[q] = CRGB::Red;
  FastLED.show();
  delay(300);      //0,3 seconds
  }
  for(int w = 1; w < NUM_LEDS; w=w+5) {
  leds[w] = CRGB::OrangeRed;
  FastLED.show();
  delay(300);
  }
  for(int e = 2; e < NUM_LEDS; e=e+5) {
  leds[e] = CRGB::Yellow;
  FastLED.show();
  delay(300);
  }
  for(int r = 3; r < NUM_LEDS; r=r+5) {
  leds[r] = CRGB::Green;
  FastLED.show();
  delay(300);
  }
  for(int t = 4; t < NUM_LEDS; t=t+5) {
  leds[t] = CRGB::Blue;
  FastLED.show();
  delay(300);
  }
  delay(10000);    //10 seconds
}

//==3== LED PURPLE-BLUE-LIGHT BLUE-GREEN-YELLOW-ORANGE-RED
void Animazione3()  {
  for(int q = 0; q < NUM_LEDS; q=q+7) {
  leds[q] = CRGB::DarkMagenta;
  FastLED.show();
  delay(300);
  }
  for(int w = 1; w < NUM_LEDS; w=w+7) {
  leds[w] = CRGB::Blue;
  FastLED.show();
  delay(300);
  }
  for(int e = 2; e < NUM_LEDS; e=e+7) {
  leds[e] = CRGB::Cyan;
  FastLED.show();
  delay(300);
  }
  for(int r = 3; r < NUM_LEDS; r=r+7) {
  leds[r] = CRGB::Green;
  FastLED.show();
  delay(300);
  }
  for(int t = 4; t < NUM_LEDS; t=t+7) {
  leds[t] = CRGB::Yellow;
  FastLED.show();
  delay(300);
  }
  for(int y = 5; y < NUM_LEDS; y=y+7) {
  leds[y] = CRGB::OrangeRed;
  FastLED.show();
  delay(300);
  }
  for(int u = 6; u < NUM_LEDS; u=u+7) {
  leds[u] = CRGB::Red;
  FastLED.show();
  delay(300);
  }
  delay(10000);      //10 seconds
}

//SWITCHING OFF
void Spegnimento()  {
    for(int i = 0; i < NUM_LEDS; i++) {
    leds[i] = CRGB::Black; 
    FastLED.delay(300);
    }
}
Christmas_tree_UPDATEDArduino
Same animations and functions, but colors are MORE CALIBRATED because they are set with the HSV method. If you are not an expert user, learn more here: https://github.com/FastLED/FastLED/wiki/Pixel-reference#setting-hsv-colors-
/*  ========== CHRISTMAS_TREE UPDATED ============
 *  Code for 150 WS2801 Digital RGB leds.
 *  Written by MARTINO GHISLENI.
 *  Based on the FASTLED library.
 *  September 2016 - 10 September 2017
 *  
 *  NOTE: COLORS ARE ENCODED WITH THE HSV METHOD.
 *  ==============================================
 */

#include <FastLED.h>
#define NUM_LEDS 150
#define DATA_PIN 2        // BLUE
#define CLOCK_PIN 3       // GREEN
CRGB leds[NUM_LEDS];
#include <Wire.h>
#include <TimeLib.h>
#include <DS1307RTC.h>


void setup() {
  FastLED.addLeds<WS2801, DATA_PIN, CLOCK_PIN, RGB>(leds, NUM_LEDS);
}


void loop() {
  tmElements_t tm;
  RTC.read(tm);
  
  int timeSinceMidnight;
  int Blocco17 = 1020;  //17:00   -> 17 * 60 = 1020 minutes from midnight
  int Blocco24 = 1439;  //23:59
  int Blocco00 = 0;     //00:00
  int Blocco08 = 480;   //08:00
  int Blocco16 = 1005;  //16:45
  
  timeSinceMidnight = (tm.Hour * 60) + tm.Minute;

  //SWITCHING ON and from 17:00 to 24:00
  if ( (timeSinceMidnight >= Blocco17) && (timeSinceMidnight <= Blocco24) ) {
    Animazione1();
    Animazione2();
    Animazione1();
    Animazione3();
  }
  
  //From MIDNIGHT to MORNING (00:00-08:00)
  if ( (timeSinceMidnight >= Blocco00) && (timeSinceMidnight < Blocco08) ) {
    Animazione1();
    Animazione2();
    Animazione1();
    Animazione3();
  }
  
  //SWITCHING OFF and from 08:00 to 16:45    =check every 10'=
  if ( (timeSinceMidnight >= Blocco08) && (timeSinceMidnight < Blocco16) ) {
    Spegnimento();
    delay(600000);
  }
  
  //WAITING FOR 5PM from 16:45 to 17:00   =check every 1'=
  if ( (timeSinceMidnight >= Blocco16) && (timeSinceMidnight < Blocco17) ) {
    delay(60000);
  }
}


/*  ===================  Animations ===================
 *  FastLED Rainbow (1);
 *  Red-Orange-Yellow-Green-Blue (2);
 *  Rainbow (1 again);
 *  Purple-Blue-LightBLue-Green-Yellow-Orange-Red (3).
 *  ===================================================
 */

//==1== FASTLED RAINBOW
void Animazione1()  {
  static uint8_t hue=0;
  for(int i = 0; i < NUM_LEDS; i++) {
  fill_rainbow(leds, NUM_LEDS, hue++);
  FastLED.show();
  delay(300);
  }
  delay(10000);    //10 seconds
}
  
//==2== LED RED-ORANGE-YELLOW-GREEN-BLUE
void Animazione2()  {
  for(int q = 0; q < NUM_LEDS; q=q+5) {
  leds[q].setHue(0);    //red
  FastLED.show();
  delay(300);      //0,3 seconds
  }
  for(int w = 1; w < NUM_LEDS; w=w+5) {
  leds[w].setHue(10);   //orange
  FastLED.show();
  delay(300);
  }
  for(int e = 2; e < NUM_LEDS; e=e+5) {
  leds[e].setHue(40);    //yellow
  FastLED.show();
  delay(300);
  }
  for(int r = 3; r < NUM_LEDS; r=r+5) {
  leds[r].setHue(96);    //green
  FastLED.show();
  delay(300);
  }
  for(int t = 4; t < NUM_LEDS; t=t+5) {
  leds[t].setHue(160);    //blue
  FastLED.show();
  delay(300);
  }
  delay(10000);    //10 seconds
}

//==3== LED PINK-PURPLE-BLUE-GREEN-YELLOW-ORANGE-RED
void Animazione3()  {
  for(int q = 0; q < NUM_LEDS; q=q+7) {
  leds[q].setHue(235);    //pink
  FastLED.show();
  delay(300);
  }
  for(int w = 1; w < NUM_LEDS; w=w+7) {
  leds[w].setHue(200);   //purple
  FastLED.show();
  delay(300);
  }
  for(int e = 2; e < NUM_LEDS; e=e+7) {
  leds[e].setHue(160);   //blue
  FastLED.show();
  delay(300);
  }
  for(int r = 3; r < NUM_LEDS; r=r+7) {
  leds[r].setHue(100);    //green
  FastLED.show();
  delay(300);
  }
  for(int t = 4; t < NUM_LEDS; t=t+7) {
  leds[t].setHue(40);   //yellow
  FastLED.show();
  delay(300);
  }
  for(int y = 5; y < NUM_LEDS; y=y+7) {
  leds[y].setHue(10);    //orange
  FastLED.show();
  delay(300);
  }
  for(int u = 6; u < NUM_LEDS; u=u+7) {
  leds[u].setHue(0);    //red
  FastLED.show();
  delay(300);
  }
  delay(10000);      //10 seconds
}

//SWITCHING OFF
void Spegnimento()  {
    for(int i = 0; i < NUM_LEDS; i++) {
    leds[i] = CRGB::Black; 
    FastLED.delay(300);
    }
}
RTC_setArduino
This code copies the hour of your PC on the RTC connected to Arduino. Just upload this code on Arduino once, and the open the Serial Monitor to see the changes. Remeber to upload this BEFORE the main code, in order to make it run correctly!
/*  ==================== SET TIME on RTC ======================
 *  Upload on Arduino and open the serial monitor.
 *  
 *  This file is taken from the Examples inluded in the Time 
 *  library.
 *  Original code: https://github.com/PaulStoffregen/Time
 *  ===========================================================
 */
 

#include <TimeLib.h>
#include <Wire.h>
#include <DS1307RTC.h>  // a basic DS1307 library that returns time as a time_t


void setup()  {
  Serial.begin(9600);
  while (!Serial) ; // Needed for Leonardo only
  setSyncProvider(RTC.get);   // the function to get the time from the RTC
  if (timeStatus() != timeSet) 
     Serial.println("Unable to sync with the RTC");
  else
     Serial.println("RTC has set the system time");      
}

void loop()
{
  if (Serial.available()) {
    time_t t = processSyncMessage();
    if (t != 0) {
      RTC.set(t);   // set the RTC and the system time to the received value
      setTime(t);          
    }
  }
  digitalClockDisplay();  
  delay(1000);
}

void digitalClockDisplay(){
  // digital clock display of the time
  Serial.print(hour());
  printDigits(minute());
  printDigits(second());
  Serial.print(" ");
  Serial.print(day());
  Serial.print(" ");
  Serial.print(month());
  Serial.print(" ");
  Serial.print(year()); 
  Serial.println(); 
}

void printDigits(int digits){
  // utility function for digital clock display: prints preceding colon and leading 0
  Serial.print(":");
  if(digits < 10)
    Serial.print('0');
  Serial.print(digits);
}

/*  code to process time sync messages from the serial port   */
#define TIME_HEADER  "T"   // Header tag for serial time sync message

unsigned long processSyncMessage() {
  unsigned long pctime = 0L;
  const unsigned long DEFAULT_TIME = 1357041600; // Jan 1 2013 

  if(Serial.find(TIME_HEADER)) {
     pctime = Serial.parseInt();
     return pctime;
     if( pctime < DEFAULT_TIME) { // check the value is a valid time (greater than Jan 1 2013)
       pctime = 0L; // return 0 to indicate that the time is not valid
     }
  }
  return pctime;
}
RTC_readArduino
Upload this code and open the Serial Monitor to check the time stored on the RTC connected to the Arduino.
/*  =================== READ TIME from RTC ====================
 *  Upload on Arduino and open the serial monitor.
 *  
 *  This file is a customized version of the "ReadTest.ino", 
 *  from the Examples inluded in the DS1307RTC library.
 *  Original code: https://github.com/PaulStoffregen/DS1307RTC
 *  ===========================================================
 */


#include <Wire.h>
#include <TimeLib.h>
#include <DS1307RTC.h>

void setup() {
  Serial.begin(9600);
  while (!Serial) ; // wait for serial
  delay(200);
  Serial.println("RTC DS3231 Read Time");
  Serial.println("--------------------");
}

void loop() {
  tmElements_t tm;

  if (RTC.read(tm)) {
    Serial.print("Time = ");
    print2digits(tm.Hour);
    Serial.write(':');
    print2digits(tm.Minute);
    Serial.write(':');
    print2digits(tm.Second);
    Serial.print(", Date = ");
    Serial.print(tm.Day);
    Serial.write('/');
    Serial.print(tm.Month);
    Serial.write('/');
    Serial.print(tmYearToCalendar(tm.Year));
    Serial.println();
  } else {
    if (RTC.chipPresent()) {
      Serial.println("The DS3231 is stopped.  Please run the SetTime");
      Serial.println("example to initialize the time and begin running.");
      Serial.println();
    } else {
      Serial.println("DS3231 read error!  Please check the circuitry.");
      Serial.println();
    }
    delay(9000);
  }
  delay(1000);
}

void print2digits(int number) {
  if (number >= 0 && number < 10) {
    Serial.write('0');
  }
  Serial.print(number);
}

Schematics

Christmas Tree Breadboard scheme
Christmas tree bb a90rc0poze

Comments

Similar projects you might like

Wooden LED Christmas Tree

Project showcase by Arduino_Jarod

  • 1,308 views
  • 0 comments
  • 7 respects

5 Minute Christmas Neopixel Led Strip

Project showcase by Alexander

  • 9,870 views
  • 14 comments
  • 24 respects

IoT Christmas Tree Topper

Project tutorial by Balázs Simon

  • 1,559 views
  • 0 comments
  • 9 respects

Huge LED Christmas Lights

Project showcase by Savva Osipov

  • 10,604 views
  • 2 comments
  • 32 respects

Bluetooth control led with lcd led status display real time.

Project tutorial by Youssef Sabaa

  • 17,302 views
  • 4 comments
  • 34 respects

LED Straw XMAS Tree

Project showcase by Auri Botines

  • 2,365 views
  • 1 comment
  • 9 respects
Add projectSign up / Login