Hallo,
ich habe ein Problem und kann mir selber nicht so recht helfen.
Auf dem ESP läuft ein Web-Server welcher eine Seite zur Verfügung
stellt. Auf dieser Seite kann man div. Schaltperioden einstellen. Das
ist eine ganz einfach Wochenschaltuhr. Jetzt habe ich aber das Problem,
dass mir der ESP unter EDGE abstürzt. Beim Firefox funktioniert es.
Firefox ist aber auch nicht ganz die Lösung, da hier das Stellen der
Uhrzeit nicht geht.
Was kann hier die Ursache des Problems sein und was kann man dagegen
tun.
Wäre schön wenn mich einer bei der Fehlersuche unterstützen könnte.
VG
Der ESP8266 hat nur etwa 5 kB im Stack frei, wenn man mehr belegt stürzt
er ab.
Anderer Ansatz: Kommentiere mal alle seriellen Ausgaben aus. Wenn die zu
lange dauern macht er nämlich einen Watchdog Reset.
Mir ist noch etwas aufgefallen:
Wenn du die erwarte Zeichenfolge "]}" nicht empfängst, dann hängst du
hier in einer Endlosschleife fest die über das Ende von data hinaus
läuft. Du ignorierst sogar den Wert von len.
ist schon sehr verschwenderisch... erstmal alles aus dem PROGMEM in den
RAM kopieren, und dann (über mehrere Zwischenschritte in den
String-Additionen, die auch alle im RAM liegen) nochmal eine
Komplett-Kopie der gesamten Antwort im RAM zurechtlegen...
Wenn dir das Templating zu kompliziert ist:
Soweit ich dem Beispielprojekt der Bibliothek entnehmen kann ist wohl
vorgesehen, dass onRequestBody() unter Umständen mehrmals mit Fragmenten
des Bodies aufgerufen wird, bis die "total" Anzahl von Bytes erreicht
sind.
Dein Code geht aber davon aus, dass das gesamte JSON Dokument in einem
Rutsch an onRequestBody() übergeben wird.
Hallo Stefan F. die seriellen Ausgaben hatte ich schon deaktiviert,
leider ohne Erfolg. Ich denke dein zweiter Tipp mit dem nichtempfangen
der Zeichenkette und dem damit verbundenen Überlauf ist schon mal ein
Punkt.
@ Εrnst B
>Wenn dir das Templating zu kompliziert ist:
1
Stringresp=String(header_html);
2
3
resp+=get_jsdate_fn();
4
resp+=get_html_table();
5
resp+=String(rem_body);
6
resp+=String(footer_html);
7
istzumindestetwassparsamer.
Diesen Teil habe ich so übernommen, der Rest sprengt meine Kenntnisse
;-)
@Stefan F.
>Soweit ich dem Beispielprojekt der Bibliothek entnehmen kann ist wohl>vorgesehen, dass onRequestBody() unter Umständen mehrmals mit Fragmenten>des Bodies aufgerufen wird, bis die "total" Anzahl von Bytes erreicht>sind.>Dein Code geht aber davon aus, dass das gesamte JSON Dokument in einem>Rutsch an onRequestBody() übergeben wird.
Okay wie würde man es den lösen?
Sirdus schrieb:> Okay wie würde man es den lösen?
Die empfangenen Bytes sammeln bis len+len+...+len den Wert von total
erreicht hat. Erst dann auswerten. Aber nicht bis zur Position von "]}"
auswerten, sondern von 0 bis total.
Auf der Console sehe ich jetzt folgendes.
Firefox:
{"start_time":[450,450,450,450,450,480,480],"stop_time":[840,840,840,840
,840,720,720],"status":1,1,1,1,1,0,0]}
123341151169711411695116105109101345891525348445253484452534844525348445
253484452564844525648934434115116111112951161051091013458915652484456524
844565248445652484456524844555048445550489344341151169711611711534589149
44494449444944494448444893125
Edge:
{"start_time":[450,450,450,450,450,480,480],"stop_time":[840,840,840,840
,840,720,720],"status":1,1,1,1ointR␅123341151169711411695116105109101345
891525348445253484452534844525348445253484452564844525648934434115116111
112951161051091013458915652484456524844565248445652484456524844555048445
5504893443411511697116117115345891494449444944491111051101168210185,1,0,
0]}␀␀\␃�␅=␅␟␅Mozilla/5.0 (Windows NT 10.0; Win64; x64)
AppleWebKit/537.36 (KHTML, like Gecko)
Chrome/106.0444944484448931250092313056153157711112210510810897475346483
240871051101001111191153278843249484648593287105110545259321205452413265
112112108101871019875105116475351554651543240757284777644321081051071013
27110199107111413267104114111109101474948544648
Die "Zahlen" kommen aus einer Print ausgabe beim Datei schreiben.
1
2
boolsave_config_file(Stringf_name,StringJson)
3
{
4
Filefile=SPIFFS.open(f_name,"w");
5
if(!file)
6
{
7
Serial.println("Error opening file for writing");
8
returnfalse;
9
}
10
11
if(!file.print(Json))
12
{
13
returnfalse;
14
}
15
16
file.close();
17
/////////////////////////////////
18
Filefile2=SPIFFS.open(f_name,"r");
19
20
if(!file2)
21
{
22
Serial.println("Failed to open file for reading");
Wenn ich es richtig sehe, wird beim Edge irgendwie die Datei geschrieben
bevor die Funktion fertig ist. Man erkennt aber auch den Rest in der
Ausgabe.
.."status":1,1,1,1 xxxx ,1,0,0]}
Sirdus schrieb:> Wenn ich es richtig sehe, wird beim Edge irgendwie die Datei geschrieben> bevor die Funktion fertig ist. Man erkennt aber auch den Rest in der> Ausgabe.
Wie Stefan geschrieben hat:
Es ist nicht garantiert, dass du nur einen einzigen Aufruf von
"handleUpload" bekommst, da können auch mehrere kommen, jeder mit einem
Teil der Daten. Erst wenn der Aufruf mit "final=true" kommt, sind die
Daten vollständig übertragen.
mit "file_data" hast du ja schon angefangen, dir diese Daten
zusammenzusammeln. Aber: Du darfst das nur beim ersten Aufruf auf
""(leer) setzen.
z.B:
oder alternativ am Ende der Datenübertragung, also im "if (final) ..."
Vorsicht: Ist keine 100%ige Lösung, wenn Zwei Uploads auf die URL
gleichzeitig passieren, zerschießt es dir den Variableninhalt.
Sirdus schrieb:> for (size_t i = 0; i < total; i++)> Auf der Console sehe ich jetzt folgendes:
(ein bisschen richtiges gefolgt von Zufallsdaten)
> Wenn ich es richtig sehe, wird beim Edge irgendwie die Datei> geschrieben bevor die Funktion fertig ist
Weil dein Code immer noch davon ausgeht, das gesamte JSON Dokument in
einem Rutsch zu empfangen. Darauf kannst du dich aber nie verlassen.
Beim TCP Protokoll können Datenströme immer in unerwartete Paketgrößen
zerlegt werden. Du wirst mit dem anderen Browser genau das gleiche
Problem bekommen wenn das JSON Dokument größer als 4 kB ist. Das ist
nämlich die maximale zulässige Paketgröße bei Ethernet. Doch darauf
kannst du dich nicht verlassen, da jedes beteiligte Programm und Gerät
den Datenstrom in kleinere Stücke zerlegen darf.
Die Funktion onRequestBody() wird mehrmals (!) mit folgenden Parametern
aufgerufen:
data: Zeiger auf die empfangenen Bytes des aktuellen Fragmentes
len: Anzahl der empfangenen Bytes in data
index: Position innerhalb der Gesamtgröße
total: Gesamte Anzahl erwarteter Bytes (wie im Content-Length header)
Angenommen dein Request Body besteht auf 3 Stücken, dann könnten sie so
aufgeteilt sein:
1
Erster Aufruf: len=128, index=0, total=300
2
Zweiter Aufruf: len=64, index=128, total=300
3
Dritter Aufruf: len=108, index=192, total=300
Wenn len+index=total ist, hast du das letzte Fragment empfangen.
Du möchtest alle Fragmente nacheinander verketten, und erst ganz zum
Schluss das JSON Dokument weiter verarbeiten. Nicht bei jedem Aufruf von
onRequestBody().
Hallo,
@ Stefan F. vielen Dank für deinen letzten Beitrag, das hat mir wirklich
geholfen das Problem zu verstehen.
Ich habe nun versucht das irgendwie umzusetzten aber so recht geht es
leider nicht.
Sirdus schrieb:> Ich habe nun versucht das irgendwie umzusetzten aber so recht geht es> leider nicht.
Dein gezeigter Quelltext ist jedenfalls der richtige Ansatz.
J. S. schrieb:> Mal die Compiler Warnungen einschalten.> if (index = 0){
Das wird es sein.
Leider funktioniert das nicht unter Firefox, Edge macht keine Probleme.
Ich sehe mit Firefox keine Print-Ausgabe. Es scheint als ob die Funktion
nicht aufgerufen wird. Im Debugfesnter vom Firefox sehe ich
NS_BINDING_ABORTED
Kann mir hier noch einer einen Tipp geben?
Mache mal eine Debug Ausgabe ganz am Anfang der Funktion um zu sehen ob
sie überhaupt aufgerufen wird.
Kontrolliere mit Wireshark, wie dein Mikrocontroller den HTTP Request
beantwortet. Du kann mit Wireshark auch gut herausfinden, worin sich die
Requests deiner beiden Browser unterscheiden.
--> keine Ausgabe
Habe es mit Wireshark aufgezeichnet, sprengt aber meinen Stack...
In der LOG sieht man erst den Firefox, dann Edge.
Beim Firefox fehlt irgendwie die Anfrage.
Sirdus schrieb:> keine Ausgabe> 123.png> Habe es mit Wireshark aufgezeichnet, sprengt aber meinen Stack...
Wieso ist doch gut. Du hast genau das gezeigt, was ich sehen wollte.
Dass ein Browser wiederholt versucht, das /favicon.ico zu laden ist ganz
normal. Dass dein µC mit darauf mit einem Error antwortet wenn er dieses
Bild nicht bereitstellen kann ist auch OK (wobei dann ein anderer
Errorcode üblich wäre, aber egal).
Was hier aber völlig fehlt ist der Aufruf /updaterc durch den Firefox
Browser. Kein Wunder dass dein Mikrocontroller nicht reagiert. Du hast
offenbar einen Fehler im HTML oder Javascript der Webseite. Hänge mal
den Seitenquelltext als HTML Datei an. Mit dem Browser abspeichern, ich
will sehen wie die Seite aus seiner Sicht aussieht. Falls sie
irgendwelche Javascripte als separate Datei includiert, dann hänge diese
bitte auch an.
Die letzte Zeile der Funktion muss weg, ich habe sie auskommentiert:
1
function updateRtc(){
2
...
3
var http = new XMLHttpRequest();
4
http.open("GET", url+"?"+params, true);
5
http.onreadystatechange = function(){
6
if(http.readyState == 4 && http.status == 200) {
7
alert("Time updated");
8
location.reload();
9
}}
10
http.send(null);
11
//location.reload();
12
}
Erklärung: Mit http.onreadystatechange richtest du eine Call-Back
Funktion ein, der aufgerufen werden soll, wenn der Request beantwortet
wurde. Da du aber schon vorher das Fenster neu lädst, ist der
Eventhandler nicht mehr Verfügbar. Der Request wird vom Browser
abgebrochen.
Schau dir auch mal deine submitFunction an, die ist auch nicht in
Ordnung:
Bei xhr.open() hast du mit dem Parameter true festgelegt, dass der
Request asynchron ausgeführt werden soll. Direkt nach xhr.send() gibst
du aber schon eine Erfolgsmeldung aus, völlig egal ob der Request
überhaupt erfolgreich beantwortet wurde. Du musst an dieser Stelle auch
wie oben eine Call-Back Funktion benutzen, um die Antwort auszuwerten.