How to Make a Driftwood Mood Lamp With Infrared Remote Control (using Arduino, an ATtiny85 and an Adafruit NeoPixel Ring)
by Artful_Dabbler in Workshop > Lighting
953 Views, 17 Favorites, 0 Comments
How to Make a Driftwood Mood Lamp With Infrared Remote Control (using Arduino, an ATtiny85 and an Adafruit NeoPixel Ring)
I wanted to make a lamp from some old aquarium driftwood that was lying around, where the colours could be selected using an infrared remote and that would run on USB power using the small powerful ATTiny85 chip.
The design allows the user to choose from warm colours (reds, purples, oranges), cool colours (greens and blues) or specific colour choices. A total of 9 different selections. It also has adjustable brightness settings.
Supplies
Equipment needed as follows:
For base:
- Old pieces of wooden patio decking
- Gnarled driftwood
- Wood glue
For electric circuitry:
- An Arduino
- Breadboard
- Adafruit Pixelring (12 LED variant)
- Infrared remote and receiver
- Capacitor 100-1000 uF and atleast 6.3v
- Resistors (470 ohm) and (4.7k ohm)
- ATtiny85
- Sparkfun ATtiny Programmer
- Micro USB power source
- L-Headers
- USB extension cable (here)
- Button switch
- Wire in different colours
- Heat shrink wrap
- (Note I have created a PCB that makes the project neater. I have shown this at the end.)
Tools needed:
- Small router for base edging
- Table saw
- Soldering iron and solder
- Dremel tool
Make the Base
The base is made from two pieces of old patio decking we had lying around.
Start by cutting off the edges using a table saw, leaving the width of both main pieces of wood at 8cm each (meaning removing 1.5cm from each side). This should leave you with two pieces of wood 16cm by 8cm. Obviously adjust this as needed based on the width of wood available.
Then glue those two pieces together to form a 16cm x 16cm base.
Next glue the offcuts to the base (per the picture) having cut the corners to 45 degrees.
This will allow enough depth to fit all the electronics into, later in the project.
Finally shape the edges with a router to give an elegant finish on the upper side.
Add the Pixel Ring, Infrared Receiver and USB Power Source
Next, drill three small holes to allow the legs of the infrared receiver to connect from the surface to the underside of the project.
Also cut three more holes in the correct position for the pixel ring (the points you need to connect are 5V, GND and data in). Ignore data out for this project.
Solder wires to the three legs of the IR receiver and also the pixel ring.
Finally cut a hole using a Dremel to allow a micro USB extension to be fitted (the one I used is shown in the image and goes from female (with a flush fitting) to male).
Test the Circuit on a Breadboard Using an Arduino
I used an arduino micro for testing but use any you have to hand.
The wiring is as follows:
- IR receiver signal wire to Pin 5 of micro arduino
- Connect Pin 9 of Arduino to Pixel ring data in wire via a 470 ohm resistor (suggested in best practice guide from Adafruit. See here for details.)
- All other lines connected to 5v and GND with a 100-1000 uF (atleast 6.3v) capacitor between the lines. I used a 1000uF 16v variant.
Next ensure that you know the correct codes from the Infrared transmitter so that you can code the buttons to do what you want them to do.
To do this follow the instructions shown here. Note the need for the IRremote.h library to be added in the Arduino IDE. The result will be that you will have an accurate list of codes for each button on your remote.
Then use the following code ensuring that you change the RGB colours to the ones you want and amending the "Define Key" section to be correct for your IR remote.
Also note that both the IRremote.h and Adafruit_NeoPixel.h libraries are needed for this code. You can add these in the Arduino IDE Manage Library tool.
The code does something quite simple:
- Buttons 1-5 just show single colours.
- Button 6 to 8 cycle though colour combinations.
- And button 9 runs the lovely Rainbowcycle sequence.
- Button 0 then turns the LEDs to Black.
- Finally the right and left keys increase or decrease the brightness.
/*Description: Press 1 on the keypad and pixelring glows one colour until another button pressed Press 2 on the keypad and pixelring glows one colour (different) until another button pressed Press 3 on the keypad and pixelring glows one colour (different) until another button pressed Press 4 on the keypad and pixelring glows one colour (different) until another button pressed Press 5 on the keypad and pixelring glows one colour (different) until another button pressed Press 6 on the keypad and pixelring glows three different colours (ColourWipe) until another button pressed Press 7 on the keypad and pixelring glows three different colours (ColourWipe v2) until another button pressed Press 8 on the keypad and pixelring glows three different colours (ColourWipe v3) until another button pressed Press 9 on the keypad and pixelring runs RainbowCycle until another button pressed. Press 0 on the keypad and all pixelring goes off. Right key - brighter setting Left key - dimmed settings */ #include <IRremote.h> #include <Adafruit_NeoPixel.h> #define RECEIVER_PIN 5 // arduino pin for reception IRrecv receiver(RECEIVER_PIN); // create a receiver object of the IRrecv class decode_results results; // create a results object of the decode_results class unsigned long key_value = 0; //save the ir code received int brightness=250; //value for the pixels brightness //===Your ir codes==== #define KEY_1 0xFF6897 #define KEY_2 0xFF9867 #define KEY_3 0xFFB04F #define KEY_4 0xFF30CF #define KEY_5 0xFF18E7 #define KEY_6 0xFF7A85 #define KEY_7 0xFF10EF #define KEY_8 0xFF38C7 #define KEY_9 0xFF5AA5 #define KEY_0 0xFF4AB5 #define KEY_RIGHT 0xFFC23D #define KEY_LEFT 0xFF22DD //===My ir codes==== /*#define KEY_1 0xFD08F7 #define KEY_2 0xFD8877 #define KEY_3 0xFD48B7 #define KEY_4 0xFD28D7 #define KEY_5 0xFDA857 #define KEY_6 0xFD6897 #define KEY_7 0xFD18E7 #define KEY_8 0xFD9867 #define KEY_9 0xFD58A7 #define KEY_0 0xFD30CF #define KEY_RIGHT 0xFD609F #define KEY_LEFT 0xFD20DF */ unsigned long KEY_IR[12]={KEY_1,KEY_2,KEY_3,KEY_4,KEY_5,KEY_6,KEY_7,KEY_8,KEY_9,KEY_0,KEY_LEFT,KEY_RIGHT}; #define NUM_PIXEL 12 //amount of pixels #define PIN 9 //arduino pin for pixelring uint16_t i, j; //define the pixel that turn on uint8_t color=0; //change the color unsigned long timePixel=0; //time for each pixel turn on Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_PIXEL, PIN, NEO_GRB + NEO_KHZ800); void setup() { Serial.begin(9600); //serial transmittion at 9600 bauds receiver.enableIRIn(); // enable the receiver receiver.blink13(true); // enable blinking of the built-in LED when IR signal occurs strip.begin(); //initialize the pixelring strip.setBrightness(brightness); //set the brightness strip.show(); // Initialize all pixels to 'off' pinMode(13, OUTPUT); } void loop() { if (receiver.decode(&results)){ //if a ir code has been received for(int num=0;num<12;num++){ //cycle for compare with KEY_IR if(results.value==KEY_IR[num]){ //compare the ir code received with KEY_IR (correct ir codes) key_value = results.value; //save the ir code received Serial.println(key_value, HEX); //show on serial monitor i=0; //reset the variables for the pixels j=0; color=0; colorRing(strip.Color(0, 0, 0), 0); //turn off the pixels num=255; //put a number >12 for get out of the cycle "for" } } receiver.resume(); // reset the receiver for the next code } switch (key_value) { //compare the key_value received and saved case KEY_1: colorWipe(strip.Color(255, 0, 0), 500); // Red break; case KEY_2: colorWipe(strip.Color(255, 0, 255), 500); // Magenta break; case KEY_3: colorWipe(strip.Color(0, 0, 255), 500); // Blue break; case KEY_4: colorWipe(strip.Color(0, 255, 255), 500); // cyan break; case KEY_5: colorWipe(strip.Color(0, 255, 0), 500); // Green break; case KEY_6: if(color==0) colorWipe(strip.Color(0, 255, 155), 500); // Turquoise else if(color==1)colorWipe(strip.Color(0, 125, 255), 500); // Ocean else if(color==2)colorWipe(strip.Color(0, 0, 255), 500); // Blue break; case KEY_7: if(color==0) colorWipe(strip.Color(255, 0, 96), 500); // Pink else if(color==1) colorWipe(strip.Color(255, 0, 0), 500); // Red else if(color==2) colorWipe(strip.Color(64, 0, 128), 500); // Purple break; case KEY_8: if(color==0)colorWipe(strip.Color(0, 255, 125), 500); // Turquoise else if(color==1)colorWipe(strip.Color(0, 255, 0), 500); // Green else if(color==2)colorWipe(strip.Color(125, 255, 0), 500); // Spring Green break; case KEY_9: rainbowCycle(20); break; case KEY_0: colorRing(strip.Color(0, 0, 0), 0); // Black key_value=0; break; case KEY_RIGHT: if(brightness<245) brightness+=10; //increase the brightness strip.setBrightness(brightness); //set the new brightness key_value=0; //reset the key_value break; case KEY_LEFT: if(brightness>11) brightness-=10;; //decrease the brightness strip.setBrightness(brightness); //set the new brightness key_value=0; //reset the key_value break; } } void colorWipe(uint32_t c, uint8_t wait) { //set the color in only one pixel if(i<NUM_PIXEL && millis()-timePixel>wait){ //compare with the "wait" time strip.setPixelColor(i, c); //set the color on pixel i strip.show(); //show the color on pixel i++; //increase the pixel number timePixel=millis(); //take the current time } else if(i>=NUM_PIXEL){ //if it reachs NUM_PIXEL, reset the variables and increase the color for keys 6,7,8 i=0; color++; if(color>2) color=0; } } void colorRing(uint32_t c, uint8_t wait){ //set the color in all the pixel ring for(uint16_t pixel=0; pixel<strip.numPixels(); pixel++) { strip.setPixelColor(pixel, c); strip.show(); delay(wait); } } // Slightly different, this makes the rainbow equally distributed throughout void rainbowCycle(uint8_t wait) { if(i<NUM_PIXEL){ strip.setPixelColor(i, Wheel(((i * 256 / strip.numPixels()) + j) & 255)); //set the rgb color (wheel subroutine) i++; //increase the pixel number } else{ strip.show(); //show the color on pixelring delay(wait); //delay for "wait" time i=0; //reset the pixel number if(j<256*5){ //for increase the J parameter for rainbowCycle effect j++; } else{ j=0; //reset the J parameter } } } // The colours are a transition r - g - b - back to r. uint32_t Wheel(byte WheelPos) { WheelPos = 255 - WheelPos; if(WheelPos < 85) { return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3); } else if(WheelPos < 170) { WheelPos -= 85; return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3); } else { WheelPos -= 170; return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0); } }
Move Project to ATTINY85
I then chose to minimise the project and make it more permanent. I chose to use the ATtiny85 for this.
The steps are as follows:
- Add the library "tiny_IRremote.h" which you can find on Github.
- Use the Sparkfun Tiny Programmer (here) to load the code below on the ATtiny85. The hook up and instruction guide is here. It is really easy to use.
- In the arduino IDE - remember to pick your board (ATTiny85), clockspeed (Internal 8mhz) and Programmer (USBTinyISP) before loading. Also Burn Bootloader first so that the ATTiny85 runs at 8mhz.
- Then wire the ATtiny85 per the Fritzing diagram attached and it should run as it did on the micro arduino.
- Note - I added a reset button to the ATTiny85 which runs from Pin 1 and uses a 4.7k resistor. See here for details.
#include <tiny_IRremote.h> #include <tiny_IRremoteInt.h> #include <Adafruit_NeoPixel.h> #define F_CPU 8000000 #define __AVR_ATtiny85__ int RECV_PIN = 1; IRrecv irrecv(RECV_PIN); decode_results results; unsigned long key_value = 0; //===Your ir codes==== #define KEY_1 0xFF6897 #define KEY_2 0xFF9867 #define KEY_3 0xFFB04F #define KEY_4 0xFF30CF #define KEY_5 0xFF18E7 #define KEY_6 0xFF7A85 #define KEY_7 0xFF10EF #define KEY_8 0xFF38C7 #define KEY_9 0xFF5AA5 #define KEY_0 0xFF4AB5 #define KEY_RIGHT 0xFFC23D #define KEY_LEFT 0xFF22DD unsigned long KEY_IR[12]={KEY_1,KEY_2,KEY_3,KEY_4,KEY_5,KEY_6,KEY_7,KEY_8,KEY_9,KEY_0,KEY_LEFT,KEY_RIGHT}; int brightness=250; //value for the pixels brightness #define NUM_PIXEL 12 //amount of pixels #define PIN 4 //arduino pin for pixelring uint16_t i, j; //define the pixel that turn on uint8_t color=0; //change the color unsigned long timePixel=0; //time for each pixel turn on Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_PIXEL, PIN, NEO_GRB + NEO_KHZ800); void setup() { irrecv.enableIRIn(); strip.begin(); //initialize the pixelring strip.setBrightness(brightness); //set the brightness strip.show(); // Initialize all pixels to 'off' } void loop() { if (irrecv.decode(&results)) { for(int num=0;num<12;num++){ //cycle for compare with KEY_IR if(results.value==KEY_IR[num]){ //compare the ir code received with KEY_IR (correct ir codes) key_value = results.value; //save the ir code received i=0; //reset the variables for the pixels j=0; color=0; colorRing(strip.Color(0, 0, 0), 0); //turn off the pixels num=255; //put a number >12 for get out of the cycle "for" } } irrecv.resume(); } switch (key_value) { //compare the key_value received and saved case KEY_1: colorWipe(strip.Color(255, 0, 0), 500); // Red break; case KEY_2: colorWipe(strip.Color(255, 0, 255), 500); // Magenta break; case KEY_3: colorWipe(strip.Color(0, 0, 255), 500); // Blue break; case KEY_4: colorWipe(strip.Color(0, 255, 255), 500); // cyan break; case KEY_5: colorWipe(strip.Color(0, 255, 0), 500); // Green break; case KEY_6: if(color==0) colorWipe(strip.Color(0, 255, 125), 500); // Turquoise else if(color==1)colorWipe(strip.Color(0, 125, 255), 500); // Ocean else if(color==2)colorWipe(strip.Color(0, 0, 255), 500); // Blue break; case KEY_7: if(color==0) colorWipe(strip.Color(255, 0, 96), 500); // Pink else if(color==1) colorWipe(strip.Color(255, 0, 0), 500); // Red else if(color==2) colorWipe(strip.Color(64, 0, 128), 500); // Purple break; case KEY_8: if(color==0)colorWipe(strip.Color(0, 255, 125), 500); // Turquise else if(color==1)colorWipe(strip.Color(0, 255, 0), 500); // Green else if(color==2)colorWipe(strip.Color(125, 255, 0), 500); // Spring Green break; case KEY_9: rainbowCycle(20); break; case KEY_0: colorRing(strip.Color(0, 0, 0), 0); // Black key_value=0; break; case KEY_RIGHT: if(brightness<245) brightness+=10; //increase the brightness strip.setBrightness(brightness); //set the new brightness key_value=0; //reset the key_value break; case KEY_LEFT: if(brightness>11) brightness-=10;; //decrease the brightness strip.setBrightness(brightness); //set the new brightness key_value=0; //reset the key_value break; } delay(10); } void colorWipe(uint32_t c, uint8_t wait) { //set the color in only one pixel if(i<NUM_PIXEL && millis()-timePixel>wait){ //compare with the "wait" time strip.setPixelColor(i, c); //set the color on pixel i strip.show(); //show the color on pixel i++; //increase the pixel number timePixel=millis(); //take the current time } else if(i>=NUM_PIXEL){ //if it reachs NUM_PIXEL, reset the variables and increase the color for keys 6,7,8 i=0; color++; if(color>2) color=0; } } void colorRing(uint32_t c, uint8_t wait){ //set the color in all the pixel ring for(uint16_t pixel=0; pixel<strip.numPixels(); pixel++) { strip.setPixelColor(pixel, c); strip.show(); delay(wait); } } // Slightly different, this makes the rainbow equally distributed throughout void rainbowCycle(uint8_t wait) { if(i<NUM_PIXEL){ strip.setPixelColor(i, Wheel(((i * 256 / strip.numPixels()) + j) & 255)); //set the rgb color (wheel subroutine) i++; //increase the pixel number timePixel=millis(); } else{ strip.show(); //show the color on pixelring if(millis()-timePixel>wait){ // delay(wait); //delay for "wait" time i=0; //reset the pixel number if(j<256*5){ //for increase the J parameter for rainbowCycle effect j++; } else{ j=0; //reset the J parameter } } } } // The colours are a transition r - g - b - back to r. uint32_t Wheel(byte WheelPos) { WheelPos = 255 - WheelPos; if(WheelPos < 85) { return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3); } else if(WheelPos < 170) { WheelPos -= 85; return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3); } else { WheelPos -= 170; return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0); } }
Permanent Project Board
I chose to make a dedicated PCB to make the project neater but you can just solder the components on a Perma Protoboard like this one here with a DIP socket. I did that and have attached a picture here with a quick drawing of the wiring again.
I have also shown the PCB that I had made through PCBway and how that is wired. It just seemed like a much neater solution. I will make a small number available through eBay if you are interested in getting one (here).
Then bring it all together in the bottom of the wooden box as neatly as possible. See image
Add the Driftwood to Finalise
Finally add the driftwood artistically and secure with wood glue. This will mean sawing part of the driftwood so that it has a flat base.
And connect to a 5V USB power source. The project is then ready to enjoy. Mine sits in the lounge on our book shelves adding a splash of colour to the room. Enjoy.