Controlling Neopixel pulse-effect with IR remote

Hi,
I’m quite new to Arduino, so I’m still a bit sketchy when it comes to coding.

I hope you guys can give me some hints.

My issue:
I have a Neopixel-like LED-strip, which I want to control with an IR remote. The LED-strip should do a breathing effect while it’s on.

I’d like button 1 on my remote to turn it on and start the breathing effect, while button 2 should turn it off.

I have two version of my code right now:
In one version, I press button 1, strip turns on, and does one cycle of breathing(brightness 50->255 ->50), then stays at 50. I can then press button 2 to turn it off. During the cycle, there’s no reaction to any button presses.

In my other version, the code that does the breathing effect is in a while loop, and it keeps breathing - but still doesn’t react to any buttons while it’s in the loop. (this is the version I’ve added below)

My question: How can I get it to listen for an input while it’s in the loop?

I’ve added my code below. Like I said, I’m a total newb, and it’s probably a bit messy, since I frankensteined from various sources and added my own inbetween.

#include <Adafruit_NeoPixel.h>
#include <IRremote.h>

#define PIN 5
#define BRIGHTNESS 50

int RECV_PIN = 11;

// Parameter 1 = number of pixels in strip
// Parameter 2 = pin number (most are valid)
// Parameter 3 = pixel type flags, add together as needed:
//   NEO_KHZ800  800 KHz bitstream (most NeoPixel products w/WS2812 LEDs)
//   NEO_KHZ400  400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers)
//   NEO_GRB     Pixels are wired for GRB bitstream (most NeoPixel products)
//   NEO_RGB     Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2)
Adafruit_NeoPixel strip = Adafruit_NeoPixel(144, PIN, NEO_GRB + NEO_KHZ800);



byte neopix_gamma[] = {  // Used to do the breathing effect
    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  1,  1,  1,
    1,  1,  1,  1,  1,  1,  1,  1,  1,  2,  2,  2,  2,  2,  2,  2,
    2,  3,  3,  3,  3,  3,  3,  3,  4,  4,  4,  4,  4,  5,  5,  5,
    5,  6,  6,  6,  6,  7,  7,  7,  7,  8,  8,  8,  9,  9,  9, 10,
   10, 10, 11, 11, 11, 12, 12, 13, 13, 13, 14, 14, 15, 15, 16, 16,
   17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 24, 24, 25,
   25, 26, 27, 27, 28, 29, 29, 30, 31, 32, 32, 33, 34, 35, 35, 36,
   37, 38, 39, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 50,
   51, 52, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 66, 67, 68,
   69, 70, 72, 73, 74, 75, 77, 78, 79, 81, 82, 83, 85, 86, 87, 89,
   90, 92, 93, 95, 96, 98, 99,101,102,104,105,107,109,110,112,114,
  115,117,119,120,122,124,126,127,129,131,133,135,137,138,140,142,
  144,146,148,150,152,154,156,158,160,162,164,167,169,171,173,175,
  177,180,182,184,186,189,191,193,196,198,200,203,205,208,210,213,
  215,218,220,223,225,228,231,233,236,239,241,244,247,249,252,255 };
IRrecv irrecv(RECV_PIN);
decode_results results;
void setup()
{
  Serial.begin(9600);
  strip.begin();
  strip.setBrightness(85);  // Lower brightness and save eyeballs!
  strip.show(); // Initialize all pixels to 'off'
  irrecv.enableIRIn(); // Start the receiver
 
  
}
void loop() {
 
  // Process the IR input, if any
  if (irrecv.decode(&results)) // have we received an IR signal?
  {
   Serial.println(results.value, HEX);  
    translateIR(); 
    irrecv.resume(); // receive the next value
  }  
  }
  void translateIR() // takes action based on IR code received
{
  switch(results.value)
  {
  case 0xFFA25D: 
  Serial.println("Button 1");
  
  strip.setBrightness(BRIGHTNESS);
  strip.begin();
  strip.show();
    while(results.value = 0xFFA25D) {
      pulseGreen(10);
    }
   
  break;
  
  case 0xFF629D: 
 
  Serial.println("Button 2");    
  strip.setBrightness(0);
      strip.show();
  break;
  
  
    default: 
    Serial.println(" other button   ");
  }// End Case
  delay(500); // Do not get immediate repeat
} //END translateIR


void pulseGreen(uint8_t wait) {  //This is the part that does the breathing effect
  for(int j = 50; j < 256 ; j++){
      for(uint16_t i=0; i<strip.numPixels(); i++) {
          strip.setPixelColor(i, strip.Color(0,j,0, neopix_gamma[j] ) );
        }
        delay(wait);
        strip.show();
       
      }
  for(int j = 255; j >= 50 ; j--){
      for(uint16_t i=0; i<strip.numPixels(); i++) {
          strip.setPixelColor(i, strip.Color(0,j,0, neopix_gamma[j] ) );
        }
        delay(wait);
        strip.show();
 
      }
      
}

My question: How can I get it to listen for an input while it's in the loop?

Generally, don't use delay() as it blocks program operation. Use millis() for timing instead.

Option 1 would be to read the input inside the for loops and break out of the loops if/when the input changes state

Option 2 would be not to use for loops and particularly don't use nested for loops. Instead let the loop() function do the looping and don't block its operation. This allows you to read the input every time through loop() so that the code remains responsive.

See
Using millis() for timing. A beginners guide, Several things at the same time and look at the BlinkWithoutDelay example in the IDE.

Thank you for your reply!

I did look at the milis() vs delay and figured I need that... I thought it was an "eventually when I understand things better". In my case, is it a question of it won't ever work as long as there's a delay in there or is it a question of delay just isn't good/as correct as milis?

Because I prefer to tackle one issue at a time :slight_smile:

Option 1 is what I've sort of been trying to do, but I thought it was something like adding an "if" inside my fors that would either break or do the off-code part if it would receive results.value that equals my button 2. But whenever I did this, it would ALWAYS run - so I think I'm not getting what value to listen for to do this?

Option 2 sounds like it's the better option, but also more difficult for me to understand, compared to option 1.

Option 2 sounds like it's the better option, but also more difficult for me to understand, compared to option 1.

I am sure that you are right so look again at using option 1

Suppose that you have two nested for loops. My suggestion would be to read the input inside the inner for loop of your animations and if the button is pressed set a boolean variable to true and break from the inner loop. Now you will be in the outer loop, so how do you get out of that ? Test the boolean variable and break from the outer loop if it is true. Note that if you have delay()s in your code it may still not be very responsive to inputs but short of using millis() for timing and restructuring your program into a state machine this cannot be avoided.

There is another option and that is to cause an interrupt when the button is pressed, set the flag variable in the ISR and exit the for loops based on its value. There has been much discussion in the forum at various times as to whether this is a proper use of an interrupt or not and I am not going to go into that here.