Sync physical button and follow sequence

Hello,

I’ve searched old threads for help, which have been useful, as they led me to the sync button example, which I thought would work but all it does is blink the inbuilt LED.

Blynk on IOS
Wemos D1 Mini
WS2812B led strip (8 leds)
Push button switch (4 pin tactile momentary)

So, the project is just these 8 leds. I’ve the zeRGBa working to adjust the colours and I have a physical button, which runs through 8 states. The 8 states are various colours and if the button is not pressed again, it will remain in that state or until the zeRGBa is adjusted.

Now I’d like a button on the Blynk app to do the same as the push button. I’m not particularly fussed if it starts the sequence from the beginning (8 states) or follows on from when the physical button was last pressed. As I’d probably either use the physical buttons or the app.

Here is my code prior to using the Blynk button;

Simply paste your code between ``` If you don’t format your code, your topic can be deleted by moderators.


#include <Adafruit_NeoPixel.h>
#include <SPI.h>
#include <BlynkSimpleEsp8266.h>
#include <ESP8266WiFi.h>

#define BUTTON_PIN   0
#define PIN 2
#define NUMPIXELS 8
#define BLYNK_PRINT Serial
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);

boolean oldState = HIGH;
int     mode     = 0;    // Currently-active animation mode, 0-9
void setup()
{
Serial.begin(9600);
Blynk.begin("VqL-vZjbWHu-AHl9ajxTqYDljTjlbWO2", "BTHub6-9FH6", "aVyt3qPnPdVR");
pixels.begin();
  pinMode(BUTTON_PIN, INPUT_PULLUP);
 // pixels.begin();           // INITIALIZE NeoPixel strip object (REQUIRED)
  pixels.show();            // Turn OFF all pixels ASAP
  pixels.setBrightness(50); // Set BRIGHTNESS to about 1/5 (max = 255)
}
BLYNK_WRITE(V2)
{

int R = param[0].asInt();
int G = param[1].asInt();
int B = param[2].asInt();
Serial.println(R);
Serial.println(G);
Serial.println(B);
for(int i=0;i<NUMPIXELS;i++){

pixels.setPixelColor(i, pixels.Color(R,G,B));

pixels.show();
}
}

void loop()
{
Blynk.run();

  // Get current button state.
  boolean newState = digitalRead(BUTTON_PIN);

  // Check if state changed from high to low (button press).
  if((newState == LOW) && (oldState == HIGH)) {
    // Short delay to debounce button.
    delay(20);
    // Check if button is still low after debounce.
    newState = digitalRead(BUTTON_PIN);
    if(newState == LOW) {      // Yes, still low
      if(++mode > 7) mode = 0; // Advance to next mode, wrap around after #8
      switch(mode) {           // Start the new animation...
        case 0:
          colorWipe(pixels.Color(  0,   0,   0), 50);    // Black/off
          break;
        case 1:
          colorWipe(pixels.Color(255,   0,   0), 50);    // Red
          break;
        case 2:
          colorWipe(pixels.Color(  0, 255,   0), 50);    // Green
          break;
        case 3:
          colorWipe(pixels.Color(  0,   0, 255), 50);    // Blue
          break;
        case 4:
          colorWipe(pixels.Color(127, 127, 127), 50);    // White 
          break;
        case 5:
          colorWipe(pixels.Color(21, 0, 55), 50);        // Purple 
          break;
        case 6:
          colorWipe(pixels.Color(112, 134, 0), 50);      // Yellow 
          break;
        case 7:
          rainbow(50);
          break;
      }
    }
  }

  // Set the last-read button state to the old state.
  oldState = newState;
}

// Fill strip pixels one after another with a color. Strip is NOT cleared
// first; anything there will be covered pixel by pixel. Pass in color
// (as a single 'packed' 32-bit value, which you can get by calling
// strip.Color(red, green, blue) as shown in the loop() function above),
// and a delay time (in milliseconds) between pixels.
void colorWipe(uint32_t color, int wait) {
  for(int i=0; i<pixels.numPixels(); i++) { // For each pixel in strip...
    pixels.setPixelColor(i, color);         //  Set pixel's color (in RAM)
    pixels.show();                          //  Update strip to match
    delay(wait);                           //  Pause for a moment
  }
}

// Rainbow cycle along whole strip. Pass delay time (in ms) between frames.
void rainbow(int wait) {
  // Hue of first pixel runs 3 complete loops through the color wheel.
  // Color wheel has a range of 65536 but it's OK if we roll over, so
  // just count from 0 to 3*65536. Adding 256 to firstPixelHue each time
  // means we'll make 3*65536/256 = 768 passes through this outer loop:
  for(long firstPixelHue = 0; firstPixelHue < 3*65536; firstPixelHue += 256) {
    for(int i=0; i<pixels.numPixels(); i++) { // For each pixel in strip...
      // Offset pixel hue by an amount to make one full revolution of the
      // color wheel (range of 65536) along the length of the strip
      // (strip.numPixels() steps):
      int pixelHue = firstPixelHue + (i * 65536L / pixels.numPixels());
      // strip.ColorHSV() can take 1 or 3 arguments: a hue (0 to 65535) or
      // optionally add saturation and value (brightness) (each 0 to 255).
      // Here we're using just the single-argument hue variant. The result
      // is passed through strip.gamma32() to provide 'truer' colors
      // before assigning to each pixel:
      pixels.setPixelColor(i, pixels.gamma32(pixels.ColorHSV(pixelHue)));
    }
    pixels.show(); // Update strip with new contents
    delay(wait);  // Pause for a moment
    firstPixelHue += 65536 / 90; // One cycle of color wheel over 90 frames  - needed line?
  }
}

And here is the code with the ‘sync physical button’ example. I’ve obviously just copied it across and changed the pins etc as I’m very new to code but I can’t figure out to what I’ve done wrong. When I press the button on Blynk, it changes the state of the LED on the Wemos

#include <Adafruit_NeoPixel.h>
#include <SPI.h>
#include <BlynkSimpleEsp8266.h>
#include <ESP8266WiFi.h>

/* Comment this out to disable prints and save space */
#define BLYNK_PRINT Serial

#define BUTTON_PIN   0
#define PIN 2
#define NUMPIXELS 8
#define BLYNK_PRINT Serial
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);

// Set your LED and physical button pins here
const int ledPin = 2;
const int btnPin = 0;

BlynkTimer timer;
void checkPhysicalButton();

int ledState = LOW;
int btnState = HIGH;

// Every time we connect to the cloud...
BLYNK_CONNECTED() {
  // Request the latest state from the server
  Blynk.syncVirtual(V2);

  // Alternatively, you could override server state using:
  //Blynk.virtualWrite(V2, ledState);
}

// When App button is pushed - switch the state
BLYNK_WRITE(V3) {
  ledState = param.asInt();
  digitalWrite(ledPin, ledState);
}
void checkPhysicalButton()
{
  if (digitalRead(btnPin) == LOW) {
    // btnState is used to avoid sequential toggles
    if (btnState != LOW) {

      // Toggle LED state
      ledState = !ledState;
      digitalWrite(ledPin, ledState);

      // Update Button Widget
      Blynk.virtualWrite(V2, ledState);
    }
    btnState = LOW;
  } else {
    btnState = HIGH;
  }
}

boolean oldState = HIGH;
int     mode     = 0;    // Currently-active animation mode, 0-9

void setup()
{
Serial.begin(9600);
Blynk.begin("VqL-vZjbWHu-AHl9ajxTqYDljTjlbWO2", "BTHub6-9FH6", "aVyt3qPnPdVR");
  // You can also specify server:
  //Blynk.begin(auth, ssid, pass, "blynk-cloud.com", 80);
  //Blynk.begin(auth, ssid, pass, IPAddress(192,168,1,100), 8080);
pixels.begin();
  pinMode(BUTTON_PIN, INPUT_PULLUP);
 // pixels.begin();           // INITIALIZE NeoPixel strip object (REQUIRED)
  pixels.show();            // Turn OFF all pixels ASAP
  pixels.setBrightness(50); // Set BRIGHTNESS to about 1/5 (max = 255)

  pinMode(ledPin, OUTPUT);
  pinMode(btnPin, INPUT_PULLUP);
  digitalWrite(ledPin, ledState);

  // Setup a function to be called every 100 ms
  timer.setInterval(100L, checkPhysicalButton);

}
BLYNK_WRITE(V2)
{

int R = param[0].asInt();
int G = param[1].asInt();
int B = param[2].asInt();
Serial.println(R);
Serial.println(G);
Serial.println(B);
for(int i=0;i<NUMPIXELS;i++){

pixels.setPixelColor(i, pixels.Color(R,G,B));

pixels.show();
}
}

void loop()
{
Blynk.run();
timer.run();

  // Get current button state.
  boolean newState = digitalRead(BUTTON_PIN);

  // Check if state changed from high to low (button press).
  if((newState == LOW) && (oldState == HIGH)) {
    // Short delay to debounce button.
    delay(20);
    // Check if button is still low after debounce.
    newState = digitalRead(BUTTON_PIN);
    if(newState == LOW) {      // Yes, still low
      if(++mode > 7) mode = 0; // Advance to next mode, wrap around after #8
      switch(mode) {           // Start the new animation...
        case 0:
          colorWipe(pixels.Color(  0,   0,   0), 50);    // Black/off
          break;
        case 1:
          colorWipe(pixels.Color(255,   0,   0), 50);    // Red
          break;
        case 2:
          colorWipe(pixels.Color(  0, 255,   0), 50);    // Green
          break;
        case 3:
          colorWipe(pixels.Color(  0,   0, 255), 50);    // Blue
          break;
        case 4:
          colorWipe(pixels.Color(127, 127, 127), 50);    // White 
          break;
        case 5:
          colorWipe(pixels.Color(21, 0, 55), 50);        // Purple 
          break;
        case 6:
          colorWipe(pixels.Color(112, 134, 0), 50);      // Yellow 
          break;
        case 7:
          rainbow(50);
          break;
      }
    }
  }

  // Set the last-read button state to the old state.
  oldState = newState;
}

// Fill strip pixels one after another with a color. Strip is NOT cleared
// first; anything there will be covered pixel by pixel. Pass in color
// (as a single 'packed' 32-bit value, which you can get by calling
// strip.Color(red, green, blue) as shown in the loop() function above),
// and a delay time (in milliseconds) between pixels.
void colorWipe(uint32_t color, int wait) {
  for(int i=0; i<pixels.numPixels(); i++) { // For each pixel in strip...
    pixels.setPixelColor(i, color);         //  Set pixel's color (in RAM)
    pixels.show();                          //  Update strip to match
    delay(wait);                           //  Pause for a moment
  }
}

// Rainbow cycle along whole strip. Pass delay time (in ms) between frames.
void rainbow(int wait) {
  // Hue of first pixel runs 3 complete loops through the color wheel.
  // Color wheel has a range of 65536 but it's OK if we roll over, so
  // just count from 0 to 3*65536. Adding 256 to firstPixelHue each time
  // means we'll make 3*65536/256 = 768 passes through this outer loop:
  for(long firstPixelHue = 0; firstPixelHue < 3*65536; firstPixelHue += 256) {
    for(int i=0; i<pixels.numPixels(); i++) { // For each pixel in strip...
      // Offset pixel hue by an amount to make one full revolution of the
      // color wheel (range of 65536) along the length of the strip
      // (strip.numPixels() steps):
      int pixelHue = firstPixelHue + (i * 65536L / pixels.numPixels());
      // strip.ColorHSV() can take 1 or 3 arguments: a hue (0 to 65535) or
      // optionally add saturation and value (brightness) (each 0 to 255).
      // Here we're using just the single-argument hue variant. The result
      // is passed through strip.gamma32() to provide 'truer' colors
      // before assigning to each pixel:
      pixels.setPixelColor(i, pixels.gamma32(pixels.ColorHSV(pixelHue)));
    }
    pixels.show(); // Update strip with new contents
    delay(wait);  // Pause for a moment
    firstPixelHue += 65536 / 90; // One cycle of color wheel over 90 frames  - needed line?
  }
}

Any advice would be greatly appreciated, thank you

To start with search “keep your void loop clean” on this forum.

You will also want to learn about interrupts for your physical button. There are some examples here.

So create an interrupt routine and move the switch case into it.

Okay, will have a look into that today.

So if I move the buttons functions elsewhere, then I should be almost there.

I’d put the switch/case code into a separate function and call it when either a debounced physical button press is detected, or a widget button press occurs via the BLYNK_WRITE(Vpin).

Pete.

Hi Pete, I’ve not had chance to have at look at this code, I’ll follow up on your advice today