[Gelöst!] ESP8266 - Formularoptionen speichern und einlesen

Hallo liebe Forenmitglieder,

ich bin neu hier und habe eine Frage an euch.

In einem Projekt starte ich im setup() auf einem ESP8266 mit server.on(...) eine login.html Webseite mit 3 Eingabefeldern (SSID, PASSWORD, ROUTER). Beim Absenden speichere ich die Inhalte der 3 Felder im server.on(...HTTP_POST...), indem ich die request->params() interiere, die Feldwerte auslese und in Textdateien (ssid.txt, pass.txt und router.txt) per LittleFS() schreibe. Das klappt alles hervorragend und jetzt die Frage:

Beim Öffnen der login.html über server.on(...HTTP_GET...) lese ich die drei Textdateien wieder in Variablen ein - klappt super!. Mein Problem ist nun aber, dass ich die Werte aus den 3 Variablen gerne wieder in die Textfelder der login.html schreiben möchte um diese Werte "quasi" als "Vorgabe" anzubieten.

Ich habe hier dann doch noch zu wenig Ahnung wie ich das am Besten anstellen sollte. Per Script und "document.getElementByID()" oder irgendwie ganz anders mit Events(OnLoad...) ? Das Laden, ausfüllen, speichern in Textdateien und Einlesen in Variablen klappt super, aber der letzte Schritt um die Daten wieder im FOrmular anzuzeigen fehlt mir hier leider.

Könnt Ihr mir hier irgendwie weiterhelfen (Code.Snipet etc.) und ein paar Tipps an die Hand geben?

Ganz lieben Dank und ich hoffe, dass ich mein Problem ausreichend gut beschreiben konnte.

Lieben Dank für eure Hilfe und bleibt gesund,
Manfred

Entweder Du schreibst die Werte vor der Antwort in den Text der Webseite oder Du überträgst die Daten anschließendper Fetch-API und setzt sie dann (wie bereits von Dir vermutet) per document.getElementByID().

Beispiele gibt es dafür bei Fips.

Gruß Tommy

du könntest im Attribut value des jeweiligen Eingabefeldes den aktuellen Wert bereits mit rausschicken.
Das Passwort würde ich als type password definieren.
(dass es trotzdem in Klartext rausgeschickt wird, soll klar sein).

    message += F("<form action='#' method='POST'>"
                 "<p>" TXT_WIFI
                 " (mode=");
    message += WiFi.getMode();   // WIFI_OFF = 0, WIFI_STA = 1, WIFI_AP = 2, WIFI_AP_STA = 3
    message += " ";
    message += txtWifiMode[WiFi.getMode()];
    message += F(")</p>"
                 "<p><input class='col3' name='wifissid' value='");
    message += getWifiSSID();  // wo auch immer das bei dir steht
    message += F("'><br>"
                 "<input class='col3' name='wifipwd' type='password' value='");
    message += getWifiPWD(); // wo auch immer das bei dir steht
    message += F("'>"
                 "<input class='col2' type='submit' value='" TXT_SAVE "'>"
                 "</p>"
                 "</form>\n");

Wofür soll es gut sein, das Passwort in einem Login-Formular vorauszufüllen?

Dann lieber nur die SSID füllen und wenn diese geändert wird, ein neues Passwort dazu verlangen, sonst das gespeicherte Passwort verwenden.

Gruß Tommy

Hallo Tommy56 und noiasca,

Danke für die superschnelle Rückmeldung im Thread. Nun, ich liefere im setup() ja eine komplette Webseite aus wie folgt:

    // Web-Server soll Login-Webseite öffnen
    server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
      request->send(LittleFS, "/login.html", "text/html");
    });
    server.serveStatic("/", LittleFS, "/");

Zuvor lese ich die gespeicherten Feldwerte in entsprechende Variablen ein:

  // Lese Datendateien in Variable ein
  ssid = readFile(LittleFS, ssidPath);  // steht für ssid.txt u.s.w.
  pass = readFile(LittleFS, passPath);
 router = readFile(LittleFS, routerPath);

Wie komme ich also wenn die Seite per HTTP_GET bereits geladen ist z.B. per

document.getElementByID().value = router;

an die Felder ran. Da hab ich echt noch zu wenig Ahnung, aber ich lerne sehr gerne dazu :wink:

LG
Manfred

Dann schau Dir die Beispiele Bei Fips an, wie ich Dir geraten habe und verstehe diese. Da hast Du alles was Du brauchst.
Wenn Du und sie Info, dass die Seite im LittleFS liegt, gleich gegeben hättest, hätte einiges weg fallen können.

Gruß Tommy

Hey Thommy56,

ich möchte (neben der SSID und dem Passwort) eben auch den zuletzt verwendeten Router mit Angeben wollen. Das Smarthome-Gerät soll ja flexibel an unetrschiedlichen Routern genutzt werden können und es wäre toll, wenn der zuletzt genutzte Router (wegen SSID und PASSWORT) angezeigt wird.

LG
Manfred

Hallo Tommy56,

das mit der FetchAPI klingt spannend. Gibt es da ein Beispielcode?

Das Ding ist eben, dass die Webseite ja als Datei geladen wird und man dann nachträglich ran müsste. Ich wäre für jede Idee oder Snippet dankbar. Bei Fips habe ich nichts passendes gefunden, das dortige Login-Formular kann ich so nicht umsetzen.

LG
Manfred

Dann schaue Dir die anderen Beispiele bei ihm an und verstehe, wie Fetch funktioniert. Dann kannst Du es auch auf Deine Forderungen anwenden. Das Erstellen von Programmen ist mehr als C&P.

Gruß Tommy

Hallo Tommy56,

ein super Tipp, dann werde ich mich wieder einige Stunden auf die Suche bei Fips machen. Ich dachte in einem Forum bekommt man vielleicht Starthilfe oder gar aktive Tipps/Code-Snippets, die dann z.B. angepasst werden können.

Ich habe hier schon viele code-samples von z.B. @Rentner oder @Derfips gesehen, die einem Fragenden sukkzesive mit aktiven Snippets und Codes zum Ergebnis geholfen haben, das Glück ist mir hier aber wohl nicht vergönnt. :cry:

Übrigens, mein Sketch hat schon über 400 Codezeilen - alles selber und sauber programmiert und läuft einwandfrei - nix mit Copy/Paste. Und Copy-Paste kann man meist auch nur dann machen, wenn man auch was zum Einfügen bekommt :wink:

Klar, ich bin ein Einsteiger, aber umso mehr auf Hilfe oder besser noch Code-Beispiele angewiesen. Mit "schau mal hier oder dort und versuche zu verstehen" wirds dann schwierig - aber ist hier wohl so. Ich steh eben jetzt vor einem neuen Problem und bat deswegen um Hilfe. Interaktion, Samples und Tipps helfen in der Regel wesentlich effizienter als auf Textstellen zu verweisen.

Dennoch Danke und sonnige Grüße,
Manfred

Hallo noiasca,

das Speichern der Feldwerte bei /HTTP_POST ist schnell gemacht und ich schreib die Daten dann in Textdateien. Beim Starten des ESP hole ich mir dir gespeicherten Feldinhalte im setup() wieder in Variablen wie folgt:

  // Lese Datendatei in Variable ein
  ssid = readFile(LittleFS, ssidPath);
  pass = readFile(LittleFS, passPath);

Nachdem ich die WiFi-Connection gestartet habe, lade ich mir die HTML-Seite direkt aus dem LittleFS() vom ESP

    server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
      request->send(LittleFS, "/index.html", "text/html");
    });

insofern müsste ich dann auf die fertig geladene Seite bzw. deren Felder zugreifen. Mit FetchAPI hab ich bisher noch nichts gemacht und ist mir auch völlig neu.

Bis dahin passt ja alles und läuft auch. Nun brauche ich eben eine Lösung, wie ich nach geladener Webseite die bereits eingelesenen Variablenwerte wieder in die Felder zurückschreibe. Ich hab inzwischen gelesen, dass es hier mehrere Ansätze gäbe (u.a. FetchAPI).

Kann ich denn z.B. mit events.onLoad() da was bewegen? Oder sollte ich in der login.html mit scripts arbeiten. Da bin ich aber auch nicht wirklich so fit :flushed:

Ich würde mich freuen wenn es hierfür irgend einen einen Lösungsansatz gäbe.

Merci!
Manfred

Hallo,
Du hast ja eigentlich das Problem das Du eine Datei vom LittleFS als statische Webseite auf den Brauser bringst und nun aber noch die Variablen auf die Seite bringen musst.

Entweder sendest Du die HTML Seite schon mit der Variablen und baust vorher alles zu einem String zusammen den Du dann versendest, das ist der Vorschlag von @noiasca weiter oben. Das geht aber schlecht wenn die HTML auf dem FS liegt. Mann könnte in der HTML Platzhalter einbauen, die Datei in einen C-String einlesen und dann mittels Sprintf() ergänzen alles versenden. Geht auch ist aber Murx.
Ich habe mal irgendwo gelesen das die AsynchronWebServer Lib mit Platzhaltern arbeiten kann, damit sollte das gehen. Ich hab das aber noch nicht damit gemacht.

Die letztlich einfachste Lösung ist allerdings tatsächlich fetch zu verwenden. Anfänglich sieht das sehr kompliziert und aufwendig aus, aber wenn man es mal verstanden hat ist es recht einfach. Ich hab vor einiger Zeit mal was dazu geschrieben. Inzwischen ist das allerdings nicht mehr ganz auf dem technisch aktuellen Stand. https://www.wikinger-tommy.de/rentner/index.html. Aber eventuell zum Verständnis geeignet.
Heinz

Hallo Heinz,

ich Danke dir für die Rückmeldung.

Hmmm, die *.html könnte ich tatsächlich recht einfach einlesen und danach mit den bereits eingelesenen Variablenwerten "zusammenbauen". Die Info mit den Platzhaltern beim AsyncWebServer finde ich natürlich auch toll, da werde ich mich mal reinfuchsen.

Und ja, die FetchAPI erschlägt einen beim "ersten" Kontakt tatsächlich. Diese Option halte ich mir als Plan-B im Background. Mein Problem ist, dass mein Projekt fast komplettiert ist und nur noch die Feldwerte in die HTML-Felder geschrieben werden müssten.

Also, Ärmel hoch und los ... villeicht gibts ja noch die eine oder andere Idee nebst code-snippet :wink:

Danke für deine klasse Tipps und bleib gesund,
Manfred

Hallo Heinz,

nun bin ich an einer Stelle wo es (mommentan) nicht mehr weitergeht. Ich habe nun die Webseite(n) als char-Konstanten angelegt und arbeite mit der processor-Funktion zum ersetzen. Das klappt alles recht ordentlich.

Beim Speichern der Optionen-Form lese ich die request-Params aus und speichere diese in Variablen und einer JSON-Datei (Wertepaar). Läuft sauber und per serial.print() erhalte ich auch alle Werte der Optionsfelder wie folgt (Auszug!):

    // Optionen-Seite soll bei POST Variablenfelder speichern
    server.on("/", HTTP_POST, [](AsyncWebServerRequest *request){
      int params = request->params();

      // Anzahl Parameter durchlaufen und auslesen
      for (int i=0; i<params; i++){
        AsyncWebParameter* p = request->getParam(i);
        if(p->isPost()){
          // HTTP-Post stationname-Wert
          if(p->name() == PARAM_INPUT_10){
            stationname = p->value().c_str();

Wenn ich nun die Optionen-Seite aufrufe, sollen per prozessor()-Funktion die Optionen wieder gesetzt werden. Das klappt auch optimal bei Textfeldern, nur beiCheckboxen und Select-Auswahlfeldern klappt das so gar nicht. Hier auch mal einen Auszug aus dem Aufruf und der Funktion:

    // Optionen-Seite im Browser öffnen
    server.on("/options", HTTP_GET, [](AsyncWebServerRequest *request){
        request->send_P(200, "text/html", optionen_html, processor);
    });

.....

String processor(const String& var){
  if(var == "STATION_NAME"){
    return stationname;
  }
  if(var == "C1V"){
    return ch1alertvalue;

Bei Textfeldern kann ich problemlos den Wert über die value=""-Option und dem Platzhalter %STATION_NAME% setzen, so wie im folgenden Codeauszug:

            <div class="StationName">
              <label class="StationNameLabel">Ger&auml;tename</label>
              <input id="stationname" type="text" name="stationname" maxlength="20" value="%STATION_NAME%">

Bei Input-Feldern mit type=checkbox und auch bei select-Feldern mit option-Auswahlen kann ich keine Ersetzungen vornehmen bzw. Einträge über die prozessor-()-Funktion vorbelegen. Für das Input-Feld als checkbox bekomme ich beim Speichern den Text-Wert "on" wenn es gechecked ist. Bei den Select-Feldern bekomme ich beim Speichern die Klartext-Werte des gewählten ioption-Eintrags (im Beispiel "Temperatur"). Hier auch ein kurzes Snippet mit einem input als checkbox und einem select mit 3 Optionseinträgen:

 <div class="SwitchChannel1">
              <label>Kanal #1</label>
              <input class="CH1-OnOff" id="ch1onoff" type="checkbox" name="ch1onoff" value="%C1C%">
              <select id="selectsensor1" name="selectsensor1" selected="%C1S%">
                <option>Temperatur</option>
                <option>Luftfeuchte</option>
                <option>Luftqualität</option>
              </select> 
            </div>

Wie schaffe ich es nun beim HTTP_GET der Optionen-Seite (siehe oben) mit der processor()-Funktion die Checkboxen (Werte: on oder off) und die Select-Boxen (Werte: Temperatur, ...) zu setzen bzw. zu belegen?

Ich bin für jeden Tipp dankbar.

Sonnige Grüße und Merci,
Manfred

Da musst Du mal etwas in HTML rein schauen.
Für Checkboxen z.B. musst Du das wort "checked" schreiben, wenn sie angehakt sein soll. Beim select dann "selected"

Gruß Tommy

Hallo Thommy,

Danke für die schnellen Hinweise. Die Thematik ist mir bekannt, abe rdie Umsetzung der gespeicherten Werte in die Parameter ist das Problem. Bei Spiechern bekomme ich wie erwähnt für die markierte Checkbox den Text-Wert "on" geliefert. Den gilt es nun in der processor()-Funktion umzusetzen. Gleiches für die Select-Felder mit je 3 Werten. Beim Speichern bekomme ich den gewählten Wert als Text zurück (z.B. "Temperatur").

Die Struktur der processor()-Funktion erlaubt ja nur in Abhängigkeit einer Variablen (%XYZ%) einen Returnwert (String) zu setzen. Beim Select gibt es 3 Möglichkeiten, aber nur einen Return-Wert. Hier hab ich aber gerade einen Knoten in der "Denke" - vielleicht ist es ja auch ganz einfach umzusetzen.

Puuuh, vielleicht kann man es ja auch ganz anders auflösen ....

Denke bis hierhin,
Manfred

Für die Checkbox musst Du ermitteln, ob die auf "on" (besser wäre ein bool true/false)steht und wenn ja %XYZ% durch "checked" ersetzen, sonst durch "".
Für den Select wirst Du über ein Array mit den Werten iterieren müssen, bis Du die Übereinstimmung findest.

Es gibt natürlich andere Wege, z.B. die Werte aus der Seite per Fetch-API und Javascript holen und dann im Browser einbauen. Beispiele
dazu gibt es bei Fips.
Egal welchen Weg Du nehmen willst, irgendetwas musst Du programmieren.

Gruß Tommy

Hallo,
Das HTML Elemente haben ja oft eine Unmenge an Eigenschaften, wie Du da mit der prozessor() Funktion drauf zugreifen kannst sollte in der Doku zum Asynchron Webserver stehen, wenn das überhaupt geht. Ich habe den noch nie benutzt.
Die Eigenschaften mit in den HTML code packen und mit einem Platzhalter vorbesetzen eventuell

https://wiki.selfhtml.org/wiki/HTML/Elemente/input
in Deinem Fall halt die Eigenschaften checked und selectedIndex.

Nun ja es gibt eine andere Möglichkeit. Java-Skript da kannst Du beliebig auf die Eigenschaften lesend und schreibend zugreifen. z.B auf das ausgewählte Element einer Select-Liste hier den Index des ausgewählten Eintrages aus einem Json Array

document.form.Einheit.selectedIndex=array[4];

Heinz

Nachtrag
ich hab noch was gelesen schau mal hier.
https://wiki.selfhtml.org/wiki/HTML/Tutorials/Formulare/Auswahllisten

@Tommy56 und Heinz,

ich habe nun eine passende Lösung gefunden. Danke an Tommy56 für die Hinweise mit "checked" und "selected". Ich habe nun mit der processor()-Funktion eine entsprechende Auswerte-Logic programmiert, die alle Komponenten (Checkbox, Select etc.) iteriert, mit dem Soll-Wert vergleicht und die entsprechenden Flags (checked, selected etc.) über die Parameter ersetzt. So werden alle gelesenen Werte beim Anzeigen (HTTP_GET) über die Funktion korrekt egsetzt.

Juhuuuuu, jetzt kann es weitergehen, das Projekt ist bald fertig!

Merci an euch beide und ein schönes WE,
Manfred

Läuft Kugelrund :wink: und sogar rasend schnell (wobei ich da ja auxch kein Timing-Problem habe)

Prima und danke für die Rückmeldung.

Gruß Tommy