Forum: PC-Programmierung Javascript und HTML in C von ESP32


von Olli Z. (z80freak)


Lesenswert?

Wenn ihr sowas wie JS, CSS oder HTML in euren Embedd-Projekten mit 
integriertem Webserver verwendet, baut ihr das dann als static const 
char JS[] Array ein? Welche Methoden nutzt ihr dafür?

Ich mache das aktuell noch als ein Array, aber teilweise sind das 
200-300 Zeilen und man muss höllisch aufpassen keinen Escape- oder 
Comment-Fehler zu machen. Ganz davon ab ist der Code nicht mehr 
lesbar...

: Bearbeitet durch User
von Richie (mikro123)


Lesenswert?

Entweder Du baust die automatische Datei-Konvertierung in Deinen 
Build-Prozess ein oder aber, da Du ja einen ESP32 nutzt, Du legst die 
Dateien auf einer eigenen Partition in einem Dateisystem im Flash ab und 
liest die Dateien dann per Storage API ein.
Das Kopieren der Dateien in die Partition geschieht automatisch beim 
Build im esp-idf.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

https://www.mikrocontroller.net/articles/Bin%C3%A4re_Daten_zum_Programm_hinzuf%C3%BCgen

Was mit Binärdaten funktioniert klappt natürlich auch mit Text (HTML 
etc). Ich finde die Variante mit objcopy am Besten - kompiliert sehr 
schnell und funktioniert entkoppelt vom Sourcecode.

: Bearbeitet durch User
von Alexander (alecxs)


Lesenswert?

Die Dateien liegen bei mir auf dem Dateisystem und werden über HTTP_GET 
aufgerufen.
1
#include <ESPAsyncWebServer.h>
2
server.on("/settings", HTTP_GET, [](AsyncWebServerRequest *req){
3
  req->send(LittleFS, "/settings.html", "text/html");
4
});

von N. M. (mani)


Lesenswert?

Definitiv Files, keine C-Strings.
Ansonsten bist du nur noch am kopieren. Und unübersichtlich ist es auch.
Wenn du noch Platz und Ladezeit sparen willst lässt du dir die großen 
Files noch in einem Prebuild step in einen neuen Ordner zippen.

Dann installierst du dir noch sowas wie den Live Server in VSC und 
kannst auch gleich noch vernünftig die Website anschauen und debuggen.

von Alexander (alecxs)


Lesenswert?

Wenn's schnell gehen muss.
1
$ xxd -i index.html > index.h

von Christoph M. (mchris)


Lesenswert?

Micropython ist für einen Webserver auch nicht schlecht:
Beitrag "Re: Micropython Wetterstation"

von Claus P. (claus_p846)


Lesenswert?

ich verwende einen Raw-String:
1
const String htmlHeader = R"---(<!DOCTYPE HTML>
2
<head>
3
<meta charset="utf-8">
4
<meta name="viewport" content="width=device-width, initial-scale=1">
5
</head>
6
)---";

Die Strings lassen sich mit += leicht konkatenieren und JavaScript code 
kann man einfach so runterschreiben.

von Εrnst B. (ernst)


Lesenswert?

Claus P. schrieb:
> ich verwende einen Raw-String:
> Die Strings lassen sich mit += leicht konkatenieren

Das klappt halt nur bei kleinen Webseiten gut, weswegen es viele 
ESP-Beispiele nach dem Schema gibt.

Aber sobald die Seite komplizierter wird, kann das zu schwer zu 
debuggenden Fehlern führen, weil der Speicher ausgeht oder zu stark 
fragmentiert.

Dein HTML-Code liegt einmal im Flash, wird dann beim String-anlegen in 
den RAM kopiert, und jedes "+=" legt potentiell nochmal eine Kopie vom 
gesamten String im RAM an.

Und die Antwort wird erst gesendet, wenn der ganze HTML-String fertig 
ist.

Bei der Lösung als Dateien im LittleFS mit dem AsyncWebserver entfallen 
diese Probleme. Große Dateien werden Blockweise gestreamt, es ist immer 
nur der gerade versendete Chunk im RAM, der HTTP-Antwort-Header und die 
Ersten Daten wandern schon zum Webbrowser, bevor die ganze Datei 
überhaupt gelesen ist.

Über die Template-Engine kannst du auch da dynamisch Werte/Texte 
einsetzen.

=> Für kleine Demo-Projekte kann man das mit den Strings machen, wenn 
absehbar ist dass es evtl. etwas umfangreicher wird, würde ich gleich 
auf eine skalierbare Lösung setzen, und mir das Umbauen später sparen.

von Alexander (alecxs)


Lesenswert?

Claus P. schrieb:
> ich verwende einen Raw-String

Dann brauchst Du aber noch ein sed für die Escapes.

Alexander schrieb:
> Die Dateien liegen bei mir auf dem Dateisystem

Hab hier mal ein Template als Demo erstellt.

https://www.mikrocontroller.net/topic/goto_post/8019977

von Εrnst B. (ernst)


Lesenswert?

Alexander schrieb:
> Dann brauchst Du aber noch ein sed für die Escapes.

Beim RAW-String? Da kannst du den String-Ende-Marker selber festlegen, 
und der darf aus bis zu 16 Zeichen bestehen. Da was zu wählen, was 
garantiert nie im HTML vorkommt, sollte möglich sein.
Statt R"---(html)---" geht auch
R"Aetioth3ee6eep5u(html)Aetioth3ee6eep5u"

von Alexander (alecxs)


Lesenswert?

Achso das ist wieder so ein C++ Standard. Okay.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

1
#embed "datei.js"

von Obelix X. (obelix)


Lesenswert?

Johann L. schrieb:
> #embed "datei.js"

Wird das vom ESP32 Compiler unterstützt?

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Obelix X. schrieb:
> Johann L. schrieb:
>> #embed "datei.js"
>
> Wird das vom ESP32 Compiler unterstützt?

Ist im C-Standard.

von Harald K. (kirnbichler)


Lesenswert?

Johann L. schrieb:
> Ist im C-Standard.

In C23. Das ist noch ziemlich frisch; es dürfte noch sehr viele Compiler 
geben, die davon nichts wissen.

https://en.cppreference.com/w/c/preprocessor/embed

von Ben B. (Firma: Funkenflug Industries) (stromkraft)


Lesenswert?

Also bei mir schwankt das. Die meisten Webseiten bastle ich mir sowieso 
außerhalb des ESP, dann muss ich sie nur einmal in den Quellcode 
kopieren und kann sie anschließend "vergessen". Geschmackssache, ich 
habe am Ende gerne alles in einer einzigen Datei.

von Pandur S. (jetztnicht)


Lesenswert?

Weshalb sollte man sich Strings vom flash ins Ram kopieren ? Die sind 
doch auch gut im flash, gleichwertig, sofern der compiler das so kann.

von Εrnst B. (ernst)


Lesenswert?

Pandur S. schrieb:
> Weshalb sollte man sich Strings vom flash ins Ram kopieren

Copy&Paste-Geschichte. Es gibt Berge an Arduino-Beispielen nach dem 
Schema
1
String response="<html>";
2
response += "<head>";
3
...

Viele Leute übernehmen das ohne Nachzudenken, und schon existiert ein 
weiteres Beispiel nach dem Schema.

Jetzt kommt noch die KI dazu, die mit all diesem Code trainiert wurde, 
und logischerweise wird die dann auch sowas ausspucken...

Aus dem Teufelskreis werden wir nicht mehr herauskommen, fürchte ich.

Aber egal, die nächste µC-Generation hat wieder mehr RAM und 
Rechenleistung, das ist sicher alles fein.

von Flunder (flunder)


Lesenswert?

String ist nicht für statische Daten gedacht und legt bestimmt auch ein 
Objekt im Speicher an. Da ist dann echt das olle Array of Char 
passender.

Wenn man das im make Prozess mit generieren kann, gibt es auch keine 
Probleme mit Zeichen, die vergessen wurden beim Escapes einfügen. Gibt 
es xxd auch für Windows (oder noch DOS) ? Ich habe unter Windows dafür 
HxD benutzt. Allerdings leider nicht aus dem Makefile, sondern im 
Handbetrieb.

Könnte man statische Dateien nicht auch auf einen potenteren Server, der 
im Internet hängt auslagern und von da einbinden ? Oder blockt da der 
Browser aus Sicherheitsbedenken ?

Den Kram gepackt im Speicher abzulegen bringt doch erst was, wenn die 
Platzersparnis den Platzbedarf der Entpackroutine übersteigt. Und 
zeitlich dürfte das Entpacken so gut wie immer verlieren.

Was hier wunderbar funktioniert hat, ist die .html Dateien in dem Sinne 
zu packen, dass man alle Zeichen rauswirft, die nichts an der 
Darstellung im Browser ändern. Also auf Gliederungen durch Einrückungen 
und Zeilenumbrüche im Quelltext verzichtet und dem Browser gleich sagt, 
hier kommt UTF8, das kannst Du Punkt und dafür keine Umschreibungen wie
1
&auml;
 mehr braucht. Auch dafür gibt es Software, die Dateien entsprechend 
tuned.

Ehrlich gesagt, habe ich mir dieses Filesystem im ESP32 noch nicht 
angeschaut. Im Endeffekt, legt das doch bestimmt auch die Datem mit ein 
paar Verwaltungsdaten im Flash ab, oder ? Den Vorteil sehe ich dann, 
wenn ich öfter mal meine Software updaten muss, aber die riesigen Daten 
gleich bleiben, dann geht das flashen schneller. Die liegen doch 
bestimmt auch im Flash, oder ? Bzw. kann ich den Bereich für das 
Filesystem auf nahezu null schrauben, um den Platz dann für Daten, die 
sich in meinem Programmcode verstecken, frei zu machen ?


Der ESP32 hat doch keine Harvard Architektur, bei dem die Daten mühsam 
vom Programmspeicher in den Datenspeicher geschafft werden müssten.

von N. M. (mani)


Lesenswert?

Flunder schrieb:
> Könnte man statische Dateien nicht auch auf einen potenteren Server, der
> im Internet hängt auslagern und von da einbinden ?

Könnte man machen. Dann verliert man aber meiner Meinung nach genau den 
Vorteil eines solchen Systems. Alles Lokal und unabhängig von anderen 
Systemen zu haben.
Du willst das Webinterface deiner Heizung ja evtl noch aufrufen wenn das 
Internet gerade nicht geht oder der externe Server gerade nicht 
erreichbar ist.

Flunder schrieb:
> Oder blockt da der Browser aus Sicherheitsbedenken ?

Lies mal zu CORS (Cross-Origin Resource Sharing) nach. Geht schon.

Flunder schrieb:
> Den Kram gepackt im Speicher abzulegen bringt doch erst was, wenn die
> Platzersparnis den Platzbedarf der Entpackroutine übersteigt. Und
> zeitlich dürfte das Entpacken so gut wie immer verlieren.

Entpackt wird ja nicht auf deinem uC. Sondern im Browser.
Du sparst so auf 2 weisen. Der Controller braucht nicht so viel Speicher 
und du kannst es deutlich schneller übertragen. Geht wirklich verdammt 
schnell das entpacken.
So hab ich schon mehr als 4MB Daten und viele JS Libraries in einem 2MB 
Controller abgelegt. Und da war noch das eigentliche Programm 
(Webserver,Applikation,...) dabei.

Flunder schrieb:
> Was hier wunderbar funktioniert hat, ist die .html Dateien in dem Sinne
> zu packen, dass man alle Zeichen rauswirft,

Ist verschwendete Liebesmühe. Wenn du die Datei komprimierst macht das 
so gut wie keinen Unterschied. Der HTML/JS Code schrumpft ziemlich 
extrem zusammen durch die Komprimierung.

Flunder schrieb:
> Ehrlich gesagt, habe ich mir dieses Filesystem im ESP32 noch nicht
> angeschaut. Im Endeffekt, legt das doch bestimmt auch die Datem mit ein
> paar Verwaltungsdaten im Flash ab, oder ?

Ja klar. Ist ja nach System einfach ein FAT. Halt nicht auf SD Card 
sondern im Flash.

Flunder schrieb:
> Den Vorteil sehe ich dann, wenn ich öfter mal meine Software updaten
> muss,

Du kannst dadurch aussehen und Funktion komplett trennen. Ein Update des 
Webinterface bedingt dann kein neues Kompilieren. Du kannst einfach die 
neuen Dateien hochladen.
Funktionserweiterungen die in Webinterface genauso.
Nur Änderungen im CPP Programm musst du dann anders updaten. Wobei das 
auch über  OTA möglich ist.

Außerdem macht es das Handling während der Entwicklung deutlich 
komfortabler.

Die ganzen Webfiles liegen einfach als normale Dateien im Projekt ohne 
etwas konvertieren oder Kompilieren zu müssen.
Wenn man dann noch irgendein Webserver Plugin für seine IDE verwendet 
(z.B. Liveserver o.ä) kann man den ganzen Webcode sehr komfortabel 
entwickeln. Und wenn man fertig ist läd man nur die neuen Dateien hoch.

von Vincent H. (vinci)


Lesenswert?

Das Problem an den ganzen Dateisystem Lösungen des ESP-IDF is, dass die 
alle globale Critical Sections haben. Sprich die würgen einfach mal so 
sämtliche User-Level Interrupts ab. Damit eignen sie sich nur für sehr 
zeitunkritische Anwendungen.

Für die objcopy Variante bietet Espressif eine CMake Funktion namens 
"target_add_binary_data", siehe: 
https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/storage/index.html

Das is zwar performanter, bringt aber eine ganz andere Reihe an 
Problemen mit sich...

Ich selbst hab eine Web-Anwendung die ich via CMake auf einen ESP32S3 
packe und dafür sind folgende Schritte notwendig:
- Clonen des Releases
- Ordner Struktur abflachen
- gzippen aller Datein (optional)
- Code Generierung eines constexpr LUT der die Datein in ihre 
ursprünglichen Pfade mapped

Das is schon alles ziemlich PITA...

von Alexander (alecxs)


Lesenswert?

Flunder schrieb:
> Ehrlich gesagt, habe ich mir dieses Filesystem im ESP32 noch nicht
> angeschaut.

Dann mach das mal.

Flunder schrieb:
> Bzw. kann ich den Bereich für das Filesystem auf nahezu null schrauben,
> um den Platz dann für Daten, die sich in meinem Programmcode verstecken,
> frei zu machen?

In Arduino gibt's da Vorschläge für Partitionsschemata zur Auswahl über 
das Menü, z.B. huge_app.csv man kann aber auch eine custom 
partitions.csv im Sketch Ordner ablegen.

https://github.com/espressif/arduino-esp32/tree/master/tools/partitions

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.