Arduino (Nano) RGB pixel LED clock

By telleropnul, June 23, 2016

UPDATE
Now using Network Time Protocol (NTP)
https://coeleveld.com/nodemcu-esp8266-esp-12e-v1-0-clock/

Bicycle rim Hero Xr-1 27 inch (700mm) 20H clincher, black.

5mm thick (depron) foam strip for padding.

DS3231 High Precision Real-Time Clock Module (replacing I2C identical DS1307)

RGB clock DS3231 High Precision Real-Time Clock Module

SMD pixel RGB strip (30 LEDs per meter, WS2812, 5050 LED)

RGB clock pixel RGB strip 60 LED per meter

RGB clock ws2812

// Code collected and completed by Tobias Floery <tobias@floery.net>

//SMD RGB pixel LED strip

// FastSPI Library from http://code.google.com/p/fastspi/
#include <FastSPI_LED.h>

// Adafruits RTClib from https://github.com/adafruit/RTClib
#include <Wire.h>
#include "RTClib.h"

RTC_DS1307 RTC;

// Sometimes chipsets wire in a backwards sort of way
//struct CRGB { unsigned char b; unsigned char r; unsigned char g; };
//struct CRGB { unsigned char r; unsigned char g; unsigned char b; };
struct CRGB { unsigned char g; unsigned char r; unsigned char b; };

struct CRGB *leds;

// Number of RGB Pixel for FastSPI
#define NUM_LEDS 60
// Datapin for FastSPI
#define PIN 11
// Datarate - valued 0 to 7.  Choose a higher value if flickering occurs
//#define RATE 0

#define FILTER_LEN 8
// Brightness level
int level=15;

// Brightness correction for Leds
unsigned char bright[] = {0, 2, 4, 7, 11, 18, 30, 40, 50, 65, 80,96,125,160, 200, 255};

void setup()
{
  
  Serial.begin(57600);

  // init RTClib  
  Wire.begin();
  RTC.begin();
  
  // Following line sets the RTC to the date & time this sketch was compiled
  /*
  RTC.adjust(DateTime(__DATE__, __TIME__));
  */
  
  // Setup FastSPI Lib
  FastSPI_LED.setLeds(NUM_LEDS);
  FastSPI_LED.setChipset(CFastSPI_LED::SPI_WS2811);
  FastSPI_LED.setPin(PIN);
  //FastSPI_LED.setDataRate(RATE);
  
  FastSPI_LED.init();
  FastSPI_LED.start();

  leds = (struct CRGB*)FastSPI_LED.getRGBData(); 

  // setup measurement for LDR
  digitalWrite(A0, HIGH);  // set pullup on analog pin 0 
  pinMode(A1, OUTPUT);
  digitalWrite(A1, LOW);    
  
}

unsigned int ldr=0;

void doLDR() {
  unsigned int ldr_value = analogRead(0);          //reads the LDR values
  
  //Adjust for LDR variations.
  //dark = 1023
  //light = 0
  //If your LDR for example reaches a max analogRead value of 350 instead of 1023 for 100% dark.
  //unsigned int ldr_adjusted=map(ldr_value,0,350,0,1023);
  unsigned int ldr_adjusted=map(ldr_value,0,700,0,1023);

  //set max limit (to avoid potential 'divide-by-zero's).
  if (ldr_adjusted >= 1023) ldr_adjusted = 1023;

  //ldr follows ldr_adjusted, but is averaged so that values only change gradually
  ldr = ((unsigned long)(FILTER_LEN-1)*ldr+ldr_adjusted)/FILTER_LEN;

  unsigned int light_level=0;

  //translate [0-1023] to [15-0]
  //light_level = (1024-ldr)>>6;
  light_level=map(ldr,0,1023,15,0);  
  if (light_level >= 15) light_level = 15;
  if (light_level <= 1) light_level = 1;

  //DEBUG SPI
  // /*
  Serial.println("ldr_value [0-???]:");
  Serial.println(ldr_value);
  Serial.println("ldr_adjusted [0-1023]:");
  Serial.println(ldr_adjusted);
  Serial.println("ldr:");
  Serial.println(ldr);
  Serial.println("light_level:");
  Serial.println(light_level);
  // */

  //level=2;  
  level = light_level;

}

DateTime old;

void loop() { 
  // get time
  DateTime now = RTC.now();
  
  // DEBUG RTC
  // /*
  Serial.print(now.year(), DEC);
  Serial.print('/');
  Serial.print(now.month(), DEC);
  Serial.print('/');
  Serial.print(now.day(), DEC);
  Serial.print(' ');
  Serial.print(now.hour(), DEC);
  Serial.print(':');
  Serial.print(now.minute(), DEC);
  Serial.print(':');
  Serial.print(now.second(), DEC);
  Serial.println();
  // */

  if (now.second()!=old.second()) {   
    old = now;
    doLDR();
  }

  // clear LED array
  memset(leds, 0, NUM_LEDS * 3);
    
  if (level < 4) {  
    // this is the night mode
    // set LED background
    for (int i=0; i<NUM_LEDS; i++) {
      leds[i].r = bright[level];
      leds[i].g = (bright[level]+1)/2;
    }  
    // set pixels
    //leds[(now.second())%60].r = bright[level];
    leds[(now.minute())%60].g = 0; 
    leds[(now.minute())%60].r = bright[level+2];
    
    unsigned char hourpos = (now.hour()%12)*5;
    leds[((59+hourpos)%60)%60].g = 0;
    leds[(hourpos)%60].g = 0;
    leds[((hourpos+1))%60].g = 0;
    
    leds[(hourpos)%60].r = bright[level+2];
    
  } else {

  
    // set pixels
    leds[(now.second())%60].r = bright[level];
    leds[(now.minute())%60].b = bright[level]; 
    
    unsigned char hourpos = (now.hour()%12)*5;
    leds[((59+hourpos)%60)%60].g = bright[level/2];
    leds[(hourpos)%60].g = bright[level];
    leds[((hourpos+1))%60].g = bright[level/2];  
  }
  // update LEDs
  FastSPI_LED.show();
  
  // wait some time
  delay(500);
}

The FastSPI_LED library is no longer available and has evolved into the FastLED library with slightly different syntax.  Use the following updated Arduino code:

// Original code by Tobias Floery <tobias@floery.net>
// Converted to FastLED by Tablelands Computers <info@tablelandscomputers.com>

// FastLED Library from https://github.com/FastLED/FastLED
#include <FastLED.h>

// Adafruits RTClib from https://github.com/adafruit/RTClib
#include <Wire.h>
#include "RTClib.h"

RTC_DS1307 RTC;

#define NUM_LEDS 60
#define LED_TYPE WS2812
#define DATA_PIN 11
#define COLOR_ORDER GRB

CRGB leds[NUM_LEDS];

// Filter averaging factor - higher value means more sluggish response to changes in ambient brightness
#define FILTER_LEN 8
// Brightness level initial value
int level=15;
// Brightness correction for Leds
unsigned char bright[] = {0, 2, 4, 7, 11, 18, 30, 40, 50, 65, 80,96,125,160, 200, 255};

void setup()
{
  
  Serial.begin(57600);

  // init RTClib  
  Wire.begin();
  RTC.begin();
  
  // Following line sets the RTC to the date & time this sketch was compiled
  /*
  RTC.adjust(DateTime(__DATE__, __TIME__));
  */
  
  // Setup FastLED Lib
  FastLED.addLeds<LED_TYPE,DATA_PIN,COLOR_ORDER>(leds,NUM_LEDS).setCorrection(TypicalLEDStrip);

  // setup measurement for LDR
  digitalWrite(A0, HIGH);  // set pullup on analog pin 0 
  pinMode(A1, OUTPUT);
  digitalWrite(A1, LOW);    
  
}

unsigned int ldr=0;

void doLDR() {
  unsigned int ldr_value = analogRead(0);          //reads the LDR values
  
  //Adjust for LDR variations.
  //dark = 1023
  //light = 0
  //If your LDR for example reaches a max analogRead value of 350 instead of 1023 for 100% dark.
  //unsigned int ldr_adjusted=map(ldr_value,0,350,0,1023);
  unsigned int ldr_adjusted=map(ldr_value,0,700,0,1023);

  //set max limit (to avoid potential 'divide-by-zero's).
  if (ldr_adjusted >= 1023) ldr_adjusted = 1023;

  //ldr follows ldr_adjusted, but is averaged so that values only change gradually
  ldr = ((unsigned long)(FILTER_LEN-1)*ldr+ldr_adjusted)/FILTER_LEN;

  unsigned int light_level=0;

  //translate [0-1023] to [15-0]
  //light_level = (1024-ldr)>>6;
  light_level=map(ldr,0,1023,15,0);  
  if (light_level >= 15) light_level = 15;
  if (light_level <= 1) light_level = 1;

  //DEBUG SPI
  // /*
  Serial.println("ldr_value [0-???]:");
  Serial.println(ldr_value);
  Serial.println("ldr_adjusted [0-1023]:");
  Serial.println(ldr_adjusted);
  Serial.println("ldr:");
  Serial.println(ldr);
  Serial.println("light_level:");
  Serial.println(light_level);
  // */

  //level=2;  
  level = light_level;

}

DateTime old;

void loop() { 
  // get time
  DateTime now = RTC.now();
  
  // DEBUG RTC
  // /*
  Serial.print(now.year(), DEC);
  Serial.print('/');
  Serial.print(now.month(), DEC);
  Serial.print('/');
  Serial.print(now.day(), DEC);
  Serial.print(' ');
  Serial.print(now.hour(), DEC);
  Serial.print(':');
  Serial.print(now.minute(), DEC);
  Serial.print(':');
  Serial.print(now.second(), DEC);
  Serial.println();
  // */

  if (now.second()!=old.second()) {   
    old = now;
    doLDR();
  }

  // clear LED array
  memset(leds, 0, NUM_LEDS * 3);
    
  if (level < 4) {  
    // this is the night mode
    // set LED background
    for (int i=0; i<NUM_LEDS; i++) {
      leds[i].r = bright[level];
      leds[i].g = (bright[level]+1)/2;
    }  
    // set pixels
    //leds[(now.second())%60].r = bright[level];
    leds[(now.minute())%60].g = 0; 
    leds[(now.minute())%60].r = bright[level+2];
    
    unsigned char hourpos = (now.hour()%12)*5;
    leds[((59+hourpos)%60)%60].g = 0;
    leds[(hourpos)%60].g = 0;
    leds[((hourpos+1))%60].g = 0;
    
    leds[(hourpos)%60].r = bright[level+2];
    
  } else {

  
    // set pixels
    leds[(now.second())%60].r = bright[level];
    leds[(now.minute())%60].b = bright[level]; 
    
    unsigned char hourpos = (now.hour()%12)*5;
    leds[((59+hourpos)%60)%60].g = bright[level/2];
    leds[(hourpos)%60].g = bright[level];
    leds[((hourpos+1))%60].g = bright[level/2];  
  }
  // update LEDs
  //FastLED.setBrightness(100);
  FastLED.show();
  FastLED.delay(500);
  
  // wait some time
  //delay(500);
}

Library Source Files:
RTClib-master
FastLED-master

RGB pixel clock 01 RGB pixel clock 02 RGB pixel clock 03 RGB pixel clock 04 RGB pixel clock 05 RGB pixel clock 06 RGB pixel clock 07 RGB pixel clock 08 RGB pixel clock 09 RGB pixel clock 10

 

Day mode

RGB pixel clock 11.jpg

 

Night mode

RGB pixel clock 12

 

For a final version of the code -including hour hand progression as the minutes fill the hour and 5 minute interval number marks:

// Original code by Tobias Floery <tobias@floery.net>
// Converted to FastLED by Tablelands Computers <info@tablelandscomputers.com>

// FastLED Library from https://github.com/FastLED/FastLED
#include <FastLED.h>

// Adafruits RTClib from https://github.com/adafruit/RTClib
#include <Wire.h>
#include "RTClib.h"

RTC_DS1307 RTC;

#define NUM_LEDS 60
#define LED_TYPE WS2812
#define DATA_PIN 11
#define COLOR_ORDER GRB

CRGB leds[NUM_LEDS];

// Filter averaging factor - higher value means more sluggish response to changes in ambient brightness
#define FILTER_LEN 8
// Brightness level initial value
int level=15;
// Brightness correction for Leds
unsigned char bright[] = {0, 2, 4, 7, 11, 18, 30, 40, 50, 65, 80,96,125,160, 200, 255};

void setup()
{
  
  Serial.begin(57600);

  // init RTClib  
  Wire.begin();
  RTC.begin();
  
  // Following line sets the RTC to the date & time this sketch was compiled
  /*
  RTC.adjust(DateTime(__DATE__, __TIME__));
  */
  
  // Setup FastLED Lib
  FastLED.addLeds<LED_TYPE,DATA_PIN,COLOR_ORDER>(leds,NUM_LEDS).setCorrection(TypicalLEDStrip);

  // setup measurement for LDR
  digitalWrite(A0, HIGH);  // set pullup on analog pin 0 
  pinMode(A1, OUTPUT);
  digitalWrite(A1, LOW);    
  
}

unsigned int ldr=0;

void doLDR() {
  unsigned int ldr_value = analogRead(0);          //reads the LDR values
  
  //Adjust for LDR variations.
  //dark = 1023
  //light = 0
  //If your LDR for example reaches a max analogRead value of 350 instead of 1023 for 100% dark.
  unsigned int ldr_adjusted=map(ldr_value,0,700,0,1023);
  
  //set max limit (to avoid potential 'divide-by-zero's).
  if (ldr_adjusted >= 1023) ldr_adjusted = 1023;

  //ldr follows ldr_adjusted, but is averaged so that values only change gradually
  ldr = ((unsigned long)(FILTER_LEN-1)*ldr+ldr_adjusted)/FILTER_LEN;

  unsigned int light_level=0;

  //translate [0-1023] to [15-0]
  //light_level = (1024-ldr)>>6;
  light_level=map(ldr,0,1023,15,0);  
  if (light_level >= 15) light_level = 15;
  if (light_level <= 1) light_level = 1;

  //DEBUG SPI
  // /*
  Serial.println("ldr_value [0-???]:");
  Serial.println(ldr_value);
  Serial.println("ldr_adjusted [0-1023]:");
  Serial.println(ldr_adjusted);
  Serial.println("ldr:");
  Serial.println(ldr);
  Serial.println("light_level:");
  Serial.println(light_level);
  // */

  //level=2;  
  level = light_level;

}

DateTime old;

void loop() { 
  // get time
  DateTime now = RTC.now();
  
  // DEBUG RTC
  // /*
  Serial.print(now.year(), DEC);
  Serial.print('/');
  Serial.print(now.month(), DEC);
  Serial.print('/');
  Serial.print(now.day(), DEC);
  Serial.print(' ');
  Serial.print(now.hour(), DEC);
  Serial.print(':');
  Serial.print(now.minute(), DEC);
  Serial.print(':');
  Serial.print(now.second(), DEC);
  Serial.println();
  // */

  if (now.second()!=old.second()) {   
    old = now;
    doLDR();
  }

  // clear LED array
  memset(leds, 0, NUM_LEDS * 3);

  if (level < 4) {  
    // this is the night mode
    // set LED background
    for (int i=0; i<NUM_LEDS; i++) {
      leds[i].r = bright[level];
      leds[i].g = (bright[level]+1)/2;
    }  
    // set pixels
    //leds[(now.second())%60].r = bright[level];
    leds[(now.minute())%60].g = 0; 
    leds[(now.minute())%60].r = bright[level+2];
    
    unsigned char hourpos = (now.hour()%12)*5;

    // To let the hour hand creep to the next hour as the minutes progress, 
    // for every 12 minutes offset the hourpos by 1 (= 1 LED).
    if (now.minute() >= 12) hourpos=hourpos+1;
    if (now.minute() >= 24) hourpos=hourpos+1;
    if (now.minute() >= 36) hourpos=hourpos+1;
    if (now.minute() >= 48) hourpos=hourpos+1;
    
    leds[((59+hourpos)%60)%60].g = 0;
    leds[(hourpos)%60].g = 0;
    leds[((hourpos+1))%60].g = 0;
    
    leds[(hourpos)%60].r = bright[level+2];
    
  } else {

    // light the number marks
    leds[0].r =  2;
    leds[15].r = 2;
    leds[30].r = 2;
    leds[45].r = 2;
    leds[0].b = 5;
    leds[15].b = 5;
    leds[30].b = 5;
    leds[45].b = 5;
  
    leds[5].r =  2;
    leds[10].r = 2;
    leds[20].r = 2;
    leds[25].r = 2;
    leds[35].r = 2;
    leds[40].r = 2;
    leds[50].r = 2;
    leds[55].r = 2;
    leds[5].b =  5;
    leds[10].b = 5;
    leds[20].b = 5;
    leds[25].b = 5;
    leds[35].b = 5;
    leds[40].b = 5;
    leds[50].b = 5;
    leds[55].b = 5;

    // set pixels
    leds[(now.second())%60].r = bright[level];
    leds[(now.second())%60].g = 0;
    leds[(now.second())%60].b = 0;

    leds[(now.minute())%60].r = 0;
    leds[(now.minute())%60].g = 0;
    leds[(now.minute())%60].b = bright[level]; 

    //hour=0, 1, 2, 3, 4, ... ,22, 23
    //hourpos = 0, 5 ,10, 15 ,20, ... , 50, 55
    unsigned char hourpos = (now.hour()%12)*5;

    // To let the hour hand creep to the next hour as the minutes progress,
    // for every 12 minutes offset the hourpos by 1 (= 1 LED).
    if (now.minute() >= 12) hourpos=hourpos+1;
    if (now.minute() >= 24) hourpos=hourpos+1;
    if (now.minute() >= 36) hourpos=hourpos+1;
    if (now.minute() >= 48) hourpos=hourpos+1;
    
    leds[((59+hourpos)%60)%60].g = bright[level/2];
    leds[(hourpos)%60].g = bright[level];
    leds[((hourpos+1))%60].g = bright[level/2];  
  }
  // update LEDs
  //FastLED.setBrightness(100);
  FastLED.show();
  FastLED.delay(500);
  
  // wait some time
  //delay(500);
}

RGB pixel clock 13

Youtube video