Martino Ghisleni
Published © GPL3+

Christmas Tree with 150 Digital LED Pixels

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

BeginnerFull instructions provided15,107
Christmas Tree with 150 Digital LED Pixels

Things used in this project

Hardware components

Christmas Tree
×1
Arduino Mega 2560
Arduino 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

Software apps and online services

Arduino IDE
Arduino IDE

Hand tools and fabrication machines

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

Story

Read more

Schematics

Christmas Tree Breadboard scheme

Code

Christmas_tree

Arduino
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_UPDATED

Arduino
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_set

Arduino
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_read

Arduino
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);
}

Credits

Martino Ghisleni

Martino Ghisleni

0 projects • 1 follower

Comments