ich habe einen ESP32 Server, der mit einem anderen ESP32 quasselt. Der Server bietet seine Daten im Format (erster Gedankenschuss!)
BEGIN,1245,020523,12.56,28.5,100,200,END
Startsignatur, Uhrzeit hhmm, Datum ttmmyy, %.2f float, %.2ffloat, int,int, END
sprintf Formatstring ist "%02d%02d%02d,%02d%02d%02d,%.2f,%.2f,%u,%u,END"
an, d.h. dieser String erscheint auch auf meinem Handy, wenn ich meine Fritzbox anfunke mit dem Browser. Klar kann man den String auch mühsam zerlegen mit den ganzen String Funktionen, wobei ChatGPT sehr wertvolle Hilfe liefert aber mit sscanf soll das doch besser gehen.
Ich weiss nicht mal ob ich die optimale Ausgabe gewäöhlt habe mit den führenden Nullen und dem %u
Sieht dann der sscanf Formatstring genauso aus? ich habe es noch nicht programmiert auf einem Test ESP32, wo ich das alles vorher ausprobiere aber ich frage mal vorher..... ist das komma der richtige Dilimeter? Sind die Formate ok?
Uhrzeit zerlegen:
stunde = zeit / 100;
min = zeit % 100;
usw.
JSON ist einfacher, man muss sich dann auch nicht drum kümmern das zu parsen. ChatGPT erzeugt da klasse Code Snippets, als Eingabe mit ein struct und raus kommt ein json konstrukt.
Welchen Du verwendest, bleibt komplett Dir überlassen. Punkt wäre ungünstig, weil das bei Deinen Float-Zahlen auch der Dezimalpunkt ist.
Ja, die Formatstrings von sscanf und sprintf sind sich sehr ähnlich, was Du bei sscanf weglassen kannst, sind Angaben wie Feldbreite oder führende Nullen.
Json zu parsen ist deutlich mehr Aufwand (den aber nimmt Dir irgendeine Library ab, die Rechenleistung brauchts trotzdem), dafür aber deutlich sicherer, weil fehlende Elemente/ungültige Zeichen etc. je nach Qualität der verwendeten Library brauchbar abgefangen werden.
Wobei helfen "Begin" und "End"?
Was spricht dagegegen, einfach einzelne Textzeilen zu verwenden (die also mit CR, LF oder CRLF getrennt werden)?
Was spricht dagegegen, einfach einzelne Textzeilen zu verwenden (die
also mit CR, LF oder CRLF getrennt werden)?
Bei gar nichts, wird gar nicht verwendet.
Spricht nichts gegen. Macht das was besser?
Ich rechne nicht mit Übertragungsfehlern bei tcp/ip.... vermute ich zumindest.
Du willst herausfinden, wo der String beginnt, den Du sscanf übergibst. Daher ist eine definierte Trennung einzelner Strings nicht unwichtig.
Ein Stringende-Zeichen (CR, LF oder CRLF) macht halt klar, daß jetzt ein vollständiger String empfangen wurde. tcp überträgt üblicherweise einen Bytestrom, d.h. Dein Musterstring
BEGIN,1245,020523,12.56,28.5,100,200,END
kann auch durchaus in mehreren Häppchen ankommen:
BEGIN,1245,020523,12.56,28
.5,100,200,END
oder auch mehrere davon hintereinander (je nachdem, wie schnell die Dinger gesendet werden):
Auf dem Handy erscheint immer nur eine Zeile, ich sende mit
server.send(200,"text/plain", message);
PS: Ein Server kann nicht senden. Der antwortet nur auf die Anfragen des Client. Also immer wenn ich mit dem Finger runter wische, alias F5 wird eine neue URI an den Server geschickt und die Seite wird neu aufgebaut. Da ich kein html verwende sind die Daten maschinenlesbar.
Ja, die Formatstrings von sscanf und sprintf sind sich sehr ähnlich, was
Du bei sscanf weglassen kannst, sind Angaben wie Feldbreite oder
führende Nullen.
Wenn du aber das Datum 020523 wieder in 3 Variablen speichern möchtest, musst du auch beim scanf die Feldbreite angeben.
Deine Empfangsroutine empfänge einzelne Zeichen oder Blöcke vom Netzwerk, stoppelt die solange zu einer Zeile zusammen, bis \r\n (o.ä.) empfangen wurde, und ruft dann erst sscanf damit auf.
Wenn du einen festen Formatstring hast, musst du bei jeder Erweiterung und auch bei manchen Bugfixes Server und Client gleichzeitig ändern.
Das solltest du nur machen, wenn es bei 2 ESPs bleibt. Spätestens, wenn du eine zusätzliche Weboberfläche für die Fehlersuche schreibst, wird dein eigenes Format aufwendig. JSON kodieren und Parsen machst so ein ESP nebenbei.
JSON kodieren und Parsen machst so ein
ESP nebenbei.
Jupp... bei JSON kann ich den ganzen Struct umwandeln, rüberschieben und den genauso wieder zusammensetzen. Trotzdem muss man bei Änderungen immer beide ändern. Für den Browser habe ich schon alles fertig, in bunt und schön optisch aufbereitet (Monat noch falsch). Jetzt fehlt nur noch ein Display im Wohnzimmer, wo die Daten auf Displays geschickt werden.
Nein, du kannst auch einen Parser nehmen, der ein JSON-Objekt erzeugt. Hat dann Methoden, mit denen du nachfragen kannst, welche Attribute vorhanden sind.
den ganzen Datenstruct, der zudem noch zwei interne Struct hat als reine Heex-Binärdaten rüberschieben, quasi Intel Hex Format für Flash Brenner.
563df28373f738e20a7b37673... usw
und auf der Gegenseite, die die gleiche CPU hat alles zurückbauen in den gleichen Struct. ggf. mit Packed arbeiten. Das geht mit atoi und strncpy ganz einfach. Checksumme hintendran und fertig.
wenn man leichter debuggen will, dann ist ein "Plain-Text" sicher von Vorteil, aber binäre Daten brauchen weniger Platz
"Plain-Text" kann auch zur Plausibliätsprüfung verwendet werden, Zahlen enthalten keine Buchstaben oder Sonderzeichen
als Delimiter ist ';' üblich, Merkhilfe: De_limiter kommt von Limit (wer noch nie etwas falsch geschrieben hat, der werfe den ersten Stein, aber Hinweise helfen es in Zukunft besser zu machen)
Formatierungsangaben (%02d oder %2d machen nur Sinn, wenn der gesamte Datensatz immer gleich lang sein soll und helfen nur wenn die Platzreserve genügen groß ist (z.B. 4711 braucht mindestens %04d oder %4d)
BEGIN und END bzw. STX und ETX sind nicht notwendig, da die Daten in TCP/IP bzw. UDP/IP eingebettet sind
eine Stunde hat 60 und nicht 100 Minuten, also stunde = zeit_in_minuten / 60; minuten = zeit_in_minuten % 60;
"Plain Text" abstelle von binäre Daten macht Sinn wenn zwischen verschiedenen Rechnerplattformen kommuniziert wird. Stichwort: Byteorder
BEGIN,1245,020523,12.56,28.5,100,200,END
Startsignatur, Uhrzeit hhmm, Datum ttmmyy, %.2f float, %.2ffloat,
int,int, END
Bei Zeit-/Datums-Angaben hält man sich vorteilhafterweise an die ISO 8601.
Zusammenfassung (aus https://de.wikipedia.org/wiki/ISO_8601):
"Die Norm enthält verschiedene Datums- und Zeitformate, die jedoch rein formal und in den meisten Fällen schon durch die Anzahl der verwendeten Ziffern unterscheidbar sind. Die Norm ist vor allem bekannt für das Datumsformat YYYY-MM-DD, das oft auch als „internationales Datumsformat“ bezeichnet wird. Das üblichste Zeitformat der Norm ist hh:mm:ss. Ein Beispiel für das Datum ist 2004-06-14 (14. Juni 2004) und für die Uhrzeit 23:34:30 (23 Uhr, 34 Minuten und 30 Sekunden) und für beides zusammen 2004-06-14T23:34:30."
Bei Zeit-/Datums-Angaben hält man sich vorteilhafterweise an die ISO
8601.
Welchen Vorteil bietet das? Wenn die Datums-/Zeitangabe in einer Datenbank gespeichert werden soll, d'accord, aber wenn nur zwei µCs miteinander reden, würde das alte Unix-Zeitformat (Sekunden seit 1970) völlig ausreichen, oder eine Abwandlung mit bekanntem festen Offset, damit das Jahr-2038-Problem verzögert wird. So etwas ist erheblich simpler zu parsen (eine Zahl, mehr nicht) und reicht völlig aus, um z.B. zwei Softwareuhren zu synchronisieren.
Bei Zeit-/Datums-Angaben hält man sich vorteilhafterweise an die ISO
8601.
Welchen Vorteil bietet das? Wenn die Datums-/Zeitangabe in einer
Datenbank gespeichert werden soll, d'accord, aber wenn nur zwei µCs
miteinander reden, würde das alte Unix-Zeitformat (Sekunden seit 1970)
völlig ausreichen, oder eine Abwandlung mit bekanntem festen Offset,
damit das Jahr-2038-Problem verzögert wird. So etwas ist erheblich
simpler zu parsen (eine Zahl, mehr nicht) und reicht völlig aus, um z.B.
zwei Softwareuhren zu synchronisieren.
Und hat zusätzlich den nicht zu unterschätzenden Vorteil, daß Alarmzeitpunkte mit einem einzigen Vergleich erkannt werden können.
Der einzige Nachteil: Es ist halt nicht menschenlesbar, was bei der Fehlersuche etwas lästig sein kann. Aber wie oft will man sich schon das Gelaber von Microcontrollern ansehen?
Der einzige Nachteil: Es ist halt nicht menschenlesbar, was bei der
Fehlersuche etwas lästig sein kann. Aber wie oft will man sich schon das
Gelaber von Microcontrollern ansehen?
Das wird aber -besonders von Anfänger- vollkommen überbewertet.
Der effektive Anteil der menschen-lesbaren Ein- und Ausgaben in einem Programm ist -gemessen an den Taktzyklen- i.d.R. verschwindend gering.
Kommt drauf an, in welcher Häuftigkeit entsprechende Telegramme in einer Kommunikation verwendet werden. Und je nach Schnittstelle kann auch die reine Telegrammlänge relevant sein (hier nicht, hier wird Netzwerk genutzt, aber es gibt ja auch serielle Schnittstellen, die mit ganz erheblich geringeren Datenraten arbeiten).
Wenn nur alle paar Sekunden oder gar Minuten so ein Telegramm ausgetauscht wird, ist die für das Erstellen und Zerlegen erforderliche Rechenleistung ziemlich sicher völlig wurscht, wenn aber so etwas mit höherer Datenrate übertragen wird, kann die Angelegenheit schon sehr anders aussehen.
Man muss sich also schon auch das Umfeld und das Anwendungsszenario betrachten, bevor man sich für eine bestimmte Lösung entscheidet. Andererseits: eine programmiertechnisch simplere Lösung richtet selten Schaden an, auch wenn es nicht auf Performance, Codegröße o.ä. ankommt.
Man muss sich also schon auch das Umfeld und das Anwendungsszenario
betrachten, bevor man sich für eine bestimmte Lösung entscheidet.
Andererseits: eine programmiertechnisch simplere Lösung richtet selten
Schaden an, auch wenn es nicht auf Performance, Codegröße o.ä. ankommt.
Nein, das muß man in so einem Fall nicht.
Menschen-lesbare Ausgaben sind immer die absolute Ausnahme gemessen am tatsächlichen Programflow.
Solche Ausgaben erfolgen maximal nur wenige Male pro Sekunde, und in der Zwischenzeit dreht dein µC Millionen Runden.
Das seltene Umstellen in Menschen-lesbare Form fällt da absolut nicht mehr ins Gewicht.
Eine zusätzliche Debug-Funktion, die so einen Wert lesbar ausgibt hat man sich auch schnell geschrieben.
Mit Unix- oder Epoch-Time lässt sich nun mal ausnahmslos sehr viel besser und effizienter arbeiten.
Ausserdem finden sich in der Standardlib auch gleich so praktische Dinge wie die Ermittlung des Wochentags etc.
das alte Unix-Zeitformat (Sekunden seit 1970) völlig ausreichen, oder
eine Abwandlung mit bekanntem festen Offset, damit das Jahr-2038-Problem
verzögert wird.
Mikrosekunden seit 1.1.1970. Dann braucht man eh 64 Bit, und dann hat man kein 2038-Problem mehr ...
Schluss mit dem sscanf Zirkus, so sieht es jetzt aus und den Code habe nicht ich geschrieben sonder ChatGPT mit der Eingabe des Structs als Input und der Aufforderung die daten zu verpacken. Noch ein wenig dran herum geschliffen und der Client sieht jetzt ganz sauber das hier und das steht auch in den Variablen nach dem parsen des Strings.
Und eines begrüsse ich wirklich bei KI wie ChatGPT: Dinge, die man nicht wirklich verstehen muss, die einfach nur funktionieren sollen, dafür ist dieses Tool klasse. Denn die Einarbeitung in JSON interessiert mich überhaupt nicht weil ich das ganz sicher nie wieder nutzen werde oder nur rudimentär. In einem anderen projekt mit den Wetterdaten musste JSON5 auf JSON6 portiert werden, auch den Code hat er oder besser es einwandfrei gemeistert.