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

901 Views, 16 Favorites, 0 Comments

How to Make a Driftwood Mood Lamp With Infrared Remote Control (using Arduino, an ATtiny85 and an Adafruit NeoPixel Ring)

Collage-1.jpg
IMG_7012.jpeg
IMG_3733.jpeg
F47YPDJL2Q5W7OJ.jpeg
FG7FCH7L2Q5W6F8.jpeg
FDMYJKQL2Q5W7IM.jpeg
Driftwood mood lamp with infrared remote control (using arduino, an ATtiny85 and a Pixelring)

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

2066A9E5-F5EF-4D19-8312-542D6F0A1A1A_1_105_c.jpeg
ED22C800-DC94-4764-831F-BEB65B2DD241_1_105_c.jpeg
F9F150FC-BA81-4FC5-B175-5875B5B6E4DE_1_105_c.jpeg
03D7ABF4-3C5A-4D85-BF49-9F98058EA948_1_105_c.jpeg
7CC596FC-E3B7-469E-82B1-5E832870E734_1_105_c.jpeg
B009F72B-C75C-4463-BCFE-B80AE96213AC_1_105_c.jpeg
1AE33FF0-3847-4FC1-887C-68D6D75EB985_1_105_c.jpeg

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

97A92A7C-B2FE-4E14-A58E-4A3A6AF64007_1_105_c.jpeg
3EBDF1B9-BEC4-45CD-8243-905F4B668E5B_1_105_c.jpeg
409FBD0D-4DE4-4EF9-8A75-27966670E1FB_1_105_c.jpeg
8ED7999F-0B00-428F-A819-0C05047B6EB6_1_105_c.jpeg
EBDC12E7-4E6A-4A4D-852E-989CAFA033C3_1_105_c.jpeg
40B8D7BF-3327-43C7-9FFD-658D1BFED750_1_105_c.jpeg
586CFC4C-BCA2-4918-9DF0-F2FFC54A7064_1_105_c.jpeg

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

66A85884-721A-4972-8C15-30873389FFCC_1_105_c.jpeg
F58518C1-6DBC-4650-BD60-00558DC69A5C_1_105_c.jpeg
Screenshot 2022-05-03 at 07.51.08.png
CC11A692-F3FA-4C0F-8CCA-BC5ED871ECFD_1_105_c.jpeg
456D1946-F3F7-42C4-BF88-1EA8F716B210_1_201_a Medium.jpeg
F5C353FF-465D-4A82-B055-0E27D6D20A4E Medium.jpeg
Changing Pixelring using IR Remote control and 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

Control IR Pixelring Attiny85_bb (1).jpg
Screenshot 2022-05-03 at 08.18.09.png
Pixelring controlled by IR remote with ATTiny85 chip

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:

  1. Add the library "tiny_IRremote.h" which you can find on Github.
  2. 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.
  3. 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.
  4. Then wire the ATtiny85 per the Fritzing diagram attached and it should run as it did on the micro arduino.
  5. 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

F910F74F-71F1-451E-AAAC-86128DC820D0_1_105_c.jpeg
IMG_3589.jpeg
Screenshot 2022-05-03 at 10.49.06.png
IMG_3654.jpeg
IMG_3746.jpeg

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

IMG_3476.jpeg
IMG_3723.jpeg
IMG_3725.jpeg
IMG_3729.jpeg
IMG_3732.jpeg
IMG_3735.jpeg
IMG_3736.jpeg
Driftwood mood lamp with infrared remote control (using arduino, an ATtiny85 and a Pixelring)

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.