Arduino/Webserver Fetch. Verständnisprobleme

Hallo,

ich verzweifele seit langer Zeit am Fetch zwischen Arduino (bzw aktuell ESP32) und Webserver. Ich verstehe das ganze Konstrukt einfach nicht. Weiß jemand wo es eine simple Anleitung gibt?

Konkret geht es darum das ich 2 Werte auf einer Webseite eingebe. Value1 und Value2.
Diese Values möchte ich im ESP32 zurück lesen. Am liebsten würde ich die Values (auch für zukünftige Projekte) ins JSON Format packen, so das ich die Values beliebig ausdehen kann. Es werden später mal über 80 verschiedene Values benötigt

Hat jemand vielleicht ein simples Beispiel für mich was er mir hier rein kopieren kann?

Also Webseite: Input Value1, Input Value2, Submit
ESP32: Get Value1/Value2 (als JSON) und serial.print Value1, Value2

Ihr würdet mir sehr sehr helfen. Vielen Dank!

Hi Tobi,
Du teilst dem ESP webserver einen Endpunkt mit
webServer.on("/values", handle_values);
Dann holst Du Dir die Werte raus:

void handle_values(){
for (uint8_t i = 0; i < webServer.args(); i++) {
    Serial.println(String(F(" ")) + webServer.argName(i) + F(": ") + webServer.arg(i));
    [...]
    }
}

Seitens der Webseite kannst Du nun mit Submit arbeiten oder per JavaScript.
Stichwort XMLHttpRequest()

Hallo,
schau dich mal bei Fips um https://fipsok.de/
Da findest Du viele Beispiele. Oder auch bei Werner
ESP8266 Webserver - Webclient - Kommunikation zwischen zwei ESP

wenn Du ganz einfach anfangen willst kannst Du dir auch mein Geschreibsel mal ansehen
https://www.wikinger-tommy.de/rentner/index.html

Heinz

1 Like

Ich hab ihn so verstanden, dass der ESP ein webclient ist, der eine fremde Webseite auf einem Server aufruft (?)...

Ich allerdings auch nicht.
Macht evtl. auch andersrum eher Sinn, und ESP Webserver ist das richtige Stichwort. Dann würde auch JavaScript/Fetch einen Sinn ergeben.

Auf dem ESP läuft mein Vorhaben nun mit dem Code (jedoch ohne JSON).

    server.on("/get", HTTP_GET, [] (AsyncWebServerRequest *request) {
    String inputMessage1;
    String inputMessage2;
    if (request->hasParam(PARAM_INPUT_1) && request->hasParam(PARAM_INPUT_2)) {
      inputMessage1 = request->getParam(PARAM_INPUT_1)->value();
      inputMessage2 = request->getParam(PARAM_INPUT_2)->value();
      //digitalWrite(inputMessage1.toInt(), inputMessage2.toInt());
    }
    else {
      inputMessage1 = "No message sent";
      inputMessage2 = "No message sent";

Der Knackpunkt ist die Gegenseite.
http://ip/get?value1=xxx&value2=xxx
kommt nun schön an. Wie verpacke ich die Values denn im Fetch, so das die Werte übetragen werden?

Nein, auf dem ESP liegt die Webseite im SPIFFS. Die Webseite soll später ein Gerät steuern, dazu werden zahlreiche Werte von der Webseite an den ESP32 übertragen, der wiederrum das Gerät über SPI ansteuert.

Für ein umfangreiches Json ist "GET" der falsche Ansatz. Verwende stattdessen "POST".

Beispiel:

async function save() {
  let form = new FormData(), data = [];
  .....
  form.append('dTime', JSON.stringify(data));	  
  const resp = await fetch('/timer', {method: 'post', body: form});
  const json = await resp.json();
}

Ich stehe leider komplett auf dem Schlauch und es wird immer schlimmer.

Kann mir jemand 2 Input Felder basteln, ein Submit Button und das dann in ein JSON Schreiben:
Input1: Value, Input2: Value. Das dann auf dem ESP32 entgegen nehmen?
Kann leider selbst nicht sagen warum mir das nicht in den Kopf will :frowning: Vielleicht würde mir das zum verständnis helfen

wozu ein JSON?
du hast ein Formular,
das Formular hat zwei Input Felder
du gibst dem Formular eine methode. zB. Post
du drückst auf SUBMIT
die zwei Felder werden vom Browser an die angegebene Server Resource übertragen
am ESP kannst du das mit server.arg, server.args, server.argName ... abfragen.

irgendwann kommt ein drittes eingabefeld hinzu.
Du erweiterst das Formular
server.args ist um eins mehr und der dritte Wert kann mit server.arg[2] abgefragt werden.

Warum willst du dir in dieser Phase das leben mit JSON schwer machen?

Ja, du hast wahrscheinlich recht. Web Programmierung ist für mich komplett neu. Und wie mache ich die 2 Eingabefelder und das Submit Button so das es in der Seite läuft und die Seite nicht neu lädt?

definiere einen Usecase was der ESP mit den zwei Werten machen soll. dann kann man ein Beispiel machen.

Sagen wir ... übergeben eines Farbwert für ein Neopixel? Das müsste am ESP32 gehen.
Oder hast was anderes vor? Irgendwas ohne weitere Abhängigkeit wäre besser...

und auf der gleichen Seite bleibt man mit einem einfach hack, du machst dir einen hidden iframe, und gibst als target deines Forms den Iframe an:

"<iframe name='i' style='display:none' ></iframe>\n" // hack to keep the button press in the window

übrigens, hier beschrieben:
https://werner.rothschopf.net/201809_arduino_esp8266_server_client_3.htm

1 Like

https://fipsok.de/Esp32-Webserver/input-esp32.tab

Erzeugt Html Input Elemente anhand der Anzahl der Datensätze in der map.
Für zwei Input Felder musst du halt einen Datensatz entfernen.

Im Prinzip genau so, jedoch brauche ich es umgekehrt. 2 Input Felder auf der Webseite die an den Arduino senden. Ich gebe es für heute auf, der Kopf will nicht mehr.
Konkret geht es um ein DA-Wandler Board was über SPI am Arduino hängt. Da sind 40 DA-Wandler drauf. Nun möchte ich z.B. an DAC4 den Wert 34232 senden. Dazu Eingabefeld DACx und Value auf der Webseite. Der Arduino nimmt die Daten entgegen und steuert über SPI den DAC 4 mit dem Wert 34232 an.

Dann ist es besser du schaust dir das morgen nochmal an.

Wo sollen denn die Input Elemente sonst sein, wenn nicht auf der Webseite. Es sind doch Html Elemente, die können doch nur vom Browser angezeigt werden.

das wäre ein rudimentäres - aber lauffähiges Beispiel für ein Form mit zwei Felder.

Im Prinzip nur das Webserver Beispiel.
Eine Root zur Ausgabe der Daten.
Eine neue Seite für das Form.
Eine Resource c.php zur Übernahme der Werte aus der Form

/*
  Process form data on a ESP32

  https://forum.arduino.cc/t/arduino-webserver-fetch-verstandnisprobleme/883380

  by noiasca
  2021-07-09 V2
 */

#include <WiFi.h>
#include <WiFiClient.h>
#include <WebServer.h>
#include <ESPmDNS.h>
#include <ArduinoOTA.h>           // for OTA Update

//#include <credentials.h>             // my credentials - remove before upload

#ifndef STASSID                        // either use an external .h file containing STASSID and STAPSK - or 
#define STASSID "your-ssid"            // ... modify these line to your SSID
#define STAPSK  "your-password"        // ... and set your WIFI password
#endif

const char* ssid = STASSID;
const char* password = STAPSK;

WebServer server(80);

const byte ledPin = 2;                  // if available define a LED Pin

uint32_t currentValue[2];            // here we store the current values from the form
const size_t noOfValues = sizeof(currentValue) / sizeof(currentValue[0]);

void handleRoot() {
  digitalWrite(ledPin, HIGH);
  String message = F("<!DOCTYPE html>\n"
                     "<html lang='en'>\n"
                     "<head>\n"
                     "<meta charset='utf-8'>\n" 
                     "<title>Example: Root</title>\n"
                     "</head>\n"
                     "<body>\n"
                     "<article>\n"
                     "<h2>Current Values</h2>\n");

  for (size_t i = 0; i < noOfValues; i++)
  {
    message += F("<p>Value ");
    message += i;
    message += F(": ");
    message += currentValue[i];
    message += F("</p>\n");
  }

  message += F("<p><a href='form.htm'>Change values</a></p>\n"
               "</article>\n"
               "</body>\n"
               "</html>\n");
  server.send(200, "text/html", message);
  digitalWrite(ledPin, LOW);
}

void handleForm() {
  digitalWrite(ledPin, HIGH);
  String message = F("<!DOCTYPE html>\n"
                     "<html lang='en'>\n"
                     "<head>\n"
                     "<meta charset='utf-8'>\n"
                     "<title>Example: Form</title>\n"
                     "</head>\n"
                     "<body>\n"
                     "<article>\n"
                     "<h2>Change Values</h2>\n"
                     "<form method='POST' action='c.php' target='_self'>\n"
                     "  <p><label for='i0'>Input 0</label><input type='text' name='i0' id='i0' size='20'></p>\n"
                     "  <p><label for='i1'>Input 1</label><input type='text' name='i1' id='i1' size='20'></p>\n"
                     "  <p><input type='submit' value='Submit'></p>\n"
                     "</form>\n"
                     "<p><a href='/'>Home</a></p>\n"
                     "</article>\n"
                     "</body>\n"
                     "</html>\n");
  server.send(200, "text/html", message);
  digitalWrite(ledPin, LOW);
}

void handle204()
{
  server.send(204);                // this page doesn't send back content
}

void handleCommand() {
  // receive command and handle accordingly
  Serial.println(F("D120 handleCommand"));
  for (uint8_t i = 0; i < server.args(); i++) {
    Serial.print(server.argName(i));
    Serial.print(F(": "));
    Serial.println(server.arg(i));

    if (server.argName(i) == "i0")
    {
      // do things for input field 0
      currentValue[0] = server.arg(i).toInt();
    }

    if (server.argName(i) == "i1")
    {
      // do things for input field 1
      currentValue[1] = server.arg(i).toInt();
    }
  }
  server.send(204);
}

void handleNotFound() {
  digitalWrite(ledPin, HIGH);
  String message = "File Not Found\n\n";
  message += "URI: ";
  message += server.uri();
  message += "\nMethod: ";
  message += (server.method() == HTTP_GET) ? "GET" : "POST";
  message += "\nArguments: ";
  message += server.args();
  message += "\n";
  for (uint8_t i = 0; i < server.args(); i++) {
    message += " " + server.argName(i) + ": " + server.arg(i) + "\n";
  }
  server.send(404, "text/plain", message);
  digitalWrite(ledPin, LOW);
}

void setup(void) {
  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, LOW);
  Serial.println(F("ESP Demo HTML Form"));
  Serial.begin(115200);
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);

  // Wait for connection
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.print(F("\nConnected to "));
  Serial.println(ssid);
  Serial.print(F("IP address: "));
  Serial.println(WiFi.localIP());

  if (MDNS.begin("esp32")) {
    Serial.println(F("MDNS responder started"));
  }

  server.on("/", handleRoot);                // the root document
  server.on("/form.htm", handleForm);        // a entry form
  server.on("/c.php", handleCommand);        // a resource to handle commands & inputs
  server.on("/favicon.ico", handle204);      // respond to the favicon with HTTP 204
  server.onNotFound(handleNotFound);         // handle HTTP 404

  server.begin();
  Serial.println(F("HTTP server started"));
  ArduinoOTA.begin();  // OTA
}

void loop(void) {
  server.handleClient();
  ArduinoOTA.handle(); // OTA
  yield();
}

edit: noch schnell OTA dazugegeben und ein wenig entrümpelt.
edit2: noch mal aufgeräumt, (Input Fips).

So, Montag morgen, der Kopf ist Fit, aber so richtig fluppt es trotzdem nicht. Zumindest steht die generelle Kommunikation.

Ich erwarte in meinem Sketch folgendes Format:

<IP>/get?dac=value&wert=value

In Javascript habe ich folgendes:

    function submitvalues(){

      outputmessage1 = document.getElementById('dac').value;
      outputmessage2 = document.getElementById('dacval').value;

      let url = '/get'+"?dac="+outputmessage1+"&wert"+outputmessage2;
      fetch(url)
        .then( function(response){
        return response.text();
        })
        .then (function(text){
          outputmessage1;
          outputmessage2;
        });
        }

Sieht hier jemand den Fehler warum die Werte nicht richtig übermittelt werden?

Hallo,
Was heißt nicht richtig ?
Wie sieht denn der zugehörige Handle im Sketch aus ?
Heinz