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.