4 Button remote for NEOPIXEL Strips & looping code when button pressed

Hi All

I have started a project with a 4 button remote and an ESP32 board, to control various 2812 RGB strips.

I am having trouble getting the correct code to keep the button on and or also to repeat code when on.

I would like to push a button and for the lighing sequence to run until I push the button again.

#include <FastLED.h>
#include <Adafruit_NeoPixel.h>
#define NUM_LEDS 16
#define NUM_LEDS2 60
CRGB leds[NUM_LEDS];
#define BLINK_TIME 50
#define BRIGHTNESS 10

int button1 = 32;
int led1 = 5;
int button2 = 33;
int led2 = 13;
int status = false;

const int buttonPin = 32;   // the number of the pushbutton pin
const int ledPin = 5;       // the number of the LED pin
const int buttonPin2 = 33;  // the number of the pushbutton pin
const int ledPin2 = 4;      // the number of the LED pin


Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_LEDS, led1, NEO_GRB + NEO_KHZ800);

void setup() {
  pinMode(led1, OUTPUT);
  pinMode(button1, INPUT_PULLUP);
  pinMode(led2, OUTPUT);
  pinMode(button2, INPUT_PULLUP);
  FastLED.addLeds<WS2811, ledPin, GRB>(leds, NUM_LEDS).setCorrection(TypicalLEDStrip);
}

void loop() {

  if (digitalRead(button1) == true) {
    status = !status;
    Strobe();
    digitalWrite(led1, status);
  }
  while (digitalRead(button1) == true)
    ;
  if (digitalRead(button2) == true) {
    status = !status;
    digitalWrite(led2, status);
  }
  while (digitalRead(button2) == true)
    ;
  delay(50);
}
void Strobe() {
  strip.fill(0x0000FF, 0, 4);
  strip.fill(0x0000FF, 12, 4);
  strip.show();
  delay(BLINK_TIME);

  strip.fill(0x00);
  strip.show();
  delay(BLINK_TIME);

  strip.fill(0x0000FF, 0, 4);
  strip.fill(0x0000FF, 12, 4);
  strip.show();
  delay(BLINK_TIME);

  strip.fill(0x00);
  strip.show();
  delay(BLINK_TIME);

  strip.fill(0x0000FF, 0, 4);
  strip.fill(0x0000FF, 12, 4);
  strip.show();
  delay(BLINK_TIME);

  strip.fill(0x00);
  strip.show();
  delay(BLINK_TIME);

  strip.fill(0xFF0000, 4, 4);
  strip.fill(0xFF0000, 8, 4);
  strip.show();
  delay(BLINK_TIME);

  strip.fill(0x00);
  strip.show();
  delay(BLINK_TIME);

  strip.fill(0xFF0000, 4, 4);
  strip.fill(0xFF0000, 8, 4);
  strip.show();
  delay(BLINK_TIME);

  strip.fill(0x00);
  strip.show();
  delay(BLINK_TIME);
}


This code.version has a functionality that transforms a momentary push-button
to a toggle-switch.

/*
overview:
function setup() is that function that is always executed only ONCE

the function loop() start doing what its nam says: LOOPING around and around infinetely
inside function loop the function GetToggleSwitchState() is called
  activationMode = GetToggleSwitchState(); // must be executed all the time
  variable activationMode toggles true/false/true/false....
  with each button-press
*/


#include <FastLED.h>
#include <Adafruit_NeoPixel.h>
#define NUM_LEDS 16
#define NUM_LEDS2 60
CRGB leds[NUM_LEDS];
#define BLINK_TIME 50
#define BRIGHTNESS 10

// Superb Tech - LED Button Tutorial - Toggle
// www.youtube.com/superbtech

// define IO-states for inputs with pull-up-resistors
// pull-up-resistors invert the logig
#define unPressed HIGH
#define pressed   LOW

const byte ToggleButtonPin = 32;
//int button1 = 32;
bool activationMode = false;

int led1 = 5;
int button2 = 33;
int led2 = 13;
int status = false;

const int buttonPin = 32;  // the number of the pushbutton pin
const int ledPin = 5;    // the number of the LED pin
const int buttonPin2 = 33;  // the number of the pushbutton pin
const int ledPin2 = 4;    // the number of the LED pin

Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_LEDS, led1, NEO_GRB + NEO_KHZ800);

void setup() {
  pinMode(led1, OUTPUT);
  pinMode(ToggleButtonPin, INPUT_PULLUP);
  pinMode(led2, OUTPUT);
  pinMode(button2, INPUT_PULLUP);
  FastLED.addLeds<WS2811, ledPin, GRB>(leds, NUM_LEDS).setCorrection( TypicalLEDStrip );
}

void loop() {

  activationMode = GetToggleSwitchState(); // must be executed all the time
  if (activationMode) {
    Strobe() ; // <<<<== inside this function you do what shall be executed only if mode isActivated is true
  }

/*  Your old code out-commented
  if (digitalRead(button1) == true) {
    status = !status;
    Strobe();
    digitalWrite(led1, status);
  }
  while (digitalRead(button1) == true);
*/
  
  if (digitalRead(button2) == true) {
    status = !status;
    digitalWrite(led2, status);
  } while (digitalRead(button2) == true);
  delay(50);
}


void Strobe() {
  strip.setPixelColor(4, strip.Color(0, 0, 255));  // set pixel 0 to blue
  strip.setPixelColor(5, strip.Color(0, 0, 255));  // set pixel 0 to blue
  strip.setPixelColor(6, strip.Color(0, 0, 255));  // set pixel 0 to blue
  strip.setPixelColor(7, strip.Color(0, 0, 255));  // set pixel 0 to blue
  strip.setPixelColor(8, strip.Color(0, 0, 255));  // set pixel 0 to blue
  strip.setPixelColor(9, strip.Color(0, 0, 255));  // set pixel 0 to blue
  strip.setPixelColor(10, strip.Color(0, 0, 255));  // set pixel 0 to blue
  strip.setPixelColor(11, strip.Color(0, 0, 255));  // set pixel 0 to blue
  strip.show();
  delay(BLINK_TIME);

  strip.setPixelColor(4, strip.Color(0, 0, 0));
  strip.setPixelColor(5, strip.Color(0, 0, 0));
  strip.setPixelColor(6, strip.Color(0, 0, 0));
  strip.setPixelColor(7, strip.Color(0, 0, 0));
  strip.setPixelColor(8, strip.Color(0, 0, 0));
  strip.setPixelColor(9, strip.Color(0, 0, 0));
  strip.setPixelColor(10, strip.Color(0, 0, 0));
  strip.setPixelColor(11, strip.Color(0, 0, 0));
  strip.show();
  delay(BLINK_TIME);

  strip.setPixelColor(4, strip.Color(0, 0, 255));  // set pixel 0 to blue
  strip.setPixelColor(5, strip.Color(0, 0, 255));  // set pixel 0 to blue
  strip.setPixelColor(6, strip.Color(0, 0, 255));  // set pixel 0 to blue
  strip.setPixelColor(7, strip.Color(0, 0, 255));  // set pixel 0 to blue
  strip.setPixelColor(8, strip.Color(0, 0, 255));  // set pixel 0 to blue
  strip.setPixelColor(9, strip.Color(0, 0, 255));  // set pixel 0 to blue
  strip.setPixelColor(10, strip.Color(0, 0, 255));  // set pixel 0 to blue
  strip.setPixelColor(11, strip.Color(0, 0, 255));  // set pixel 0 to blue
  strip.show();
  delay(BLINK_TIME);

  strip.setPixelColor(4, strip.Color(0, 0, 0));
  strip.setPixelColor(5, strip.Color(0, 0, 0));
  strip.setPixelColor(6, strip.Color(0, 0, 0));
  strip.setPixelColor(7, strip.Color(0, 0, 0));
  strip.setPixelColor(8, strip.Color(0, 0, 0));
  strip.setPixelColor(9, strip.Color(0, 0, 0));
  strip.setPixelColor(10, strip.Color(0, 0, 0));
  strip.setPixelColor(11, strip.Color(0, 0, 0));
  strip.show();
  delay(BLINK_TIME);

  strip.setPixelColor(4, strip.Color(0, 0, 255));  // set pixel 0 to blue
  strip.setPixelColor(5, strip.Color(0, 0, 255));  // set pixel 0 to blue
  strip.setPixelColor(6, strip.Color(0, 0, 255));  // set pixel 0 to blue
  strip.setPixelColor(7, strip.Color(0, 0, 255));  // set pixel 0 to blue
  strip.setPixelColor(8, strip.Color(0, 0, 255));  // set pixel 0 to blue
  strip.setPixelColor(9, strip.Color(0, 0, 255));  // set pixel 0 to blue
  strip.setPixelColor(10, strip.Color(0, 0, 255));  // set pixel 0 to blue
  strip.setPixelColor(11, strip.Color(0, 0, 255));  // set pixel 0 to blue
  strip.show();
  delay(BLINK_TIME);

  strip.setPixelColor(4, strip.Color(0, 0, 0));  // set pixel 0 to black
  strip.setPixelColor(5, strip.Color(0, 0, 0));  // set pixel 0 to black
  strip.setPixelColor(6, strip.Color(0, 0, 0));  // set pixel 0 to black
  strip.setPixelColor(7, strip.Color(0, 0, 0));  // set pixel 0 to black
  strip.setPixelColor(8, strip.Color(0, 0, 0));
  strip.setPixelColor(9, strip.Color(0, 0, 0));
  strip.setPixelColor(10, strip.Color(0, 0, 0));
  strip.setPixelColor(11, strip.Color(0, 0, 0));
  strip.show();
  delay(BLINK_TIME);

  strip.setPixelColor(0, strip.Color(255, 0, 0));  // set pixel 0 to red
  strip.setPixelColor(1, strip.Color(255, 0, 0));  // set pixel 0 to red
  strip.setPixelColor(2, strip.Color(255, 0, 0));  // set pixel 0 to red
  strip.setPixelColor(3, strip.Color(255, 0, 0));  // set pixel 0 to red
  strip.setPixelColor(12, strip.Color(255, 0, 0));  // set pixel 0 to black
  strip.setPixelColor(13, strip.Color(255, 0, 0));  // set pixel 0 to black
  strip.setPixelColor(14, strip.Color(255, 0, 0));  // set pixel 0 to black
  strip.setPixelColor(15, strip.Color(255, 0, 0));  // set pixel 0 to black
  strip.show();
  delay(BLINK_TIME);

  strip.setPixelColor(0, strip.Color(0, 0, 0));  // set pixel 0 to black
  strip.setPixelColor(1, strip.Color(0, 0, 0));  // set pixel 0 to black
  strip.setPixelColor(2, strip.Color(0, 0, 0));  // set pixel 0 to black
  strip.setPixelColor(3, strip.Color(0, 0, 0));  // set pixel 0 to black
  strip.setPixelColor(12, strip.Color(0, 0, 0));  // set pixel 0 to black
  strip.setPixelColor(13, strip.Color(0, 0, 0));  // set pixel 0 to black
  strip.setPixelColor(14, strip.Color(0, 0, 0));  // set pixel 0 to black
  strip.setPixelColor(15, strip.Color(0, 0, 0));  // set pixel 0 to black
  strip.show();
  delay(BLINK_TIME);

  strip.setPixelColor(0, strip.Color(255, 0, 0));  // set pixel 0 to red
  strip.setPixelColor(1, strip.Color(255, 0, 0));  // set pixel 0 to red
  strip.setPixelColor(2, strip.Color(255, 0, 0));  // set pixel 0 to red
  strip.setPixelColor(3, strip.Color(255, 0, 0));  // set pixel 0 to red
  strip.setPixelColor(12, strip.Color(255, 0, 0));  // set pixel 0 to black
  strip.setPixelColor(13, strip.Color(255, 0, 0));  // set pixel 0 to black
  strip.setPixelColor(14, strip.Color(255, 0, 0));  // set pixel 0 to black
  strip.setPixelColor(15, strip.Color(255, 0, 0));  // set pixel 0 to black
  strip.show();
  delay(BLINK_TIME);

  strip.setPixelColor(0, strip.Color(0, 0, 0));  // set pixel 0 to black
  strip.setPixelColor(1, strip.Color(0, 0, 0));  // set pixel 0 to black
  strip.setPixelColor(2, strip.Color(0, 0, 0));  // set pixel 0 to black
  strip.setPixelColor(3, strip.Color(0, 0, 0));  // set pixel 0 to black
  strip.setPixelColor(12, strip.Color(0, 0, 0));  // set pixel 0 to black
  strip.setPixelColor(13, strip.Color(0, 0, 0));  // set pixel 0 to black
  strip.setPixelColor(14, strip.Color(0, 0, 0));  // set pixel 0 to black
  strip.setPixelColor(15, strip.Color(0, 0, 0));  // set pixel 0 to black
  strip.show();
  delay(BLINK_TIME);

  strip.setPixelColor(0, strip.Color(255, 0, 0));  // set pixel 0 to red
  strip.setPixelColor(1, strip.Color(255, 0, 0));  // set pixel 0 to red
  strip.setPixelColor(2, strip.Color(255, 0, 0));  // set pixel 0 to red
  strip.setPixelColor(3, strip.Color(255, 0, 0));  // set pixel 0 to red
  strip.setPixelColor(12, strip.Color(255, 0, 0));  // set pixel 0 to black
  strip.setPixelColor(13, strip.Color(255, 0, 0));  // set pixel 0 to black
  strip.setPixelColor(14, strip.Color(255, 0, 0));  // set pixel 0 to black
  strip.setPixelColor(15, strip.Color(255, 0, 0));  // set pixel 0 to black
  strip.show();
  delay(BLINK_TIME);

  strip.setPixelColor(0, strip.Color(0, 0, 0));  // set pixel 0 to black
  strip.setPixelColor(1, strip.Color(0, 0, 0));  // set pixel 0 to black
  strip.setPixelColor(2, strip.Color(0, 0, 0));  // set pixel 0 to black
  strip.setPixelColor(3, strip.Color(0, 0, 0));  // set pixel 0 to black
  strip.setPixelColor(12, strip.Color(0, 0, 0));  // set pixel 0 to black
  strip.setPixelColor(13, strip.Color(0, 0, 0));  // set pixel 0 to black
  strip.setPixelColor(14, strip.Color(0, 0, 0));  // set pixel 0 to black
  strip.setPixelColor(15, strip.Color(0, 0, 0));  // set pixel 0 to black
  strip.show();
  delay(BLINK_TIME);

  strip.setPixelColor(4, strip.Color(0, 0, 255));  // set pixel 0 to blue
  strip.setPixelColor(5, strip.Color(0, 0, 255));  // set pixel 0 to blue
  strip.setPixelColor(6, strip.Color(0, 0, 255));  // set pixel 0 to blue
  strip.setPixelColor(7, strip.Color(0, 0, 255));  // set pixel 0 to blue
  strip.setPixelColor(8, strip.Color(0, 0, 255));  // set pixel 0 to blue
  strip.setPixelColor(9, strip.Color(0, 0, 255));  // set pixel 0 to blue
  strip.setPixelColor(10, strip.Color(0, 0, 255));  // set pixel 0 to blue
  strip.setPixelColor(11, strip.Color(0, 0, 255));  // set pixel 0 to blue
  strip.show();
  delay(BLINK_TIME);

  strip.setPixelColor(4, strip.Color(0, 0, 0));
  strip.setPixelColor(5, strip.Color(0, 0, 0));
  strip.setPixelColor(6, strip.Color(0, 0, 0));
  strip.setPixelColor(7, strip.Color(0, 0, 0));
  strip.setPixelColor(8, strip.Color(0, 0, 0));
  strip.setPixelColor(9, strip.Color(0, 0, 0));
  strip.setPixelColor(10, strip.Color(0, 0, 0));
  strip.setPixelColor(11, strip.Color(0, 0, 0));
  strip.show();
  delay(BLINK_TIME);

  strip.setPixelColor(4, strip.Color(0, 0, 255));  // set pixel 0 to blue
  strip.setPixelColor(5, strip.Color(0, 0, 255));  // set pixel 0 to blue
  strip.setPixelColor(6, strip.Color(0, 0, 255));  // set pixel 0 to blue
  strip.setPixelColor(7, strip.Color(0, 0, 255));  // set pixel 0 to blue
  strip.setPixelColor(8, strip.Color(0, 0, 255));  // set pixel 0 to blue
  strip.setPixelColor(9, strip.Color(0, 0, 255));  // set pixel 0 to blue
  strip.setPixelColor(10, strip.Color(0, 0, 255));  // set pixel 0 to blue
  strip.setPixelColor(11, strip.Color(0, 0, 255));  // set pixel 0 to blue
  strip.show();
  delay(BLINK_TIME);

  strip.setPixelColor(4, strip.Color(0, 0, 0));
  strip.setPixelColor(5, strip.Color(0, 0, 0));
  strip.setPixelColor(6, strip.Color(0, 0, 0));
  strip.setPixelColor(7, strip.Color(0, 0, 0));
  strip.setPixelColor(8, strip.Color(0, 0, 0));
  strip.setPixelColor(9, strip.Color(0, 0, 0));
  strip.setPixelColor(10, strip.Color(0, 0, 0));
  strip.setPixelColor(11, strip.Color(0, 0, 0));
  strip.show();
  delay(BLINK_TIME);

  strip.setPixelColor(4, strip.Color(0, 0, 255));  // set pixel 0 to blue
  strip.setPixelColor(5, strip.Color(0, 0, 255));  // set pixel 0 to blue
  strip.setPixelColor(6, strip.Color(0, 0, 255));  // set pixel 0 to blue
  strip.setPixelColor(7, strip.Color(0, 0, 255));  // set pixel 0 to blue
  strip.setPixelColor(8, strip.Color(0, 0, 255));  // set pixel 0 to blue
  strip.setPixelColor(9, strip.Color(0, 0, 255));  // set pixel 0 to blue
  strip.setPixelColor(10, strip.Color(0, 0, 255));  // set pixel 0 to blue
  strip.setPixelColor(11, strip.Color(0, 0, 255));  // set pixel 0 to blue
  strip.show();
  delay(BLINK_TIME);

  strip.setPixelColor(4, strip.Color(0, 0, 0));  // set pixel 0 to black
  strip.setPixelColor(5, strip.Color(0, 0, 0));  // set pixel 0 to black
  strip.setPixelColor(6, strip.Color(0, 0, 0));  // set pixel 0 to black
  strip.setPixelColor(7, strip.Color(0, 0, 0));  // set pixel 0 to black
  strip.setPixelColor(8, strip.Color(0, 0, 0));
  strip.setPixelColor(9, strip.Color(0, 0, 0));
  strip.setPixelColor(10, strip.Color(0, 0, 0));
  strip.setPixelColor(11, strip.Color(0, 0, 0));
  strip.show();
  delay(BLINK_TIME);

  strip.setPixelColor(0, strip.Color(255, 0, 0));  // set pixel 0 to red
  strip.setPixelColor(1, strip.Color(255, 0, 0));  // set pixel 0 to red
  strip.setPixelColor(2, strip.Color(255, 0, 0));  // set pixel 0 to red
  strip.setPixelColor(3, strip.Color(255, 0, 0));  // set pixel 0 to red
  strip.setPixelColor(12, strip.Color(255, 0, 0));  // set pixel 0 to black
  strip.setPixelColor(13, strip.Color(255, 0, 0));  // set pixel 0 to black
  strip.setPixelColor(14, strip.Color(255, 0, 0));  // set pixel 0 to black
  strip.setPixelColor(15, strip.Color(255, 0, 0));  // set pixel 0 to black
  strip.show();
  delay(BLINK_TIME);

  strip.setPixelColor(0, strip.Color(0, 0, 0));  // set pixel 0 to black
  strip.setPixelColor(1, strip.Color(0, 0, 0));  // set pixel 0 to black
  strip.setPixelColor(2, strip.Color(0, 0, 0));  // set pixel 0 to black
  strip.setPixelColor(3, strip.Color(0, 0, 0));  // set pixel 0 to black
  strip.setPixelColor(12, strip.Color(0, 0, 0));  // set pixel 0 to black
  strip.setPixelColor(13, strip.Color(0, 0, 0));  // set pixel 0 to black
  strip.setPixelColor(14, strip.Color(0, 0, 0));  // set pixel 0 to black
  strip.setPixelColor(15, strip.Color(0, 0, 0));  // set pixel 0 to black
  strip.show();
  delay(BLINK_TIME);

  strip.setPixelColor(0, strip.Color(255, 0, 0));  // set pixel 0 to red
  strip.setPixelColor(1, strip.Color(255, 0, 0));  // set pixel 0 to red
  strip.setPixelColor(2, strip.Color(255, 0, 0));  // set pixel 0 to red
  strip.setPixelColor(3, strip.Color(255, 0, 0));  // set pixel 0 to red
  strip.setPixelColor(12, strip.Color(255, 0, 0));  // set pixel 0 to black
  strip.setPixelColor(13, strip.Color(255, 0, 0));  // set pixel 0 to black
  strip.setPixelColor(14, strip.Color(255, 0, 0));  // set pixel 0 to black
  strip.setPixelColor(15, strip.Color(255, 0, 0));  // set pixel 0 to black
  strip.show();
  delay(BLINK_TIME);

  strip.setPixelColor(0, strip.Color(0, 0, 0));  // set pixel 0 to black
  strip.setPixelColor(1, strip.Color(0, 0, 0));  // set pixel 0 to black
  strip.setPixelColor(2, strip.Color(0, 0, 0));  // set pixel 0 to black
  strip.setPixelColor(3, strip.Color(0, 0, 0));  // set pixel 0 to black
  strip.setPixelColor(12, strip.Color(0, 0, 0));  // set pixel 0 to black
  strip.setPixelColor(13, strip.Color(0, 0, 0));  // set pixel 0 to black
  strip.setPixelColor(14, strip.Color(0, 0, 0));  // set pixel 0 to black
  strip.setPixelColor(15, strip.Color(0, 0, 0));  // set pixel 0 to black
  strip.show();
  delay(BLINK_TIME);

  strip.setPixelColor(0, strip.Color(255, 0, 0));  // set pixel 0 to red
  strip.setPixelColor(1, strip.Color(255, 0, 0));  // set pixel 0 to red
  strip.setPixelColor(2, strip.Color(255, 0, 0));  // set pixel 0 to red
  strip.setPixelColor(3, strip.Color(255, 0, 0));  // set pixel 0 to red
  strip.setPixelColor(12, strip.Color(255, 0, 0));  // set pixel 0 to black
  strip.setPixelColor(13, strip.Color(255, 0, 0));  // set pixel 0 to black
  strip.setPixelColor(14, strip.Color(255, 0, 0));  // set pixel 0 to black
  strip.setPixelColor(15, strip.Color(255, 0, 0));  // set pixel 0 to black
  strip.show();
  delay(BLINK_TIME);

  strip.setPixelColor(0, strip.Color(0, 0, 0));  // set pixel 0 to black
  strip.setPixelColor(1, strip.Color(0, 0, 0));  // set pixel 0 to black
  strip.setPixelColor(2, strip.Color(0, 0, 0));  // set pixel 0 to black
  strip.setPixelColor(3, strip.Color(0, 0, 0));  // set pixel 0 to black
  strip.setPixelColor(12, strip.Color(0, 0, 0));  // set pixel 0 to black
  strip.setPixelColor(13, strip.Color(0, 0, 0));  // set pixel 0 to black
  strip.setPixelColor(14, strip.Color(0, 0, 0));  // set pixel 0 to black
  strip.setPixelColor(15, strip.Color(0, 0, 0));  // set pixel 0 to black
  strip.show();
  delay(BLINK_TIME);
}

bool GetToggleSwitchState() {
  // "static" makes variables persistant over function calls
  static bool toggleState     = false;
  static bool lastToggleState = false;

  static byte buttonStateOld = unPressed;
  static unsigned long buttonScanStarted  =  0;
  unsigned long buttonDebounceTime = 50;
  static unsigned long buttonDebounceTimer;

  byte buttonStateNew;

  if ( TimePeriodIsOver(buttonDebounceTimer, buttonDebounceTime) ) {
    // if more time than buttonDebounceTime has passed by
    // this means let pass by some time until
    // bouncing of the button is over
    buttonStateNew = digitalRead(ToggleButtonPin);

    if (buttonStateNew != buttonStateOld) {
      // if button-state has changed
      buttonStateOld = buttonStateNew;
      if (buttonStateNew == unPressed) {
        // if button is released
        toggleState = !toggleState; // toggle state-variable
      } // the attention-mark is the NOT operator
    }   // which simply inverts the boolean state
  }     // !true  = false   NOT true  is false
  //       !false = true    NOT false is true
  return toggleState;
}

// easy to use helper-function for non-blocking timing
boolean TimePeriodIsOver (unsigned long &startOfPeriod, unsigned long TimePeriod) {
  unsigned long currentMillis  = millis();
  if ( currentMillis - startOfPeriod >= TimePeriod ) {
    // more time than TimePeriod has elapsed since last time if-condition was true
    startOfPeriod = currentMillis; // a new period starts right here so set new starttime
    return true;
  }
  else return false;            // actual TimePeriod is NOT yet over
}

/* explanation of the most important details:

  realising a functionality where using a momentary push-button
  acts as a toogle-switch
  push       => activated  push again => DE-activated
  push again => activated  push again => DE-activated
  etc. etc. ...
  This needs quite some code. This code is well organised in MULTIPLE functions
  where each function is a senseful SUB-program

  This is the reason why function loop looks super-short:

  void loop () {
  activationMode = GetToggleSwitchState(); // must be executed all the time
  if (activationMode) {       // function that does what its name says
    //code to execute only when toggled to be acctive
  }

  Huh that's all? No. Of course there is more (below function loop)
*/

best regards Stefan

And here is your code more compact through the use of arrays and functions and for-loops

/*
  overview:
  function setup() is that function that is always executed only ONCE

  the function loop() start doing what its nam says: LOOPING around and around infinetely
  inside function loop the function GetToggleSwitchState() is called
  activationMode = GetToggleSwitchState(); // must be executed all the time
  variable activationMode toggles true/false/true/false....
  with each button-press
*/


#include <FastLED.h>
#include <Adafruit_NeoPixel.h>
#define NUM_LEDS 16
#define NUM_LEDS2 60
CRGB leds[NUM_LEDS];
#define BLINK_TIME 50
#define BRIGHTNESS 10

// Superb Tech - LED Button Tutorial - Toggle
// www.youtube.com/superbtech

// define IO-states for inputs with pull-up-resistors
// pull-up-resistors invert the logig
#define unPressed HIGH
#define pressed   LOW

const byte ToggleButtonPin = 32;
//int button1 = 32;
bool activationMode = false;

int led1 = 5;
int button2 = 33;
int led2 = 13;
int status = false;

const int buttonPin = 32;  // the number of the pushbutton pin
const int ledPin = 5;    // the number of the LED pin
const int buttonPin2 = 33;  // the number of the pushbutton pin
const int ledPin2 = 4;    // the number of the LED pin

// Pixel-numbers stored in an array for sequential access over IdxNr
const byte LedNr_blue[] = {4, 5, 6, 7, 8, 9, 10, 11};
const byte LedNr_red[]  = {0, 1, 2, 3, 12, 13, 14, 15};

Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_LEDS, led1, NEO_GRB + NEO_KHZ800);

void setup() {
  pinMode(led1, OUTPUT);
  pinMode(ToggleButtonPin, INPUT_PULLUP);
  pinMode(led2, OUTPUT);
  pinMode(button2, INPUT_PULLUP);
  FastLED.addLeds<WS2811, ledPin, GRB>(leds, NUM_LEDS).setCorrection( TypicalLEDStrip );
}

void loop() {

  activationMode = GetToggleSwitchState(); // must be executed all the time
  if (activationMode) {
    Strobe() ; // <<<<== inside this function you do what shall be executed only if mode isActivated is true
  }

  /*  Your old code out-commented
    if (digitalRead(button1) == true) {
      status = !status;
      Strobe();
      digitalWrite(led1, status);
    }
    while (digitalRead(button1) == true);
  */

  if (digitalRead(button2) == true) {
    status = !status;
    digitalWrite(led2, status);
  } while (digitalRead(button2) == true);
  delay(50);
}


void pixel1_blue() {
  for (byte IdxNr = 0; IdxNr < 8; IdxNr++) {
    strip.setPixelColor(LedNr_blue[IdxNr], strip.Color(0, 0, 255));
  }
  strip.show();
}


void pixel1_black() {
  for (byte IdxNr = 0; IdxNr < 8; IdxNr++) {
    strip.setPixelColor(LedNr_blue[IdxNr], strip.Color(0, 0, 0));
  }
  strip.show();
}


void pixel2red() {
  for (byte IdxNr = 0; IdxNr < 8; IdxNr++) {
    strip.setPixelColor(LedNr_red[IdxNr], strip.Color(255, 0, 0));
  }
  strip.show();
}


void pixel2black() {
  for (byte IdxNr = 0; IdxNr < 8; IdxNr++) {
    strip.setPixelColor(LedNr_red[IdxNr], strip.Color(0, 0, 0));
  }
  strip.show();
}


void Strobe() {

  for (byte i = 0; i < 3; i++) { // 0 to 3 = 4 times On/off
    pixel1_blue();
    delay(BLINK_TIME);
    pixel1_black();
    delay(BLINK_TIME);
  }

  for (byte i = 0; i < 3; i++) { // 0 to 3 = 4 times On/off
    pixel2red();
    delay(BLINK_TIME);
    pixel2black();
    delay(BLINK_TIME);
  }
}


bool GetToggleSwitchState() {
  // "static" makes variables persistant over function calls
  static bool toggleState     = false;
  static bool lastToggleState = false;

  static byte buttonStateOld = unPressed;
  static unsigned long buttonScanStarted  =  0;
  unsigned long buttonDebounceTime = 50;
  static unsigned long buttonDebounceTimer;

  byte buttonStateNew;

  if ( TimePeriodIsOver(buttonDebounceTimer, buttonDebounceTime) ) {
    // if more time than buttonDebounceTime has passed by
    // this means let pass by some time until
    // bouncing of the button is over
    buttonStateNew = digitalRead(ToggleButtonPin);

    if (buttonStateNew != buttonStateOld) {
      // if button-state has changed
      buttonStateOld = buttonStateNew;
      if (buttonStateNew == unPressed) {
        // if button is released
        toggleState = !toggleState; // toggle state-variable
      } // the attention-mark is the NOT operator
    }   // which simply inverts the boolean state
  }     // !true  = false   NOT true  is false
  //       !false = true    NOT false is true
  return toggleState;
}

// easy to use helper-function for non-blocking timing
boolean TimePeriodIsOver (unsigned long &startOfPeriod, unsigned long TimePeriod) {
  unsigned long currentMillis  = millis();
  if ( currentMillis - startOfPeriod >= TimePeriod ) {
    // more time than TimePeriod has elapsed since last time if-condition was true
    startOfPeriod = currentMillis; // a new period starts right here so set new starttime
    return true;
  }
  else return false;            // actual TimePeriod is NOT yet over
}

/* explanation of the most important details:

  realising a functionality where using a momentary push-button
  acts as a toogle-switch
  push       => activated  push again => DE-activated
  push again => activated  push again => DE-activated
  etc. etc. ...
  This needs quite some code. This code is well organised in MULTIPLE functions
  where each function is a senseful SUB-program

  This is the reason why function loop looks super-short:

  void loop () {
  activationMode = GetToggleSwitchState(); // must be executed all the time
  if (activationMode) {       // function that does what its name says
    //code to execute only when toggled to be acctive
  }

  Huh that's all? No. Of course there is more (below function loop)
*/

best regards Stefan

@cps_learntoarduino here's another example of turning a pushbutton into an on/off switch:

See the discussion and a link to simultions here:

Try it here

Wokwi_badge State Change Detection


What this does not address is the fact that unless you look at the button, digitalRead() it, you will not get any control.

If your Stobe() function takes some time to execute, during that time the button will not be responsive.

Solving this is a next step up in coding little things like this, say if your intent is to have a button more or less instantly turn on and off the effect.

// https://wokwi.com/projects/380600410686023681
// https://forum.arduino.cc/t/storing-button-state/1185825

const int  buttonPin = 2;    // the pin that the pushbutton to ground
const int ledPin = 13;       // the pin where an LED and series 1K resistor to ground is attached

int buttonState = 0;         // current state of the button
int lastButtonState = 0;     // previous state of the button

int ledState = 0;            // LED starts off. non-zero will mean on

void setup() {
  // initialize serial communication:
  Serial.begin(115200);

  // initialize the button pin as a input, using the internal pull-up - pressed switch reads LOW:
  pinMode(buttonPin, INPUT_PULLUP);

  // initialize the LED as an output:
  pinMode(ledPin, OUTPUT);
}

void loop() {


// INPUT
  // read the pushbutton input pin:
  buttonState = !digitalRead(buttonPin);


// PROCESS
  // compare the buttonState to its previous state
  if (buttonState != lastButtonState) {
    // the state has changed, check what it is now
    if (buttonState == HIGH) {
      // if the current state is HIGH then the button went from off to on:
      Serial.println("switch is pressed.");

      ledState = !ledState;   // and toggle the LED state
    } 
    else {
      // if the current state is LOW then the button went from on to off:
      Serial.println("                 switch is released"); 
    }
  }
  // update the last state for next time through the loop
  lastButtonState = buttonState;


// OUTPUT
  digitalWrite(ledPin, ledState ? HIGH : LOW);

  delay(50);   // poor man's debounce - run the loop way slower than the button bounce.
}

a7

And here a code-version that does all the timing in a non-blocking manner.
This means the code is very responsive to button presses

/*
  overview:
  function setup() is that function that is always executed only ONCE

  the function loop() start doing what its nam says: LOOPING around and around infinetely
  inside function loop the function GetToggleSwitchState() is called
  activationMode = GetToggleSwitchState(); // must be executed all the time
  variable activationMode toggles true/false/true/false....
  with each button-press
*/


#include <FastLED.h>
#include <Adafruit_NeoPixel.h>
#define NUM_LEDS 16
#define NUM_LEDS2 60
CRGB leds[NUM_LEDS];
#define BLINK_TIME 50
#define BRIGHTNESS 10

// Superb Tech - LED Button Tutorial - Toggle
// www.youtube.com/superbtech

// define IO-states for inputs with pull-up-resistors
// pull-up-resistors invert the logig
#define unPressed HIGH
#define pressed   LOW

const byte ToggleButtonPin = 32;
//int button1 = 32;
bool activationMode = false;

int led1 = 5;
int button2 = 33;
int led2 = 13;
int status = false;

const int buttonPin = 32;  // the number of the pushbutton pin
const int ledPin = 5;    // the number of the LED pin
const int buttonPin2 = 33;  // the number of the pushbutton pin
const int ledPin2 = 4;    // the number of the LED pin

// Pixel-numbers stored in an array for sequential access over IdxNr
const byte LedNr_blue[] = {4, 5, 6, 7, 8, 9, 10, 11};
const byte LedNr_red[]  = {0, 1, 2, 3, 12, 13, 14, 15};

const byte sm_start         = 0;
const byte sm_wait_blue_on  = 1;
const byte sm_wait_blue_off = 2;
const byte sm_wait_red_on   = 3;
const byte sm_wait_red_off  = 4;

byte myState = sm_start;
byte blinkCounter = 1;
unsigned long myLedTimer;

Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_LEDS, led1, NEO_GRB + NEO_KHZ800);

void setup() {
  pinMode(led1, OUTPUT);
  pinMode(ToggleButtonPin, INPUT_PULLUP);
  pinMode(led2, OUTPUT);
  pinMode(button2, INPUT_PULLUP);
  FastLED.addLeds<WS2811, ledPin, GRB>(leds, NUM_LEDS).setCorrection( TypicalLEDStrip );
}

void loop() {

  activationMode = GetToggleSwitchState(); // must be executed all the time
  if (activationMode) {
    Strobe() ; // <<<<== inside this function you do what shall be executed only if mode isActivated is true
  }

  /*  Your old code out-commented
    if (digitalRead(button1) == true) {
      status = !status;
      Strobe();
      digitalWrite(led1, status);
    }
    while (digitalRead(button1) == true);
  */

  if (digitalRead(button2) == true) {
    status = !status;
    digitalWrite(led2, status);
  } while (digitalRead(button2) == true);
  delay(50);
}


void pixel1_blue() {
  for (byte IdxNr = 0; IdxNr < 8; IdxNr++) {
    strip.setPixelColor(LedNr_blue[IdxNr], strip.Color(0, 0, 255));
  }
  strip.show();
}


void pixel1_black() {
  for (byte IdxNr = 0; IdxNr < 8; IdxNr++) {
    strip.setPixelColor(LedNr_blue[IdxNr], strip.Color(0, 0, 0));
  }
  strip.show();
}


void pixel2red() {
  for (byte IdxNr = 0; IdxNr < 8; IdxNr++) {
    strip.setPixelColor(LedNr_red[IdxNr], strip.Color(255, 0, 0));
  }
  strip.show();
}


void pixel2black() {
  for (byte IdxNr = 0; IdxNr < 8; IdxNr++) {
    strip.setPixelColor(LedNr_red[IdxNr], strip.Color(0, 0, 0));
  }
  strip.show();
}


void myStateMachine() {

  switch (myState) {

    case sm_start:
      pixel1_blue();
      myState = sm_wait_blue_on;
      break; // IMMIDIATELY jump down to END-OF-SWITCH
      
    case sm_wait_blue_on:
      if (TimePeriodIsOver(myLedTimer,BLINK_TIME) ) {
        pixel1_black();
        myState = sm_wait_blue_off;
      }
      break; // IMMIDIATELY jump down to END-OF-SWITCH

    case sm_wait_blue_off:
      if (TimePeriodIsOver(myLedTimer,BLINK_TIME) ) {
        
        blinkCounter++;
        if (blinkCounter < 5) {
          myState = sm_wait_blue_on;
        }
        else {
          blinkCounter = 1;
          myState = sm_wait_red_on;
        }
      }
      break; // IMMIDIATELY jump down to END-OF-SWITCH

    case sm_wait_red_on:
      if (TimePeriodIsOver(myLedTimer,BLINK_TIME) ) {
        myState = sm_wait_red_off;
      }
      break; // IMMIDIATELY jump down to END-OF-SWITCH

    case sm_wait_red_off:
      if (TimePeriodIsOver(myLedTimer,BLINK_TIME) ) {
        blinkCounter++;
        if (blinkCounter < 5) {
          myState = sm_wait_red_on;
        }
        else {
          blinkCounter = 1;
          myState = sm_start;
        }
      }
      break; // IMMIDIATELY jump down to END-OF-SWITCH
      
  } // END-OF-SWITCH
}


void Strobe() {
  myStateMachine();
}


bool GetToggleSwitchState() {
  // "static" makes variables persistant over function calls
  static bool toggleState     = false;
  static bool lastToggleState = false;

  static byte buttonStateOld = unPressed;
  static unsigned long buttonScanStarted  =  0;
  unsigned long buttonDebounceTime = 50;
  static unsigned long buttonDebounceTimer;

  byte buttonStateNew;

  if ( TimePeriodIsOver(buttonDebounceTimer, buttonDebounceTime) ) {
    // if more time than buttonDebounceTime has passed by
    // this means let pass by some time until
    // bouncing of the button is over
    buttonStateNew = digitalRead(ToggleButtonPin);

    if (buttonStateNew != buttonStateOld) {
      // if button-state has changed
      buttonStateOld = buttonStateNew;
      if (buttonStateNew == unPressed) {
        // if button is released
        toggleState = !toggleState; // toggle state-variable
      } // the attention-mark is the NOT operator
    }   // which simply inverts the boolean state
  }     // !true  = false   NOT true  is false
  //       !false = true    NOT false is true
  return toggleState;
}

// easy to use helper-function for non-blocking timing
boolean TimePeriodIsOver (unsigned long &startOfPeriod, unsigned long TimePeriod) {
  unsigned long currentMillis  = millis();
  if ( currentMillis - startOfPeriod >= TimePeriod ) {
    // more time than TimePeriod has elapsed since last time if-condition was true
    startOfPeriod = currentMillis; // a new period starts right here so set new starttime
    return true;
  }
  else return false;            // actual TimePeriod is NOT yet over
}

/* explanation of the most important details:

  realising a functionality where using a momentary push-button
  acts as a toogle-switch
  push       => activated  push again => DE-activated
  push again => activated  push again => DE-activated
  etc. etc. ...
  This needs quite some code. This code is well organised in MULTIPLE functions
  where each function is a senseful SUB-program

  This is the reason why function loop looks super-short:

  void loop () {
  activationMode = GetToggleSwitchState(); // must be executed all the time
  if (activationMode) {       // function that does what its name says
    //code to execute only when toggled to be acctive
  }

  Huh that's all? No. Of course there is more (below function loop)
*/

best regards Stefan

1 Like

Hi @StefanL38, Thank you so much for your time in reworking this code, I have so much more to learn in this coding space... wow. your code, time and effort is much apprieciated!

Hi Alto777 thank you for your time and assistance I will be looking at this example to learn more! some earlier code i assembled worked for an LED but not a neopixel strip and then i ended up down the debounce rabbit hole.

1 Like

Hi @StefanL38, the code appears to be stuck flashing just once for the blue (on and off) when the button is pushed the first time then the second button push stops the blue flashing but the strobe effect does not function. I have tried to work through the myStateMachine case's but am not having much luck getting anything to work any better. I have found your article A Demo-Code explaining the switch-case state-machine and how to do things (almost) in parallel

1 Like

I have posted three code versions. To which code-version are you refererring to?

Easiest way to identify is if you post your sketch just as the sketch is right in that moment.

best regards Stefan

Why do you include both of these libraries???

Here you create an array of CRGB objects for FastLED:

Here you create an Adafruit_NeoPixel object:

Here you register the CRGB object with FastLED:

What you're doing makes no sense!!!

Your code is a mixture of two original codes one for Adafruit neopixel one for fastled

If you put together the ingredients for a cake and chili con carne how does it taste?
Awful "does not work"

Your mixed up code uses two different libraries and different io-pins

As the next step you have to make a descision which code to keep and which to drop.

From mixing the codes in this way I can conclude that you have almost no knowledge about writing code. Very normal to start coding. But this project with two strips is too many steps at once if you don't know how to write code.
Reduce the whole thing to a single neopixel strip and start from there

best regards Stefan

Hi @gfvalvo, I have been learning/working with both FAST LED and Adafruit looking at many examples to learn from, I will tidy this up.

I am very new to the Neopixel strips and coding, I did setup a stepper motor a few years ago with some code which was very different and took some time to learn.

Hi @StefanL38, yes im very new to NEOPIXELS and coding. I found the two FASTLED and Adafruit were the most used and suppoted code bases and have had separate bits working in each. I will tidy up the code and repost.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.