Ws2812 als Anzeige in einer Ventilsteuerung richtig einsetzen

hallo Gemeinde,

ich habe wieder eine kleine Frage wo ich die Lösung womöglich zu Kompliziert angehe. Diesemal betrifft es die LEDs WS2812. Da sie schön klein sind habe ich mich für diese Entschieden zumal ich nur eine Datenleitung brauche.

Hardware:
ArduinoNanoESP32
WS2812
Automatikventil (Aquastar MP6)

nun meine Frage.
Ich sitze hier vor einem Automatikventil und wollte diese Leds in den Code einfügen so dasa wenn ich einen Taster (Touch) benutze diese den Status anzeigt. Soweit so gut,

der code wo ich es am liebsten einsetzen würde.

// Ventil Handsteuerung wenn keine WiFi oder CanBus Komunikation besteht.
void touch_hand() {
  // Prüfen und Steuern der Ventile basierend auf GPIO-Eingängen

  // Filtern
  if (digitalRead(TOUCH_FILTERN) == HIGH) {
    digitalWrite(VENTIL_FILTERN, HIGH);
    Serial.println("Pos. Filtern wird anfahren");
    lastmillis = millis();
  } else if (millis() - lastmillis >= pos_wechsel) {
    digitalWrite(VENTIL_FILTERN, LOW);
  }

  // Rückspülen
  if (digitalRead(TOUCH_RUECKSPUELEN) == HIGH) {
    digitalWrite(VENTIL_RUECKSPUELEN, HIGH);
    Serial.println("Pos. Rückspühlen wird anfahren");
    lastmillis = millis();
  } else if (millis() - lastmillis >= pos_wechsel) {
    digitalWrite(VENTIL_RUECKSPUELEN, LOW);
  }

  // Klarspülen
  if (digitalRead(TOUCH_KLARSPUELEN) == HIGH) {
    digitalWrite(VENTIL_KLARSPUELEN, HIGH);
    Serial.println("Pos. Klarspühlen wird anfahren");
    lastmillis = millis();
  } else if (millis() - lastmillis >= pos_wechsel) {
    digitalWrite(VENTIL_KLARSPUELEN, LOW);
  }

  // Zirkulation
  if (digitalRead(TOUCH_ZIRKULATION) == HIGH) {
    digitalWrite(VENTIL_ZIRKULATION, HIGH);
    Serial.println("Pos. Zirkulieren wird anfahren");
    lastmillis = millis();
  } else if (millis() - lastmillis >= pos_wechsel) {
    digitalWrite(VENTIL_ZIRKULATION, LOW);
  }

  // Entleeren
  if (digitalRead(TOUCH_ENTLEEREN) == HIGH) {
    digitalWrite(VENTIL_ENTLEEREN, HIGH);
    Serial.println("Pos. Entleeren wird anfahren");
    lastmillis = millis();
  } else if (millis() - lastmillis >= pos_wechsel) {
    digitalWrite(VENTIL_ENTLEEREN, LOW);
  }

  // Geschlossen
  if (digitalRead(TOUCH_CLOSE) == HIGH) {
    digitalWrite(VENTIL_CLOSE, HIGH);
    Serial.println("Pos. Geschlossen wird anfahren");
    lastmillis = millis();
  } else if (millis() - lastmillis >= pos_wechsel) {
    digitalWrite(VENTIL_CLOSE, LOW);
  }

  // Winter
  if (digitalRead(TOUCH_WINTER) == HIGH) {
    digitalWrite(VENTIL_WINTER, HIGH);
    Serial.println("Pos. Winterstellung wird anfahren");
    lastmillis = millis();
  } else if (millis() - lastmillis >= pos_wechsel) {
    digitalWrite(VENTIL_WINTER, LOW);
  }

  // Reset
  if (digitalRead(TOUCH_RESET) == HIGH) {
    digitalWrite(VENTIL_RESET, HIGH);
    Serial.println("Pos. Reset ausführen");
    lastmillis = millis();
  } else if (millis() - lastmillis >= reset) {
    digitalWrite(VENTIL_RESET, LOW);
  }
}

Aber ich habe mich dazu entschlossen es seperat zu machen. Hier der Anfang mit dem ich getestet habe, leider nicht mit dem Erfolg den ich mir erhofft hatte.

void status_led() {
  // Status LED (Ventilfreigabe)
  if (digitalRead(VFRG) == HIGH) {       
    leds[3] = CRGB::Green;
  } else {
    leds[3] = CRGB::Red;
  }
  // Status LED (ESP-OK)
  if (digitalRead(Reset) == HIGH) {       
    leds[4] = CRGB::Blue;
  } else {
    leds[4] = CRGB::Red;
  }
  // Status LED (Error)
  if (digitalRead(VENTIL_ERROR) == LOW) {       
    leds[5] = CRGB::Green;
  } else {
    leds[5] = CRGB::Red;
  }

  // Positions - Anzeige
  if (digitalRead(TOUCH_FILTERN) == HIGH) {
    leds[0] = CRGB::Green;
    leds[1] = CRGB::Black;
    leds[2] = CRGB::Black;
    leds[6] = CRGB::Black;
    leds[7] = CRGB::Black;
    leds[8] = CRGB::Black;
    leds[9] = CRGB::Black;
  } else if (digitalRead(TOUCH_RUECKSPUELEN) == HIGH) {
    leds[0] = CRGB::Black;
    leds[1] = CRGB::Black;
    leds[2] = CRGB::Black;
    leds[6] = CRGB::Black;
    leds[7] = CRGB::Black;
    leds[8] = CRGB::Black;
    leds[9] = CRGB::Green;
  } else if (digitalRead(TOUCH_KLARSPUELEN) == HIGH) {
    leds[0] = CRGB::Black;
    leds[1] = CRGB::Black;
    leds[2] = CRGB::Green;
    leds[6] = CRGB::Black;
    leds[7] = CRGB::Black;
    leds[8] = CRGB::Black;
    leds[9] = CRGB::Black;
  }

  // LEDs aktualisieren (nur einmal aufrufen)
  FastLED.show();
}

Leider bleiben die LEDs nicht Dauerhaft an wenn ich eine Position anwähle. wie kann ich dies Ändern so das ich, wenn ich eine Taste drücke diese für 2 sec blinkt und dann dauerhaft anbleibt?
auch habe ich Status LEDs, diese machen was sie sollen ausser die Error LED

es gibt 6 verschiedene Meldungen die von 1sec bis 6 sec blinken. diese werte ich auch aus im code um zu sehen was für ein Fehler vorhanden ist.

// Fehlerauswertung 6 Wege Ventil
void error() {
  if (ventilError)  // Auslöser
  {
    if (!ausgeloest)  // War noch nicht ausgelöst
    {
      errStart = millis();  // Startzeit merken
      ausgeloest = true;    // merker setzen
    }
  } else  // nicht mehr ausgelöst
  {
    if (ausgeloest)  // merker war gesetzt
    {
      switch (millis() - errStart)  // Auswahl, was passiertist
      {
        case 100 ... 1100:
          err_6WVT = 1;
          Serial.println(F("Error: Power failure at the valve"));
          break;
        case 1900 ... 2100:
          err_6WVT = 2;
          Serial.println(F("Error: Position error"));
          break;
        case 2900 ... 3100:
          err_6WVT = 3;
          Serial.println(F("Error: Power error"));
          break;
        case 3900 ... 4100:
          err_6WVT = 4;
          Serial.println(F("Error: Power Errorstate"));
          break;
        case 4900 ... 5100:
          err_6WVT = 5;
          Serial.println(F("Error: Single Hall Errorstate"));
          break;
        case 5200 ... 6100:
          err_6WVT = 6;
//          error_LED, LOW;
          Serial.println(F("Error: Hall Errorstate"));
          break;
        default:
          break;
      }
      ausgeloest = false;
    }
  }
  if (buttonState == HIGH && digitalRead(VENTIL_ERROR) == LOW) {
    err_6WVT = 0;
    // Serial.println(F("Error: NO Error"));
  }
}

dafür würde ich auch eine LED von den WS2812 nutzen um das Fehlerbild optisch darstellen zu können.

Leider verkompliziere das ganze so sehr das es unübersichtlich wird und die Lösung nicht den erfolg hat den ich mir vorstelle. Daher frage ich hier um Rat wie ich es am besten umsetzen kann.

Danke für die Mühe die sich der ein oder andere macht der sich den Code anschaut und am überlegen ist.

Gruß Luzi

Ohne den ganzen Code zu sehen ist eine Antwort schwierig.
Aber ein kann man schon sagen: Ersetzte die ganze if Orgie durch eine (ggf. mehrere) Statemaschiene(n) und wahrscheinlich lösen sich alle deine Probleme in Luft auf.

Sie möchten die Status-LEDs ständig aktualisieren, egal ob aus, blinkend oder an. Sie benötigen zwei Timer. Eine zum Halten von "zwei Sekunden" und eine zum Halten der "Blinkrate". In den ersten zwei Sekunden nach dem Aufrufen der Status-LED-Funktion blinken die LEDs. Halten Sie die LEDs länger als zwei Sekunden konstant

unsigned long timer2S, timeout2S = 2000; // two seconds timing
unsigned long timerBlink, timeoutBlink = 250; // blink timing

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
}

void loop() {
  status();
}

void status() {
  if (millis() - timer2S < timeout2S) { // if less than two seconds...
    if (millis() - timerBlink > timeoutBlink) { // ...blink
      timerBlink = millis(); // reset timer
      blink(); // change LED state
    }
  } else { // beyond two seconds...
    digitalWrite(LED_BUILTIN, HIGH); // steady state ON
  }
}

void blink () {
  digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN)); // change LED state
}

nein, falsch vormuliert,

hintergrund ist, Das Ventil hat mehrere Stellungen was es anfahren kann, dazu brauch es aber immer ein signal von min 2 sec dauer damit es die neue pos. anfahren kann. diese 2 sec soll die led blinken und anzeigen das eine neue pos. angefahren wird. danach soll sie dauerhaft an sein. ich habe für jede pos. eine led ist pos1 angewählt soll nur diese led an sein und die andern aus. wird pos2 gewählt soll led 1 ausgehen led2 binken für die 2 sec und dann anbleiben, genauso bei den anderen pos.

Es wäre wirklich Sinnvoll den kompletten Skatch zu senden.
Denn irgendwo stellst Du ja unbeabsichtigt die LED auf Black.
Denn der Zustand bleibt erhalten am WS2812. Du kannst das gerne prüfen indem Du den Pin abziehst, wenn mal alle LED an sind. Ich geh mal davon aus das Du einen Widerstand 100 -300 Ohm in Reihe zu Din hast

Du liegst falsch. Der von mir bereitgestellte Code blinkt genau zwei Sekunden lang und bleibt für den Rest der Zeit konstant. Ihre Aufgabe bestand lediglich darin, herauszufinden, wann die Status-LED-Funktion aufgerufen werden muss.

hier der ganze code. die leds bekommen den neuen status aus der loop
das black habe ich gesetzt. müsste nicht sein


#include <WiFi.h>
#include <time.h>
#include <esp_sntp.h>
#include <FastLED.h>

#pragma GCC diagnostic ignored "-Wmissing-field-initializers"

#include "config.h"

void loop() {
  FastLED.clear ();
  touch_auto();        // Ventilsteuerung vom ESP gesteuert Automatikbetrieb. Positionen werden selstätig angefahren jeh nach Bedingung
  touch_hand();        // Ventil Hanbetrieb wenn keine Komunikation per WiFi oder Canbus möglich (Notbetrieb)
  error();             // Auserten der Auftretenden Fehlerzustände vom Ventil
  collect_data();      // Modbus Daten sammeln und Übertragen
//  modbus_read();     // empfangen der Daten
  printLocalTime();    // it will take some time to sync time :)
  canbus();
  status_led();       // WS2812 Status Anzeige für die einzelnen Pos des Automatikventil + Betrieb, Error, Komunikation

  buttonState = digitalRead(buttonPin);
   vTaskDelay(500);  // 500ms warten
  // LEDs aktualisieren (nur einmal aufrufen)
      FastLED.show();
}

void touch_auto() {
  if (Serial.available() > 0) {
    posAuto = Serial.read();  // Save character received.
    Serial.flush();           // Clear receive buffer.

    switch (posAuto) {
      case 'f':
        if (digitalRead(VENTIL_FILTERN) == LOW) {  // && (TOUCH_ENABLE) == HIGH)  //
          digitalWrite(VENTIL_FILTERN, HIGH);
            Serial.println("Pos. Filtern wird anfahren");
          lastmillis = millis();
        } else {
          if (millis() - lastmillis >= pos_wechsel) {
            digitalWrite(VENTIL_FILTERN, LOW);
          }
        }
        break;
      case 'b':
        if (digitalRead(VENTIL_RUECKSPUELEN) == LOW) {  // && (TOUCH_ENABLE) == HIGH)
          digitalWrite(VENTIL_RUECKSPUELEN, HIGH);
            Serial.println("Pos. Rückspühlen wird anfahren");
          lastmillis = millis();
        } else {
          if (millis() - lastmillis >= pos_wechsel) {
            digitalWrite(VENTIL_RUECKSPUELEN, LOW);
          }
        }
        break;
      case 'k':
        if (digitalRead(VENTIL_KLARSPUELEN) == LOW) {  // && (TOUCH_ENABLE) == HIGH)
          digitalWrite(VENTIL_KLARSPUELEN, HIGH);
            Serial.println("Pos. Klarspühlen wird anfahren");
          lastmillis = millis();
        } else {
          if (millis() - lastmillis >= pos_wechsel) {
            digitalWrite(VENTIL_KLARSPUELEN, LOW);
          }
        }
        break;
      case 'z':
        if (digitalRead(VENTIL_ZIRKULATION) == LOW) {  // && (TOUCH_ENABLE) == HIGH)
          digitalWrite(VENTIL_ZIRKULATION, HIGH);
           Serial.println("Pos. Zirkulieren wird anfahren");
          lastmillis = millis();
        } else {
          if (millis() - lastmillis >= pos_wechsel) {
            digitalWrite(VENTIL_ZIRKULATION, LOW);
          }
        }
        break;
      case 'e':
        if (digitalRead(VENTIL_ENTLEEREN) == LOW) {  // && (TOUCH_ENABLE) == HIGH)
          digitalWrite(VENTIL_ENTLEEREN, HIGH);
          Serial.println("Pos. Entleeren wird anfahren");
          lastmillis = millis();
        } else {
          if (millis() - lastmillis >= pos_wechsel) {
            digitalWrite(VENTIL_ENTLEEREN, LOW);
          }
        }
        break;
      case 'c':
        if (digitalRead(VENTIL_CLOSE) == LOW) {  // && (TOUCH_ENABLE) == HIGH)
          digitalWrite(VENTIL_CLOSE, HIGH);
          Serial.println("Pos. Geshlossen wird anfahren");
          lastmillis = millis();
        } else {
          if (millis() - lastmillis >= pos_wechsel) {
            digitalWrite(VENTIL_CLOSE, LOW);
          }
        }
        break;
      case 'w':
        if (digitalRead(VENTIL_WINTER) == LOW) {  // && (TOUCH_ENABLE) == HIGH)
          digitalWrite(VENTIL_WINTER, HIGH);
          Serial.println("Pos. Winterstellung wird anfahren");
          lastmillis = millis();
        } else {
          if (millis() - lastmillis >= pos_wechsel) {
            digitalWrite(VENTIL_WINTER, LOW);
          }
        }
        break;
      case 'r':
        if (digitalRead(VENTIL_RESET) == LOW) {  // && (TOUCH_ENABLE) == HIGH)
          digitalWrite(VENTIL_RESET, HIGH);
         Serial.println("Pos. Reset ausführen");
          lastmillis = millis();
        } else {
          if (millis() - lastmillis >= reset) {
            digitalWrite(VENTIL_RESET, LOW);
          }
        }
        break;
      case '?':
        break;

      default:
        Serial.print("'");
        Serial.print((char)posAuto);
        Serial.println("' Befehl wurde ausgefürt");
        break;
    }
  }
}

// Ventil Handsteuerung wenn keine WiFi oder CanBus Komunikation besteht.
void touch_hand() {
  // Prüfen und Steuern der Ventile basierend auf GPIO-Eingängen

  // Filtern
  if (digitalRead(TOUCH_FILTERN) == HIGH) {
    digitalWrite(VENTIL_FILTERN, HIGH);
    Serial.println("Pos. Filtern wird anfahren");
    lastmillis = millis();
  } else if (millis() - lastmillis >= pos_wechsel) {
    digitalWrite(VENTIL_FILTERN, LOW);
  }

  // Rückspülen
  if (digitalRead(TOUCH_RUECKSPUELEN) == HIGH) {
    digitalWrite(VENTIL_RUECKSPUELEN, HIGH);
    Serial.println("Pos. Rückspühlen wird anfahren");
    lastmillis = millis();
  } else if (millis() - lastmillis >= pos_wechsel) {
    digitalWrite(VENTIL_RUECKSPUELEN, LOW);
  }

  // Klarspülen
  if (digitalRead(TOUCH_KLARSPUELEN) == HIGH) {
    digitalWrite(VENTIL_KLARSPUELEN, HIGH);
    Serial.println("Pos. Klarspühlen wird anfahren");
    lastmillis = millis();
  } else if (millis() - lastmillis >= pos_wechsel) {
    digitalWrite(VENTIL_KLARSPUELEN, LOW);
  }

  // Zirkulation
  if (digitalRead(TOUCH_ZIRKULATION) == HIGH) {
    digitalWrite(VENTIL_ZIRKULATION, HIGH);
    Serial.println("Pos. Zirkulieren wird anfahren");
    lastmillis = millis();
  } else if (millis() - lastmillis >= pos_wechsel) {
    digitalWrite(VENTIL_ZIRKULATION, LOW);
  }

  // Entleeren
  if (digitalRead(TOUCH_ENTLEEREN) == HIGH) {
    digitalWrite(VENTIL_ENTLEEREN, HIGH);
    Serial.println("Pos. Entleeren wird anfahren");
    lastmillis = millis();
  } else if (millis() - lastmillis >= pos_wechsel) {
    digitalWrite(VENTIL_ENTLEEREN, LOW);
  }

  // Geschlossen
  if (digitalRead(TOUCH_CLOSE) == HIGH) {
    digitalWrite(VENTIL_CLOSE, HIGH);
    Serial.println("Pos. Geschlossen wird anfahren");
    lastmillis = millis();
  } else if (millis() - lastmillis >= pos_wechsel) {
    digitalWrite(VENTIL_CLOSE, LOW);
  }

  // Winter
  if (digitalRead(TOUCH_WINTER) == HIGH) {
    digitalWrite(VENTIL_WINTER, HIGH);
    Serial.println("Pos. Winterstellung wird anfahren");
    lastmillis = millis();
  } else if (millis() - lastmillis >= pos_wechsel) {
    digitalWrite(VENTIL_WINTER, LOW);
  }

  // Reset
  if (digitalRead(TOUCH_RESET) == HIGH) {
    digitalWrite(VENTIL_RESET, HIGH);
    Serial.println("Pos. Reset ausführen");
    lastmillis = millis();
  } else if (millis() - lastmillis >= reset) {
    digitalWrite(VENTIL_RESET, LOW);
  }
}
void status_led() {
  // Status LED (Ventilfreigabe)
  if (digitalRead(VFRG) == HIGH) {       
    leds[3] = CRGB::Green;
  } else {
    leds[3] = CRGB::Red;
  }
  // Status LED (Error)
  if (digitalRead(VENTIL_ERROR) == LOW) {       
    leds[5] = CRGB::Green;
  } else {
    leds[5] = CRGB::Red;
  }

  // Positions - Anzeige
  if (digitalRead(TOUCH_FILTERN) == HIGH) {
    leds[0] = CRGB::Green;
    leds[1] = CRGB::Black;
    leds[2] = CRGB::Black;
    leds[6] = CRGB::Black;
    leds[7] = CRGB::Black;
    leds[8] = CRGB::Black;
    leds[9] = CRGB::Black;
  } else if (digitalRead(TOUCH_RUECKSPUELEN) == HIGH) {
    leds[0] = CRGB::Black;
    leds[1] = CRGB::Black;
    leds[2] = CRGB::Black;
    leds[6] = CRGB::Black;
    leds[7] = CRGB::Black;
    leds[8] = CRGB::Black;
    leds[9] = CRGB::Green;
  } else if (digitalRead(TOUCH_KLARSPUELEN) == HIGH) {
    leds[0] = CRGB::Black;
    leds[1] = CRGB::Black;
    leds[2] = CRGB::Green;
    leds[6] = CRGB::Black;
    leds[7] = CRGB::Black;
    leds[8] = CRGB::Black;
    leds[9] = CRGB::Black;
  }

/*
//------------------------------------ STEP 14
  for (int i = 0; i <= 6; i++) {
    for (int i = 0; i <= 3; i++) {
       for (int i = 10; i >= 0; i--) {
          leds[i] = CRGB::Red; 
          FastLED.show();         
          }
          FastLED.clear ();
       }
    for (int i = 0; i <= 3; i++) {
       for (int i = 0; i <= 10; i++) {
        leds[i] = CRGB::Blue; 
        FastLED.show();  
       }
        FastLED.clear ();
    }
     for (int i = 0; i <= 3; i++) {
       for (int i = 0; i <= 10; i++) {
          leds[i] = CRGB::Red; 
          FastLED.show();  
       }
          FastLED.clear ();
     }
  }
*/
}

void WiFiEvent(WiFiEvent_t event) {
  //  Serial.printf("[WiFi-event] event: %d\n", event);
  switch (event) {
    case ARDUINO_EVENT_WIFI_READY:
      Serial.println("WiFi interface ready");
      break;
    case ARDUINO_EVENT_WIFI_SCAN_DONE:
      Serial.println("Completed scan for access points");
      break;
    case ARDUINO_EVENT_WIFI_STA_START:
      Serial.println("WiFi client started");
      break;
    case ARDUINO_EVENT_WIFI_STA_STOP:
      Serial.println("WiFi clients stopped");
      break;
    case ARDUINO_EVENT_WIFI_STA_CONNECTED:
      digitalWrite(WiFi_ON, LOW);
      digitalWrite(TOUCH_ENABLE, HIGH);
      Serial.println("Connected to access point");
      break;
    case ARDUINO_EVENT_WIFI_STA_DISCONNECTED:
      digitalWrite(WiFi_ON, HIGH);
      digitalWrite(TOUCH_ENABLE, LOW);
      Serial.println("Disconnected from access point");
      break;
    case ARDUINO_EVENT_WIFI_STA_AUTHMODE_CHANGE:
      Serial.println("Authentication mode of access point has changed");
      break;
    case ARDUINO_EVENT_WIFI_STA_GOT_IP:
      Serial.print("Obtained IP address: ");
      Serial.println(WiFi.localIP());
      break;
    case ARDUINO_EVENT_WIFI_STA_LOST_IP:
      Serial.println("Lost IP address and IP address is reset to 0");
      break;
    case ARDUINO_EVENT_WPS_ER_SUCCESS:
      Serial.println("WiFi Protected Setup (WPS): succeeded in enrollee mode");
      break;
    case ARDUINO_EVENT_WPS_ER_FAILED:
      Serial.println("WiFi Protected Setup (WPS): failed in enrollee mode");
      break;
    case ARDUINO_EVENT_WPS_ER_TIMEOUT:
      Serial.println("WiFi Protected Setup (WPS): timeout in enrollee mode");
      break;
    case ARDUINO_EVENT_WPS_ER_PIN:
      Serial.println("WiFi Protected Setup (WPS): pin code in enrollee mode");
      break;
    case ARDUINO_EVENT_WIFI_AP_START:
      Serial.println("WiFi access point started");
      break;
    case ARDUINO_EVENT_WIFI_AP_STOP:
      Serial.println("WiFi access point  stopped");
      break;
    case ARDUINO_EVENT_WIFI_AP_STACONNECTED:
      Serial.println("Client connected");
      break;
    case ARDUINO_EVENT_WIFI_AP_STADISCONNECTED:
      Serial.println("Client disconnected");
      break;
    case ARDUINO_EVENT_WIFI_AP_STAIPASSIGNED:
      Serial.println("Assigned IP address to client");
      break;
    case ARDUINO_EVENT_WIFI_AP_PROBEREQRECVED:
      Serial.println("Received probe request");
      break;
    case ARDUINO_EVENT_WIFI_AP_GOT_IP6:
      Serial.println("AP IPv6 is preferred");
      break;
    case ARDUINO_EVENT_WIFI_STA_GOT_IP6:
      Serial.println("STA IPv6 is preferred");
      break;
    default: break;
  }
}

void printLocalTime() {
  struct tm timeinfo;
  if (!getLocalTime(&timeinfo)) {
    //   Serial.println("No time available (yet)");
    return;
  }
  //  Serial.println(&timeinfo, "%A, %B %d %Y %H:%M:%S");
}

void timeavailable(struct timeval* t) {
  Serial.println("Got time adjustment from NTP!");
  printLocalTime();
}

void WiFiGotIP(WiFiEvent_t event, WiFiEventInfo_t info) {
  //  writeHMICmd("va_ip.txt=\"" + IPAddress(info.got_ip.ip_info.ip.addr).toString() + "\"");
}

// Fehlerauswertung 6 Wege Ventil
void error() {
  if (ventilError)  // Auslöser
  {
    if (!ausgeloest)  // War noch nicht ausgelöst
    {
      errStart = millis();  // Startzeit merken
      ausgeloest = true;    // merker setzen
    }
  } else  // nicht mehr ausgelöst
  {
    if (ausgeloest)  // merker war gesetzt
    {
      switch (millis() - errStart)  // Auswahl, was passiertist
      {
        case 100 ... 1100:
          err_6WVT = 1;
          Serial.println(F("Error: Power failure at the valve"));
          break;
        case 1900 ... 2100:
          err_6WVT = 2;
          Serial.println(F("Error: Position error"));
              leds[4] = CRGB::Red;
          break;
        case 2900 ... 3100:
          err_6WVT = 3;
          Serial.println(F("Error: Power error"));
            leds[4] = CRGB::Red;
          break;
        case 3900 ... 4100:
          err_6WVT = 4;
          Serial.println(F("Error: Power Errorstate"));
            leds[4] = CRGB::Red;
          break;
        case 4900 ... 5100:
          err_6WVT = 5;
            leds[4] = CRGB::Red;
          Serial.println(F("Error: Single Hall Errorstate"));
          break;
        case 5200 ... 6100:
          err_6WVT = 6;
//          error_LED, LOW;
            leds[4] = CRGB::Red;
          Serial.println(F("Error: Hall Errorstate"));
          break;
        default:
          break;
      }
      ausgeloest = false;
    }
  }
  if (buttonState == HIGH && digitalRead(VENTIL_ERROR) == LOW) {
    err_6WVT = 0;
      leds[4] = CRGB::Green;
    // Serial.println(F("Error: NO Error"));
  }
}

// Sammeln der Daten die an den Slave gesendet werden sollen
void collect_data() {
}  // End of collect_data

// lesen der Modbusdaten
void modbus_read() {  // lesen der Modbusdaten (ventilpos)
  }

void IRAM_ATTR timer_isr() {
//  digitalWrite(V_FRG_LED, !digitalRead(V_FRG_LED));
}

void canbus() {
  if (!driver_installed) {
    // Driver not installed
    vTaskDelay(1000);
    return;
  }
  // Check if alert happened
  uint32_t alerts_triggered;
  twai_read_alerts(&alerts_triggered, pdMS_TO_TICKS(POLLING_RATE_MS));
  twai_status_info_t twaistatus;
  twai_get_status_info(&twaistatus);

  // Handle alerts
  if (alerts_triggered & TWAI_ALERT_ERR_PASS) {
    Serial.println("Alert: TWAI controller has become error passive.");
  }
  if (alerts_triggered & TWAI_ALERT_BUS_ERROR) {
    Serial.println("Alert: A (Bit, Stuff, CRC, Form, ACK) error has occurred on the bus.");
    Serial.printf("Bus error count: %lu\n", twaistatus.bus_error_count);
  }
  if (alerts_triggered & TWAI_ALERT_RX_QUEUE_FULL) {
    Serial.println("Alert: The RX queue is full causing a received frame to be lost.");
    Serial.printf("RX buffered: %lu\t", twaistatus.msgs_to_rx);
    Serial.printf("RX missed: %lu\t", twaistatus.rx_missed_count);
    Serial.printf("RX overrun %lu\n", twaistatus.rx_overrun_count);
  }

  // Check if message is received
  if (alerts_triggered & TWAI_ALERT_RX_DATA) {
    // One or more messages received. Handle all.
    twai_message_t message;
    while (twai_receive(&message, 0) == ESP_OK) {
      handle_rx_message(message);
    }
  }
}

uint64_t gpioChTime[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
bool gpioState[8] = { false, false, false, false, false, false, false, false };

void ARDUINO_ISR_ATTR GPIO_CHANGE(void* arg) {
  uint8_t* pin = (uint8_t*)arg;
  String state;
  gpioState[*pin] = digitalRead(*pin);
  if (gpioState[*pin]) {
    gpioChTime[*pin] = millis();
    state = "up";
    Serial.printf("GPIO %i %s\r\n", *pin, state);
  } else {
    state = "down";
    if ((millis() - gpioChTime[*pin]) > 20) {
      Serial.printf("GPIO %i %s time %d \r\n", *pin, state, millis() - gpioChTime[*pin]);
    } else {
      // prell verhalten
    }
  }
}

void setup() {
  Serial.begin(115200);
  // Clear receive buffer.
//  Serial.flush();

// WS2812 LED
 FastLED.addLeds<WS2812, LED_PIN, GRB>(leds, NUM_LEDS);

  WiFi.disconnect(true);  // bestehende verbindungen beenden und speicher löschen
                          //  vTaskDelay(500 / portTICK_PERIOD_MS);  // 500ms warten
  if (!WiFi.config(local_IP, gateway, subnet, primaryDNS, secondaryDNS)) {
    //    Serial.println("STA Failed to configure");
  }
  //  Serial.printf("Connecting to %s ", ssid);

  // Examples of different ways to register wifi events
  WiFi.onEvent(WiFiEvent);
  WiFi.onEvent(WiFiGotIP, WiFiEvent_t::ARDUINO_EVENT_WIFI_STA_GOT_IP);
  WiFiEventId_t eventID = WiFi.onEvent([](WiFiEvent_t event, WiFiEventInfo_t info) {
    //   Serial.print("WiFi lost connection. Reason: ");
    //   Serial.println(info.wifi_sta_disconnected.reason);
  },
                                       WiFiEvent_t::ARDUINO_EVENT_WIFI_STA_DISCONNECTED);
  FastLED.addLeds<WS2812, LED_PIN, GRB>(leds, NUM_LEDS);

  // Verbindung WLAN starten
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    vTaskDelay(1000 / portTICK_PERIOD_MS);  // 1s warten
    Serial.print(".");
  }
  // Serial.printf(" CONNECTED\r\n");
  // Zeit synchronisierung
  sntp_set_time_sync_notification_cb(timeavailable);
  configTime(gmtOffset_sec, daylightOffset_sec, ntpServer1);

  pinMode(buttonPin, INPUT_PULLDOWN);
  attachInterruptArg(buttonPin, GPIO_CHANGE, (void*)&buttonPin, CHANGE);

  pinMode(VENTIL_ERROR, INPUT_PULLDOWN);
  attachInterruptArg(VENTIL_ERROR, GPIO_CHANGE, (void*)&ventilError, CHANGE);

  pinMode(TOUCH_FILTERN, INPUT_PULLDOWN);
  attachInterruptArg(TOUCH_FILTERN, GPIO_CHANGE, (void*)&touchFiltern, CHANGE);

  pinMode(TOUCH_RUECKSPUELEN, INPUT_PULLDOWN);
  attachInterruptArg(TOUCH_RUECKSPUELEN, GPIO_CHANGE, (void*)&touchRueckspuelen, CHANGE);

  pinMode(TOUCH_ENTLEEREN, INPUT_PULLDOWN);
  attachInterruptArg(TOUCH_ENTLEEREN, GPIO_CHANGE, (void*)&touchEntleeren, CHANGE);

  pinMode(TOUCH_KLARSPUELEN, INPUT_PULLDOWN);
  attachInterruptArg(TOUCH_KLARSPUELEN, GPIO_CHANGE, (void*)&touchKlarspuelen, CHANGE);

  pinMode(TOUCH_CLOSE, INPUT_PULLDOWN);
  attachInterruptArg(TOUCH_CLOSE, GPIO_CHANGE, (void*)&touchClose, CHANGE);

  pinMode(TOUCH_ZIRKULATION, INPUT_PULLDOWN);
  attachInterruptArg(TOUCH_ZIRKULATION, GPIO_CHANGE, (void*)&touchZirkulation, CHANGE);

  pinMode(TOUCH_WINTER, INPUT_PULLDOWN);
  attachInterruptArg(TOUCH_WINTER, GPIO_CHANGE, (void*)&touchWinter, CHANGE);

  pinMode(VFRG, INPUT_PULLDOWN);
  attachInterruptArg(VFRG, GPIO_CHANGE, (void*)&touchFiltern, CHANGE);


  pinMode(LED_PIN, OUTPUT);
  pinMode(WiFi_ON, OUTPUT);
  pinMode(TOUCH_ENABLE, OUTPUT);  // Setzt den Digitalpin 5 als Outputpin Touchtasten ON/OFF
  pinMode(VENTIL_FILTERN, OUTPUT);
  pinMode(VENTIL_RUECKSPUELEN, OUTPUT);
  pinMode(VENTIL_ENTLEEREN, OUTPUT);
  pinMode(VENTIL_KLARSPUELEN, OUTPUT);
  pinMode(VENTIL_CLOSE, OUTPUT);
  pinMode(VENTIL_ZIRKULATION, OUTPUT);
  pinMode(VENTIL_WINTER, OUTPUT);
  pinMode(VENTIL_RESET, OUTPUT);

  byte timer_id = 0;
  unsigned int prescaler = 80;
  unsigned int limit = 1000000;  // int is 4 bytes on the ESP32
  timer = timerBegin(timer_id, prescaler, true);
  timerAttachInterrupt(timer, &timer_isr, true);
  timerAlarmWrite(timer, limit, true);
  timerAlarmEnable(timer);

  // Initialize configuration structures using macro initializers
  twai_general_config_t g_config = TWAI_GENERAL_CONFIG_DEFAULT((gpio_num_t)TX_PIN, (gpio_num_t)RX_PIN, TWAI_MODE_LISTEN_ONLY);
  twai_timing_config_t t_config = TWAI_TIMING_CONFIG_500KBITS();  //Look in the api-reference for other speed sets.
  twai_filter_config_t f_config = TWAI_FILTER_CONFIG_ACCEPT_ALL();

  // Install TWAI driver
  if (twai_driver_install(&g_config, &t_config, &f_config) == ESP_OK) {
    Serial.println("Driver installed");
  } else {
    Serial.println("Failed to install driver");
    return;
  }

  // Start TWAI driver
  if (twai_start() == ESP_OK) {
    Serial.println("Driver started");
  } else {
    Serial.println("Failed to start driver");
    return;
  }

  // Reconfigure alerts to detect frame receive, Bus-Off error and RX queue full states
  uint32_t alerts_to_enable = TWAI_ALERT_RX_DATA | TWAI_ALERT_ERR_PASS | TWAI_ALERT_BUS_ERROR | TWAI_ALERT_RX_QUEUE_FULL;
  if (twai_reconfigure_alerts(alerts_to_enable, NULL) == ESP_OK) {
    Serial.println("CAN Alerts reconfigured");
  } else {
    Serial.println("Failed to reconfigure alerts");
    return;
  }

  // TWAI driver is now successfully installed and started
  driver_installed = true;
} // ende Setup

static void handle_rx_message(twai_message_t& message) {
  // Process received message
  if (message.extd) {
    Serial.println("Message is in Extended Format");
  } else {
    Serial.println("Message is in Standard Format");
  }
  Serial.printf("ID: %lx\nByte:", message.identifier);
  if (!(message.rtr)) {
    for (int i = 0; i < message.data_length_code; i++) {
      Serial.printf(" %d = %02x,", i, message.data[i]);
    }
    Serial.println("");
  }
}

und die dazugehöhrende config

#ifndef __config__
#define __config__

// Services
#define WITH_WIFI
#define WITH_HTTP
#define WITH_TIMER  // synchronisierung

#define LED_PIN     48
#define NUM_LEDS    10

CRGB leds[NUM_LEDS];

// Definition Eingangspin Eingabe Interrupts
#define VFRG 3  // led 3 
#define VENTIL_ERROR 4 // led 5
int ventilError = VENTIL_ERROR;
//#define VENTIL_CFG_RESET GPIO_NUM_46  // B0

#define TOUCH_FILTERN 6         // GPIO9   Filtern
#define TOUCH_RUECKSPUELEN 12   // GPIO47  Rückspülen
#define TOUCH_ENTLEEREN 11      // GPIO38  Entleeren
#define TOUCH_KLARSPUELEN 10    // GPIO21  Klarspühlen
#define TOUCH_CLOSE 9           // GPIO18  Geschlossen
#define TOUCH_ZIRKULATION 8     // GPIO17  Zirkulieren
#define TOUCH_WINTER 7          // GPIO10  Winter
#define TOUCH_RESET 17          // GPIO1   Ventil reset auslösen bei Fehlern


// Definition Ausgangspin HIGH
#define VENTIL_FILTERN 18      // A1 Filtern
#define VENTIL_RUECKSPUELEN 24 // A7 Rückspülen
#define VENTIL_ENTLEEREN 23    // A6 Entleeren
#define VENTIL_KLARSPUELEN 22  // A5 Klarspühlen
#define VENTIL_CLOSE 21        // A4 Geschlossen
#define VENTIL_ZIRKULATION 20  // A3 Zirkulieren
#define VENTIL_WINTER 19       // A2 Winter
#define VENTIL_RESET 17        // A0 Ventil reset auslösen bei Fehlern

#define TOUCH_ENABLE 5         // GPIO8  Outputpin Einschalten der Touchtasten wenn keine Komunikation WIFI, CANBus
#define TIMER_PIN 2            // GPIO5  OutputPin für Zeitschaltuhr 24h Timer

IPAddress local_IP(xxx,xxx,xxx,xxx);
IPAddress gateway(xxx,xxx,xxx,xxx);

IPAddress subnet(xxx,xxx,xxx,xxx);
IPAddress primaryDNS(xxx,xxx,xxx,xxx);  // FB DNS
IPAddress secondaryDNS(8, 8, 8, 8);      // Google DNS
IPAddress slaveIp(xxx,xxx,xxx,xxx); // IP-Adresse des Modbus-Slaves
const uint16_t modbusPort = xxx;      // Standardport für Modbus TCP
const uint16_t REGISTER_ADDRESS = 45; // Adresse des Registers im Slave (z.B. 30)

const char *ssid = "***********";
const char *password = "********";

//int inByte = 0;  // incoming serial byte

#include "driver/twai.h"
#define POLLING_RATE_MS 1000

#define RX_PIN 1
#define TX_PIN 0

static bool driver_installed = false;

void modbus_read();
void collect_data();
void error();
void touch_auto();
void touch_hand();
void canbus();
void status_led();
// Interupt Timer
hw_timer_t* timer = NULL;

static unsigned long errStart = millis();  // deinition & initialisierung
static bool ausgeloest = false;            // Merker

//unsigned long startTime = 0;
unsigned long lastmillis = 0;
const unsigned long pos_wechsel = 2000;  // Zeit in ms für Positionswechsel
const unsigned long reset = 10000;        // Zeit in ms für Reset des Automatikventil
const char *ntpServer1 = "xxx,xxx,xxx,xxx";
const long gmtOffset_sec = 0;
const int daylightOffset_sec = 0;
const char *time_zone = "CET-1CEST,M3.5.0,M10.5.0/3";  // TimeZone rule for Europe/Rome including daylight adjustment rules (optional)
const int Zeituhr = 250;                               // Zeitschaltuhr für Pumpenausgang

const int WiFi_ON = 16;  // WLAN Status LED

char posHand = 0;
char posAuto = 0;

int touchFiltern       = TOUCH_FILTERN;
int touchRueckspuelen  = TOUCH_RUECKSPUELEN;
int touchKlarspuelen   = TOUCH_KLARSPUELEN;
int touchZirkulation   = TOUCH_ZIRKULATION;
int touchEntleeren     = TOUCH_ENTLEEREN;
int touchClose         = TOUCH_CLOSE;
int touchWinter        = TOUCH_WINTER;
int touchReset         = TOUCH_RESET;

int Reset = 0;      // Reset Automatikventil
int V_Status = 0;   // Ventilstatus Position Ventil
int buttonPin = 3;  // Ventilfreigabe
int buttonState = 0;
int Z_old;

int err_6WVT = 0;  // vorbesetzen der Fehlervariable mit "kein Fehler"

#endif

ich habe noch ein Foto hinzugefügt damit man sehen kann was ich meine


Das ist das erste was mir ins Auge springt.
Wenn Du in der Loop die LED löscht wie soll dann der Status bleiben?
Für den Rest haben wir ja Leute die sich bestens mit dem ESP32 auskennen. Dazu gehöre ich nicht.

Deine LOOP
void loop() {

  FastLED.clear ();
  touch_auto();        // Ventilsteuerung vom ESP gesteuert Automatikbetrieb. Positionen werden selstätig angefahren jeh nach Bedingung
  touch_hand();        // Ventil Hanbetrieb wenn keine Komunikation per WiFi oder Canbus möglich (Notbetrieb)
  error();             // Auserten der Auftretenden Fehlerzustände vom Ventil
  collect_data();      // Modbus Daten sammeln und Übertragen
//  modbus_read();     // empfangen der Daten
  printLocalTime();    // it will take some time to sync time :)
  canbus();
  status_led();       // WS2812 Status Anzeige für die einzelnen Pos des Automatikventil + Betrieb, Error, Komunikation

  buttonState = digitalRead(buttonPin);
   vTaskDelay(500);  // 500ms warten
  // LEDs aktualisieren (nur einmal aufrufen)
      FastLED.show();
}
sieht doch auch so aus
void loop() {
  FastLED.show();
  FastLED.clear ();
  touch_auto();        // Ventilsteuerung vom ESP gesteuert Automatikbetrieb. Positionen werden selstätig angefahren jeh nach Bedingung
  touch_hand();        // Ventil Hanbetrieb wenn keine Komunikation per WiFi oder Canbus möglich (Notbetrieb)
  error();             // Auserten der Auftretenden Fehlerzustände vom Ventil
  collect_data();      // Modbus Daten sammeln und Übertragen
//  modbus_read();     // empfangen der Daten
  printLocalTime();    // it will take some time to sync time :)
  canbus();
  status_led();       // WS2812 Status Anzeige für die einzelnen Pos des Automatikventil + Betrieb, Error, Komunikation

  buttonState = digitalRead(buttonPin);
   vTaskDelay(500);  // 500ms warten
  // LEDs aktualisieren (nur einmal aufrufen)    
}

ich habe es gesehen, wurde entfernt das clear, nunn bleibt der status erhalten, die led zeigen den jeweilgen status nun an, aber wie bekomme ich das so noch gestaltet das sie erst blinken bevor die einzelnen leds dauerhaft leuchten? kann man das nicht auch in eine case anweisung oder so verpacken.

Man kann!

  uint32_t jetzt = millis();
  switch (schritt) {
    case 0:
      if (digitalRead(TOUCH_A)) {
        vorhin = jetzt;
        schritt++;
      }
      break;
    case 1:
      if (jetzt - blink >= BLINKINTERVALL) {
        if (leds[3]) {
          leds[3] = CRGB::Black;
        } else {
          leds[3] = CRGB::Yellow;
        }
        blink=jetzt;
        if (jetzt - vorhin >= AKTIVINTERVALL) {
          leds[3] = CRGB::Green;
          schritt++;
        }
        break;
      case 2:
        if (digitalRead(TOUCH_R)) {
          leds[3] = CRGB::Black;
          schritt = 0;
        }
        break;
      }
  }
1 Like

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