This is a small project for a mood lamp in a glass vase with 4 x 15 5050 Neopixels. The Neopixel strips are mounted on a 1cm x 1cm x 20cm hollow aluminium profile inside the vase and connected accordingly. I drilled a hole into the vase’s bottom for the three cables 5V, GND, and DI leading to the Wemos D1 mini which is buried in the wooden socket of the lamp. Blynk is used to control the different patterns, speed and brightness as well as on/off the light. There are 12 patterns you may chose from. Program updates can be sent through the wireless network using OTA.
- Blynk server 0.23.5 on Orange Pi
- Blynk library 0.4.6
- Android phone
Here are a screen shot of the Blynk project, some videos and the code running on the Wemos. Hope you enjoy.
Activity 10: Fire
Activity 4: rainbowCycle
Activity 7: TwinkleRandom
/*
Neopixel stonelamp by Markus Rohner
Version 1.0 23. 3. 2017
Funtion: 12 activities
Aknowledgements:
1. Adafruit Neopixel library: http://learn.adafruit.com/adafruit-neopixel-uberguide/neomatrix-library
2. Arduino – LEDStrip effects for NeoPixel and FastLED: https://www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/
Pin assignments:
* Wemos
D2 to DI 5050 RGB LED string
Blynk Virtual Pins:
V0: ON OFF Button
V1: Activity slider
V2: Terminal
V8: Blink button
V10: Brightness slider
V11: Speed slider
V12: Colour select
V13: ON OFF LED
V14: UP LED
Bill of material:
-Wemos D1 mini
-Adafruit Neopixelstring 60 LEDs
-1000uF capacitor
-5V 4A Power Supply
*/
#include <ESP8266WiFi.h>
#include <ESP8266mDNS.h>
#include <WiFiUdp.h>
#include <ArduinoOTA.h>
// Set ESP8266 Serial object
#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>
#include <SimpleTimer.h>
SimpleTimer timer;
// Blynk
//#define BLYNK_DEBUG
//#define BLYNK_PRINT Serial
int ONOFF_LED = V13;
int UP_LED = V14;
long int last_UP_change = millis();
bool runn = 1;
WidgetTerminal terminal(V2);
// RGB Lights
#include <Adafruit_NeoPixel.h>
#define NUM_LEDS 60
const int NUM_LEDS4 = NUM_LEDS/4;
#define PIN D2
//const int long red = 16711680;
//const int long green = 65280;
const int long blue = 255;
int brightness = 155;
int standard_speed = 50;
int current_activity = 0;
int this_activity = 0;
long current_color = blue;
bool lamp_on = false;
bool blinkon = false;
Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_LEDS, PIN, NEO_GRB + NEO_KHZ800);
// Wireless settings
const char AUTH[] = "*******************";
const char SSID[] = "********";
const char PASSWORD[] = "*************";
// Timing
volatile int WDTCount = 0;
void setup() {
Serial.begin(115200);
Serial.println(F("setup start"));
//Blynk
WiFi.mode(WIFI_STA);
Blynk.begin(AUTH, SSID, PASSWORD,"192.168.178.36",8442);
while (Blynk.connect() == false) { // Wait until connected
if ((millis() - last_UP_change) > 30000) { // 30s before reset
Serial.println(F("resetting"));
terminal.println(F("resetting"));
terminal.flush();
ESP.restart();
}
}
wait(500);
// Init Neopixels
strip.begin();
all_lights(0);
//OTA
// Port defaults to 8266
// ArduinoOTA.setPort(8266);
// Hostname defaults to esp8266-[ChipID]
ArduinoOTA.setHostname("D1-Stonelamp");
// No authentication by default
ArduinoOTA.setPassword((const char *)"***");
ArduinoOTA.onStart([]() {
Serial.println("Start");
});
ArduinoOTA.onEnd([]() {
Serial.println("\nEnd");
});
ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
});
ArduinoOTA.onError([](ota_error_t error) {
Serial.printf("Error[%u]: ", error);
if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
else if (error == OTA_END_ERROR) Serial.println("End Failed");
});
ArduinoOTA.begin();
Serial.println(F("Entering loop"));
wait(3000);
timer.setInterval(2003L, blinkonoff);
//timer.setInterval(1000L, ISRwatchdog);
printStatus();
Serial.println();
Blynk.virtualWrite(ONOFF_LED,0);
Blynk.virtualWrite(UP_LED,0);
}
void loop() {
Blynk.run();
if(!Blynk.connected()) {
Serial.println(F("Resetting in loop"));
ESP.restart();
}
WDTCount = 0;
timer.run();
ArduinoOTA.handle();
activity(current_activity);
}
void activity(int activity_button) {
if (lamp_on) {
this_activity = activity_button;
strip.setBrightness(brightness);
switch (activity_button) {
case 0: // no activity
all_lights(current_color);
if (blinkon) {
wait(standard_speed*2);
strip.setBrightness(0);
strip.show();
wait(standard_speed*2);
strip.setBrightness(brightness);
}
break;
case 1: // colorWipe
colorWipe(0);
colorWipe(current_color);
break;
case 2: // theaterChase
theaterChase(strip.Color(random(255), random(255), random(255)));
break;
case 3: // rainbow
rainbow();
break;
case 4: // rainbowCycle
rainbowCycle();
break;
case 5: // theaterChaseRainbow
theaterChaseRainbow();
break;
case 6: // CylonBounce
CylonBounce(splitColor (current_color,'r'), splitColor (current_color,'g'), splitColor (current_color,'b'), 3);
break;
case 7: // TwinkleRandom
TwinkleRandom(20,false);
break;
case 8: // Sparkle
Sparkle(random(255), random(255), random(255));
break;
case 9: // RunningLights
RunningLights(splitColor (current_color,'r'), splitColor (current_color,'g'), splitColor (current_color,'b'));
break;
case 10: // Fire
Fire(55,120);// was 55,120
break;
case 11: // fade
FadeInOut(splitColor (current_color,'r'), splitColor (current_color,'g'), splitColor (current_color,'b'));
break;
case 12: // rotate
rotate();
break;
}
}
else {
strip.setBrightness(0);
strip.show();
}
}
// Fill the dots one after the other with a color (1)
void colorWipe(uint32_t c) {
for (int i = 0; i < NUM_LEDS4; i++) {
if (!lamp_on || this_activity != current_activity) break;
for (int j = 0; j < 4; j++) {
strip.setPixelColor(i+j*NUM_LEDS4,c);
}
strip.show();
wait(standard_speed/3);
}
}
//Theatre-style crawling lights. (2)
void theaterChase(uint32_t c) {
for (int j = 0; j < 10; j++) { //do 10 cycles of chasing
if (!lamp_on || this_activity != current_activity) break;
for (int q = 0; q < 3; q++) {
if (!lamp_on || this_activity != current_activity) break;
for (int i = 0; i < NUM_LEDS4; i = i + 3) {
if (!lamp_on || this_activity != current_activity) break;
for (int m = 0; m < 4; m++) {
strip.setPixelColor(i + q + m*NUM_LEDS4, c); //turn every third pixel on
}
}
strip.show();
wait(standard_speed*3);
for (int i = 0; i < NUM_LEDS; i = i + 3) {
if (!lamp_on || this_activity != current_activity) break;
for (int m = 0; m < 4; m++) {
strip.setPixelColor(i + q + m*NUM_LEDS4, 0); //turn every third pixel off
}
}
}
}
}
// (3)
void rainbow() {
uint16_t i, j;
for (j = 0; j < 256; j+=2) {
if (!lamp_on || this_activity != current_activity) break;
for (i = 0; i < NUM_LEDS4; i++) {
if (!lamp_on || this_activity != current_activity) break;
for (int m = 0; m < 4; m++) {
strip.setPixelColor(i + m*NUM_LEDS4,Wheel((i + j) & 255));
strip.show();
wait(standard_speed/5);
}
}
}
}
// Slightly different, this makes the rainbow equally distributed throughout (4)
void rainbowCycle() {
uint16_t i, j;
for (j = 0; j < 256 * 5; j++) { // 5 cycles of all colors on wheel
if (!lamp_on || this_activity != current_activity) break;
for (i = 0; i < NUM_LEDS4; i++) {
if (!lamp_on || this_activity != current_activity) break;
for (int m = 0; m < 4; m++) {
strip.setPixelColor(i + m*NUM_LEDS4, Wheel(((i * 256 / NUM_LEDS4) + j) & 255));
}
}
strip.show();
wait(standard_speed/2);
}
}
//Theatre-style crawling lights with rainbow effect (5)
void theaterChaseRainbow() {
for (int j = 0; j < 256; j+=2) { // cycle all 256 colors in the wheel
if (!lamp_on || this_activity != current_activity) break;
for (int q = 0; q < 3; q++) {
if (!lamp_on || this_activity != current_activity) break;
for (int i = 0; i < NUM_LEDS4; i = i + 3) {
if (!lamp_on || this_activity != current_activity) break;
for (int m = 0; m < 4; m++) {
strip.setPixelColor(i + q + m*NUM_LEDS4, Wheel( (i + j) % 255)); //turn every third pixel on
}
}
strip.show();
wait(standard_speed*3);
for (int i = 0; i < NUM_LEDS4; i = i + 3) {
if (!lamp_on || this_activity != current_activity) break;
for (int m = 0; m < 4; m++) {
strip.setPixelColor(i + q + m*NUM_LEDS4, 0); //turn every third pixel off
}
}
}
}
}
// (6)
void CylonBounce(byte red, byte green, byte blue, int EyeSize){
for(int i = 0; i < NUM_LEDS4-EyeSize-2; i++) {
if (!lamp_on || this_activity != current_activity) break;
all_lights(0);
for (int m = 0; m < 4; m++) {
setPixel(i+ m*NUM_LEDS4, red/10, green/10, blue/10);
}
for(int j = 1; j <= EyeSize; j++) {
if (!lamp_on || this_activity != current_activity) break;
for (int m = 0; m < 4; m++) {
setPixel(i + j + m*NUM_LEDS4, red, green, blue);
}
}
for (int m = 0; m < 4; m++) {
setPixel(i + EyeSize + 1 + m*NUM_LEDS4, red/10, green/10, blue/10);
}
strip.show();
wait(standard_speed/2);
}
wait(standard_speed);
for(int i = NUM_LEDS4-EyeSize-2; i > 0; i--) {
if (!lamp_on || this_activity != current_activity) break;
all_lights(0);
for (int m = 0; m < 4; m++) {
setPixel(i + m*NUM_LEDS4, red/10, green/10, blue/10);
}
for(int j = 1; j <= EyeSize; j++) {
if (!lamp_on || this_activity != current_activity) break;
for (int m = 0; m < 4; m++) {
setPixel(i + j + m*NUM_LEDS4, red, green, blue);
}
}
for (int m = 0; m < 4; m++) {
setPixel(i +EyeSize + 1 + m*NUM_LEDS4, red/10, green/10, blue/10);
}
strip.show();
wait(standard_speed/2);
}
wait(standard_speed);
}
// (7)
void TwinkleRandom(int Count,boolean OnlyOne) {
all_lights(0);
for (int i=0; i<Count; i++) {
if (!lamp_on || this_activity != current_activity) break;
setPixel(random(NUM_LEDS),random(0,255),random(0,255),random(0,255));
strip.show();
wait(standard_speed);
if(OnlyOne) {
all_lights(0);
}
}
wait(standard_speed/2);
}
// (8)
void Sparkle(byte red, byte green, byte blue) {
all_lights(0);
int Pixel = random(NUM_LEDS);
setPixel(Pixel,red,green,blue);
strip.show();
wait(standard_speed);
setPixel(Pixel,0,0,0);
}
// (9)
void RunningLights(byte red, byte green, byte blue) {
int Position=0;
for(int i=0; i<NUM_LEDS4*2; i++) {
if (!lamp_on || this_activity != current_activity) break;
Position++; // = 0; //Position + Rate;
for(int i=0; i<NUM_LEDS4; i++) {
if (!lamp_on || this_activity != current_activity) break;
for (int m = 0; m < 4; m++) {
if (!lamp_on || this_activity != current_activity) break;
setPixel(i + m*NUM_LEDS4,((sin(i+Position) * 127 + 128)/255)*red,
((sin(i+Position) * 127 + 128)/255)*green,
((sin(i+Position) * 127 + 128)/255)*blue);
}
}
strip.show();
wait(standard_speed*2);
}
}
// (10)
void Fire(int Cooling, int Sparking) {
static byte heat[NUM_LEDS];
int cooldown;
// Step 1. Cool down every cell a little
for (int m = 0; m < 4; m++) {
for( int i = 0; i < NUM_LEDS4; i++) {
cooldown = random(0, ((Cooling * 10) / NUM_LEDS4) + 2);
if(cooldown>heat[i + m*NUM_LEDS4]) {
heat[i + m*NUM_LEDS4]=0;
} else {
heat[i + m*NUM_LEDS4]=heat[i + m*NUM_LEDS4]-cooldown;
}
}
}
// Step 2. Heat from each cell drifts 'up' and diffuses a little
for (int m = 0; m < 4; m++) {
for( int k = NUM_LEDS4 - 1; k >= 2; k--) {
if (!lamp_on || this_activity != current_activity) break;
heat[k + m*NUM_LEDS4] = (heat[k + m*NUM_LEDS4 - 1] + heat[k + m*NUM_LEDS4 - 2] + heat[k + m*NUM_LEDS4 - 2]) / 3;
}
}
// Step 3. Randomly ignite new 'sparks' near the bottom
for (int m = 0; m < 4; m++) {
if( random(255) < Sparking ) {
int y = random(3); //was 7
heat[y + m*NUM_LEDS4] = heat[y + m*NUM_LEDS4] + random(160,255);
}
}
// Step 4. Convert heat to LED colors
for( int j = 0; j < NUM_LEDS; j++) {
if (!lamp_on || this_activity != current_activity) break;
setPixelHeatColor(j, heat[j]);
}
strip.show();
wait(standard_speed);
}
void setPixelHeatColor (int Pixel, byte temperature) {
// Scale 'heat' down from 0-255 to 0-191
byte t192 = round((temperature/255.0)*191);
// calculate ramp up from
byte heatramp = t192 & 0x3F; // 0..63
heatramp <<= 2; // scale up to 0..252
// figure out which third of the spectrum we're in:
if( t192 > 0x80) { // hottest
setPixel(Pixel, 255, 255, heatramp);
} else if( t192 > 0x40 ) { // middle
setPixel(Pixel, 255, heatramp, 0);
} else { // coolest
setPixel(Pixel, heatramp, 0, 0);
}
}
//(11)
void FadeInOut(byte red, byte green, byte blue){
float r, g, b;
for(int k = 20; k < 256; k=k+1) {
if (!lamp_on || this_activity != current_activity) break;
r = (k/256.0)*red;
g = (k/256.0)*green;
b = (k/256.0)*blue;
all_lights(r,g,b);
wait(standard_speed/6);
}
for(int k = 255; k >= 20; k=k-2) {
if (!lamp_on || this_activity != current_activity) break;
r = (k/256.0)*red;
g = (k/256.0)*green;
b = (k/256.0)*blue;
all_lights(r,g,b);
wait(standard_speed/6);
}
}
//Rotate (12)
void rotate() {
all_lights(0);
for (int m = 0; m < 4; m++) {
for (int i = m*NUM_LEDS4; i < (m+1)*NUM_LEDS4; i++) {
if (!lamp_on || this_activity != current_activity) break;
strip.setPixelColor(i,current_color);
}
strip.show();
wait(standard_speed*2);
for (int i = m*NUM_LEDS4; i < (m+1)*NUM_LEDS4; i++) {
if (!lamp_on || this_activity != current_activity) break;
strip.setPixelColor(i,0);
}
strip.show();
}
}
void all_lights(int g, int r, int b) {
wait(1);
for (int x = 0; x < NUM_LEDS; x++) {
strip.setPixelColor(x, g, r, b);
}
strip.show();
}
void all_lights(int color) {
wait(1);
for (int x = 0; x < NUM_LEDS; x++) {
strip.setPixelColor(x,color);
}
strip.show();
}
// Input a value 0 to 255 to get a color value.
// 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);
}
}
/**
splitColor() - Receive a uint32_t value, and spread into bits.
*/
byte splitColor ( uint32_t c, char value )
{
switch ( value ) {
case 'r': return (uint8_t)(c >> 16);
case 'g': return (uint8_t)(c >> 8);
case 'b': return (uint8_t)(c >> 0);
default: return 0;
}
}
void printStatus() {
Serial.print(F(" ON: "));
Serial.print(lamp_on);
Serial.print(F(" Blink: "));
Serial.print(blinkon);
Serial.print(F(" Activity: "));
Serial.print(current_activity);
Serial.print(F(" Color: "));
Serial.print(current_color);
Serial.print(F(" Brightness: "));
Serial.print(brightness);
Serial.print(F(" Speed: "));
Serial.println(standard_speed);
terminal.print(F(" ON:"));
terminal.print(lamp_on);
terminal.print(F(" Blk:"));
terminal.print(blinkon);
terminal.print(F(" Act:"));
terminal.print(current_activity);
terminal.print(F(" Col:"));
terminal.print(current_color);
terminal.print(F(" Bright:"));
terminal.print(brightness);
terminal.print(F(" Spd:"));
terminal.println(standard_speed);
terminal.flush();
}
void wait (int ms) {
long current_time = millis();
long end_time = current_time + ms;
while (current_time < end_time) {
if (!lamp_on || this_activity != current_activity) break;
current_time = millis();
}
Blynk.run();
timer.run();
}
void blinkonoff(){
// Turn runn LED on/off
Blynk.virtualWrite(UP_LED,runn * 255); // turn Up off
runn = !runn;
last_UP_change = millis();
WDTCount = 0;
}
BLYNK_WRITE(V0) { //ON Off
if (param.asInt()) lamp_on = 1;
else {
all_lights(0);
lamp_on = 0;
}
Blynk.virtualWrite(ONOFF_LED,lamp_on * 255); // turn Up off
printStatus();
}
BLYNK_WRITE(V1) { //Activity slider
current_activity = param.asInt();
printStatus();
}
BLYNK_WRITE(V8) { //Blink
if (param.asInt()) blinkon = true;
else blinkon = false;
printStatus();
}
BLYNK_WRITE(V10) { // Brightness slider
brightness = param.asInt();
strip.setBrightness(brightness);
strip.show();
printStatus();
}
BLYNK_WRITE(V11) { // Speed
standard_speed = param.asInt();
printStatus();
}
BLYNK_WRITE(V12) { //RGB light
current_color = param[2].asInt() + 256*param[1].asInt() + 256*256*param[0].asInt();
printStatus();
}
void ISRwatchdog() {
WDTCount++;
if (WDTCount == 5) {
Serial.println(F("WDT reset"));
terminal.println(F("WDT reset"));
terminal.flush();
ESP.reset();
}
}
void setPixel(int Pixel, byte red, byte green, byte blue) {
strip.setPixelColor(Pixel, strip.Color(red, green, blue));
}