Helfe bei Schrankenbeleuchtung

Hallo liebe Gemeinde,

erstmal zum Projekt:

LED Strip neopixel 60/m

  • Schranke geschossen konsant Rot
  • Schranke öffnet Lauflicht von 0 bis 239 in rot ( 10Block ) bis geöffnet
  • Schranke geöffnet konsant Rot
  • Schranke schlisst Lauflicht 239 auf 0 in rot ( 10Block ) bis geschlossen
  • Schranke geschossen konsant Rot

diese wird von Senoren überwacht.

Diese funktioniert auch siehe Sketch.

jetzt soll wenn die Schranke oben(geöffnet) ist, nach Taster(input) und einer Zeit das LED auf Blau blinken und wieder nach einer Zeit zurück auf rot, diese funktioniert leider nicht.



#include <Adafruit_NeoPixel.h>

#define LED_PIN        6      // Anschluss für den Neopixel-Streifen
#define NUM_PIXELS     239    // Anzahl der LEDs im Streifen (Index 0 bis 239)


#define SWITCH_BOTTOM  9      // unterer Endschalter: normal geschlossen (read HIGH)
#define SWITCH_TOP     10      // oberer Endschalter: normal offen (read LOW)


#define TRAFFIC_SIGNAL 2      // Ampelsignal-Taster an Pin 2 weil wegen interrupt 0


Adafruit_NeoPixel strip(NUM_PIXELS, LED_PIN, NEO_RGB + NEO_KHZ800);


// Zustandsdefinitionen
enum BarrierState {
  FULL_CLOSED,    // Schranke voll geschlossen – statisch Rot
  OPEN_RUNNING,   // Schranke im Öffnungsprozess – Lauflicht (roter Block von 10 LEDs)
  FULL_OPEN,      // Schranke voll geöffnet – statisch Rot
  CLOSE_RUNNING   // Schranke im Schließprozess – Lauflicht (roter Block von 10 LEDs)
};

BarrierState state = FULL_CLOSED;

// Variablen zur Erkennung von Zustandsänderungen an den Schaltern
int prevBottomState;
int prevTopState;



unsigned long previousMillis = 0;
const unsigned long interval = 25;  // Animationsgeschwindigkeit in ms (doppelt so schnell)
int animIndex = 0;  // Verschiebungsindex für das Lauflicht
unsigned long signalStartTime = 0;
bool signalActive = false;
bool blinking = false;
const unsigned long blinkInterval = 500;  // 500 ms für Blinken
unsigned long lastBlinkTime = 0;
bool blinkState = false;
unsigned long blinkStartTime = 0;  // Zeitpunkt, an dem das Blinken startet
unsigned long currentMillis = millis();


// Hilfsfunktion: Setzt alle LEDs auf die angegebene Farbe
void setAllPixels(uint32_t color) {
  for (int i = 0; i < NUM_PIXELS; i++) {
    strip.setPixelColor(i, color);
  }
  strip.show();
}

// Animationsroutine für das Öffnen (Lauflicht von LED 239 bis 0)
void animateOpen() {
  // Alle LEDs ausschalten
  for (int i = 0; i < NUM_PIXELS; i++) {
    if (((i + animIndex) / 10) % 2 == 0) {
      strip.setPixelColor(i, strip.Color(255, 0, 0)); // Rot
    } else {
      strip.setPixelColor(i, 0); // Aus
    }
  }
  strip.show();
  animIndex = (animIndex + 1) % 20; // Schrittweise verschieben (max. 20 für 10er-Muster)

}

// Animationsroutine für das Schließen (Lauflicht von LED 0 bis 239)
void animateClose() {
  for (int i = 0; i < NUM_PIXELS; i++) {
    if (((i - animIndex) / 10) % 2 == 0) {
      strip.setPixelColor(i, strip.Color(255, 0, 0)); // Rot
    } else {
      strip.setPixelColor(i, 0); // Aus
    }
  }
  strip.show();
  animIndex = (animIndex + 1) % 20;
}
void setup() {
  // Schalter als INPUT_PULLUP, sodass definierte Zustände vorliegen:
  // - SWITCH_BOTTOM: Normalerweise geschlossen (HIGH), wechselt zu LOW beim Öffnen.
  // - SWITCH_TOP: Normalerweise offen (LOW), wechselt zu HIGH beim Schließen.
  pinMode(SWITCH_BOTTOM, INPUT_PULLUP);    // unterer Endschalter
  pinMode(SWITCH_TOP, INPUT_PULLUP);      // oberer Endschalter
  pinMode(TRAFFIC_SIGNAL, INPUT);  // Taster mit Pulldown-Widerstand //INPUT
  attachInterrupt(0, pin_ISR, RISING); //interrupt verbinden CHANGE, LOW, FALLING, RISING,

  // Initialisierung des LED-Streifens
  strip.begin();
  strip.show();

  // Startzustand: Schranke voll geschlossen (statisch Rot)
  setAllPixels(strip.Color(255, 0, 0));
  state = FULL_CLOSED;

Serial.begin(9600);
  // Initiale Schalterzustände speichern
  prevBottomState = digitalRead(SWITCH_BOTTOM);     // unterer Endschalter
  prevTopState = digitalRead(SWITCH_TOP);           // oberer Endschalter
  
}


void loop() {
  // Aktuelle Schalterzustände auslesen
  int bottomState = digitalRead(SWITCH_BOTTOM);
  int topState = digitalRead(SWITCH_TOP);

  currentMillis = millis();

Serial.println(signalActive);

  // Zustandswechsel: Schranke öffnen
  if (state == FULL_CLOSED) {
    // Wenn der untere Schalter, der normalerweise geschlossen ist, öffnet (Wechsel von LOW zu HIGH)
    if (prevBottomState == LOW && bottomState == HIGH) {
      state = OPEN_RUNNING;
      animIndex = 0; // Animation zurücksetzen
    }
  }

  if (state == OPEN_RUNNING) {
    // Führe die Animation aus, sofern das Intervall erreicht ist
    if (currentMillis - previousMillis >= interval) {
      previousMillis = currentMillis;
      animateOpen();
    }
    // Wenn der obere Schalter schließt (wird LOW), gilt die Schranke als voll geöffnet.
    if (topState == LOW) {
      state = FULL_OPEN;
      setAllPixels(strip.Color(255, 0, 0)); // LED-Band dauerhaft rot
    }
  }

  // Zustandswechsel: Schranke schließen
  if (state == FULL_OPEN) {
    // Wenn der obere Schalter, der geschlossen war, wieder öffnet (Wechsel von LOW zu HIGH)
    if (prevTopState == LOW && topState == HIGH) {
      state = CLOSE_RUNNING;
      animIndex = 0;
    }
  }

if (state == CLOSE_RUNNING) {
    if (currentMillis - previousMillis >= interval) {
      previousMillis = currentMillis;
      animateClose();
    }
    // Wenn der untere Schalter wieder schließt (wird LOW), ist die Schranke voll geschlossen.
    if (bottomState == LOW) {
      state = FULL_CLOSED;
      setAllPixels(strip.Color(255, 0, 0));  // LED-Band dauerhaft rot
    }
  }

  // Aktualisiere die vorherigen Schalterzustände
  prevBottomState = bottomState;
  prevTopState = topState;

  

  // Nach 20 Sekunden Blinken starten
  if (signalActive && !blinking && prevTopState == 0 && (currentMillis - signalStartTime >= 21000)) {
    blinking = true;
    blinkStartTime = currentMillis;  // Zeitpunkt speichern, ab dem das Blinken startet
  }
 

  // Blinken steuern
  if (blinking) {
    if (currentMillis - lastBlinkTime >= blinkInterval) {
      lastBlinkTime = currentMillis;
      blinkState = !blinkState;
      uint32_t color = blinkState ? strip.Color(0, 0, 255) : strip.Color(0, 0, 0); // blau blinken
      setAllPixels(color);
    }

    // Blinken nach 20 Sekunden stoppen (nach Beginn des Blinkens)
    if (currentMillis - blinkStartTime >= 28000) {
      blinking = false;
      setAllPixels(strip.Color(255, 0, 0));  // Zurück zu rot
      
      
    }

    signalActive = false; //geaendert, signal muss wieder false sein
  }
}

void pin_ISR()
{


    if(!signalActive)
    {
        signalActive = true;
        
        signalStartTime = currentMillis;
    }
}



wo liegt der Fehler?

VG Sascha

@schrubbismoba11 ,

:warning:
Im englischen Teil des Forum müssen die Beiträge und Diskussionen in englischer Sprache verfasst werden.
Deswegen wurde diese Diskussion in den deutschen Teil des Forums verschoben.
mfg ein Moderator.

Dieser Wert muss 240 sein, damit der Index von 0 bis 239 zählt.

Ne ist richtig so, da ich eine Led abschneiden musste.

Ich kann den "roten" und den "blauen Blitz" sehen... Überprüfen Sie Ihre Verkabelung oder Stromversorgung.

Der löst halt den signalActive nicht aus wenn das Signal kommt.

Ich sehe signalActive LOW im SerialMonitor, das blau aktiviert. Vergewissern Sie sich, dass das mit TRAFFIC_SIGNAL verbundene Gerät funktioniert.

Ja das sehe ich auch, sobald aber der Taster betätigt wird solle ein High kommen und das blinken in blau auslösen.

Gibt es einen Grund, TRAFFIC_SIGNAL mit einem Interrupt zu erkennen?

Wenn es 239 Pixel sind, ist der Kommentar mindestens irreführend.

Beim Zustandsautomaten empfehle ich Dir } else if ( zu verwenden, sonst wird "Aktualisiere die vorherigen Schalterzustände" nicht (sicher) erreicht. Oder Du schwenkst gleich auf swtch/case um.

Mit strip.fill(color); brauchst Du die Funktion nicht.

So dieses ist gelöst, bin auf dem falschen Pin gewesen.

Neues Problem, jetzt löst signalActive aber auch aus, wenn die Schranke unten ist und sie dann wieder hoch fährt geht sie ins blinken. Das soll aber nicht passieren. Vielleicht noch eine abhängig das signalActive nur auslöst wenn oben ist.

Jetzt habe ich es mal auf den Uno r4 WiFi geschrieben und da löst signalActive nicht aus.

Ja es ist ein Ampel Signal um nicht immer denn im Loop Abfrage zu haben, ist ein interrupt.

Du meinst, es ist ein kurzes Signal, das während loop verpaßt werden könnte?

Unsere Beiträge haben sich überschnitten, ich habe #9 inzwischen ergänzt.

Ja ist es.

Dann ist die Verwendung eines Merkers eine gute Idee.

Derzeit sehe ich konstant Rot, rotes Lauflicht rauf und runter und blau blinkt es auch.

Ausbaufähig.

#include <Adafruit_NeoPixel.h>

constexpr uint8_t LED_PIN {6};      // Anschluss für den Neopixel-Streifen
constexpr uint8_t NUM_PIXELS {239};    // Anzahl der LEDs im Streifen (Index 0 bis 239)

constexpr uint8_t SWITCH_BOTTOM {9};      // unterer Endschalter: normal geschlossen (read HIGH)
constexpr uint8_t SWITCH_TOP {10};      // oberer Endschalter: normal offen (read LOW)

constexpr uint8_t TRAFFIC_SIGNAL {2};      // Ampelsignal-Taster an Pin 2 weil wegen interrupt 0

Adafruit_NeoPixel strip(NUM_PIXELS, LED_PIN, NEO_RGB + NEO_KHZ800);

// Zustandsdefinitionen
enum BarrierState
{
  FULL_CLOSED,    // Schranke voll geschlossen – statisch Rot
  OPEN_RUNNING,   // Schranke im Öffnungsprozess – Lauflicht (roter Block von 10 LEDs)
  FULL_OPEN,      // Schranke voll geöffnet – statisch Rot
  BLUE_BLINK_WAIT,
  BLUE_BLINKING,
  CLOSE_RUNNING   // Schranke im Schließprozess – Lauflicht (roter Block von 10 LEDs)
};

BarrierState state = FULL_CLOSED;
BarrierState lastState = CLOSE_RUNNING;

constexpr uint32_t rt {0xFF0000};
constexpr uint32_t bl {0x0000FF};
constexpr uint32_t sw {0x000000};

// Variablen zur Erkennung von Zustandsänderungen an den Schaltern
bool prevBottomState;
bool prevTopState;

unsigned long previousMillis = 0;
const unsigned long interval = 25;  // Animationsgeschwindigkeit in ms (doppelt so schnell)
int animIndex = 0;  // Verschiebungsindex für das Lauflicht
unsigned long signalStartTime = 0;
bool signalActive = false;
bool blinking = false;
const unsigned long blinkInterval = 500;  // 500 ms für Blinken
unsigned long lastBlinkTime = 0;
bool blinkState = false;
unsigned long blinkStartTime = 0;  // Zeitpunkt, an dem das Blinken startet
unsigned long currentMillis = millis();

void setup()
{
  // Schalter als INPUT_PULLUP, sodass definierte Zustände vorliegen:
  // - SWITCH_BOTTOM: Normalerweise geschlossen (HIGH), wechselt zu LOW beim Öffnen.
  // - SWITCH_TOP: Normalerweise offen (LOW), wechselt zu HIGH beim Schließen.
  pinMode(SWITCH_BOTTOM, INPUT_PULLUP);    // unterer Endschalter
  pinMode(SWITCH_TOP, INPUT_PULLUP);      // oberer Endschalter
  pinMode(TRAFFIC_SIGNAL, INPUT);  // Taster mit Pulldown-Widerstand //INPUT
  //attachInterrupt(0, pin_ISR, RISING); //interrupt verbinden CHANGE, LOW, FALLING, RISING,
  // Initialisierung des LED-Streifens
  strip.begin();
  strip.show();
  // Startzustand: Schranke voll geschlossen (statisch Rot)
  setAllPixels(rt);
  Serial.begin(9600);
  // Initiale Schalterzustände speichern
  prevBottomState = digitalRead(SWITCH_BOTTOM);     // unterer Endschalter
  prevTopState = digitalRead(SWITCH_TOP);           // oberer Endschalter
}

void loop()
{
  currentMillis = millis();

  switch (state)
  {
    case FULL_CLOSED:
      if (state != lastState)
      {
        setAllPixels(rt);  // LED-Band dauerhaft rot
        lastState = state;
      }

      // Wenn der untere Schalter, der normalerweise geschlossen ist, öffnet (Wechsel von LOW zu HIGH)
      if (digitalRead(SWITCH_BOTTOM))
      { state = OPEN_RUNNING; } // Zustandswechsel: Schranke öffnen

      break;

    case OPEN_RUNNING:
      if (state != lastState)
      {
        setAllPixels(sw);
        previousMillis = currentMillis;
        animIndex = 0; // Animation zurücksetzen
        lastState = state;
      }

      // Führe die Animation aus, sofern das Intervall erreicht ist
      if (currentMillis - previousMillis >= interval)
      {
        previousMillis = currentMillis;
        animateOpen();
      }

      // Wenn der obere Schalter schließt (wird LOW), gilt die Schranke als voll geöffnet.
      if (!digitalRead(SWITCH_TOP))
      { state = FULL_OPEN; }

      break;

    // Zustandswechsel: Schranke schließen
    case FULL_OPEN:
      if (state != lastState)
      {
        setAllPixels(rt); // LED-Band dauerhaft rot
      }

      // Wenn der obere Schalter, der geschlossen war, wieder öffnet (Wechsel von LOW zu HIGH)
      if (digitalRead(SWITCH_TOP))
      {
        state = CLOSE_RUNNING;
      }
      else if (digitalRead(TRAFFIC_SIGNAL))
      {
        signalStartTime = currentMillis;
        state = BLUE_BLINK_WAIT;
      }

      break;

    case BLUE_BLINK_WAIT:

      // Nach 20 Sekunden Blinken starten
      if (currentMillis - signalStartTime >= 21000)
      {
        blinkStartTime = currentMillis;  // Zeitpunkt speichern, ab dem das Blinken startet
        blinkState = true;
        setAllPixels(bl);
        state = BLUE_BLINKING;
      }

      break;

    case BLUE_BLINKING:
      if (currentMillis - lastBlinkTime >= blinkInterval)
      {
        lastBlinkTime = currentMillis;
        blinkState = !blinkState;
        setAllPixels(blinkState ? bl : sw);
      }

      // Blinken nach 20 Sekunden stoppen (nach Beginn des Blinkens)
      if (currentMillis - blinkStartTime >= 28000)
      {
        setAllPixels(rt);  // Zurück zu rot
        state = FULL_OPEN;
      }

      break;

    case CLOSE_RUNNING:
      if (state != lastState)
      {
        setAllPixels(sw);
        previousMillis = currentMillis;
        animIndex = 0; // Animation zurücksetzen
        lastState = state;
      }

      if (currentMillis - previousMillis >= interval)
      {
        animateClose();
        previousMillis = currentMillis;
      }

      // Wenn der untere Schalter wieder schließt (wird LOW), ist die Schranke voll geschlossen.
      if (!digitalRead(SWITCH_BOTTOM))
      { state = FULL_CLOSED; }

      break;
  }
}

// Hilfsfunktion: Setzt alle LEDs auf die angegebene Farbe
void setAllPixels(const uint32_t color)
{
  for (int i = 0; i < NUM_PIXELS; i++)
  { strip.setPixelColor(i, color); }

  strip.show();
}

// Animationsroutine für das Öffnen (Lauflicht von LED 239 bis 0)
void animateOpen()
{
  // Alle LEDs ausschalten
  for (int i = 0; i < NUM_PIXELS; i++)
  {
    if (((i + animIndex) / 10) % 2 == 0)
    { strip.setPixelColor(i, rt); }// Rot
    else
    { strip.setPixelColor(i, sw); }// Aus
  }

  strip.show();
  animIndex = (animIndex + 1) % 20; // Schrittweise verschieben (max. 20 für 10er-Muster)
}

// Animationsroutine für das Schließen (Lauflicht von LED 0 bis 239)
void animateClose()
{
  for (int i = 0; i < NUM_PIXELS; i++)
  {
    if (((i - animIndex) / 10) % 2 == 0)
    { strip.setPixelColor(i, rt); }// Rot
    else
    { strip.setPixelColor(i, sw); } // Aus
  }

  strip.show();
  animIndex = (animIndex + 1) % 20;
}
#include <Adafruit_NeoPixel.h>

constexpr uint8_t LED_PIN {6};      // Anschluss für den Neopixel-Streifen
constexpr uint8_t NUM_PIXELS {239};    // Anzahl der LEDs im Streifen (Index 0 bis 239)

constexpr uint8_t SWITCH_BOTTOM {9};      // unterer Endschalter: normal geschlossen (read HIGH)
constexpr uint8_t SWITCH_TOP {10};      // oberer Endschalter: normal offen (read LOW)

constexpr uint8_t TRAFFIC_SIGNAL {2};      // Ampelsignal-Taster an Pin 2 weil wegen interrupt 0

Adafruit_NeoPixel strip(NUM_PIXELS, LED_PIN, NEO_RGB + NEO_KHZ800);

// Zustandsdefinitionen
enum BarrierState
{
  FULL_CLOSED,    // Schranke voll geschlossen – statisch Rot
  OPEN_RUNNING,   // Schranke im Öffnungsprozess – Lauflicht (roter Block von 10 LEDs)
  FULL_OPEN,      // Schranke voll geöffnet – statisch Rot
  BLUE_BLINK_WAIT,
  BLUE_BLINKING,
  CLOSE_RUNNING   // Schranke im Schließprozess – Lauflicht (roter Block von 10 LEDs)
};

BarrierState state = FULL_CLOSED;
BarrierState lastState = CLOSE_RUNNING;

constexpr uint32_t rt {0xFF0000};
constexpr uint32_t bl {0x0000FF};
constexpr uint32_t sw {0x000000};

// Variablen zur Erkennung von Zustandsänderungen an den Schaltern
bool prevBottomState;
bool prevTopState;

unsigned long previousMillis = 0;
const unsigned long interval = 25;  // Animationsgeschwindigkeit in ms (doppelt so schnell)
int animIndex = 0;  // Verschiebungsindex für das Lauflicht
unsigned long signalStartTime = 0;
bool signalActive = false;
bool blinking = false;
const unsigned long blinkInterval = 500;  // 500 ms für Blinken
unsigned long lastBlinkTime = 0;
bool blinkState = false;
unsigned long blinkStartTime = 0;  // Zeitpunkt, an dem das Blinken startet
unsigned long currentMillis = millis();

void setup()
{
  // Schalter als INPUT_PULLUP, sodass definierte Zustände vorliegen:
  // - SWITCH_BOTTOM: Normalerweise geschlossen (HIGH), wechselt zu LOW beim Öffnen.
  // - SWITCH_TOP: Normalerweise offen (LOW), wechselt zu HIGH beim Schließen.
  pinMode(SWITCH_BOTTOM, INPUT_PULLUP);    // unterer Endschalter
  pinMode(SWITCH_TOP, INPUT_PULLUP);      // oberer Endschalter
  pinMode(TRAFFIC_SIGNAL, INPUT);  // Taster mit Pulldown-Widerstand //INPUT
  //attachInterrupt(0, pin_ISR, RISING); //interrupt verbinden CHANGE, LOW, FALLING, RISING,
  // Initialisierung des LED-Streifens
  strip.begin();
  strip.show();
  // Startzustand: Schranke voll geschlossen (statisch Rot)
  setAllPixels(rt);
  Serial.begin(9600);
  // Initiale Schalterzustände speichern
  prevBottomState = digitalRead(SWITCH_BOTTOM);     // unterer Endschalter
  prevTopState = digitalRead(SWITCH_TOP);           // oberer Endschalter
}

void loop()
{
  currentMillis = millis();

  switch (state)
  {
    case FULL_CLOSED:
      if (state != lastState)
      {
        setAllPixels(rt);  // LED-Band dauerhaft rot
        lastState = state;
      }

      // Wenn der untere Schalter, der normalerweise geschlossen ist, öffnet (Wechsel von LOW zu HIGH)
      if (digitalRead(SWITCH_BOTTOM))
      { state = OPEN_RUNNING; } // Zustandswechsel: Schranke öffnen

      break;

    case OPEN_RUNNING:
      if (state != lastState)
      {
        setAllPixels(sw);
        previousMillis = currentMillis;
        animIndex = 0; // Animation zurücksetzen
        lastState = state;
      }

      // Führe die Animation aus, sofern das Intervall erreicht ist
      if (currentMillis - previousMillis >= interval)
      {
        previousMillis = currentMillis;
        animateOpen();
      }

      // Wenn der obere Schalter schließt (wird LOW), gilt die Schranke als voll geöffnet.
      if (!digitalRead(SWITCH_TOP))
      { state = FULL_OPEN; }

      break;

    // Zustandswechsel: Schranke schließen
    case FULL_OPEN:
      if (state != lastState)
      {
        setAllPixels(rt); // LED-Band dauerhaft rot
      }

      // Wenn der obere Schalter, der geschlossen war, wieder öffnet (Wechsel von LOW zu HIGH)
      if (digitalRead(SWITCH_TOP))
      {
        state = CLOSE_RUNNING;
      }
      else if (digitalRead(TRAFFIC_SIGNAL))
      {
        signalStartTime = currentMillis;
        state = BLUE_BLINK_WAIT;
      }

      break;

    case BLUE_BLINK_WAIT:

      // Nach 20 Sekunden Blinken starten
      if (currentMillis - signalStartTime >= 21000)
      {
        blinkStartTime = currentMillis;  // Zeitpunkt speichern, ab dem das Blinken startet
        blinkState = true;
        setAllPixels(bl);
        state = BLUE_BLINKING;
      }

      break;

    case BLUE_BLINKING:
      if (currentMillis - lastBlinkTime >= blinkInterval)
      {
        lastBlinkTime = currentMillis;
        blinkState = !blinkState;
        setAllPixels(blinkState ? bl : sw);
      }

      // Blinken nach 20 Sekunden stoppen (nach Beginn des Blinkens)
      if (currentMillis - blinkStartTime >= 28000)
      {
        setAllPixels(rt);  // Zurück zu rot
        state = FULL_OPEN;
      }

      break;

    case CLOSE_RUNNING:
      if (state != lastState)
      {
        setAllPixels(sw);
        previousMillis = currentMillis;
        animIndex = 0; // Animation zurücksetzen
        lastState = state;
      }

      if (currentMillis - previousMillis >= interval)
      {
        animateClose();
        previousMillis = currentMillis;
      }

      // Wenn der untere Schalter wieder schließt (wird LOW), ist die Schranke voll geschlossen.
      if (!digitalRead(SWITCH_BOTTOM))
      { state = FULL_CLOSED; }

      break;
  }
}

// Hilfsfunktion: Setzt alle LEDs auf die angegebene Farbe
void setAllPixels(const uint32_t color)
{
  for (int i = 0; i < NUM_PIXELS; i++)
  { strip.setPixelColor(i, color); }

  strip.show();
}

// Animationsroutine für das Öffnen (Lauflicht von LED 239 bis 0)
void animateOpen()
{
  // Alle LEDs ausschalten
  for (int i = 0; i < NUM_PIXELS; i++)
  {
    if (((i + animIndex) / 10) % 2 == 0)
    { strip.setPixelColor(i, rt); }// Rot
    else
    { strip.setPixelColor(i, sw); }// Aus
  }

  strip.show();
  animIndex = (animIndex + 1) % 20; // Schrittweise verschieben (max. 20 für 10er-Muster)
}

// Animationsroutine für das Schließen (Lauflicht von LED 0 bis 239)
void animateClose()
{
  for (int i = 0; i < NUM_PIXELS; i++)
  {
    if (((i - animIndex) / 10) % 2 == 0)
    { strip.setPixelColor(i, rt); }// Rot
    else
    { strip.setPixelColor(i, sw); } // Aus
  }

  strip.show();
  animIndex = (animIndex + 1) % 20;
}

Erstmal danke für deine Arbeit, aber mir ist aufgefallen das der Taster Ampel nicht abgefragt wird. Denn die Schranke soll nicht sofort in die Zeit für blinken gehen, wenn sie öffnen ist. Erst wenn das Signal Ampel kommt soll er die Zeit starten und dann ins blinken gehen und wieder zurück auf rot.

Moment, erklär mal kurz, welcher SWITCH_ wird gesucht.
Und was soll dann passieren?
Ich hab den Code noch auf der Arbeitsfläche - ich bau Dir das ggfls. noch fertig.

Der TRAFFIC_SIGNAL soll die Zeit auslösen 21 sec. warten und dann blinken und dann nach 28 sec. Wieder auf rot und das nur wenn die Schranke offen ist und nicht wenn das TRAFFIC_SIGNAL kommt wenn sie geschlossen ist und dann nach hoch fährt, offen ist das Zeitprogramm abläuft.

Also hab ich das richtig verstanden:

Ja richtig nur wenn die Schranke offnen ist soll die Zeit ausgelöst werden.