ESP8266 WebServer Problem

Hallo zusammen,

ich arbeite gerade an einem kleinen Projekt mit einem Wemos D1 Mini.
Ich will über GET Requests ein paar Relais schalten. Diese müssen zwingend zeitverzögert geschaltet werden, und genau da beginnt das Problem. Sobald ich ein delay verwende, funktioniert der Webserver nicht mehr. Ich habe mich jetzt durch gefühlt 10 verschiedene Beispiel-Sketche gelesen und jeder dieser Sketche sieht komplett anders aus. Ich weiß nicht mehr, was nun mittlerweile der richtige Ansatz ist und was ich falsch mache ich blick überhaupt nicht mehr durch.

Hier mein Code:

#define FASTLED_ALLOW_INTERRUPTS 0

#include <ESP8266WiFi.h>
#include <ESPAsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include <FastLED.h>

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

IPAddress local_IP (192, 168, 2, 150);
IPAddress gateway (192, 168, 2, 1);
IPAddress subnet (255, 255, 255, 0);

AsyncWebServer server(80);

CRGB leds[2];

void setup() {
  pinMode(D2, OUTPUT);
  pinMode(D5, OUTPUT);
  pinMode(D6, OUTPUT);
  pinMode(D7, OUTPUT);

  digitalWrite(D2, HIGH);
  digitalWrite(D5, HIGH);
  digitalWrite(D6, HIGH);
  digitalWrite(D7, HIGH);

  FastLED.addLeds<WS2812, D1, GRB>(leds, 2);
  FastLED.setBrightness(255);

  WiFi.mode(WIFI_STA);  
  WiFi.setSleepMode(WIFI_NONE_SLEEP);
  WiFi.setAutoReconnect(true);
  WiFi.persistent(true);
  WiFi.config(local_IP, gateway, subnet);
  WiFi.begin(ssid, password);

  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send(200, "text/plain", "I am root");
  });

  server.on("/A", HTTP_GET, [] (AsyncWebServerRequest *request) {
    mode_A();
    request->send(200, "text/plain", "OK");
  });

  server.on("/B", HTTP_GET, [] (AsyncWebServerRequest *request) {
    mode_B();
    request->send(200, "text/plain", "OK");
  });
  
  server.begin();

  blank();
  
  leds[0] = CRGB::Blue;
  leds[1] = CRGB::Blue;
  FastLED.show();
  delay(1000);

  blank();
}

void loop() {
  delay(1);
}

void blank() {
  leds[0] = CRGB::Black;
  leds[1] = CRGB::Black;
  FastLED.show();
}

void mode_A() {
  digitalWrite(D2, HIGH);
  digitalWrite(D5, HIGH);
  digitalWrite(D6, HIGH);
  digitalWrite(D7, HIGH);
  delay(500);
  digitalWrite(D2, LOW);
  delay(100);
  digitalWrite(D5, LOW);
  delay(100);
  digitalWrite(D6, LOW);
  delay(100);
  digitalWrite(D7, LOW);

  blank();
  leds[0] = CRGB::Blue;
  leds[1] = CRGB::Black;
  FastLED.show();
}

void mode_B() {
  digitalWrite(D2, HIGH);
  digitalWrite(D5, HIGH);
  digitalWrite(D6, HIGH);
  digitalWrite(D7, HIGH);
  delay(500);
  digitalWrite(D6, LOW);
  delay(100);
  digitalWrite(D7, LOW);

  blank();
  leds[0] = CRGB::Black;
  leds[1] = CRGB::Blue;
  FastLED.show();
}

Sobald ich die delay's rausnehme, funktioniert alles reibungslos.

wie genau?
eine Verzögerung beim Einschalten? bzw. meinst du diese sequenz mit mehreren Relais?

Du brauchst eine Verzögerung die mit millis() funktioniert.
Ein Beispiel dafür findest du in den Beispielen der IDE mit BlinkWithoutDelay.

Genau so wie in meinem Code mit den entsprechenden delays. Lässt sich nicht verkürzen leider. Ohne delays läuft alles. mit delays hängt sich der webserver anscheinend auf. Keine Rückmeldung mehr und geschaltet wird auch nix mehr.

Hm ich hab wirklich ne Weile gesucht jetzt und keinerlei Beispiele gefunden. Hättest du nen Ansatz für mich? Soll ich das im main loop machen? oder in den jeweiligen server.on Deklarationen?

hm weis noch nicht,

einfach zwei separate FSM, die den Ablauf ansteuern.

Die Frage ist, was soll passieren, wenn mode_A noch läuft und mode_B aktiviert werden würde?

und ist es absicht, dass da zwei Ausgänge in mode_B nicht mehr zurückgesetzt werden?

Beides. Millis() müssen in der loop() abgefragt werden. Das Ergebnis muss dann die Webseite bzw. deine Relais beeinflussen.

werden sie doch. HIGH ist aus in diesem Fall.
Es kann immer nur ein get request gesendet werden von daher kein Problem.

Und wie mache ich das dann mit einer zeitlichen Abfolge am besten? Ich habe ja mehrere delays in der Schaltsequenz.

doch, wenn man das nicht blockierend umbaut, dann wird das zum Problem. Daher frage ich was passieren soll...

Du brauchst für jede Schaltsequenz einen eigenen Zähler der beim Einschalten die Zeit speichert und wenn die Zeit abgelaufen ist, das entsprechende Relais tatsächlich schaltet.

es wird zeitverzögert in 1 Stunden Abständen abwechselnd ein get request mit A und B gesendet von einem Computer. Da kommt sich nichts in die Queere.

Habs nicht getestet, aber das sind mal die ersten 51% für modus_A

// https://forum.arduino.cc/t/esp8266-webserver-problem/1307675/11

#define FASTLED_ALLOW_INTERRUPTS 0

#include <ESP8266WiFi.h>
#include <ESPAsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include <FastLED.h>

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

IPAddress local_IP (192, 168, 2, 150);
IPAddress gateway (192, 168, 2, 1);
IPAddress subnet (255, 255, 255, 0);

AsyncWebServer server(80);

CRGB leds[2];


uint8_t status = 0;           // wo befindet sich die FSM gerade
uint32_t previousMillis = 0;  // letzter Zeitstempel
uint32_t interval = 0;        // aktueller Intervall

void setup() {
  Serial.begin(115200),
  pinMode(D2, OUTPUT);
  pinMode(D5, OUTPUT);
  pinMode(D6, OUTPUT);
  pinMode(D7, OUTPUT);

  digitalWrite(D2, HIGH);
  digitalWrite(D5, HIGH);
  digitalWrite(D6, HIGH);
  digitalWrite(D7, HIGH);

  FastLED.addLeds<WS2812, D1, GRB>(leds, 2);
  FastLED.setBrightness(255);

  WiFi.mode(WIFI_STA);
  WiFi.setSleepMode(WIFI_NONE_SLEEP);
  WiFi.setAutoReconnect(true);
  WiFi.persistent(true);
  WiFi.config(local_IP, gateway, subnet);
  WiFi.begin(ssid, password);

  server.on("/", HTTP_GET, [](AsyncWebServerRequest * request) {
    request->send(200, "text/plain", "I am root");
  });

  server.on("/A", HTTP_GET, [] (AsyncWebServerRequest * request) {
    mode_A();
    request->send(200, "text/plain", "OK");
  });

  server.on("/B", HTTP_GET, [] (AsyncWebServerRequest * request) {
    mode_B();
    request->send(200, "text/plain", "OK");
  });

  server.begin();

  blank();

  leds[0] = CRGB::Blue;
  leds[1] = CRGB::Blue;
  FastLED.show();
  delay(1000);

  blank();
}

void loop() {
  delay(1);
  runFSM();
}

void blank() {
  leds[0] = CRGB::Black;
  leds[1] = CRGB::Black;
  FastLED.show();
}


void mode_A() {
  if (status == 0)
    status = 1;
  else
    Serial.println("momentan nicht zulässig");

}

void runFSM() {
  switch (status) {
    case  1:
      previousMillis = millis(); // Timer aufziehen
      digitalWrite(D2, HIGH);
      digitalWrite(D5, HIGH);
      digitalWrite(D6, HIGH);
      digitalWrite(D7, HIGH);
      interval = 500;
      status++;  // weiterschalten in den nächsten Status
      break;
    case 2:
      if (millis() - previousMillis > interval) {
        previousMillis = millis(); // Timer aufziehen
        digitalWrite(D2, LOW);
        interval = 100;
        status++;

      }
      break;
    case 3:
      if (millis() - previousMillis > interval) {
        previousMillis = millis(); // Timer aufziehen
        digitalWrite(D5, LOW);
        interval = 100;
        status++;
      }
      break;
    case 4:
      if (millis() - previousMillis > interval) {
        previousMillis = millis(); // Timer aufziehen
        digitalWrite(D6, LOW);
        interval = 100;
        status++;
      }
      break;
    case 5:
      if (millis() - previousMillis > interval) {
        digitalWrite(D7, LOW);
        blank();
        leds[0] = CRGB::Blue;
        leds[1] = CRGB::Black;
        FastLED.show();
        status = 0;  // zurück in IDLE
      }
      break;
  }
}

void mode_B() {
  // fehlt noch
}


void mode_B_Alt_zum_spaeteren_umbauen() {
  digitalWrite(D2, HIGH);
  digitalWrite(D5, HIGH);
  digitalWrite(D6, HIGH);
  digitalWrite(D7, HIGH);
  delay(500);
  digitalWrite(D6, LOW);
  delay(100);
  digitalWrite(D7, LOW);

  blank();
  leds[0] = CRGB::Black;
  leds[1] = CRGB::Blue;
  FastLED.show();
}
//

schau dir das mal an und versuche das nachzuvollziehen.
Eventuell funktioniert es auch (kompilieren tut es).
Oder ich hab irgendwas vergessen.

Wenns klick gemacht hat, wäre mein Tipp, einfach cases 10 bis 12 für modeB zu verwenden ... start ist dann halt case 10 und am Ende von 12 springst du wieder in Status 0.

Geht sicher schöner, aber das geht halt auf die Schnelle.

1 Like

Puh. Hat ne Weile gebraucht. Nicht meine Stärke das Programmieren.. Aber hab das Prinzip verstanden, auch wenn meine Kopfhaut 90°C hat. Danke dir :slight_smile: