Introduction: Rainbow Ambient Clock

Hello Instructables, Hello World.

This is my first ever project here. Hope you like it and sorry for any mistakes.

Here's a clock that not only tells the time, but it also shows temperature and humidity, using colors! Made with a 12 led ring. Helpful for people with poor eye sight that now may be able to tell the time much easier with this device. Also a colorful gadget to decorate and light up a corner in your house.

In time telling, blue led indicate hours, red tens of minutes and yellow unit minutes. If any indications overlap, colors add themselves accordingly as :

  • Blue + Yellow = Green
  • Blue + Red = Purple
  • Red + Yellow = Orange
  • Blue + Red + Yellow = White

Every 70 seconds a temperature and humidity display comes up. For temperature a green background is used (red indicates tens and yellow units) and for humidity a teal one (same color indications also). Then follows a rainbow and back to time telling. Note that although temperature and humidity tens use led numbering from top - like minute units, for time tens show up as would in a conventional clock (every two leds). Of course, all these can be changed at will...

Time can be set by pressing the two mini push buttons. By pressing the first one (line A4) you can set the time (blue led) and by pressing the second one (line A5) you can set the minutes (red and yellow leds). Overlap leds change their colors accordingly. If you miss your setting, the whole thing goes round again. By pressing simultaneously both buttons, you may reset seconds (set to zero). A time buffer of 100ms protect buttons from being pressed accidentally.

Step 1: Items Needed...

You will need:

  • An Arduino nano (or whichever else you choose) with a usb connection to power up and program
  • A 12-bit ring led type WS2812 for display
  • An RTC controller to keep your time, type RTC3231, also capable to provide ambient temperature
  • An RTH11 sensor for humidity
  • Two resistors, 330R + 10K
  • Two mini dip switches for setting the time
  • Wires to connect everything up
  • A breadboard
  • Some plexiglass art as shown for the front (.cdr file provided)

I got these parts from ebay :

Dip switches come in a set of a 100!!! from ebay. Resistors can be purchased from your local electronics parts store, as also from ebay.

Cables and breadboard can too be found on ebay or a retail electronics shop.

Proposed plexiglass for face, as suggested here, can be ordered from a local cutting facility using the provided .cdr file:

Step 2: Schematics and Programing...

You may build this project in several ways according to schematics.

A breadboard can be used, but you can also glue all parts (boards) behind the ring led and its face in a sandwich like fashion separated by double side adhesive tape (photos of this will come up here soon). One may also build his/her own printed board to host all parts.

I have chosen to use a usb embedded arduino nano for the ease of providing power to the unit. A smaller and more compact version could be built using a USB to TTL converter like this one below from ebay, but you would have to find an alternate way to provide power (5Volts) because after programing the arduino, the TTL converter has to go:

Programing file contains annotations for your understanding.

There are several libraries for DS3231 out there, so I am providing here the one that I use. Also note that you may find a version of DHT11 that already includes R1 (usually sits on a small board and is not a raw component). In such a case omit R1.

So you bring together all parts as shown and program your arduino with your computer. If you decide to use the mini module without the usb port, you can afterwards disconnect and remove the TTL adapter. Doing so saves you space and power.

Actual code:

<p>#include            //I2C communication library<br>#include "ds3231.h"         //Real Time Clock library
#include         //Fast Led library
#include             //DHT humidity-temperature sensor</p><p>#define LED_PIN     5       //Control pin for LEDs
#define COLOR_ORDER GRB     //Define color protocol
#define CHIPSET     WS2811  //Chipset set for WS2811
#define NUM_LEDS    12      //Declare number of leds
#define BRIGHTNESS  35      //Declare led brightness</p><p>dht DHT;                    //Initialize DHT
#define DHT11_PIN 2         //Data pin for DHT</p><p>CRGB leds[NUM_LEDS];        //Acknoledge number of leds to system</p><p>byte ora ;                  //Hour variable
byte mindec ;               //Ten minutes variable
byte minmon ;               //Unit minutes variable
byte seconds = 0;           //Seconds variable
int counter1;               //Counter variable for data show
int idex = 0;               //Variable for rainbow index
int ihue = 0;               //Variable for rainbow hue
float temperature;          //Temperature variable 
int humidity;               //Humidity variable</p><p>void setup()
{
  FastLED.addLeds(leds, NUM_LEDS);
  FastLED.setBrightness( BRIGHTNESS );
    
  Serial.begin(9600);     //Initialize serial port
  Wire.begin();           //Initialize I2C communication library
  DS3231_init(0x00);      //Initialize Real Time Clock for 1Hz square wave output 
  
  pinMode(8, INPUT);      //Set pin for time/date mode button to input
  digitalWrite(8, HIGH);  //Turn on pullup resistors
  pinMode(9, INPUT);      //Set pin for time/date set button to input
  digitalWrite(9, HIGH);  //Turn on pullup resistors
  
  //Initialize system with a rainbow
  for(int i=0; i<12; i++) {rainbow();}
  for(int j=0; j<12; j++) {leds[j]=CRGB::Black;FastLED.delay(100);}
}</p><p>void loop(){
  
  if((DS3231_get_addr(0x0E) & 0x20) == 0){DS3231_init(0x20);} //Init temperature sensor
  temperature = DS3231_get_treg();  //Get temperature from RTC
  struct ts t;                      //Structure for retrieving and storing time data from RTC
  DS3231_get(&t);                   //Get time to t structure
  int chk = DHT.read11(DHT11_PIN);  //Obtain humidity variable from data line
  humidity = DHT.humidity;          //Get humidity and store to variable
  mindec=0;                         //Initialize variable for ten minutes
  minmon=0;                         //Initialize variable for unit minutes</p><p>  FastLED.clear();                  //Clear all display
  
  //Displaying actual time
  if (t.hour>=12){leds[t.hour-12]= CRGB::Blue;ora=t.hour-12;}
    else {
      leds[t.hour]= CRGB::Blue; ora=t.hour;
    }
  if (t.min<10 && t.min!=0) {leds[t.min]=CRGB::Yellow;minmon=(t.min);}
    else {
      mindec=int((t.min/10)*2); minmon=(t.min-((mindec/2)*10));
      if (mindec==minmon && minmon!=0){leds[mindec]= CRGB::Orange;}
      else {
      leds[mindec] = CRGB::Red ;leds[minmon] = CRGB::Yellow ;
      //if (minmon==0){leds[minmon] = CRGB::Black;}
      }
    }
    
  //Correcting overlapping colors/indications
  if (ora==minmon){leds[ora]=CRGB::Green;}
  if (ora==mindec){leds[ora]=CRGB::Purple;}
  if (ora==minmon && ora==mindec){leds[ora]=CRGB::White;}
  
  //Toggle seconds to make seconds effect
  if (seconds==0){
    leds[int(t.sec/5)]=CRGB::DimGrey;leds[int(t.sec/5)].nscale8( 64);seconds++;
  }
  else {
    seconds--;
  }
    
  FastLED.show();
  delay(800);
  
  counter1++;           //Increase counter for displaying temp/hum
  
  if (counter1>70) {  //Time up to display temperature and humidity
        counter1=0;   //Initialize counter for next data show
        //Display temperature
        if (temperature<=0){for(int j = NUM_LEDS; j >=0 ; j-- ) {leds[j] = CRGB::White; leds[j].nscale8(64);delay(20);}}//Subzero tempratures appear in white background
          else {for(int j = NUM_LEDS; j >=0 ; j-- ) {leds[j] = CRGB::Green; leds[j].nscale8(64);delay(20);}
          }
        if (temperature<10) {leds[int(temperature)]=CRGB::Yellow;}
            else {mindec=int((temperature/10)); minmon=(temperature-(mindec*10));
              if (mindec==minmon){leds[mindec]= CRGB::Orange;}
                else {leds[mindec] = CRGB::Red ;leds[minmon] = CRGB::Yellow ;
                } 
            }
        FastLED.show(); //Show temperature in green background for 4 secs
        delay(4000);
        
        //Display humidity
        for(int j = NUM_LEDS; j >=0 ; j-- ) {leds[j] = CRGB::Teal; leds[j].nscale8(48);delay(20);}      
        if (humidity<10) {leds[int(humidity)]=CRGB::Yellow;}
            else {mindec=int((humidity/10)); minmon=(humidity-(mindec*10));
              if (mindec==minmon){leds[mindec]= CRGB::Orange;}
                else {leds[mindec] = CRGB::Red ;leds[minmon] = CRGB::Yellow ;
                } 
            }
        FastLED.show(); //Show humidity in teal background for 4sec
        delay(4000);
  
        //Rainbow effect call
        for(int i=0; i<12; i++) {rainbow();}
        for(int j=0; j<12; j++) {leds[j]=CRGB::Black;FastLED.delay(100);}
        }
  
  // Set time using buttons</p><p>      if(!digitalRead(8) && digitalRead(9)){ //Increment hour if button held dowm
        delay(100); //100ms delay to avoid accidental button triggering
        t.hour = t.hour + 1; //Increment the hour 
        if (t.hour>23){t.hour=0;}
        Wire.beginTransmission(DS3231_I2C_ADDR);
        Wire.write(2);
        Wire.write((t.hour/10*16)+(t.hour%10));
        Wire.endTransmission();
      } </p><p>      if(!digitalRead(9) && digitalRead(8)){ //Increment minutes if button held down
        delay(100); //100ms delay to avoid accidental button triggering
              t.min = t.min + 1; //Increment minutes 
        if (t.min>59){t.min=0;}
        Wire.beginTransmission(DS3231_I2C_ADDR);
        Wire.write(1);
        Wire.write((t.min/10*16)+(t.min%10));
        Wire.endTransmission();
      }</p><p>      if(!digitalRead(9) && !digitalRead(8)){ //Reset seconds if both buttons held down
        delay(100); //100ms delay to avoid accidental button triggering
              t.sec = 0; //Reset seconds 
        Wire.beginTransmission(DS3231_I2C_ADDR);
        Wire.write(0);
        Wire.write((t.sec/10*16)+(t.sec%10));
        Wire.endTransmission();
      }</p><p>}</p><p>void rainbow() //Rainbow function
{
  idex++;
  ihue=ihue+22;
  if(idex>=NUM_LEDS){idex=0;}
  if(ihue>=255){ihue=0;}
      leds[idex]=CHSV(ihue,255,255);
  FastLED.show();
  FastLED.delay(100);
}</p>

Step 3: Finalizing the Clock!

Two marbles like the ones shown can be glued behind the two front legs of the plexiglass to keep the clock standing. Tilt may be adjusted to fit your taste and viewing angle. The standing clock shown above uses this principle. It also uses a nano-mini without the usb controller and the much smaller DS3231 without the memory chip (it also includes a rechargeable battery for time keeping). A simple smart phone charger of 5 volts is used to supply power to the unit.

Fritzing project file also provided for the ones that would be interested to make a printed board for their clock (Parts could be adjusted and moved around at will according to your needs). Project includes schematics and code.

May we all have HAPPY HOURS !!!