Forum: Mikrocontroller und Digitale Elektronik ESP32 HTTP Client: Fehlercode -1 nach einiger Zeit?


von Thorsten M. (cortex_user)


Lesenswert?

Hallo,

mit dem Seeeduino XIAO ESP32 fiel es mir das este Mal auf, dass die GET 
Abfrage von openwaether.org nur die erste kurze Zeit funktioniert und 
danach nur noch der Fehlercode -1 zurückliefert, was einfach heisst dass 
die Seite nicht gefunden wurde. Ich zieh mir da einen JSON String 
runter.

url = openwaether.api./data/....
HTTPClient http;

int result = http.get(url)

ergibt result = -1

Häh? Normalerweise funktioniert etwas nicht einmal und dann nie wieder 
zudem es auf einem normalen ESP32 WROOM einwandfrei spielt. Ich verwende 
aber String in der Funktion als Container für die Payload der Seite. 
Openweather erlaubt 1000 Aufrufe pro Monat und 60/Minute. Danach 
ersheint ein leerer Datensatz.

Testweise habe ich mal google.de aufgerufen, was Fehler 301 
zurückliefert, weil google kein http unterstützt.

Ich benutze wificlient.h und HTTPClient als Libs für die Arduino IDE.

Gruss, Thorsten

: Bearbeitet durch User
von Helmut -. (dc3yc)


Lesenswert?

Thorsten M. schrieb:
> url = openwaether.api./data/....

Und mit dieser URL soll das funktionieren? Glaub ich nicht...

von Obelix X. (obelix)


Lesenswert?

Am PC mit dem Browser wird "openwaether.org" auch nicht gefunden.

von Εrnst B. (ernst)


Lesenswert?

Zeig mal mehr code. Dein Schnipsel ist nicht korrekt, und passt nicht 
zur aktuellen Version vom ESP32-HTTP-Client:

https://github.com/espressif/arduino-esp32/blob/master/libraries/HTTPClient/src/HTTPClient.h#L211

Auch das aussenherum ist wichtig:
Z.B. erzeugst du jedesmal einen neuen HTTP-Client, mit Keep-Alive oder 
ohne, räumst du nach dem Request auch wieder auf? Wie stellst du das 
Timing mit "60 Requests pro Minute" sicher? Wie schnell ändert sich das 
Wetter bei dir, dass du eine so hohe Polling-Frequenz brauchst?

von Thorsten M. (cortex_user)


Lesenswert?

Εrnst B. schrieb:
> Z.B. erzeugst du jedesmal einen neuen HTTP-Client, mit Keep-Alive oder
> ohne, räumst du nach dem Request auch wieder auf? Wie stellst du das
> Timing mit "60 Requests pro Minute" sicher? Wie schnell ändert sich das
> Wetter bei dir, dass du eine so hohe Polling-Frequenz brauchst?

Dass ich die richtige url benutzte sollte klar sein. Code heute abend, 
bin auf Arbeit in der Pause. Nur was ich im Kopf hatte. Und es geht nur 
um den Fehlercode, die URL ist wumpe dabei.

: Bearbeitet durch User
von Εrnst B. (ernst)


Lesenswert?

Thorsten M. schrieb:
> Und es geht nur
> um den Fehlercode,

der ist "Connection Refused". z.B. Wlan offline, Firewall sperrt den 
Zugriff, aber auch: Keine freien TCP-Sockets am ESP mehr verfügbar, weil 
alle in irgendwelchen verlorenen Keep-Alive HTTP-Clients hängen.

Bei zuvielen Zugriffen auf den Service würde der eher mit HTTP Error 
"509 Bandwidth exceeded" oder so antworten.

: Bearbeitet durch User
von Thorsten M. (cortex_user)


Angehängte Dateien:

Lesenswert?

Hier ist mal ein Teil des Codes. Lief den ganzen Tag 1x die Stunde, nach 
3-4 Aufrufen Fehlercode -1 . Aktuell läuft er an einer http Testseite, 
die für ssolche Zwecke besteht wo nur Text drauf ist einwandfrei 
durch... komisch. -1 heisst dass die url nicht erreicht wurde aber im 
Browser kriege ich einwandfrei den json container angezeigt, egal wie 
oft ich F5 drücke.

Spielt einwandfrei:
http://www.testingmcafeesites.com/index.html

Spielt nicht oder nur wenige Male
http://api.openweathermap.org/data/2.5/forecast?q=Kassel,DE&APPID=<XXXXXXXXXXXXXXXXX>&mode=json&units=metric&cnt=1
1
static JsonDocument doc;
2
static HTTPClient http;
3
static String payload;
4
5
/* Anfragen an Server richten */
6
int RequestWeather() {
7
8
  String url = openweather;
9
10
  /* Starte die Anfrage und hole die payload ab */
11
  http.begin(url);
12
  debugln("GET Anfrage ...");
13
  int httpCode = http.GET();
14
  debug("HTTP Fehlercode:");
15
  debugln(httpCode);
16
17
  if (httpCode > 0) {
18
    if (httpCode == HTTP_CODE_OK) {
19
      payload = http.getString();
20
      debugln(F("HTTP Weather Request successful."));
21
22
      // Versuche das JSON-Dokument zu analysieren
23
      DeserializationError jsonError = deserializeJson(doc, payload);
24
      if (jsonError) {
25
        debug(F("JSON Weather parsing error!"));

: Bearbeitet durch User
von Εrnst B. (ernst)


Lesenswert?

Bei dir im Screenshot schaut's doch auch so aus, als würden alle 
Requests beantwortet ("HTTP 200 OK"), nur das Json-Parsing schlägt fehl.

Bau mal im
if (jsonError) {
eine Ausgabe von "payload" mit ein, damit du schauen kannst ob das 
gültiges Json ist.

Falls ja: Hat dein JsonDocument genug Speicher?

Hat dein ESP genug freien Speicher für String und JsonDocument 
gleichzeitig?

von Thorsten M. (cortex_user)


Lesenswert?

Εrnst B. schrieb:
> f (jsonError) {
> eine Ausgabe von "payload" mit ein, damit du schauen kannst ob das
> gültiges Json ist.

Auf der Testseite steht nur Testzeugs, da parsed json natürlich nicht. 
Hauptsache die Seite lädt. Lese aber grad auf openwaethermap, dass sie 
die api 2.5 diesen Monat abschalten und ein neues Bezahlmodell 
einführen. Kann sein, dass die die Anfragen einfach begrenzen. Jetzt 
gibt es Wetter nur noch gegen Geld.

von Rolf (rolf22)


Lesenswert?

Wenn man immer wieder 'http.begin' aufruft, ohne vorher mit 'http.end()' 
aufzuräumen, dann sind vermutlich irgendwann irgendwelche Ressourcen 
erschöpft.

von Thorsten M. (cortex_user)


Lesenswert?

Rolf schrieb:
> Wenn man immer wieder 'http.begin' aufruft, ohne vorher mit 'http.end()'
> aufzuräumen, dann sind vermutlich irgendwann irgendwelche Ressourcen
> erschöpft.

Das ist schon alles ok so. Es tritt nach endlosem Testen nur aufd wenn 
ich langsamer als 1 Mal die Minute abtaste. So verrückt das klingt. Alle 
5 Minuten und dann ist die zweite Abtastung nach Reset schon ein Fehler. 
Auch die NTP Zeit Abfrage schlägt dann fehl um die interne Uhr zu 
synchronisieren weil Ticker.h Timer nicht sonderlich genau sind. Reichen 
würde 1x die Stunde. Und ich vermute fast dass dieser Seeeduino Xiao ne 
Macke hat in seinen Eingeweidden, denn das ist noch nie passiert vorher. 
Ich teste das mal mit nem normalen Esp32 Board am WE. Gibt aber auch 
noch andere Libraries und Möglichkeiten als die verwendete.
1
/* Anfragen an Server richten */
2
int RequestWeather() {
3
4
  JsonDocument doc;
5
  HTTPClient http;
6
  String payload;
7
8
  String url = openweather;
9
10
  debugln("GET Anfrage Openweathermap...");
11
  http.begin(url);
12
  int httpCode = http.GET();
13
  debug("HTTP Fehlercode:");
14
  debugln(httpCode);
15
16
  if (httpCode > 0) {
17
    if (httpCode == HTTP_CODE_OK) {
18
      payload = http.getString();
19
      debugln(F("HTTP Weather Request successful."));
20
21
      // Versuche das JSON-Dokument zu analysieren
22
      DeserializationError jsonError = deserializeJson(doc, payload);
23
      if (jsonError) {
24
        debug(F("JSON Weather parsing error!"));
25
        http.end();
26
        return 0;
27
      } else {
28
        // Drucke den analysierten JSON-Inhalt in Buffer
29
        //serializeJsonPretty(doc, Serial);
30
      }
31
32
      /* Daten auslesen in Variablen */
33
      JsonObject item = doc.as<JsonObject>(); /* Erzeuge ein Json Wurzel Object */
34
      item = doc["list"][0];                  /* zeige auf Array der Liste Index = 0 */
35
      Temperatur = (float)item["main"]["temp"];
36
      Windspeed = 3.6 * (float)item["wind"]["speed"];
37
      WetterID = (int)item["weather"][0]["id"];
38
      Wettertext = String(item["weather"][0]["description"]);
39
      Druck = (int)item["main"]["pressure"];
40
      Wolkendichte = (int)item["clouds"]["all"];
41
      Feuchte = (int)item["main"]["humidity"];
42
      Windstaerke = GetWindstaerke(Windspeed);
43
    }
44
  } else {
45
    debugln(F("HTTP Weather Request failed!"));
46
    http.end();
47
    return 0;
48
  }
49
50
  http.end();
51
  return 1;
52
}

: Bearbeitet durch User
von Monk (roehrmond)


Lesenswert?

Zeige mal detailliert, wie du die Stromversorgung gemacht hast. 
Schaltplan, Fotos samt Netzteil und Leitungen. Ich will auch die 
Platzierung der Pufferkondensatoren sehen.

Weil: Dort liegt fast immer die Problemursache bei "seltsamen" 
Instabilitäten nach längerer zeit.

von Thorsten M. (cortex_user)


Lesenswert?

Aehm... Usb Stecker rein und fertig. Seeeduino Ciao eben. 20ma Display 
dran und 3 Leds Schaltplan im Kopf, verdraten und fertig am I2C Bus

von Εrnst B. (ernst)


Lesenswert?

Thorsten M. schrieb:
> Auch die NTP Zeit Abfrage schlägt dann fehl um die interne Uhr zu
> synchronisieren weil Ticker.h Timer nicht sonderlich genau sind.

Solche Details wären halt am Anfang hilfreich.
d.H. es liegt nicht am HTTPClient, es liegt nicht am Json-Parser. 
Vermutlich ist der ESP aus dem WLan geflogen...

Verwendest du Sleep-Modi? Lange Schleifen ohne delay() und yield()?

Ansonsten: Zielgerichtet den Fehler suchen. z.B. Ausgabe von 
"WiFi.isConnected()", "WiFi.localIP()" usw. im Fehlerfall.
Vom PC einen Ping auf den ESP durchlaufenlassen. Bricht der ab, wenn die 
Fehler auftreten?

Thorsten M. schrieb:
> Ich teste das mal mit nem normalen Esp32 Board am WE

Gerade beim Problem mit langen Schleifen kann das helfen das Problem zu 
verschleiern, Single-Core vs. Dual-Core.

: Bearbeitet durch User
von Thorsten M. (cortex_user)


Lesenswert?

Dafuer hab3 ich wifi Events, die allerdings nicht getriggert haben. Ich 
reduziere alles die Tage auf diese eine Routin3 und schaue weiter

Via Handy
Thorsten

von Monk (roehrmond)


Lesenswert?

Thorsten M. schrieb:
> Aehm... Usb Stecker rein und fertig

Das USB Kabel kann schon der Knackpunkt sein. Oder das Netzteil regelt 
schwankende Stromaufnahme nicht schnell genug aus.

Thorsten M. schrieb:
> Seeeduino Ciao eben

Das scheint es nicht zu geben. Wo sind die technischen Unterlagen zu dem 
Modul, insbesondere der Schaltplan? Es gab schon öfter mangelhafte 
gestaltete Module.

Wenn es dieses ist:
https://files.seeedstudio.com/wiki/XIAO_WiFi/Resources/Seeeduino-XIAO-ESP32C3-SCH.pdf

Dann hat es zu wenig Pufferkapazität. Hänge an 3,3V und GND einen 100µF 
Elko. Das hat schon vielen geholfen.

: Bearbeitet durch User
von Thorsten M. (cortex_user)


Lesenswert?

Monk schrieb:
> Dann hat es zu wenig Pufferkapazität. Hänge an 3,3V und GND einen 100µF
> Elko. Das hat schon vielen geholfen.

Das werde ich am WE machen in meiner Werkstatt. Übrigens läuft alles 
auch, wenn man den Code komplett zusammen streicht und nur die Client 
Routine stehen lässt. Alle Timer raus usw. Da scheint irgendwas 
strubblig zu werden. Also ertst puffern, dann Code Stück für Stück 
wieder dazu geben und schauen ob es nach jedem Schritt noch läuft. 
Mancher Code ist ja auch fehlerhaft aus den Libraries.

Tja, die Wunder der Technik... immer wieder ein Vergnügen :-)

von Thorsten M. (cortex_user)


Lesenswert?

Kurze Info: Der 100uF Elko an 3.3V out vom Modul hat das Problem 
vollständig behoben!

: Bearbeitet durch User
von Monk (roehrmond)


Lesenswert?

Thorsten M. schrieb:
> Der 100uF Elko an 3.3V out vom Modul hat das Problem
> vollständig behoben!

Siehst du, man kann den Tipp gar nicht oft genug wiederholen.

: Bearbeitet durch User
von Jens K. (jensky)


Lesenswert?


von Thorsten M. (cortex_user)


Angehängte Dateien:

Lesenswert?

:-))))

von Monk (roehrmond)


Lesenswert?

Mache das Display mal dunkler, wenn es länger als 1 Jahr halten soll. 
Oder ergänze den Aufbau mit einem PIR Sensor, womit das Display nur bei 
Bedarf eingeschaltet wird.

von Thorsten M. (cortex_user)


Lesenswert?

Monk schrieb:
> Mache das Display mal dunkler, wenn es länger als 1 Jahr halten soll.
> Oder ergänze den Aufbau mit einem PIR Sensor, womit das Display nur bei
> Bedarf eingeschaltet wird.

Das geht nicht, 0 oder 1. Es brennt schnell ein, daher ständig wechselt 
und nachts geht es aus. Zeit kommt vom NTP Server. 4 Pins ablöten, neues 
Display rein und fertig. 4 Euro das Stück bei Aliexpress. Das EEPROM 
oben wird schon so rolierend beschrieben, dass die Datensätze der 
Grafiken immer neue Plätze buchen.
1
/* Datensicherung im EEPROM rolierend */
2
void SafeToEE(tables_t* data) {
3
4
  const int len = sizeof(*data);
5
6
  /* Erzeuge eine zufällige Blockadresse */
7
  const int max_blocks = EESIZE / len;
8
  int newBlock = random(0, max_blocks);
9
10
  EE_WritePtr = newBlock * len;  // Zieladresse im EEPROM
11
  data->valid = DVALID;          // Block gültig markieren
12
  data->blknr++;                 // Laufende Nummer
13
14
  sprintf(buf, "EE Block Nr.%u Data Set = %d Adr = %04X", newBlock, data->blknr, EE_WritePtr);
15
  debugln(buf);
16
17
  /* Funktion erwartet den Typ als Parameter ohne Angabe der Länge */
18
  myMem.put(EE_WritePtr, *data);
19
}
20
21
22
/* Daten lesen aus aktuellem Datensatz */
23
int ReadFromEE(tables_t* data) {
24
25
  uint16_t EE_AdrPtr = 0;
26
  uint16_t maxn = 0;
27
  uint16_t adr_found = 0;
28
  bool found = false;
29
30
  /* Position von valid ermitteln */
31
  const uint32_t validOffs = (uintptr_t) & (data->valid) - (uintptr_t) & (*data);
32
  const uint32_t blknrOffs = (uintptr_t) & (data->blknr) - (uintptr_t) & (*data);
33
  const int len = sizeof(*data);
34
35
  /* EE durcchsuchen nach gültigem valid */
36
  int16_t marke, id;
37
  while (EE_AdrPtr < (EESIZE - len)) {
38
    myMem.get(EE_AdrPtr + validOffs, marke);  // Valid Marke auslesen als int16_t
39
    if (marke == DVALID) {
40
      myMem.get(EE_AdrPtr + blknrOffs, id);  // Block Nummer auslesen als int16_t
41
      sprintf(buf, "Adresse: %04X = %u ID = %u", EE_AdrPtr, marke, id);
42
      debug(buf);
43
      /* Werte müsen gecasted werden! */
44
      if ((uint16_t)id >= maxn) {
45
        adr_found = EE_AdrPtr;
46
        maxn = (uint16_t)id;
47
        debug("*");
48
      }
49
      debugln();
50
      found = true;
51
    }
52
    EE_AdrPtr += len;  // Nächster Datensatz
53
  }

: Bearbeitet durch User
von Monk (roehrmond)


Lesenswert?

Thorsten M. schrieb:
> Das geht nicht, 0 oder 1

Aber selbstverständlich kann man den Kontrast per Software einstellen!

Auszug aus meinem Treiber:
1
    i2c.beginTransmission(display_address);
2
    i2c.write(0x00);
3
    i2c.write(0x81);
4
    i2c.write(contrast); 
5
    i2c.endTransmission();

Mir reicht in Innenräumen ein kleiner "contrast" Wert um 50.

> Es brennt schnell ein,

Eben deswegen der Vorschlag mit dem PIR Sensor. Du kannst es im 
Ruhezustand auf einen ganz niedrigen Kontrast (z.B. 8) stellen und wenn 
der Sensor auslöst für eine Minute auf 128 erhöhen.

: Bearbeitet durch User
von Thorsten M. (cortex_user)


Angehängte Dateien:

Lesenswert?

Monk schrieb:
> Aber selbstverständlich kann man den Kontrast per Software einstellen!

Ich baue es mal eben ein.... ist aber nur fürs Büro mit dem Handy als 
Hotspot für Wifi da Firmen Wlan leider an MAC Adresse gekoppelt ist aus 
Sicherheitsgründen. Könnte ich zwar ändern im XIAO auf die meines 
Laptops aber lieber nicht.

PS: Klappt! :-) Danke! 50 reicht vollkommen aus.

: Bearbeitet durch User
von Monk (roehrmond)


Lesenswert?

Thorsten M. schrieb:
> 50 reicht vollkommen aus.

Probiere noch weniger. Das Auge reagiert logarithmisch. Vielleicht 
reicht dir sogar 20.

von Thorsten M. (cortex_user)


Lesenswert?

Das passt schon mit 60 jetzt, der Kontrast ist sogar noch besser 
geworden. Vielleicht spendiere ich noch einen LDR für den A0 Pin für die 
Licht Sensierung mit einer Look Up Table für die Helligkeit. Gibt es ja 
diese Logarithmus Tabellen für LEDs.

Ups... Sturmwarnung für heute abend. Windstärke 5-6 ... woher das?

: Bearbeitet durch User
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.