Turai Botond
Published © GPL3+

Shelf lighting

Upgrade the IKEA KALLAX or other shelf with mood lighting. You can integrate shelf lighting into your smart home system.

IntermediateShowcase (no instructions)20 hours268
Shelf lighting

Things used in this project

Hardware components

Espressif ESP32 Development Board - Developer Edition
Espressif ESP32 Development Board - Developer Edition
×1
Flora RGB Neopixel LEDs- Pack of 4
Adafruit Flora RGB Neopixel LEDs- Pack of 4
×1
Alarm cable 4 core
×1
Anycubic i3 Mega 3D printer
Anycubic i3 Mega 3D printer
Any 3D printer
×1

Software apps and online services

Arduino IDE
Arduino IDE

Hand tools and fabrication machines

Soldering Station, Hobbyist
Soldering Station, Hobbyist
Solder Wire, Lead Free
Solder Wire, Lead Free
Drill / Driver, Cordless
Drill / Driver, Cordless
Tape, Double Sided
Tape, Double Sided

Story

Read more

Custom parts and enclosures

3D design

You can load the plans into the slicing program of 3D printers.

Schematics

Schematic

Circuit

Code

Demo code for ESP-32

Arduino
Program the ESP-32 using the Arduino IDE
#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
  #include <avr/power.h>
#endif
#define PIN        2
#define NUMPIXELS 16

Adafruit_NeoPixel pixels(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);


uint8_t rVal=254, gVal=1, bVal=127;
int rDir=-1, gDir=1, bDir=-1;

float easeInOutQuad(const float& x) {
  return x < 0.5f ? 2.0f * x * x : 1.0f - pow(-2.0f * x + 2.0f, 2) / 2.0f;
}

void setup() {
#if defined(__AVR_ATtiny85__) && (F_CPU == 16000000)
  clock_prescale_set(clock_div_1);
#endif

  pixels.begin();
  pixels.clear();
  for(float j = 0; j < 1; j += 0.01){
    float m = easeInOutQuad(j);
    for(int i=0; i<NUMPIXELS; i++) {
      pixels.setPixelColor(i, pixels.Color((uint8_t)(rVal * m),(uint8_t)(gVal * m),(uint8_t)(bVal * m)));
    }
    pixels.show();
    delay(10);
  }
}

void loop() {
  rVal = rVal + rDir;
  gVal = gVal + gDir;
  bVal = bVal + bDir;
  if (rVal >= 255 || rVal <= 0) rDir *= -1;
  if (gVal >= 255 || gVal <= 0) gDir *= -1;
  if (bVal >= 255 || bVal <= 0) bDir *= -1;
  for(int i=0; i<NUMPIXELS; i++) {
    pixels.setPixelColor(i, pixels.Color(rVal,gVal,bVal));
  }
  pixels.show();
  delay(20);
}

OpenSCAD script

SCAD
I designed the PCB supports using OpenSCAD. You can change the plans if you want.
// Constants
//units are in mm
$fn = 128;

neopixel_radius = 4.95;
led_radius = 2.0;
material_thickness = 1;
cable_holder_height = 5.5;
cable_holder_depth = 30;
cable_radius = 2;
pcb_height = 2.00;

cover_dist = 12.0;
show_neopixel = false;
show_cable = false;
show_holder = true;
show_cover = true;

cable_holder_width = (neopixel_radius * 2) + (2 * material_thickness);

if(show_neopixel){
    translate([0,0, (cable_holder_height/2) - 2.05])
    neopixel(r=neopixel_radius, w= 2);
}

if(show_cable){
    translate([0,-neopixel_radius - 1,0.2])
    cable(r=cable_radius, l=40);
    
    rotate([0,0,180])
    translate([0,-neopixel_radius - 1,0.2])
    cable(r=cable_radius, l=40);
}


group(){
    if(show_holder){
        cable_holder(
            w = cable_holder_width, 
            h = cable_holder_height, 
            d = cable_holder_depth, 
            t = material_thickness,
            r = neopixel_radius,
            cable_r = cable_radius,
            pcb_h = pcb_height
        );
    }

    if(show_cover){
        translate([0, 0, (cable_holder_height/2) + cover_dist])
        cable_holder_cover(
            w = cable_holder_width, 
            h = cable_holder_height, 
            d = cable_holder_depth, 
            t = material_thickness,
            r1 = neopixel_radius,
            r2 = led_radius,
            cable_r = cable_radius
        );
    }
}

module cable_holder_cover(w, h, d, t, r1, r2, cable_r){
    gap = 0.1;
    dimming = 0.25;
    difference(){
        group(){
            // pöcök 1
            rotate([0, 180, 90])
            translate([
                -(d - (2*t))/2,
                (-w/2) + t,
                t + gap+dimming
            ])
            prism(l = (d - (2*t)), w = t/2, h = t/2);
            
            translate([
                (w/2)- (2.5*t),
                -d/2 + t,
               - t - (t/2) -dimming - gap
            ])
            cube([(t), (d - (2*t)), 2*t + gap], false);
            
            
            //rotate([0, 0, 180])
            translate([
                (w/2)- (2*t) + t/2,
                -d/2 + t,
                -t - gap - dimming
            ])
            cube([t/2, (d - (2*t)), dimming ], false);
            
            // pöcök 2
            rotate([0,0, 180])
            group(){
                rotate([0, 180, 90])
                translate([
                    -(d - (2*t))/2,
                    (-w/2) + t,
                    t + gap+dimming
                ])
                prism(l = (d - (2*t)), w = t/2, h = t/2);
                
                translate([
                    (w/2)- (2.5*t),
                    -d/2 + t,
                   - t - (t/2) -dimming - gap
                ])
                cube([(t), (d - (2*t)), 2*t + gap], false);
                
                
                //rotate([0, 0, 180])
                translate([
                    (w/2)- (2*t) + t/2,
                    -d/2 + t,
                    -t - gap - dimming
                ])
                cube([t/2, (d - (2*t)), dimming ], false);
            }
              
            translate([0, 0, t/2])
            cube([w, d, t],true);
        }
        //led hole
        cylinder(h = h/2, r1=r2/2, r2 = r2*2, center = true);
        extra = 1;
        translate([
            -(r1+0.1),
            -(r1+extra), 
            -h/2
        ])
        
        cube([((r1+extra) * 2), ((r1+extra) * 2), h/2], center = false);
                
    }
    //cable upper holder
    cable_holder_gap = -0.03;
    //Here
    rotate([90,0,0])
    translate([0,  -cable_r-0.53, (d/2)-(t/2)])
    
    difference(){
        group(){
            cylinder(h = t, r = cable_r+t, center = true);
            
            translate([0,2*(t+0.1),0])
            cube([2*cable_r+t,t,t], center = true);
        }
        cylinder(h = (2 * t)+2, r = cable_r, center = true);
        translate([0, -cable_r - (t), 0])
        cube([2*(cable_r+t),2*(cable_r+t),(2 * t)+2], center = true);
        
        translate([-cable_r - (t/2)+cable_holder_gap,  cable_r, 0])
        cube([t, 2*cable_r,(2 * t)+2], center = true);
        
        rotate([0,180,0])
        translate([-cable_r - (t/2)+cable_holder_gap,  cable_r, 0])
        cube([t, 2*cable_r,(2 * t)+2], center = true);
        
        cube([2 * cable_r + 2, 2*t,(2 * t)+2], center = true);  
    }
    
    
    
    
    rotate([90,0,180])
    translate([0,  -cable_r-0.53, (d/2)-(t/2)])
    difference(){
        group(){
            cylinder(h = t, r = cable_r+t, center = true);
            translate([0,2*(t+0.1),0])
            cube([2*cable_r+t,t,t], center = true);
        }
        cylinder(h = (2 * t)+2, r = cable_r, center = true);
        translate([0, -cable_r - (t), 0])
        cube([2*(cable_r+t),2*(cable_r+t),(2 * t)+2], center = true);
        
        translate([-cable_r - (t/2)+cable_holder_gap,  cable_r, 0])
        cube([t, 2*cable_r,(2 * t)+2], center = true);
        rotate([0,180,0])
        translate([-cable_r - (t/2)+cable_holder_gap,  cable_r, 0])
        cube([t, 2*cable_r,(2 * t)+2], center = true);
        
        cube([2 * cable_r + 2, 2*t,(2 * t)+2], center = true);  
    }
    
}

module cable_holder(w, h, d, t, r, cable_r, pcb_h){
    difference(){
        group(){
            difference(){
                cube([w, d, h], true);
                
                translate([0, 0, t])
                cube([w - (2 * t), d + (2* t), h], true);
            }
            //perem 1
            translate([
                (w/2) - t, 
                0, 
                (h/2) - (t/2)
            ])
            cube([t/2, d, t], true);
            //perem 2
            rotate([0, 00, 180])
            translate([
                (w/2) - t, 
                0, 
                (h/2) - (t/2)
            ])
            cube([t/2, d, t], true);
        }
        translate([0,0,t])
        cylinder(h = h, r = r, center = true);
    }
    
    
    difference(){
        group(){
            cylinder(h = h, r = r + t, center = true);
            
            translate([(w/2) - (3*t), -(r+2*t)/2 - 2, -h/2])
            cube([2*t,2*t,h], center = false);
            
            rotate([180,0,0])
            translate([(w/2) - (3*t), -(r+2*t)/2 - 2, -h/2])
            cube([2*t,2*t,h], center = false);
            
            rotate([180,180,0])
            translate([(w/2) - (3*t), -(r+2*t)/2 - 2, -h/2])
            cube([2*t,2*t,h], center = false);
            
            rotate([0,180,0])
            translate([(w/2) - (3*t), -(r+2*t)/2 - 2, -h/2])
            cube([2*t,2*t,h], center = false);
        }
        cylinder(h = h+1, r = r, center = true);
        cube([w/1.8, d, h+1], true);
    }
    // oldal fal 1
    difference(){
        translate([0,(d-t)/2,0])
        cube([w, t, h], center = true);
        rotate([90, 0, 0])
        translate([0, cable_r/9, -(d/2) + (t/2)])
        cylinder(h = (2 * t), r = cable_r, center = true);
        
        rotate([90, 0, 0])
        translate([0, cable_r+cable_r/9, -(d/2) + (t/2)])
        cube([(2*cable_r)+0.1,2*cable_r,cable_r], center = true);
    }
    
    // oldal fal 2
    difference(){
        translate([0,-(d-t)/2,0])
        cube([w, t, h], center = true);
        rotate([90, 0, 0])
        translate([0,  cable_r/9, (d/2) - (t/2)])
        cylinder(h = (2 * t), r = cable_r, center = true);
        
        rotate([90, 0, 180])
        translate([0, cable_r+cable_r/9, -(d/2) + (t/2)])
        cube([(2*cable_r)+0.1,2*cable_r,cable_r], center = true);
    }
    //PCB holders
    rotate([90, 0, 90])
    translate([-t/2, -(h/2) + t, -(w/2) + (t)])
    cube([t,pcb_h,t], center = false);
    
    rotate([90, 0, -90])
    translate([-t/2, -(h/2) + t, -(w/2) + (t)])
    cube([t,pcb_h,t], center = false);
}

module prism(l, w, h){
    polyhedron(
        points=[[0,0,0], [l,0,0], [l,w,0], [0,w,0], [0,w,h], [l,w,h]],
        faces=[[0,1,2,3],[5,4,3,2],[0,4,5,1],[0,3,4],[5,2,1]]
    );
}

module neopixel(r, w){
    pcb_h = 0.9;
    led_s = 4.9;
    led_h = 2.65 - pcb_h;
    color([0,0.6,0])
    cylinder(h = pcb_h, r =r);
    color(c=[0.2,0.2,0.20])
    translate([0, 0,1])
    cube([led_s,led_s,led_h], center = true);
}

module cable(r, l){
    color([0.6,0,0],alpha=0.2)
    rotate([90,0,0])
    cylinder(h=l, r = r, center = false);
}

Credits

Turai Botond

Turai Botond

5 projects • 21 followers
Check out my youtube channel for exciting projects: www.youtube.com/@botondturai

Comments