für diejenigen, die es interessiert. Ich habe lange verzweifelt an einem Server, der mir Messdaten aufs Handy spielt als Webseite und der immer wieder mal einfror, d.h. das Hauptprogramm zur Steuerung der Balkonsolaranlage zur Speisung ins Netz, in die Batterien oder von den Batterien ins Netz (mit einem Inverter, der Batterien akzeptiert und den MPPT abschaltet) lief noch aber nix mehr mit Webanzeige. Aus lauter Not ein Wifi Relais eingebaut als Reset EIn/Aus. Er stürzte dabei völlig unregelmäßig ab, mal nach ein paar Stunden, mal erst nach einem Tag usw.
Bis mir dann die idee kam mit der KI "Gemini Advanced" (kostet was aber gut) mal den ganzen Arduino Code hoch zu laden und analysieren zu lassen. Da kann man einfach die Dateien reinziehen, muss nichts abtippen. Die Analyse spuckte vieles aus, u.a. dass die exzessive Verwendung von String Literalen und String Umwandlungen, die man ja gern macht bei HTML Seiten Erzeugung um den Riesenstring zu erzeugen, der mit send an den Client geschickt wird Probleme auf dem Heap erzeugen kann. denn String nicht nicht nur den Heap sondern erzeugt auch temporäre lokale Fragmente auf dem Stack, wenn es Float etc umwandelt in Text. Der Stack ist nur 4bKB gross beim ESP32, die sind schnell voll mit lokalen Buffern.
Gemini schrieb mir die komplexe Webausgabe um auf Standard C. Irre was die KI da leistet! Sie machte auf Anhieb alles richtig, schneller als jeder Mensch das hinkriegen würde. Selbst eine Analyse nach MISRA kann das Ding durchführen. Da sie den ganzen Code hatte wurde auch Buffer gleich richtig dimensioniert für die json Ausgabe an weitere Clients, z.b die Anzeigetafel. If then else Gräber wurden aufgelöst und verkleinert usw. Und das Ding lief auf Anhieb! Seit Tagen absturzfrei durch. HTML Code erzeugen mit dieser KI ist ein Kinderspiel, ob Buttons, javascript, CSS Styles oder was auch immer. Damit kriegt man sehr komplexe Sachen hin mit dem ESP32.
Falls es also noch jemand nicht glaubt: String ist ein heisses Eisen! Kann funktionieren, muss aber nicht. Vor allem nicht bei dynamischen Ausgaben, denn es hat zb. keinen Destruktor, das Zeug stopft den Speicher zu, bis Absturz.
Wieder was dazugelernt :-) Der Code hier ist komplett KI erzeugt, auch die Variablennamen wurden angepasst.
1
/* Bei Inverter Betrieb Batterie grau machen */
2
strcat(msg,"Batterie ");// Batterie Text immer hinzufügen
3
dtostrf(Data.UBatterie/2.0,1,1,fbuf);// Konvertiere float zu String
4
if(Flags.fInvertSolarPower)
5
{
6
strcat(msg,"<span style=\"color:#A4A4A4\">");// Graue Schrift wenn Inverter aktiv
7
strcat(msg,fbuf);
8
strcat(msg," V</span><br/>");
9
}
10
else
11
{
12
strcat(msg,fbuf);
13
strcat(msg," V<br/>");// Keine spezielle Formatierung wenn kein Inverter aktiv
dass die exzessive Verwendung von String Literalen und String
Umwandlungen, die man ja gern macht bei HTML Seiten Erzeugung um den
Riesenstring zu erzeugen
Das ist halt die hässliche und suboptimale Variante.
Liefere doch lieber einfach ein statisches HTML aus. Beim ESP kannst du die Dateien sogar nachträglich auf das Filesystem laden und neue Versionen aktualisieren bei Bedarf.
Dann musst du auf ESP Seite rein garnichts ersetzen oder mit Strings machen.
Sobald das HTML auf PC Seite angekommen ist soll es lieber asynchrone Requests über JS machen. Dann brauchst du nur relativ kleine JSON "Strings" mit den aktuellen Prozessdaten zusammensetzen die noch nicht einmal eine dynamische allokierung von Speicher benötigen.
So sinkt der dynamische Speicherbedarf sehr schnell und die Latenz sucht.
So, und um wirklich was zu gewinnen, könntest du die KI das noch auf einen AsyncHTTPServer umschreiben lassen, unter Verwendung der Template-Engine, mit HTML, CSS und JS auf dem Dateisystem.
Die Herangehensweise "Erstmal das ganze HTML im RAM zusammenbauen, und dann erst raussenden" (Egal ob strcat oder String) passt zwar für so kleine "Hallo Welt"-Beispiele, kommt aber schnell an ihre Grenzen.
Und ja, das kriegt die KI auch (zumindest großteils) hin.
Gibt keine :-) Dachte mir, das könnte jemand interessieren :-) Die Ablage im Filesystem wäre zu aufwendig, denn es werden viele Dinge erst berechnet und dann ein String daraus gebaut.
Die Herangehensweise "Erstmal das ganze HTML im RAM zusammenbauen, und
dann erst raussenden" (Egal ob strcat oder String) passt zwar für so
kleine "Hallo Welt"-Beispiele, kommt aber schnell an ihre Grenzen.
Aber für jemand, der das noch nie gemacht hat ist das ja ein Anfang. Die fortschrittlicheren Dinge lernt man ja erst nachher. Ich haue das alles als HTML raus oder als großer json Container, je nachdem was im GET steht. Teilweise auch mit POST, wenn zb Daten in beide Richtungen fliessen sollen. OTA Update sowieso. Asynchroner Server Code ist schwerer zu debuggen, damit habe ich noch keine Erfahrungen gemacht.
Die
Ablage im Filesystem wäre zu aufwendig, denn es werden viele Dinge erst
berechnet und dann ein String daraus gebaut.
Genau das kannst du damit loswerden. In's HTML packst du Variablen wie z.B
<span id="voltage>%BAT_VOLTAGE%</span>
Speicherst das HTML-File so ins Filesystem, und beim raussenden kannst du die Variable mit dem aktuellen Wert ersetzen lassen.
Und das als Stream, es muss nie das ganze HTML auf einmal in den RAM.
=> Kein Problem mit sehr großen Dateien, kein Problem mehrere Requests gleichzeitig zu bearbeiten.
Oder du machst das HTML gleich komplett statisch, und aktualisierst die Werte per fetch/json, websocket, SSE, ... wie von Mani vorgeschlagen.
Die KI hat dir deinen Vorschlaghammer durch einen Pflasterstein ersetzt. Gut, der ist leichter erhältlich, vielleicht auch handlicher. Schonmal ein Fortschritt.
Zum Schrauben reindrehen gehen beide irgendwie, schön ist keine Lösung.
Wenn du die KI vorsichtig in Richtung Schraubendreher schubst, findet die auch was Passenderes.
Eben gerade nicht. Ist viel einfacher weil es sich vorab auch einfach am PC entwickeln und debuggen lässt.
denn es werden viele Dinge
erst berechnet und dann ein String daraus gebaut.
Das kannst du ja machen. Aber du musst das ja nicht auf dem schwächsten Glied (ESP) machen. Die HTML einfach so wie sie ist zu übertragen und nachträglich die Prozessdaten nachladen ist viel einfacher und Ressourcen schonender.
Das kannst du ja machen. Aber du musst das ja nicht auf dem schwächsten
Glied (ESP) machen. Die HTML einfach so wie sie ist zu übertragen und
nachträglich die Prozessdaten nachladen ist viel einfacher und
Ressourcen schonender.
Ich behalte es im Kopf dass es so geht. Aber da muss ich mich erst einarbeiten. Webprogrammierung ist Neuland für mich, bin froh dass ich was angezeigt bekomme und das Daten hin und her laufen. Sobald die Notwendigkeit besteht schaue ich mir das mal an.
Im grunde stehen da texte wie
Spannung = x.yz Volt
und Infotexte über den betriebsmode, sowie Bargraphen aus * und #, die anzeigen wie voll der Akkku ist.
Der Code ist irre. Irre scheiße. Eine wilde strcat-Orgie. Alleine schon die Verwendung von strcat(). Dann noch ohne die aktuelle Belegung des Puffers mit zu zählen. Statt dessen der Glaube an:
Da sie den ganzen Code hatte wurde auch Buffer
gleich richtig dimensioniert
Sicher, sicher ... Sogar wenn die KI wirklich für den gegebenen Fall richtig mit gerechnet hat (hast du das selber nachgerechnet oder behauptest du das nur?), spätestens wenn jemand anfängt an den Strings was zu ändern ist die ganze KI-Berechnung fürn Arsch.
Der Code bettelt dann förmlich nach einem Pufferüberlauf weil er nicht robust geschrieben ist. Echter Scheißdreck.
Falls es also noch jemand nicht glaubt: String ist ein heisses Eisen!
Es hilft ungemein zu wissen was man tut, statt sich von einer KI verarschen zu lassen. Ehrlich, als offensichtlicher Anfänger rumzutröten wie man solchen Code zu schreiben hat ist lachhaft.
Wieder was dazugelernt :-)
Nein, du hast dich von einer KI verarschen lassen.
Der Code ist irre. Irre scheiße. Eine wilde strcat-Orgie.
Es ist ist in diesem Forum nur eine Frage der Zeit, wann die "Helden" mit narzisstischer Persönlichkeitsstörung auftauchen und jeden Thread in den Dreck ziehen, wo nicht alles so gemacht wird, wie sie es meinen. Gut, dass ich den Alptraum solche asozialen Kollegen zu haben schon lange hinter mir weiß. Ich beende daher meine Teilnahme in diesem Fred und wünsche alles Gute bis irgendwann mal wieder.
mit genau den Problemen! Allerdings mit der Stream-Library, da wird nicht der ganze Riesenstring am Schluss versendet, sondern Stück für Stück. Aber das mühsame zusammensetzen des HTML mit Einfügen der Daten blieb...
Der Code ist irre. Irre scheiße. Eine wilde strcat-Orgie.
Es ist ist in diesem Forum nur eine Frage der Zeit, wann die "Helden"
mit narzisstischer Persönlichkeitsstörung auftauchen und jeden Thread in
den Dreck ziehen, wo nicht alles so gemacht wird, wie sie es meinen.
Gut, dass ich den Alptraum solche asozialen Kollegen zu haben schon
lange hinter mir weiß. Ich beende daher meine Teilnahme in diesem Fred
und wünsche alles Gute bis irgendwann mal wieder.
Die Worte von Hannes sind schon sehr drastisch, und das geht so nicht.
Das sieht ja gruselig aus, diese strcat Orgie. Spaghetticode at its best.
Warum nimmt man nicht einfach sprintf, um die Ausgaben in einem Rutsch zu erzeugen?
Es ist auch praktisch, wenn Ausgaben immer nach dem gleichen Schema erfolgen, dann kann sie auch der Mensch besser parsen.
Dann kann man sich dafür Hilfsfunktionen schreiben, denen dann nur die Unterschiede übergeben werden.
Der Code hier ist komplett KI erzeugt, auch
die Variablennamen wurden angepasst.
Und der Code ist großer Mist, weil er /strcat/ benutzt. Damit gibt es überhaupt keinen Schutz vor Pufferüberläufen.
Wie groß ist "msg"?
Eben. Funktionen wie /strcpy/, /strcat/ oder auch /sprintf/ sollte man konsequent vermeiden, außer in Fällen, wo ganz offensichtlich ist, daß das Ziel niemals überschrieben werden kann.
Stattdessen verwendet man /strncpy/, /strncat/ und /snprintf/.
Es ist ist in diesem Forum nur eine Frage der Zeit, wann die "Helden"
mit narzisstischer Persönlichkeitsstörung auftauchen und jeden Thread in
den Dreck ziehen, wo nicht alles so gemacht wird, wie sie es meinen.
So kann man natürlich auch reagieren. Ist dann halt nur blöd, wenn man a) nichts gelernt hat und b) der Code einem auf die Füße fällt.
Der kleinste ESP32 hat meines Wissens nach 520kB RAM, ich verstehe nicht wieso man da nicht einfach mit std::string arbeitet?
Ich hab z.B. eine kleine Anwendung die ein "Captive Portal" liefert. Im Code wird hierzu statisches HTML mit "{}" Plathaltern hinterlegt. Ein Element darin kann etwa so aussehen:
man sollte eine abschätzbare Mindestgröße des Strings anlegen. Im Grunde kennt man die Größe die man benötigt + etwas Reserve. Das wirkt der dynamischen Speicherreservierung entgegen. Was auf dem PC egal ist, ist auf einem µC nicht egal. Der Umgang damit ist entscheidend. Man lernt immer dazu.
Falls es also noch jemand nicht glaubt: String ist ein heißes Eisen!
Das ist mir beim ESP8266 aufgefallen, mein erster Kontakt zu Arduino. Dass man schnell zu viel Speicher belegt war mir eigentlich schon vorher klar. Aber die vielen praktischen Methoden dieser Klasse können den Heap je nach Anwendung dermaßen fragmentieren, dass nach einiger Zeit trotz freiem Speicher nichts mehr geht.
Ich bevorzuge []char und die zugehörigen Funktionen der standard C Bibliothek. Sie sind weniger komfortabel, aber es ist offensichtlicher, was dabei im Speicher passiert.
Die Stream-Methoden readString() und readStringUntil() sind auch gemein, denn sie können mehr Daten lesen, als in den Stack passen. DOS Angriffe leicht gemacht :-)
Die Stream-Methoden readString() und readStringUntil() sind auch gemein,
denn sie können mehr Daten lesen, als in den Stack passen. DOS Angriffe
leicht gemacht :-)
OT: was bitte soll an den bisherigen Reaktionen asozial oder narzisstisch sein? Meinungsverschiedenheiten und die Darstellung von Unzulänglichkeiten oder Verbesserungsmöglichkeiten haben auch rein gar nichts mit asozialem Verhalten oder gar Narzissmus zu tun. Schlimm ist hingegen, dass Du die Leute hier mit diesen Attributen titulierst.
Eben. Funktionen wie strcpy, strcat oder auch sprintf sollte man
konsequent vermeiden, außer in Fällen, wo ganz offensichtlich ist, daß
das Ziel niemals überschrieben werden kann.
Stattdessen verwendet man strncpy, strncat und snprintf.
Eigentlich sind seit C11 eher strcpy_s, strcat_s und sprintf_s als "secure" nachfolger vorgesehen (keine Ahnung ob der von Arduino verwendete GCC das unterstützt):
Finde ich überhaupt nicht. Ja, er ist sehr deutlich geworden, aber sind wir denn inzwischen so zart besaitet, dass man solch harmloses Geschimpfe bzw. deren Verfasser gleich als asozial oder narzisstisch titulieren muss?
Ich habe auch keinerlei Verständnis und bin sehr empfindsam darüber, wie im Netz bzw. in social media miteinander umgegangen wird. Aber Hannes' Worte hätte ich jetzt sicher nicht in diese Schublade gepackt.
Wenn natürlich nur noch das Warmduschergeplänkel von ChatGPT(*) als erträglich eingestuft wird, wird einem ein rauerer Ton verstörend vorkommen.
Wie gesagt, ich bin auch ein großer Freund höflicher Umgangsformen. Aber ich habe auf mc schon sehr viel schlimmere Texte gelesen als in diesem Thread.
ciao
Marci
(*) Das ist jetzt nicht negativ gemeint. Mir gefällt die sehr höfliche und angenehme Ausdrucksweise von ChatGpt auch. Aber das muss meinetwegen nicht zum Standard der zwischenmenschlichen Kommunikation werden.
Das sieht ja gruselig aus, diese strcat Orgie. Spaghetticode at its
best.
Warum nimmt man nicht einfach sprintf, um die Ausgaben in einem Rutsch
zu erzeugen
Das ist der Maschine sowas von egal! Das ist der gleiche Quark wie mit den
msg += String(..) + String ("Lalalaa") Gräbern, die sich in hunderten Programmen finden und auch die Libs strotzen vor Strings.
Für mich sieht das alles ordentlich aus und nachvollziehbar. Außerdem wird eben der "Riesenstring" gebraucht, der an send übergeben wird und bei etlichen "Bargraphen", die aus Ascii Zeichen bestehen und die berechnet werden müssen kommt printf an seine Grenzen.
Es läuft einwandfrei durch und hat sich nie wieder aufgehängt
Dank KI wenig Arbeit damit gehabt
"Schönheit" des Codes interessiert hier niemanden, es muss einfach nur funktionieren und Platz hat der ESP soviel, dass es wumpe ist.
Danke für den Link, diese Async Sache schaue ich mir mal an, das scheint doch "fortschrittlicher" zu sein, wenn man es mal durchdrungen hat.
Und der Ton hier ist mir egal, ich bin nur froh solche Leute nicht um mich haben zu müssen. Den letzten haben wir rausgeworfen, der meinte andere Kollegen ständig abwerten zu müssen, die seinem "Genie" nicht huldigen, Narzissmus eben. Ich muss mich da nicht anpassen, ich drehe mich um und gehe.
1
memset(msg,0,sizeof(msg));/* Wichtig, msg wieder löschen! */
Sorry, der Code geht für mich gar nicht. Mag für ein Hobbyprojekt gehen.
Aber wenn man nach 5 Jahren da Änderungen vornehmen muss, dann fragt man sich selber, was man damals für einen Mist gebaut hat.
Oder man bekommt solch einen Code vom Kollegen, und darf sich mit obskuren Fehlern durch kleine Änderungen durchschlagen.
Sobald man nur etwas an dem style ändert, reicht möglicherweise der Platz in colorcode nicht aus. Da ist doch schon ein Fehler vorbereitet.
Für mich ist das keine defensive, portable Programmierung, sondern einmaliger Hobby-Müll, der im Keller bleiben sollte.
Aber auf keinen Fall veröffentlicht werden sollte. Davon lernt die KI nur das schlechte.
Das ist der Maschine sowas von egal! Das ist der gleiche Quark wie mit
den
msg += String(..) + String ("Lalalaa") Gräbern, die sich in hunderten
Programmen finden und auch die Libs strotzen vor Strings.
Schön, wenn jemand C und C++ (oder C# etc.) dureinanderwirft.
Die String-Überladung von "+=" gibt es in C gar nicht (da man da auch gar nichts überladen kann).
Bei C darf man sich um die Einhaltung von Speichergrenzen selber kümmern. Die interessieren den Compiler einen Dreck, weil der davon ausgeht, dass man weiß, was man tut.
Er hat sein Problem schneller gelöst, als er es ohne KI hätte können.
Also alles richtig gemacht.
Bis ihm der Code spätestens nächste Woche auf die Füße fällt, und er dann noch ratloser da steht, weil er nun gar nicht mehr versteht, was da eigentlich passiert.
Aber ChatGPT wirds schon irgend wie richten - hoffentlich.
Was soll die "/ 2.0f" Orgie bewirken?
Das kürzt sich doch eh raus.
Da hast Du recht aber das ist nur für mich, damit ich weiss, dass die Batteriespannung / 2 geteilt wird. Mir sind die Spannungen von 12V geläufiger als die von 24V. Musst Du jetzt nicht verstehen, ich habe mir dabei was gedacht. Das kürzt sich schon beim Kompilieren raus. Im Übrigen gute Einwürfe aber von "Peda" kenne ich das nicht anders :-)
Eben. Funktionen wie strcpy, strcat oder auch sprintf sollte man
konsequent vermeiden, außer in Fällen, wo ganz offensichtlich ist, daß
das Ziel niemals überschrieben werden kann.
Stattdessen verwendet man strncpy, strncat und snprintf.
Eigentlich sind seit C11 eher strcpy_s, strcat_s und sprintf_s als
"secure" nachfolger vorgesehen (keine Ahnung ob der von Arduino
verwendete GCC das unterstützt):
Er hat sein Problem schneller gelöst, als er es ohne KI hätte können.
Also alles richtig gemacht.
Bis ihm der Code spätestens nächste Woche auf die Füße fällt, und er
dann noch ratloser da steht, weil er nun gar nicht mehr versteht, was da
eigentlich passiert.
Wieder die Tatsachen verdreht. /Vorher/ stand er ratlos da und hatte mir sporadischen Crashes zu kämpfen.
Jetzt läuft es stabil und das Problem ist gelöst.
Dass der Code nicht schön, nicht gut dokumentiert, und im Falle weiterer Änderungen fehleranfällig ist stelle ich nicht in Abrede.
Der Vollständigkeit halber, strcat hat 2 Nachteile:
Man muss aufpassen, dass man den Buffer wirklich gross genug gewählt hat. Sonst crashts.
Jedes mal, wenn man strcat aufruft, ist das wie "strcpy(dest+strlen(dest),src)". Anders gesagt, der String, den man erweitert, wird jedes mal nach dem 0 byte durchsucht.
(Ich verstehe ehrlich gesagt nicht, warum man strcpy nicht einen Pointer auf das Ende des Strings zurückgeben liess, aber das ist jetzt nunmal so, wie es ist)
(Ich verstehe ehrlich gesagt nicht, warum man strcpy nicht einen Pointer
auf das Ende des Strings zurückgeben liess, aber das ist jetzt nunmal
so, wie es ist)
Wenn du das für so sinnvoll hälst, könntest du leicht einen Wrapper schreiben der das so macht.
Hier hat Peda ausnahmsweise mal Abstraktion verstanden.
Genau so sollte man es machen: Man macht (String) Funktionen genau für die aktuelle Applikation. Und da drin kann man dann sämtliche str Sauereinen veranstalten die man will. Man kann die Implementierung jederzeit auch auf printf ändern oder auf sonst was. Und man muss genau in dieser Funktion, und nur dort, nach Fehler und Überläufen in str Funktionen suchen.
Einfach an zig Stellen im programm mit strcat rumpfuschen ist eben genau das: Pfusch.
(Ich verstehe ehrlich gesagt nicht, warum man strcpy nicht einen Pointer
auf das Ende des Strings zurückgeben liess, aber das ist jetzt nunmal
so, wie es ist)
Wenn du das für so sinnvoll hälst, könntest du leicht einen Wrapper
schreiben der das so macht.
Warum muss eigentlich der komplette Output zuvor in einem riesengroßen Buffer landen? Man kann durchaus zwischendurch auch mal irgendeine write-Funktion aufrufen, um schon mal einen Teil des Ausgabestrings loszuwerden. So kann man die benötigte Buffergröße auf einen sinnvollen Wert eindampfen.
Möchte man doch erst den kompletten Buffer füllen, dann noch eine Bemerkung zum vorgeschlagenen strcat() in der C-Variante:
Abgesehen von möglichen Buffer-Overflows ist diese Funktion für große Buffer extrem ineffizient. Das liegt daran, dass strcat() jedes mal die aktuelle Stringlänge des Buffers erst ermitteln muss, bevor es dann etwas anhängen kann. Das macht strlen() in der Regel durch Iteration über alle Zeichen im Buffer.
Führt man hier aber immer die Länge des Buffers mit, dann wird aus:
1
strcat(buffer,str);
ein:
1
staticintlen=0;
2
...
3
strcpy(buffer+len,str);
4
len+=strlen(str);
Dann wird die Stringlänge nur für die kleinen anzuhängenden Strings ermittelt und nicht jedes Mal für den riesengroßen Brocken. Das geht wesentlich schneller.