Under-counter RGB light

November, 2012

I’ve got a dark spot in the corner of my kitchen.  For years, my wife has been hinting (aka nagging) that we need to mount a lamp underneath the cabinets to provide more light.  The problem is that people living in my house (who shall not be named) have a tendency to leave lights on all the time.  So, I came up with the idea of automating the light and using an RGB LED strip like I did for the RGB Lamp project I did earlier.

I built a prototype Arduino tripple-stack control board using an Arduino Uno, An Xbee shield from Sparkfun, and an RGB shield from open-electronics.org.  Based on previous experience, I knew about the quirks of the Sparkfun Xbee shield, so was able to get the Arduino communicating with my PC quickly and easily.  I also knew from previous experience that the RGB Shield would do well driving the LED strip.  I also wired up a Sharp IR range finder sensor to trigger the light.

My thinking was that this is the first of many LED strip controllers that I would place around the house.  I’d leverage the Xbee’s mesh network capabilities to broadcast RGB values throughout the house using a single Xbee Pro connected to a Watchdog server, and have the modules display different colors whenever I want simultaneously.  I’m thinking I could use the colors to display house status when someone returns to an unoccupied house (green is good, yellow is warning, red is bad, etc.)

I mounted the assembly underneath the cabinet in the corner of the kitchen.  The LED strip has an adhesive back that  used to attach it to the bottom edge of the cabinet.  I attached some anchors and used hook-and-loop strips to strap in the Ardunio tripple stack.  I attached it near a wall outlet and used a 12V wall wart to power the electronics.  Finally, I mounted the Sharp IR range finder using some metal strips so it hangs down just below the lip of the cabinet.

Now, when I walk into the dark corner of the kitchen, the light automatically turns on.  It starts counting down from 10 minutes and then it turns off.  If the Sharp sensor detects a presence, it re-starts the clock.  This approach has worked really well.  I can also turn the lights on at any time via the Xbee radio.  I wrote a simple color-picker app to manually select and send RGB values to the light.

Next steps are to build additional light strips and deploy them.  I’m thinking of putting one inside the china cabinet in the dining room, and maybe another set inside the bookshelves in my living room.  Finally, I’m thinking of replacing the LED lights I have underneath the cabinets in both my upstairs bathroom with these.

Pictures:

DSCN0010  The finished product.

DSCN0011  Sharp IR range finder detects me when I approach and turns on the light.

DSCN0012  Arduino with Xbee and RGB Shields strapped in underneath the counter.

ColorPicker  Watchdog Color Picker App – sends RGB values to the lamp

Source Code:

/*******************************************************************
  Kitchen RGB Light by Bithead942

 When new serial data arrives, this sketch adds it to a String.
 The expected string format is:
     "r=###,b=###,g=###"
 It is terminated with an '\n' character (ASCII 13 or 10)
 The valid number range for each parameter is 0 to 255
 Upon receipt, the sketch updates the lights using the RGB shield using Pulse Width Modulation (PWM)

 PINS USED:
    Xbee Shield
      Tx       0
      Rx       1

    RBG Shield
      Red      3
      Green    5
      Blue     6

 *********************************************************************/

String inString = "";         // a string to hold incoming data
boolean stringComplete = false;  

int red = 3;    // RED LED connected to PWM pin 3
int green = 5;    // GREEN LED connected to PWM pin 5
int blue = 6;    // BLUE LED connected to PWM pin 6
int r=255; 
int g=255; 
int b=255;

char colorArr[5];
String temp="";
int Pos_r;
int Pos_g;
int Pos_b;
int End;

int distance = 0;
unsigned int iCounter = 0;
unsigned int LIGHTTIME = 60000;  //10 minutes
boolean bCount;

void setup() {
  pinMode(red, OUTPUT);
  pinMode(green, OUTPUT);
  pinMode(blue, OUTPUT);

  Serial.begin(9600);
  // reserve 200 bytes for the inputString:
  inString.reserve(20);
  inString = "";

  rgb(255,255,255);
  delay(500);
  rgb(0,0,0);
}

void loop() {
  if (stringComplete) 
  {
    //Check for valid command
    temp="";
    Pos_r = inString.indexOf("r");
    Pos_g = inString.indexOf("g");
    Pos_b = inString.indexOf("b");
    End = inString.indexOf("\n");

      if(Pos_r>=0)
      {
         temp=inString.substring((Pos_r+2), (Pos_g-1));
         temp.toCharArray(colorArr, 5);
         r=(atoi(colorArr));
      }
      if(Pos_g>=0)
      {
         temp=inString.substring((Pos_g+2), (Pos_b-1));
         temp.toCharArray(colorArr, 5);
         g=(atoi(colorArr));
      }         
      if(Pos_b>=0)
      {
         temp=inString.substring((Pos_b+2), (End-1));
         temp.toCharArray(colorArr, 5);
         b=(atoi(colorArr));
      }      

      if ((Pos_r>=0)&&(Pos_g>=0)&&(Pos_b>=0)) 
      {
         iCounter = 0;
         bCount = true;
         rgb(r,g,b);
      }

    // clear the string:
    inString = "";
    stringComplete = false;
  }

   distance = analogRead(0);

   if (distance >= 60)
      {
      if ((Pos_r>=0)&&(Pos_g>=0)&&(Pos_b>=0)) 
        {
        rgb(r,g,b);
        } 
      iCounter = 0;
      bCount = true;
      }
   else if (iCounter >= LIGHTTIME)
      {
      rgb(0,0,0);
      iCounter = 300000;  //5 minutes
      bCount = false;
      }

   if (bCount) iCounter++;
   delay(10);
}

/*
  SerialEvent occurs whenever a new data comes in the
 hardware serial RX.  This routine is run between each
 time loop() runs, so using delay inside loop can delay
 response.  Multiple bytes of data may be available.
 */
void serialEvent() {
  while (Serial.available()) 
  {
    // get the new byte:
    char inChar = (char)Serial.read(); 
    // add it to the inputString:
    inString += inChar;
    // if the incoming character is a newline, set a flag
    // so the main loop can do something about it:
    if (inChar == 13 or inChar == 10) 
    {
      stringComplete = true;
    } 
  }
}

void rgb(int r, int g, int b)
{

  if (r>255) r=255;
  if (g>255) g=255;
  if (b>255) b=255;
  if (r<0) r=0;
  if (g<0) g=0;
  if (b<0) b=0;

  analogWrite(red, r);
  analogWrite(green, g);
  analogWrite(blue, b);
}
Advertisements

2 Comments

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s