ESP32 Google Script - Unterschiedliches WLan

Hallo zusammen,

ich habe ein schwer nachvollziehbares Verhalten beim WiFiClientSecure.
Und zwar nutze ich einen ESP32 an einem eInk-Display.
Dieser verbindet sich mit dem WLan und bezieht einen einfachen Text von einem Projekt auf https://script.google.com

Die Herausforderung hier ist, dass die erste Anfrage auf einen 302 "Moved Temporarily" stößt.
Im Header steht dann
Location: https://script.googleusercontent.com/macros/echo?user_content_key=SeCrEtUnIqUeKeY
welches dann der Pfad für die Redirection ist.

Folge ich diesem Link, so erhalte ich sauber meinen Rückgabetext vom Script. Zumindest in einem WLAN.
Im anderen WLAN ist es eine Chance von ~1/20 dass der zweite Response irgendetwas enthält. Weder Header, noch Body. Lediglich ein paar Zeilenumbrüche.

Jetzt würde man meinen, es liegt am Router?! Leider beides die identischen Standardgeräte vom pinken T. Es gibt keinen Eintrag in dessen Firewall o.ä.
Nutze ich den Postman am Laptop zum Ausführen des Get´s, so erhalte ich immer den korrekten Response.
Im Script selbst kann ich die eingehende Anfrage ebenfalls erkennen.

Was kann das also sein? Läuft der WiFiClient über? Timeout, wegen einer langsameren (oder gar zu schnellen) Verbindung?

Der Code ist wahrlich kein Meisterwerk..

String GetGoogleScriptResult() {
  WiFiClientSecure client;
  String movedURL;
  String line;

  if (!client.connect(HOST, HTTPS_PORT)) 
    return "";

  SendGet(client, "https://" + String(HOST) + "/macros/s/" + ScriptId + "/exec" + SecretParam);

  ReadHeader(client, movedURL);

  movedURL.trim();
  if (movedURL.length() > 10) {
    Serial.println("Forewarding URL: \"" + movedURL + "\"");
    client.stop();
    // https:// = 8 chars
    String newHost = movedURL.substring(8);
    newHost.remove(newHost.indexOf('/'));
    char newHostChars[newHost.length() + 1];
    newHost.toCharArray(newHostChars, sizeof(newHostChars));
        
    if (client.connect(newHostChars, HTTPS_PORT))
      SendGet(client, movedURL);
    else 
      Serial.println("Redirect failed!");

    //Read Header again:
    ReadHeader(client, movedURL);
  }


  while (client.connected()) {
    if (client.available()) {
      line += client.readStringUntil('\r');
    }
  }
  client.stop();
  return line;
}

void SendGet(WiFiClientSecure &client, String adress) {
  client.println("GET " + adress);
  client.println("Host: " + String(HOST));
  //client.println("Connection: close");
  client.println("Connection: keep-alive");
  client.println("Content-Type: text/plain");
  client.println("Pragma: no-cache");
  client.println("Cache-Control: no-cache");
  client.println("User-Agent: ESP32");
  client.println("Accept: application/json");
  client.println();
}

void ReadHeader(WiFiClientSecure &client, String &movedURL) {
  String line;
  Serial.println("Header:");
  while (client.connected()) {
    line = client.readStringUntil('\n');
    Serial.println(line);
    if (line == "\r")
      break;
    if (line.indexOf("Location") >= 0) {  // Rerouting
      movedURL = line.substring(line.indexOf(":") + 2 ) ;
    }
  }
}

Denke, trotz des "historisch gewachsenem" Code, kann man die Idee erkennen.
Es wird immer der Header ausgelesen, bis ein einzelner Zeilenumbruch erscheint (welcher Header von Body trennt).
Ist ein "Location" enthalten, wird die Anfrage nochmal an diese Adresse gesendet und wieder bis zum Body ausgelesen.

Irgendwelche Ideen, wie ich dem Ganzen weiter auf den Grund gehen könnte?

Ein unzufriedenstellendes Teilupdate:
Setze ich den WiFiClientSecure auf
client.setTimeout(10);
Erhöhe ich die Wahrscheinlichkeit, dass es klappt auf 1 von 3 Versuchen.
Die Durchführungsdauer schaut so aus:

Müsste also mit der Anfrage, Handshake, etc, eigentlich mit 5 Sekunden locker auskommen.
Was noch verwundert, ist dass dort zwei Ausführungen noch auf "Wird ausgeführt" stehen.
Denke das waren die Fälle, wo schon das erste Get() ins leere gelaufen ist.

Wenn ich keine Daten erhalte, führt

while (client.connected()) {    
    line = client.readStringUntil('\n');
    Serial.println(line);
}

zu exakt 4 CarriageReturn+Linefeeds, welche vom println stammen.
Die dauern so im Schnitt 3 Sekunden in Summe. Entsprechend scheint der Timeout nicht bis zum bitteren Ende zu warten.
Irgendwo dort liegt wohl der Hase im Pfeffer!

Nun >20 mal getestet und dann ging gar nix mehr. Alles nochmal vom Strom genommen und es geht wieder nur bis zum Redirect :face_with_symbols_over_mouth:
Irgendwas verschluckt meine Daten!

Vielleicht mal die Funktion readStringUntil('\n'); durch eine eigene Routine ersetzen; damit habe ich bisher gute Erfahrungen gemacht:

String ClientReadline() {
  String mycmd = "";
  char c = char(0);
  do {
    if (client.available() > 0) { // read the incoming command
      c = client.read();
      if (c != char(13)) {
        mycmd = mycmd + c;
      }
    }
  } while (c != char(13));
  return mycmd;
}

So vermeidet man Abhängigkeiten vom TimeOut in readStringUntil().

Wenn das nicht genügt, weil durch irgendwelche Verzögerungen das Endezeichen erst in einem deutlich späteren Paket übermittelt wird, kann man eine solche Funktion auch in der loop() regelmäßig aufrufen und den Rückgabewert erst dann an die weitere Auswertung übergeben, wenn das Endezeichen gekommen ist (Achtung: Das Folgende ist mehr oder weniger "Pseudocode", um das Prinzip zu zeigen) :

String mycmd = "";

void Evaluate(String aCmd){
   // Hier bearbeiten
  }


void ClientReadline() {
    while (client.available() > 0) { // read the incoming command
      c = client.read();
      if (c != char(13)) {  mycmd = mycmd + c; } 
                    else {  Evaluate(mycmd); mycmd = "";}
    }
}

void loop(){
  
  ...
  ClientReadLine();
  ...
  }

P.S.: Wenn das Endezeichen variiert (\r oder \n) wäre das noch zu berücksichtigen ..

1 Like

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