After seeing the SplashLight from Avoooq and enjoying the image of a pouring bottle lamp, I felt I had to make one and make it awesome. My first idea was to recycle a lamp from around the house and create something completely new. I discovered that all my lamps already had a good use case. So I dug into the electronics drawers and found I had an unused Arduino UNO and enough electronic bits and lights to build my own lamp.
So first I had to protoype something. NeoPixels from Adafruit seemed like a good lighting choice with the Arduino board I had and I just happened to have a nice 60 strand without a purpose. I had 4 matching potentiometers and enough solder and wire to get started. Figuring that a mode selection switch and individual red, green, and blue controls would give me maximum flexibility, I began prototyping.
Once I had the basic code banged out (and I am a terrible and lazy coder…like all the good ones), I began refining the functions of the potentiomters. I ended up with four modes.
- A white light mode with a variable brightness knob.
- Three knobs controlling red, green and blue to create your own specific lighting color.
- A simple random color applied to random pixel mode.
- Run all of the Adafruit example strand tests and more.
Here is a listing of the code below. Be sure to grab the NeoPixel library and read the Uberguide for NeoPixel:
include <Adafruit_NeoPixel.h> define PIN 6 define MODEPIN 0 define REDPIN 1 define GREENPIN 2 define BLUEPIN 3 int MODEPOT = 0; int MODE = 0; int REDPOT = 0; int REDCTL = 0; int GREENPOT = 0; int GREENCTL = 0; int BLUEPOT = 0; int BLUECTL = 0; int rand1 = 0; int rand2 = 0; int rand3 = 0; int rand4 = 0; // Parameter 1 = number of pixels in strip // Parameter 2 = Arduino pin number (most are valid) // Parameter 3 = pixel type flags, add together as needed: // NEOKHZ800 800 KHz bitstream (most NeoPixel products w/WS2812 LEDs) // NEOKHZ400 400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers) // NEOGRB Pixels are wired for GRB bitstream (most NeoPixel products) // NEORGB Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2) AdafruitNeoPixel strip = AdafruitNeoPixel(60, PIN, NEOGRB + NEOKHZ800); // IMPORTANT: To reduce NeoPixel burnout risk, add 1000 uF capacitor across // pixel power leads, add 300 - 500 Ohm resistor on first pixel's data input // and minimize distance between Arduino and first pixel. Avoid connecting // on a live circuit...if you must, connect GND first void setup() { strip.begin(); strip.show(); // Initialize all pixels to 'off' // Enable for testing // Serial.begin(9600); } void loop() { MODEPOT = analogRead(MODEPIN); REDPOT = analogRead(REDPIN); GREENPOT = analogRead(GREENPIN); BLUEPOT = analogRead(BLUEPIN); MODE = MODEPOT * (5.0 / 1023.0); REDCTL = REDPOT * (255.0 / 1023.0); GREENCTL = GREENPOT * (255.0 / 1023.0); BLUECTL = BLUEPOT * (255.0 / 1023.0); // Enable for testing // Serial.println(GREENPOT); // Serial.println(GREENCTL); if (MODE >= 0 && MODE < .5){ // Off colorWipe(strip.Color(0, 0, 0), 5); // Nothing } if (MODE >= .5 && MODE < 2){ // First Position colorWipe(strip.Color(REDCTL, REDCTL, REDCTL), 5); // White } if (MODE >= 2 && MODE < 3.5){ // Second Position colorWipe(strip.Color(REDCTL, GREENCTL, BLUECTL), 5); // COLOR MIX Based on Knob Position } if (MODE >= 3.5 && MODE < 4.5){ // Third Position rand1 = random(10, 127); rand2 = random(10, 127); rand3 = random(10, 127); rand4 = random(0, 60); // 60 is the number of my NeoPixels, yours may vary strip.setPixelColor(rand4, rand1, rand2, rand3); // Random Pixel Firing strip.show(); } if (MODE >= 4.5){ // Fourth Position Modified strand testing theaterChase(strip.Color(255, 255, 255), 50); // White theaterChase(strip.Color(255, 0, 0), 50); // Red theaterChase(strip.Color( 0, 255, 0), 50); // Green theaterChase(strip.Color( 0, 0, 255), 50); // Blue theaterChase(strip.Color( 0, 255, 255), 50); // Cyan theaterChase(strip.Color( 255, 0, 255), 50); // Purple theaterChase(strip.Color( 255, 255, 0), 50); // Yellow rainbow(20); rainbowCycle(20); theaterChaseRainbow(50); } } // Fill the dots one after the other with a color void colorWipe(uint32t c, uint8t wait) { for(uint16t i=0; i<strip.numPixels(); i++) { strip.setPixelColor(i, c); strip.show(); delay(wait); } } // Single entry Color void colorSingle(uint32t c,uint8t wait) { for(uint16t i=0; i<strip.numPixels(); i++) { strip.setPixelColor(i, c); strip.show(); delay(wait); } } void rainbow(uint8t wait) { uint16t i, j; for(j=0; j<256; j++) { for(i=0; i<strip.numPixels(); i++) { strip.setPixelColor(i, Wheel((i+j) & 255)); } strip.show(); delay(wait); } } // Slightly different, this makes the rainbow equally distributed throughout void rainbowCycle(uint8t wait) { uint16t i, j; for(j=0; j<256*5; j++) { // 5 cycles of all colors on wheel for(i=0; i< strip.numPixels(); i++) { strip.setPixelColor(i, Wheel(((i * 256 / strip.numPixels()) + j) & 255)); } strip.show(); delay(wait); } } //Theatre-style crawling lights. void theaterChase(uint32t c, uint8t wait) { for (int j=0; j<10; j++) { //do 10 cycles of chasing for (int q=0; q < 3; q++) { for (int i=0; i < strip.numPixels(); i=i+3) { strip.setPixelColor(i+q, c); //turn every third pixel on } strip.show(); delay(wait); for (int i=0; i < strip.numPixels(); i=i+3) { strip.setPixelColor(i+q, 0); //turn every third pixel off } } } } //Theatre-style crawling lights with rainbow effect void theaterChaseRainbow(uint8t wait) { for (int j=0; j < 256; j++) { // cycle all 256 colors in the wheel for (int q=0; q < 3; q++) { for (int i=0; i < strip.numPixels(); i=i+3) { strip.setPixelColor(i+q, Wheel( (i+j) % 255)); //turn every third pixel on } strip.show(); delay(wait); for (int i=0; i < strip.numPixels(); i=i+3) { strip.setPixelColor(i+q, 0); //turn every third pixel off } } } } // Input a value 0 to 255 to get a color value. // The colours are a transition r - g - b - back to r. uint32t 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); } }
With the code ready enough, I turned to producing something more than a protypical collection of loose wires and alligator clips. Time to exercise the 3D printer. With my aging, but by no means useless, Makerbot Replicator 2, I began modeling and printing a case for the Arduino and a place to attach all of the potentiometers. After way more iterations than a skilled engineer would have taken, I arrived upon a flexible design that I could assemble the parts into.
I was able to solder together everything following this basic layout:
Finally, some wire routing and soldering to get the lamp assembled and I am ready for a first test:
Here are a few more pictures of the finished project:
Avooq December 3, 2014
This is really cool, using strip lighting inside the bottle is very nice. Having a clear Splash with the lights inside the fountain might also be very effective.
Rich Thompson December 4, 2014 — Post Author
A clear splash with lights moving downward would look really cool…good idea.