CloudCloud with Physical remote

Video!

I’ve made a cloud connected cloud with 2 Wemos D1 minis, 70 neopixels, the FastLED library, and most importantly: Blynk!

There are several modes right now including lightning, solid color, mood lamp, rainbow with glitter, chase, and off. I got the idea from here, borrowed some code from here, and got advice/help from Jamin and Costas! It can be controlled via the Blynk App (my layout isn’t shown yet, I’ll try to upload it later) or a physical controller utilizing the Blynk Bridge.

Its not quite finished yet as I have to make a more permanent remote that is child proof, and I also have to wire the cloud portion more permanently so I can hang it in my daughters room.

This has been a great learning experience for me in Arduino, Blynk, wiring in general, soldering (never soldered until now), coding, and electronics in general! I hope you all like it!

Cloud code: (sorry for the lack of commenting, I’ll try to add some later…)

#define BLYNK_PRINT Serial    // Comment this out to disable prints and save space
#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>
#include <FastLED.h>
#include <SimpleTimer.h>
 
// How many leds in your strip?
#define NUM_LEDS 70
#define DATA_PIN 12
 
CRGB leds[NUM_LEDS];
 
// You should get Auth Token in the Blynk App.
// Go to the Project Settings (nut icon).
 
char auth[] = "CODE";
 
// Your WiFi credentials.
// Set password to "" for open networks.
char ssid[] = "NETGEAR67";
char pass[] = "PW";
 
int varonoff;
int qq = 0;
 
int varHue = 50;
int varSat = 255;
int varVal = 150;
uint8_t gHue = 0; // rotating "base color" used by many of the patterns
 
WidgetTerminal terminal(V9);
 
SimpleTimer timer;
int chasetimer = 0;
int rainbowtimer = 0;
int solidtimer = 0;
int moodlamptimer = 0;
int LIGHTNINGtimer = 0;


int t1 = 0;
int t2 = 0;
int t3 = 0;

int L1 = 0;
int loop1 = 0;
int looplength = 0;
 
BLYNK_WRITE(V0) {
   switch (param.asInt())
   {
     case 1: { // Item 1
       timer.enable(chasetimer);
       timer.disable(rainbowtimer);
       timer.disable(solidtimer);
       timer.disable(LIGHTNINGtimer);
       timer.disable(moodlamptimer);
       break;
     }
     case 2: { // Item 2
       timer.enable(rainbowtimer);
       timer.disable(chasetimer);
       timer.disable(solidtimer);
       timer.disable(LIGHTNINGtimer);
       timer.disable(moodlamptimer);
       break;
     }
     case 3: { // Item 3
       timer.enable(solidtimer);
       timer.disable(rainbowtimer);
       timer.disable(chasetimer);
       timer.disable(LIGHTNINGtimer);
       timer.disable(moodlamptimer);
       break;
     }
     case 4: { // Item 4
       timer.enable(moodlamptimer);
       timer.disable(rainbowtimer);
       timer.disable(chasetimer);
       timer.disable(LIGHTNINGtimer);
       timer.disable(solidtimer);
       break;
     }
     case 5: { // Item 5
       timer.enable(LIGHTNINGtimer);
       timer.disable(chasetimer);
       timer.disable(rainbowtimer);
       timer.disable(solidtimer);
       timer.disable(moodlamptimer);
       varHue = 190;
       varSat = 20;
       varVal = 255;
       Serial.println("lightning enabled");
       break;
     }
     case 6: { // Item 6

       timer.disable(chasetimer);
       timer.disable(rainbowtimer);
       timer.disable(solidtimer);
       timer.disable(LIGHTNINGtimer);
       ledoff();
       break;
     }
     default: {
       Serial.println("Unknown item selected");
     }
   }
 }
 
 
 
BLYNK_WRITE(V1)
{
  varHue = param.asInt();
  terminal.print("Hue: ");
  terminal.println(varHue);
  terminal.flush();
}

BLYNK_WRITE(V2)
{
  varSat = param.asInt();
  terminal.print("Saturation: ");
  terminal.println(varSat);
  terminal.flush();
}

BLYNK_WRITE(V3)
{
  varVal = param.asInt();
  terminal.print("Value: ");
  terminal.println(varVal);
  terminal.flush();
}

 
 
void setup()
{
  Serial.begin(9600);
  FastLED.addLeds<WS2812B, DATA_PIN, GRB>(leds, NUM_LEDS);
  Blynk.begin(auth, ssid, pass); 
 
  chasetimer = timer.setInterval(75L, chase);
  rainbowtimer = timer.setInterval(20L, rainbowWithGlitter);
  solidtimer = timer.setInterval(100L, solid);
  moodlamptimer = timer.setInterval(100L, moodlamp);
  LIGHTNINGtimer = timer.setInterval(300L, LIGHTNING);
 
    timer.disable(chasetimer);
    timer.disable(rainbowtimer);
    timer.disable(solidtimer);
    timer.disable(moodlamptimer);
    timer.disable(LIGHTNINGtimer);
 
  timer.setInterval(1000L,senduptime);

t1 = timer.setInterval(2L, v1);
t2 = timer.setInterval(100L, v2);
t3 = timer.setInterval(3L, v3);
 
timer.disable(t1);
timer.disable(t2);
timer.disable(t3);


}
 
void loop()
{
  Blynk.run();
    timer.run(); // Initiates SimpleTimer
    FastLED.show();
}
 
 
 
void senduptime(){
 
    Blynk.virtualWrite(V20, millis() / 1000);
 
}
 
  void chase() {
 
  fadeToBlackBy( leds, NUM_LEDS, 20);
      leds[qq] = CHSV( varHue, varSat, varVal);
      qq++;
      if (qq >= 69){
        qq = 0;
      }
}
    
 
void rainbow()
{
  // FastLED's built-in rainbow generator
  fill_rainbow( leds, NUM_LEDS, gHue, 7);
  gHue++;
}
 
void rainbowWithGlitter()
{
  // built-in FastLED rainbow, plus some random sparkly glitter
  rainbow();
  addGlitter(80);
}
 
void addGlitter( fract8 chanceOfGlitter)
{
  if ( random8() < chanceOfGlitter) {
    leds[ random16(NUM_LEDS) ] += CRGB::White;
  }
}
 
void ledoff(){
  fill_solid(leds, NUM_LEDS, CRGB::Black);
}

void solid(){
  fill_solid(leds, NUM_LEDS, CHSV(varHue,varSat,varVal));  
}

void moodlamp(){
  fill_solid(leds, NUM_LEDS, CHSV(varHue,varSat,varVal));
  varHue++;
}


//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
//Lightning related functions start here

void LIGHTNING()
{
  int randlightning = random8(100);

  if (randlightning < 10){
  switch (random(1,4)){
    case 1:{
      timer.enable(t1);
      timer.disable(t2);
      timer.disable(t3);
      Serial.println("lightning case 1");
      break;
    }
    case 2:{
      timer.enable(t2);
      timer.disable(t1);
      timer.disable(t3);
      Serial.println("lightning case 2");
      break;
    }
    case 3:{
      timer.enable(t3);
      timer.disable(t2);
      timer.disable(t1);
      Serial.println("lightning case 3");
      break;
    }
}
}
}


 
void v1(){

//Serial.println(loop1);

  if (loop1 == 0){
    //FastLED.delay(random8(1000,2000));
    looplength = random8(15,30);
    L1 = random8(NUM_LEDS-looplength);
  }
  if (loop1 < looplength){
    loop1++;
    leds[L1] = CHSV( varHue, varSat, varVal);
    L1++;
    
  }
  if (loop1 == looplength){
    loop1 = 0;
    ledoff();
    FastLED.show();
    FastLED.delay(random8(15,50));
    for (int i = L1 - looplength;  i <=L1; i++){
      leds[i] = CHSV( varHue, varSat, varVal);
    }
    FastLED.show();
    FastLED.delay(random8(15,50));
    ledoff();
    FastLED.delay(random8(50,100));
    for (int i = L1 - looplength;  i <=L1; i++){
      leds[i] = CHSV( varHue, varSat, varVal);
    }
    FastLED.show();
    FastLED.delay(random8(50,100));
    ledoff();
    timer.disable(t1);
  }
FastLED.show();
}
 
void v2(){

solid();
FastLED.show();
FastLED.delay(random8(25,100));
ledoff();
FastLED.show();
FastLED.delay(random8(25,50));
solid();
FastLED.show();
FastLED.delay(random8(25,100));
ledoff();
FastLED.show();
FastLED.delay(random8(25,50));
solid();
FastLED.show();
FastLED.delay(random8(25,100));
ledoff();
FastLED.show();
FastLED.delay(random8(25,50));

timer.disable(t2);
}
 
void v3(){

  if (loop1 == 0){
    //FastLED.delay(random8(1000,2000));
    looplength = random8(25,40);
    L1 = random8(NUM_LEDS);
  }
  if (loop1 < looplength){
    loop1++;
    leds[L1] = CHSV( varHue, varSat, varVal);
    L1 = random8(NUM_LEDS);;
    
  }
  if (loop1 == looplength){
    loop1 = 0;
    ledoff();
    FastLED.delay(random8(25,50));
    FastLED.show();

    timer.disable(t3);
  } 
FastLED.show();
}

Remote Code:

#define BLYNK_PRINT Serial   
 
#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>
#include <SimpleTimer.h>
 
char auth[] = "AUTHCODE";
// Your WiFi credentials.
// Set password to "" for open networks.
char ssid[] = "NETGEAR67";
char pass[] = "PW";
 
uint8_t varHueB = 0;
uint8_t varSatB = 0;
uint8_t varValB = 0;
int varModeB = 0;
// Bridge widget on virtual pin 1
WidgetBridge bridge1(V1);
 
 
// Timer for blynking
SimpleTimer timer;
 
 
 
void hueplus(){
  varHueB = varHueB +10 ;
  bridge1.virtualWrite(V1, varHueB); 
}
 
void satplus(){
  varSatB = varSatB +20 ;
  bridge1.virtualWrite(V2, varSatB); 
}
 
void valplus(){
  varValB = varValB +20 ;
  bridge1.virtualWrite(V3, varValB); 
}
 
void modeplus(){
  varModeB++;
  if (varModeB > 5){
    varModeB = 0;
  }
  bridge1.virtualWrite(V0, varModeB); 
}
void setup()
{
  //Serial.begin(9600);
  Blynk.begin(auth, ssid, pass);
 
  while (Blynk.connect() == false) {
    // Wait until connected
  }
 
 
// Make pin 2 default HIGH, and attach INT to our handler
pinMode(2, INPUT_PULLUP); //wemos pin D4
pinMode(0, INPUT_PULLUP); //wemos pin D3
pinMode(4, INPUT_PULLUP); //wemos pin D2
pinMode(5, INPUT_PULLUP); //wemos pin D1
 
}
 
BLYNK_CONNECTED() {
  bridge1.setAuthToken("otherAUTHCODE"); // Place the AuthToken of the second hardware here
}
 

int prevState4 = -1;
int currState4 = -1;
long lastChangeTime4 = 0;
 
int prevState3 = -1;
int currState3 = -1;
long lastChangeTime3 = 0;
 
int prevState2 = -1;
int currState2 = -1;
long lastChangeTime2 = 0;
 
int prevState1 = -1;
int currState1 = -1;
long lastChangeTime1 = 0;
 
void checkPin4()
{
  // Invert state, since button is "Active LOW"
  int state4 = !digitalRead(2);
 
// Debounce mechanism
  long t4 = millis();
  if (state4 != prevState4) {
    lastChangeTime4 = t4;
  }

  if (t4 - lastChangeTime4 > 50) {
    if (state4 != currState4) {
      currState4 = state4;
      if  (state4 == 1){
        valplus();
        //Serial.println("button 4 pushed");
      }
    }
  }
  prevState4 = state4;   
}
 
void checkPin3()
{
  // Invert state, since button is "Active LOW"
  int state3 = !digitalRead(0);
 
// Debounce mechanism
  long t3 = millis();
  if (state3 != prevState3) {
    lastChangeTime3 = t3;
  }
  if (t3 - lastChangeTime3 > 50) {
    if (state3 != currState3) {
      currState3 = state3;
      if  (state3 == 1){      
        satplus();
        //Serial.println("button 3 pushed");
      }
    }
  }
  prevState3 = state3;
}
 
void checkPin2()
{
  // Invert state, since button is "Active LOW"
  int state2 = !digitalRead(4);
 
// Debounce mechanism
  long t2 = millis();
  if (state2 != prevState2) {
    lastChangeTime2 = t2;
  }
  if (t2 - lastChangeTime2 > 50) {
    if (state2 != currState2) {
      currState2= state2;
      if  (state2 == 1){ 
        hueplus();
        //Serial.println("button 2 pushed");
      }
    }
  }
  prevState2 = state2;
}
void checkPin1()
{
  // Invert state, since button is "Active LOW"
  int state1 = !digitalRead(5);
 
// Debounce mechanism
  long t1 = millis();
  if (state1 != prevState1) {
    lastChangeTime1 = t1;
  }
  if (t1 - lastChangeTime1 > 50) {
    if (state1 != currState1) {
      currState1 = state1;
      if  (state1 == 1){ 
        modeplus();
        //Serial.println("button 1 pushed");
      }
    }
  }
  prevState1 = state1;
}

void loop()
{
  Blynk.run();
  timer.run();
  checkPin4();
  checkPin3();
  checkPin2();
  checkPin1();
}
3 Likes

Amazing project…
Cool video

1 Like

Well done Jon! Great looking cloud and love the physical remote idea.
Did you get any photos of the build? I’ve love to see behind the cloud :slight_smile:

Unfortunately I don’t have any photos of the build, but it’s fairly similar to the link I posted. Main difference is that I built the main shape out of cardboard and used cotton balls instead of pillow stuffing. I also wrapped my led strip in plastic wrap before gluing it on so I can salvage the leds for a future project if need be!

Nice project … Any reason using physical remote instead using smartphone with BlynkApps? Or if you still prefer physical one you can use old IR remote control and coding some IR receiving one… Just my thought …

I am using the app too. My main reason for a physical remote is to have a control for my laddr to use. I thought about IR, it’s even what the project I linked to used, but I think building my own remote is much more flexible. I’m thinking about going with arcade buttons to make it more child friendly.

2 Likes