Avoid delay blocking button press?

Hello! I'm working on a project that involves two different LEDs. The LEDs follow an animation that doesn't change through out the program. I have two buttons on my board - one to enable the lights, and one to disable them. The problem I quickly encountered is that the Turn Off button doesn't always work, you have to long press it in order to turn of the lights. I realized that this is because my light animation contains lots of delays, which blocks the Turn Off button press from being registered.

I have looked into the BlinkWithoutDelay project and it seems very clever, but I can't wrap my head around integrating it into my program since I have different delay intervals. This is my current code:

bool lightsOn = true;

void setup() {
  Serial.begin(9600);
  pinMode(2, INPUT); //Right button (Turn off)
  pinMode(3, INPUT); //Left button (Turn on)
  pinMode(4, OUTPUT); //Blue LED
  pinMode(5, OUTPUT); //Red LED
}

 void loop() {
  if(digitalRead(2) == 1) { //Check for Turn Off button press (this gets blocked by the animation sequence below)
    lightsOn = false;
    } else if(digitalRead(3) == 1) { //Check for Turn On button press
      lightsOn = true;
      }
    
  if(lightsOn == true) { //Animation starts here
    digitalWrite(4, 1);
    digitalWrite(5, 0);
    delay(100);
    digitalWrite(4, 0);
    digitalWrite(5, 0);
    delay(150);
    digitalWrite(4, 1);
    digitalWrite(5, 0);
    delay(400);
    digitalWrite(4, 0);
    digitalWrite(5, 1);
    delay(100);
    digitalWrite(4, 0);
    digitalWrite(5, 0);
    delay(150);
    digitalWrite(4, 0);
    digitalWrite(5, 1);
    delay(400);
    } else {
      digitalWrite(4, 0); //Turn off blue LEDs
      digitalWrite(5, 0); //Turn off red LEDs
      }
}

Big thanks for any input how I should go about making this animation without the use of delays! :slight_smile:

Here is one way to do the millis() timing using arrays.

const unsigned long times[] = {100, 150, 400, 100, 150, 400};
const byte yellowStates[] = {1, 0, 1, 0, 0, 0};
const byte blueStates[] =   {0, 0, 0, 1, 0, 1};

const byte yellowLedPin = 5;
const byte blueLedPin = 6;

void setup()
{
   Serial.begin(115200);
   pinMode(yellowLedPin, OUTPUT);
   pinMode(blueLedPin, OUTPUT);
   digitalWrite(yellowLedPin, yellowStates[0]);
   digitalWrite(blueLedPin, blueStates[0]);
}

void loop()
{
   static unsigned long timer = 0;
   static int index = 0;
   if (millis() - timer >= times[index])
   {
      timer = millis();
      digitalWrite(yellowLedPin, yellowStates[index]);
      digitalWrite(blueLedPin, blueStates[index]);
      index++;
      if (index > 5)
      {
         index = 0;
      }
   }
}

You can simply use the button library

IoT_hobbyist:
You can simply use the button library

It's not the button code that is the problem. It is all the delay()s used to make the LEDs blink

...R