Probleme débutant neopixel

Bonjour,
je suis débutant dans la programmation arduino. (je suis électricien et informaticien)
Mon projet est de mettre en lumiere une Montgolfier en métal (voir photo)
Il y aura donc un dichro led en 12volt dans le panier qui sera piloter par un relais et un ou deux ruban
Néopixel sur l'anneau en cuivre.
Un télérupteur alimente les alimentation du système.
Il y aura un bouton poussoir pour changer le mode d'éclairage.

J'ai un problème avec le changement de mode d'animation avec le bouton poussoir.
Je pense avoir identifier le problème mais je ne sais pas modifier le programme pour que ça fonctionne.
Quand on n'a des animation un peu complexe avec un delai je n'arrive pas à changer d'animation (ça bloque à "case 3".

Merci de votre aide

#include <Adafruit_NeoPixel.h>
#include <avr/power.h>

#define PIN            6 // Which pin on the Arduino is connected to the NeoPixels ; On a Trinket or Gemma we suggest changing this to 1
#define NUMPIXELS      60 // How many NeoPixels are attached to the Arduino?
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);

int relai = 3; //  le relai active le signal de déclenchement - actif haut;

// PushButton Stat
boolean PushButtonStat = false;

// PushbuttonPin
const int  PushbuttonPin = 7; 

// Variables will change:
int buttonPushCounter = 0;   // counter for the number of button presses
int buttonState = 0;         // current state of the button
int lastButtonState = 0;     // previous state of the button
int NumberOfMode = 9;        // 7 + 2 mode OFF

long Mode1previousMillis = 0; 
long Mode2previousMillis = 0;
long Mode3previousMillis = 0;

long PushButtonpreviousMillis = 0; 

 unsigned long currentMillis = 0;

long Mode1Interval = 50;   // Timer (Delay) Mode 1
long Mode2Interval = 500;   // Timer (Delay) Mode 2
long Mode3Interval = 50;   // Timer (Delay) Mode 3

long Pushinterval = 750;

long blinkMillis = 300; // Blinker delay

// Color Set Mode 1
int R = 250;
int G = 250;
int B = 250;

// Color Set Mode 2
int R_2 = 0;
int G_2 = 0;
int B_2 = 50;

// Color Set Mode 3
int R_3 = 0;
int G_3 = 50;
int B_3 = 0;

// Color Set Mode 4
int R_4 = 250;
int G_4 = 0;
int B_4 = 250;

// Color Set Mode 5
int R_5 = 0;
int G_5 = 20;
int B_5 = 25;

// Color Set Mode 6
int R_6 = 25;
int G_6 = 20;
int B_6 = 0;

// Color Set Mode 7
int R_7 = 0;
int G_7 = 0;
int B_7 = 30;

// Color Set Mode 8
int R_8 = 0;
int G_8 = 0;
int B_8 = 30;




// **** Test ******************

long FirstcurrentMillis = 0;
long FirstpreviousMillis = 0;

long SeccurrentMillis = 0;
long SecpreviousMillis = 0;

long ThirdcurrentMillis = 0;
long ThirdpreviousMillis = 0;

int testvalue = 0;
int ledState = LOW;
int LedPos = 0;
int LedPos2 = 0;
boolean LedOff = false;

// ************Test***********


// Program Start //

void setup() {
  pinMode (relai, OUTPUT); // Définir la broche "relai" comme étant une sortie;  
  pinMode(PushbuttonPin, INPUT_PULLUP);  // initialize the button pin as a input:
  Serial.begin(9600);         // initialize serial communication:
  pixels.begin();             // This initializes the NeoPixel library.
}

/* Définition des couleurs */
int RED[3] = {255, 0, 0}; // Couleur Rouge
int GREEN[3] = {0, 255, 0}; // Couleur Verte
int CYAN[3] = {0, 255, 255}; // Couleur Cyan
int YELLOW[3] = {255, 125, 0}; // Couleur Jaune
int ORANGE[3] = {255, 40, 0}; // Couleur Orange
int PURPLE[3] = {255, 0 , 255}; // Couleur Violette
int PINK[3] = {255, 0, 100}; // Couleur Rose
int BLUE[3] = {0, 0, 255}; // Couleur Bleu
int WHITE[3] = {255, 255, 255}; // Couleur Blanche

void loop() {
 
currentMillis = millis();

 // Push Button Counter
 if(currentMillis - PushButtonpreviousMillis > Pushinterval) 
  {
     buttonState = digitalRead(PushbuttonPin);
                     
    // compare the buttonState to its previous state
     if (buttonState != lastButtonState) 
     {
       // if the state has changed, increment the counter
        if (buttonState == HIGH) 
        {
           // if the current state is HIGH then the button
           // wend from off to on:
          buttonPushCounter++;
          Serial.println("on");
          Serial.print("number of button pushes:  ");
          Serial.println(buttonPushCounter);
        } 
        
         else
         {
         // if the current state is LOW then the button
         // wend from on to off:
          Serial.println("off"); 
         }
     }
       // save the current state as the last state, 
        //for next time through the loop
        lastButtonState = buttonState;
                            
       if (buttonPushCounter == NumberOfMode)
        {
          buttonPushCounter = 0; // reset buttonPushCounter
        }
  }  // Push Button Counter
             

//***************** Start Modes **********************//

  switch (buttonPushCounter)
  {
    case 0:
    digitalWrite (relai, LOW); // relai inactif
           for (int i = 0; i<NUMPIXELS; i++)
            {
                   pixels.setPixelColor(i, pixels.Color(0,0,B));  // All Leds OFF.
                   pixels.show(); // This sends the updated pixel color to the hardware.
            }
    
    break;
    
    case 1:
           for (int i = 0; i<NUMPIXELS; i++)
            {
                   pixels.setPixelColor(i, pixels.Color(R,G,B)); 
                   pixels.show(); // This sends the updated pixel color to the hardware.
            }
    
    break;
    
    case 2:
          digitalWrite (relai, HIGH); // Le relai s'active
           anim_fire();
          break;
    
    case 3:
           SeccurrentMillis = millis();
                     
                     if(SeccurrentMillis - SecpreviousMillis > 40)     
                            {
                              theaterChaseRainbow(50);
                            }

                            if (LedPos > NUMPIXELS)
                              {
                                 LedPos = 0;
                              }
          break;
    
    case 4:
           SeccurrentMillis = millis();
                     
                     if(SeccurrentMillis - SecpreviousMillis > 40)     
                            {
                              SecpreviousMillis = SeccurrentMillis;
                                
                                  pixels.setPixelColor(LedPos, pixels.Color(R_6,G_6,B_6)); 
                                  pixels.show(); // This sends the updated pixel color to the hardware. 
                                  pixels.setPixelColor(LedPos - 1 , pixels.Color(0,0,0)); // turn off previous led
                                  pixels.show(); // This sends the updated pixel color to the hardware.
                                  LedPos = LedPos + 1 ;
                            }

                            if (LedPos > NUMPIXELS)
                              {
                                 LedPos = 0;
                              }
    break;

J'avais trouver cette exemple dans la librairie adafruit mais on il faut attendre que l'animation soit fini pour que le bouton soit actif et on ne peut pas boucler.

// Simple demonstration on using an input device to trigger changes on your
// NeoPixels. Wire a momentary push button to connect from ground to a
// digital IO pin. When the button is pressed it will change to a new pixel
// animation. Initial state has all pixels off -- press the button once to
// start the first animation. As written, the button does not interrupt an
// animation in-progress, it works only when idle.

#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
 #include <avr/power.h> // Required for 16 MHz Adafruit Trinket
#endif

// Digital IO pin connected to the button. This will be driven with a
// pull-up resistor so the switch pulls the pin to ground momentarily.
// On a high -> low transition the button press logic will execute.
#define BUTTON_PIN   2

#define PIXEL_PIN    6  // Digital IO pin connected to the NeoPixels.

#define PIXEL_COUNT 16  // Number of NeoPixels

// Declare our NeoPixel strip object:
Adafruit_NeoPixel strip(PIXEL_COUNT, PIXEL_PIN, NEO_GRB + NEO_KHZ800);
// Argument 1 = Number of pixels in NeoPixel strip
// Argument 2 = Arduino pin number (most are valid)
// Argument 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)
//   NEO_RGBW    Pixels are wired for RGBW bitstream (NeoPixel RGBW products)

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

void setup() {
  pinMode(BUTTON_PIN, INPUT_PULLUP);
  strip.begin(); // Initialize NeoPixel strip object (REQUIRED)
  strip.show();  // Initialize all pixels to 'off'
}

void loop() {
  // 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 > 8) mode = 0; // Advance to next mode, wrap around after #8
      switch(mode) {           // Start the new animation...
        case 0:
          colorWipe(strip.Color(  0,   0,   0), 50);    // Black/off
          break;
        case 1:
          colorWipe(strip.Color(255,   0,   0), 50);    // Red
          break;
        case 2:
          colorWipe(strip.Color(  0, 255,   0), 50);    // Green
          break;
        case 3:
          colorWipe(strip.Color(  0,   0, 255), 50);    // Blue
          break;
        case 4:
          theaterChase(strip.Color(127, 127, 127), 50); // White
          break;
        case 5:
          theaterChase(strip.Color(127,   0,   0), 50); // Red
          break;
        case 6:
          theaterChase(strip.Color(  0,   0, 127), 50); // Blue
          break;
        case 7:
          rainbow(10);
          break;
        case 8:
          theaterChaseRainbow(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<strip.numPixels(); i++) { // For each pixel in strip...
    strip.setPixelColor(i, color);         //  Set pixel's color (in RAM)
    strip.show();                          //  Update strip to match
    delay(wait);                           //  Pause for a moment
  }
}

// Theater-marquee-style chasing lights. Pass in a color (32-bit value,
// a la strip.Color(r,g,b) as mentioned above), and a delay time (in ms)
// between frames.
void theaterChase(uint32_t color, int wait) {
  for(int a=0; a<10; a++) {  // Repeat 10 times...
    for(int b=0; b<3; b++) { //  'b' counts from 0 to 2...
      strip.clear();         //   Set all pixels in RAM to 0 (off)
      // 'c' counts up from 'b' to end of strip in steps of 3...
      for(int c=b; c<strip.numPixels(); c += 3) {
        strip.setPixelColor(c, color); // Set pixel 'c' to value 'color'
      }
      strip.show(); // Update strip with new contents
      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<strip.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 / strip.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:
      strip.setPixelColor(i, strip.gamma32(strip.ColorHSV(pixelHue)));
    }
    strip.show(); // Update strip with new contents
    delay(wait);  // Pause for a moment
  }
}

// Rainbow-enhanced theater marquee. Pass delay time (in ms) between frames.
void theaterChaseRainbow(int wait) {
  int firstPixelHue = 0;     // First pixel starts at red (hue 0)
  for(int a=0; a<30; a++) {  // Repeat 30 times...
    for(int b=0; b<3; b++) { //  'b' counts from 0 to 2...
      strip.clear();         //   Set all pixels in RAM to 0 (off)
      // 'c' counts up from 'b' to end of strip in increments of 3...
      for(int c=b; c<strip.numPixels(); c += 3) {
        // hue of pixel 'c' is offset by an amount to make one full
        // revolution of the color wheel (range 65536) along the length
        // of the strip (strip.numPixels() steps):
        int      hue   = firstPixelHue + c * 65536L / strip.numPixels();
        uint32_t color = strip.gamma32(strip.ColorHSV(hue)); // hue -> RGB
        strip.setPixelColor(c, color); // Set pixel 'c' to value 'color'
      }
      strip.show();                // Update strip with new contents
      delay(wait);                 // Pause for a moment
      firstPixelHue += 65536 / 90; // One cycle of color wheel over 90 frames
    }
  }
}

Les delay peuvent t'empêcher de capter un appui sur le bouton et tu ne passeras pas à l'animation suivante. Est-ce ce que tu remarques ?
Dans ce cas, il faut repenser l'architecture du code (en faire une machine à états) ce qui est un peu complexe, ou remplacer les delay par des boucles qui ne font que lire le bouton poussoir et sortir de la fonction d'animation (donc interrompre l'animation) si le BP est appuyé.

Merci pour votre réponse.
C'est ce que je pensais car les animations simple ne posent pas de problèmes.
Lire l'état du bouton est une bonne solution mais je suis débutant.
Je comprend quelque truc mais les histoires de bouton c'est pas encore ça.

Sinon une machine à état comme ça?

// La librairie de gestion des boutons
#include <OneButton.h>
const byte buttonPin = 7; // notre bouton est sur la pin 7
OneButton button(buttonPin, true); // true pour le mettre en INPUT_PULLUP

// les pins utilisées pour les LEDs
const byte pinLedRouge = 8;
const byte pinLedOrange = 9;
const byte pinLedJaune = 10;
const byte pinLedVerte = 11;

// la liste des états possible de notre système
// ainsi qu'une variable etatCourant prenant une de ces valeurs
enum {REPOS, ETAT_V, ETAT_VJ, ETAT_VJO, ETAT_VJOR} etatCourant;

// ------------------------------------------------------
// Cette fonction installe l'état initial
// ------------------------------------------------------
void mettreAuRepos()
{
  digitalWrite(pinLedVerte,  LOW);
  digitalWrite(pinLedJaune,  LOW);
  digitalWrite(pinLedOrange, LOW);
  digitalWrite(pinLedRouge,  LOW);
  etatCourant = REPOS;
}

// ------------------------------------------------------
// La fonction de call back, appellée automatiquement quand on clique
// ------------------------------------------------------
void simpleclick()
{
  switch (etatCourant) {
    case REPOS: // on était au repos et on a un appui, on allume la verte
      digitalWrite(pinLedVerte, HIGH); // LED verte alimentée
      etatCourant = ETAT_V; // on note le nouvel état de notre système
      break;

    case ETAT_V: // on était led verte allumée et on a un appui, on allume la jaune
      digitalWrite(pinLedJaune, HIGH); // LED jaune alimentée
      etatCourant = ETAT_VJ;// on note le nouvel état de notre système
      break;

    case ETAT_VJ: // vert et jaune allumées, on a un appui, on allume la orange
      digitalWrite(pinLedOrange, HIGH); // LED orange alimentée
      etatCourant = ETAT_VJO;// on note le nouvel état de notre système
      break;

    case ETAT_VJO:// vert, orange et jaune allumées, on a un appui, on allume la rouge
      digitalWrite(pinLedRouge, HIGH); // LED rouge alimentée
      etatCourant = ETAT_VJOR;// on note le nouvel état de notre système
      break;

    case ETAT_VJOR: // tout était allumé, on a un appui, on retourne au repos
      mettreAuRepos(); // on retourne à l'état initial
      break;
  }
}

// ------------------------------------------------------
// On initialise notre système dans le setup
// ------------------------------------------------------
void setup() {
  pinMode (pinLedRouge, OUTPUT);
  pinMode (pinLedOrange, OUTPUT);
  pinMode (pinLedJaune, OUTPUT);
  pinMode (pinLedVerte, OUTPUT);

  //conditions Initiales
  mettreAuRepos();

  // On attache la fonction simpleClick() comme callBack
  button.attachClick(simpleclick);
}

void loop() {
  // On vérifie l'état des boutons, ce qui déclenche l'appel de la fonction callBack si nécessaire
  button.tick();

  // ici on peut faire autre chose du moment que ça ne prend pas trop longtemps

}

Peut être faudrait il (c'est désagréable, mais vaut peut être mieux l'envisager dès le début) trouver une bibliothèque qui mange moins de cycles, moins de RAM Adafruit_NeoPixel vs. FastLED - LEDs and Multiplexing - Arduino Forum
fast_led http://fastled.io/ semble ramasser quelques louanges (parfois même de leur concurrent naturel, Adafruit) depuis au moins 5 ans ...

Cette remarque n'est pas incompatible avec la suppression des delais.
Si une machine à états est trop compliquée, l'idée de lesept de remplacer delay(wait) par une fonction
bool delayEtBouton(wait, bouton) est peut être assez facile à mettre en oeuvre
en tête de loop(), vous avez un bloc d'une vingtaine de lignes qui gère les changements d'état: il faudrait en faire une fonction vide, comme ça:

void calculEtat() {
currentMillis = millis();

 // Push Button Counter
 if(currentMillis - PushButtonpreviousMillis > Pushinterval)  {
     buttonState = digitalRead(PushbuttonPin);
                     
    // compare the buttonState to its previous state
     if (buttonState != lastButtonState)     {
       // if the state has changed, increment the counter
        if (buttonState == HIGH)    {
           // if the current state is HIGH then the button
           // wend from off to on:
          buttonPushCounter++;
          Serial.println("on");
          Serial.print("number of button pushes:  ");
          Serial.println(buttonPushCounter);
        }    else         {
         // if the current state is LOW then the button
         // wend from on to off:
          Serial.println("off");
         }
     }
     // save the current state as the last state,
      //for next time through the loop
      lastButtonState = buttonState;
                           
       if (buttonPushCounter == NumberOfMode)   {
          buttonPushCounter = 0; // reset buttonPushCounter
        }
  }  // Push Button Counter
}
// suivie de 
void loop(){
calculEtat();// on remet la partie amputée...

//***************** Start Modes **********************//

  switch (buttonPushCounter)
  { etc.....

A cette etape, le code ne devrait pas être pire -ni mieux qu'avant; mais ensuite,les delay(wait) peuvent être remplacés par une scrutation "simultanée" du bouton et du timer... profitant du bout de code qui gére l'évolution des états

Merci pour le conseil de choisir "fastled" je vais me pencher dessus, c'est bien d'avoir des conseils quand on débute.

J'ai modifier avec votre code.
Par contre j'ai pas compris "bool delayEtBouton(wait, bouton)"
J'ai mis "bool delay(wait, bouton) mais il me dit "'button' was not declared in this scope"
Il faut peut être mettre "buttonPushCounter" a la place?

Bon, j'avais ecrit une fonction avant de m'apercevoir que toutes vos variables (ou presque) sont globales. (pour me faire pardonner, je vais invoquer la canicule et le stress thermique)
Tres souvent, les machines d'état sont programmées en deux parties bien distinctes:
un bout qui calcule le nouvel etat (qui peut rester le même)
et un bout qui, suivant l'état, effectue diverses actions.
C'est le cas fans le code de votre post numéro 1
Je propose donc
a) de faire une fonction à partir du bout de code qui débute loop; je l'ai nommée "calculEtat" dans le post 5 ( j'espère qu'elle se compile, n'ayant pas d'accès à l'IDE Arduino et copiant collant laborieusement)

b) de reprendre l'idée de lesept, et de glisser cette fonction, qui gère l'etat, non seulement dans le debut de loop, mais dans les delais longs où on ne peut pas contrôler. Cela implique de disposer d'une fversion modifiée de delai, qui est bloqant, pour qu'il se débloque lors d'un changement d'état.
La fonction originale de delai ArduinoCore-avr/wiring.c at master · arduino/ArduinoCore-avr · GitHub, livrée avec arduino, est la suivante:

void delay(unsigned long ms) {
        uint16_t start = (uint16_t)micros();

        while (ms > 0) {
                yield(); 
                if (((uint16_t)micros() - start) >= 1000) {
                        ms--;
                        start += 1000;
                }
        }
}

yield est une fonction très intrigante; sur la plupart des arduini esp8266 - What is the secret of the arduino `yield()`function? - Stack Overflow , elle ne fait .... rien du tout...(mais avec quel talent)
JE pense qu'il faudrait la transformer ainsi (et l'appeler à la place de chaque "delay(wait);"

void delayMoinsBloquant(unsigned long ms) {
         int oldCounter =  buttonPushCounter ; // je garde trace de la variable globale
        uint16_t start = (uint16_t)micros();

        while (ms > 0) {
                yield(); // je garde precieusement cette function exotique,peu gourmande en ressources.
                calculEtat(); modifie des variables globales
                if (buttonPushCounter  != oldCounter ) return ; // cas où il ne faut pas bloquer, car action sur le boutons
                if (((uint16_t)micros() - start) >= 1000) {
                        ms--;
                        start += 1000;
                }
        }
}

Bonjour, merci de vous donnez autant de mal.
J'ai bien intégrer les deux fonctions (pas de problème de compil)
Vous allez me prendre pour un nul (enfin c'est déjà fait).
Le delay(wait) je remplace par delayMoinsBloquant(unsigned long ms)?
J'ai essayer divers chose mais ça ne fonctionne pas.
Je ne sais pas remplacer le delay.

Exemple :

// théâtre d'arc-en-ciel.
void theaterChaseRainbow(int ms) {
  int firstPixelHue = 0;     // First pixel starts at red (hue 0)
  for(int a=0; a<30; a++) {  // Repeat 30 times...
    for(int b=0; b<3; b++) { //  'b' counts from 0 to 2...
      pixels.clear();         //   Set all pixels in RAM to 0 (off)
      // 'c' counts up from 'b' to end of strip in increments of 3...
      for(int c=b; c<pixels.numPixels(); c += 3) {
        // hue of pixel 'c' is offset by an amount to make one full
        // revolution of the color wheel (range 65536) along the length
        // of the strip (strip.numPixels() steps):
        int      hue   = firstPixelHue + c * 65536L / pixels.numPixels();
        uint32_t color = pixels.gamma32(pixels.ColorHSV(hue)); // hue -> RGB
        pixels.setPixelColor(c, color); // Set pixel 'c' to value 'color'
      }
      pixels.show();                // Update strip with new contents
      delayMoinsBloquant(unsigned long ms);                 // Pause for a moment
      firstPixelHue += 65536 / 90; // Un cycle de roue chromatique sur 90 images
    }
  }

J'ai trouver une autre façon de remplacer le delay mais plus je lis les tuto et plus ça ce mélange.
C'est la fonction "millis" mais je ne sais pas si on peut l'adapter sur une animation led.

L'idée que je proposais consiste à écrire une fonction que l'on appellera à la place d'un delay. Par exemple, si tu as delay(500); on mettrait à la place une ligne du genre

bool appuiBouton = newDelay(500);

Cette fonction scruterait la pin reliée au bouton et renverrait par exemple true si le bouton a été enfoncé avant la fin du délai et false sinon. Bien sûr, en cas d'appui sur le bouton, la fonction doit s'arrêter.

Voici un moyen de faire cette fonction, il doit y en avoir d'autres. Je suppose que la pin du bouton est appelée buttonPin et qu'il est en mode INPUT_PULLUP

bool newDelay (unsigned long duration) {
  unsigned long timer = millis () ;
  while (millis() - timer < duration) {
    if (digitalRead (buttonPin) == LOW) return true ;
 } 
  return false;
}

À tester, j'écris ça sur mon portable... Donc pas testé.

Bien sûr, après avoir fait le remplacement, il faut utiliser le résultat renvoyé par cette fonction. Si elle renvoie true, il faut stopper l'animation en cours et passer à la suite...

Bonsoir,
je pense que je vais laisser tomber, j'ai pas le niveau pour comprendre tous ça.
Je vais me contenter des effet basique sans les "delay".
On verra demain si je suis plus en forme

Non, c'est tout simple, dans ton exemple, tu fais ça :

// théâtre d'arc-en-ciel.
void theaterChaseRainbow(int ms) {
  int firstPixelHue = 0;     // First pixel starts at red (hue 0)
  for(int a=0; a<30; a++) {  // Repeat 30 times...
    for(int b=0; b<3; b++) { //  'b' counts from 0 to 2...
      pixels.clear();         //   Set all pixels in RAM to 0 (off)
      // 'c' counts up from 'b' to end of strip in increments of 3...
      for(int c=b; c<pixels.numPixels(); c += 3) {
        // hue of pixel 'c' is offset by an amount to make one full
        // revolution of the color wheel (range 65536) along the length
        // of the strip (strip.numPixels() steps):
        int      hue   = firstPixelHue + c * 65536L / pixels.numPixels();
        uint32_t color = pixels.gamma32(pixels.ColorHSV(hue)); // hue -> RGB
        pixels.setPixelColor(c, color); // Set pixel 'c' to value 'color'
      }
      pixels.show();                // Update strip with new contents

      if (newDelay(50)) return;      // <-- modification ici (mettre la bonne valeur, j'ai mis 50 au pif)

      firstPixelHue += 65536 / 90; // Un cycle de roue chromatique sur 90 images
    }
  }

A tester...

Bonjour,
j'ai repris espoir (hier j'ai passé des heures à chercher des tutos avec la fonction millis) , il y a un mieux le bouton arrête le défilement du raimbow mais ne change pas d’animation.
Mais c'est normal car il faut renvoyer l'info "true" pour changer de mode.
Je sais pas si c'est dans "void calculetat" ?

#include <Adafruit_NeoPixel.h>
#include <avr/power.h>

#define PIN            6 // Which pin on the Arduino is connected to the NeoPixels ; On a Trinket or Gemma we suggest changing this to 1
#define NUMPIXELS      60 // How many NeoPixels are attached to the Arduino?
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);


// PushButton Stat
boolean PushButtonStat = false;

// PushbuttonPin
const int  PushbuttonPin = 7; 

// Variables will change:
int buttonPushCounter = 0;   // counter for the number of button presses
int buttonState = 0;         // current state of the button
int lastButtonState = 0;     // previous state of the button
int NumberOfMode = 9;        // 7 + 2 mode OFF

long Mode1previousMillis = 0; 
long Mode2previousMillis = 0;
long Mode3previousMillis = 0;

long PushButtonpreviousMillis = 0; 

 unsigned long currentMillis = 0;

long Mode1Interval = 50;   // Timer (Delay) Mode 1
long Mode2Interval = 500;   // Timer (Delay) Mode 2
long Mode3Interval = 50;   // Timer (Delay) Mode 3

long Pushinterval = 750;

long blinkMillis = 300; // Blinker delay

// Color Set Mode 1
int R = 250;
int G = 250;
int B = 250;


// **** Test ******************

long FirstcurrentMillis = 0;
long FirstpreviousMillis = 0;

long SeccurrentMillis = 0;
long SecpreviousMillis = 0;

long ThirdcurrentMillis = 0;
long ThirdpreviousMillis = 0;

int testvalue = 0;
int ledState = LOW;
int LedPos = 0;
int LedPos2 = 0;
boolean LedOff = false;

// ************Test***********

// Program Start //

void setup() {
    
  pinMode(PushbuttonPin, INPUT_PULLUP);  // initialize the button pin as a input:
  Serial.begin(9600);         // initialize serial communication:
  pixels.begin();             // This initializes the NeoPixel library.
}

// calcul etat bouton
void calculEtat() {
currentMillis = millis();

 // Push Button Counter
 if(currentMillis - PushButtonpreviousMillis > Pushinterval)  {
     buttonState = digitalRead(PushbuttonPin);
                    
    // compare the buttonState to its previous state
     if (buttonState != lastButtonState)     {
       // if the state has changed, increment the counter
        if (buttonState == HIGH)    {
           // if the current state is HIGH then the button
           // wend from off to on:
          buttonPushCounter++;
          Serial.println("on");
          Serial.print("number of button pushes:  ");
          Serial.println(buttonPushCounter);
        }    else         {
         // if the current state is LOW then the button
         // wend from on to off:
          Serial.println("off");
         }
     }
     // save the current state as the last state,
      //for next time through the loop
      lastButtonState = buttonState;
                          
       if (buttonPushCounter == NumberOfMode)   {
          buttonPushCounter = 0; // reset buttonPushCounter
        }
  }  // Push Button Counter
}


void loop(){
calculEtat();
        
//***************** Start Modes **********************//

  switch (buttonPushCounter)
  {
    case 0:
    
           for (int i = 0; i<NUMPIXELS; i++)
            {
                   pixels.setPixelColor(i, pixels.Color(0,0,0));  // All Leds OFF.
                   pixels.show(); // This sends the updated pixel color to the hardware.
            }
    
    break;
    
    case 1:
           
    
    break;
    
    case 2:
          
    break;
    
    case 3:
           theaterChaseRainbow();
    break;
    
    case 4:
           

    break;
    
    case 5 : // Blink Mode

      FirstcurrentMillis = millis();
       
       if(FirstcurrentMillis - FirstpreviousMillis > blinkMillis)     
          {
             FirstpreviousMillis = FirstcurrentMillis;        
               if (ledState == LOW)
               {
                     for (int i = 0; i<NUMPIXELS; i++)
                     {
                     pixels.setPixelColor(i, pixels.Color(R_5,G_5,B_5)); 
                     pixels.show(); // This sends the updated pixel color to the hardware. 
                     ledState = HIGH;
                     }
             }
               else
               {
                     for (int i = 0; i<NUMPIXELS; i++)
                     {
                     pixels.setPixelColor(i, pixels.Color(0,0,0)); 
                     pixels.show(); // This sends the updated pixel color to the hardware.
                     ledState = LOW;
                   }
               }
                   }
    break;
    
    case 6 : // 
             
                     SeccurrentMillis = millis();
                     
                     if(SeccurrentMillis - SecpreviousMillis > 40)     
                            {
                              SecpreviousMillis = SeccurrentMillis;
                                
                                  pixels.setPixelColor(LedPos, pixels.Color(R_6,G_6,B_6)); 
                                  pixels.show(); // This sends the updated pixel color to the hardware. 
                                  pixels.setPixelColor(LedPos - 1 , pixels.Color(0,0,0)); // turn off previous led
                                  pixels.show(); // This sends the updated pixel color to the hardware.
                                  LedPos = LedPos + 1 ;
                            }

                            if (LedPos > NUMPIXELS)
                              {
                                 LedPos = 0;
                              }

   break;
    
    case 7 :
    
               for (int i = 0; i<NUMPIXELS; i++)
            {
                   pixels.setPixelColor(i, pixels.Color(0,0,0));  // All Leds OFF.
                   pixels.show(); // This sends the updated pixel color to the hardware.
            }
    
    LedPos2 = 0;
    break;
    
    
    
    case 8 :
     
      ThirdcurrentMillis = millis();

          if(ThirdcurrentMillis - ThirdpreviousMillis > 350)     
               {
                    ThirdpreviousMillis = ThirdcurrentMillis;
                    
                    pixels.setPixelColor(0, pixels.Color(R_8,G_8,B_8)); // start from the first led
                    pixels.show(); // This sends the updated pixel color to the hardware.
                    pixels.setPixelColor(0 + LedPos2, pixels.Color(R_8,G_8,B_8)); // turn on each led one by one
                    pixels.show(); // This sends the updated pixel color to the hardware.  
                    LedPos2 = LedPos2 + 1 ;
                     
                     Serial.println("LedPos2");
                     Serial.println(LedPos2);
                    //LedOff = false;
                }
         if (LedPos2 >= NUMPIXELS)
               {
                   LedPos2 = 0;
               }

     break;
  }


  
} // end of loop

// Delay
bool newDelay (unsigned long duration) {
  unsigned long timer = millis () ;
  while (millis() - timer < duration) {
    if (digitalRead (PushbuttonPin) == LOW) return true ;
 }
  return false;
} 
// théâtre d'arc-en-ciel.
void theaterChaseRainbow() {
  int firstPixelHue = 0;     // First pixel starts at red (hue 0)
  for(int a=0; a<30; a++) {  // Repeat 30 times...
    for(int b=0; b<3; b++) { //  'b' counts from 0 to 2...
      pixels.clear();         //   Set all pixels in RAM to 0 (off)
      // 'c' counts up from 'b' to end of strip in increments of 3...
      for(int c=b; c<pixels.numPixels(); c += 3) {
        // hue of pixel 'c' is offset by an amount to make one full
        // revolution of the color wheel (range 65536) along the length
        // of the strip (strip.numPixels() steps):
        int      hue   = firstPixelHue + c * 65536L / pixels.numPixels();
        uint32_t color = pixels.gamma32(pixels.ColorHSV(hue)); // hue -> RGB
        pixels.setPixelColor(c, color); // Set pixel 'c' to value 'color'
      }
      pixels.show();                // Update strip with new contents

      if (newDelay(50)) return;      // <-- modification ici (mettre la bonne valeur, j'ai mis 50 au pif)

      firstPixelHue += 65536 / 90; // Un cycle de roue chromatique sur 90 images
    }
  }
   }

Ce qui est compliqué dans ta machine d'état c'est que le bouton sert à plusieurs choses : interrompre une animation et en lancer une autre.

A ta place, j'aurais tendance à enlever l'appel à calculEtat() au début de la loop et modifier le newDelay pour qu'il passe lui-même à l'animation suivante, comme ceci :

bool newDelay (unsigned long duration) {
 unsigned long timer = millis () ;
 while (millis() - timer < duration) {
   if (digitalRead (PushbuttonPin) == LOW) {
   delay (30);  //  anti-rebond (peut-être même pas nécessaire, mais autant le mettre)
   buttonPushCounter = (buttonPushCounter+1)%NumberOfMode; // % = modulo : on ne dépasse pas le nombre maximum
   return true ;
}
 return false;
}

Par contre, ça devrait fonctionner pour le theaterChase, mais pas pour les autres qui n'ont pas de delay : donc il faut ajouter au début de la loop un appel à newDelay

void loop(){
  newDelay(20);

Je mets le 20 au hasard, il faudra le régler (si ça marche :slight_smile: )

C'est trop coooooollllll. ça fonctionne.
Franchement merci beaucoup à vous deux.
En plus ça permet de faire défiler les modes assez rapidement quand on reste appuyer sur le bouton.
Je n'en reste pas là, je vais essayer de passer par du Fastled pour alléger la ram.

Super ! FastLED est une bonne bibliothèque, tu trouveras des exemples un peu partout

Oui c'est top mais le problème c'est que j'ai deux strip différent et il y en a un qui n'est pas pris encore en compte avec fastled, c'est des RVBW. En cherchant bien j'ai trouver un hack pour simuler la 4 emme pixel mais ça ne fonctionne pas.

Tu as une référence pour cette bande ? Tu tiens vraiment à utiliser FastLED ? Si ça marche avec Adafruit et si tu penses que ça ne marche pas avec FastLED, ne te complique pas le vie...

Oui c'est de la SK6812.
Avec fastled c'est plus facile de gérer deux strips qui sont déclarer sur des pins différentes.
J'ai pas trouver avec adafruit comment gérer deux strips en même temps déclarer en miroir.
Alors qu'avec fastled c'est super simple.