WiFi Verbindung per Javascript triggern

Hi zusammen,

ich hab mal wieder ne Sache, bei der ich einfach nicht weiter komme ;-(

Mir ist noch nicht ganz klar, wie man eine Funktion per Javascript auf dem ESP antriggert und dann den Server-Response auswertet.

Als Beispiel habe ich mal den folgenden Sketch erstellt (soll wirklich nur ein fiktives Beispiel sein):

In dem Beispiel baut der ESP ja einen Accesspoint auf und versucht zugleich, sich mit meinem WLAN zu verbinden (WiFi_AP_STA eben). Da die Zugangsdaten falsch sind, schlägt das in dem Beispiel fehl.

Auf der Serverseite gibts den Button "Verbinden".

Sollzustand wäre:
Wenn man auf den Button klickt, soll die Funktion "WiFi_conn()" aufgerufen werden. Innerhalb dieser Funktion versucht der ESP dann 15 Sekunden lang, eine Verbindung aufzubauen
Auf Seite des Servers (also auf der Seite mit dem Button) soll dann eine Meldung ausgegeben werden, ob die Verbindung geklappt hat, oder nicht.

In meinem kläglichen Versuch kommt aber gar keine Rückmeldung.

 #include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>

unsigned long connTimer = 0;
unsigned long connCancel = 0;
unsigned long mainTimer = 0;

ESP8266WebServer server(80);

char indexPage[] PROGMEM = R"=====(
<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Test</title>
  </head>
  <body>
    <button onclick="neu_verbinden();">Verbinden</button>
  </body>
</html>
<script>
  function neu_verbinden() {
    var url="/neu_verbinden";
    var xmlhttp = new XMLHttpRequest();
    xmlhttp.open('POST', url, false); //False, weil ich ja eine synchrone Abfrage machen will...
    xmlhttp.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
    xmlhttp.onreadystatechange = function() {
      if (xmlhttp.readyState == 4) {
          if(xmlhttp.status == 200) {
            var onlinestatus=xmlhttp.responseText;
            alert(onlinestatus);
            if (onlinestatus=="1") {
              alert("Verbunden!");
            } else {
              alert("Nicht verbunden!");
            }
          } 
      }  
    };
    xmlhttp.send();
    }
</script>
)=====";


void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);

  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }
  
  // Accesspoint aufbauen
  WiFi.mode(WIFI_AP_STA);
  WiFi.softAP("TestAP12345678", "123456789");
  // Verbindung mit meinem Router-WLAN aufbauen
  WiFi_conn();
  
  // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Startseite / Tageswerte
  server.on("/", display_root);
  server.on("/neu_verbinden", WiFi_conn);
  server.begin(); // Server starten
}

void loop() {
  // put your main code here, to run repeatedly:
  server.handleClient();
  mainTimer=millis();
  delay(100);
}

void display_root() {
  Serial.println("Display root");
  server.send(200, "text/html", indexPage);
}


void WiFi_conn() {
  Serial.println("Neu verbinden!");
  WiFi.begin("MeineSSID", "MeinPW");
  
  connTimer = millis();
  connCancel = mainTimer + 15000;

  while (WiFi.status() != WL_CONNECTED && connTimer < connCancel)
  {
    yield();
    connTimer = millis();
    Serial.print(".");
    delay(500);
  }

  if (WiFi.status() == WL_CONNECTED) {
    Serial.println("Verbunden!");
    server.send(200, "text/plain", "1");
  } else {
    Serial.println("Nicht verbunden!");
    server.send(200, "text/plain", "2");
  }
}

Ich würd mich sehr freuen, wenn mir jemand vom Holzweg runter helfen könnte :wink:

Danke schon mal für eure Tips.

LG und schönen Restsonntag allen.
Daniel

Schau Dir die Fetch-Api (Beispiele bei Fips) oder AJAX an.

Gruß Tommy

Hey Tommy;-)

Ich würde in dem Fall gerne bei klassischem Ajax bleiben also kein Fetch.
Nach meiner Info wird fetch von älteren Browsern nicht unterstützt.

Und mit eben Ajax komm ich irgendwie nicht weiter auch nicht mit Fips Seite;-(

Aber wo genau liegt denn der Fehler in meinem Script?

Da das andere Forum zur Zeit tot ist, kann ich Dir mein AJAX-Beispiel nicht zeigen und muss Dich auf die Literatur verweisen.
Was verstehst Du unter "Alte Browser"? Wer Fetch nicht kann ist älter als 5 Jahre und sollte nicht mehr unterstützt werden. Fetch wird mittlerweile sogar von MS propagiert.

Gruß Tommy

Ok, dann seh ich mir mal die fetch-API an.
Mich hätte halt trotzdem mal interessiert, warum mein Beispiel ned funktioniert...wäre ein guter Lerneffekt gewesen :wink:
Aber trotzdem Danke Tommy und guts nächtle

was sagt denn die javascript console?
hatte mal vor ca 2 Jahren das problem das plötzlich crosssite scripting komplett blockiert wurde von browsern.

Hi,

Kuck ich morgen gleich mal und poste die Consolen-Ausgabe.

LG Daniel

Das wir mittlerweile komploett blockiert, wenn man nicht die zugehörigen Attribute setzt. SameOriginPolicy

Das gilt sowohl für AJAX, als auch für Fetch.

Gruß Tommy

Schritt 1 wäre da meines erachtens sowieso zunächst mal den Button in ein Form zu packen und einfach da "neu_verbinden" aufzurufen ob das grundsätzlich klappt.
Erst danach würde ich versuchen, das mit JS zu probieren.

P.S. so ein Timer ist nicht Überlauf-Sicher:

connTimer < connCancel

Hi,

so wie mein Sketch aktuell ist, klappt der Aufruf der Funktion "neu_verbinden" (bzw. void Wifi_conn()). Das Problem ist nur, dass eben keine Rückmeldung beim Client ankommt, obwohl ich ja

Auf Serverseite und

Auf Client-Seite habe.

Wenn ich die Ajax-Abfrage assynchron mache, sprich den 3. Parameter hier auf "true" setze

wird die Funktion "Wifi_conn()" auch wieder aufgerufen (der Aufruf klappt also wie gesagt sehr gut) aber schon nach ca. 5 Sekunden "Nicht verbunden" zurück gemeldet

Hier wird dann eben das Problem sein, dass mein Javascript-Client nicht wartet, bis die 15 Sekunden Verbindungsversuch rum sind.

Wie von Tommy vorgeschlagen, werde ich auch die fetch-API probieren.
Aber trotzdem sollte es doch auch mit oldschool-AJAX umsetzbar sein.

Wie macht ihr das denn, wenn ihr mit einem Button auf einer HTML-Seite des Servers eine Funktion des ESP antriggern wollt, die HTML-Seite jedoch geöffnet bleiben und auf eine Rückmeldung des Servers warten und diese dann ausgeben soll?

LG und guten Start in die Woche allen hier

halbwissen:
ich kenne nicht die Timeouts vom xmlhttp aber ich gehe davon aus, dass die kürzer sind als deine Reconnects. Vermutlich kannst du das mit einem HTTP header field versuchen anzupassen, aber imho nicht notwendig.

Aus meiner sicht sollst du das asyncron machen.
Ein Request zum losschicken der Reconnect Aktion (und da brauchst nur ein HTTP 200 oder 204 zurück)

und asyncron halt den Verbindungssstatus abfragen (mit einem separaten Request)

ob du dann diese zwei Requests in deinem JavaScript klammerst bleibt dir überlassen. Aber 15 Sekunden würde ich in einer GUI nicht warten wollen.

auch so. Es gibt einen Button der eine Aktion ausführt.
Separat wird der Status der Ausgänge/Eingänge sowieso aktualisiert.

Hi,

ja dann werd ichs auch so machen.
Ich löse asynchron die Funktion auf dem ESP aus und überwache separat/parallel alle paar Sekunden den aktuellen Status der Rückmeldung.

Nichts desto trotz muss ich mich jetzt endlich mal mit dem Thema fetch auseinander setzen.

Und hier muss ich mir auch noch Gedanken zu machen, völlig berechtigter Einwand :wink:

eigentlich sehe ich das mit Fetch so: wenn es nicht noch irgend einen zwigenden Grund gibt (wie z.B. ein Uralt-Tablet mit Android Jahrgang steinalt oder dass unbedingt IE unterstützt werden muss), dann würde ich bei einem neuen Projekt Fetch verwenden *)

https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch#browser_compatibility

*) (das ich selber noch mehrere alte Projekte mit xhr habe ist halt historisch...)

so gehts mir auch :wink:
In der reinen "Web"-Welt benutze ich mittlerweile hauptsächlich jquery.
Da geht ja auch alles etwas einfacher.

So sollte es doch passen (habs mal in eine separate Funktion gepackt)

void fuenf_sekunden () {
unsigned long startzeit=millis();
unsigned long dauer=5000;

while (millis()-startzeit < dauer) {
// Der Inhalt dieser Schleife wird 5 Sekunden lang ausgeführt
}
}

Damit sollte ich doch auch bei einem Überlauf von millis() sicher unterwegs sein, oder?

LG
Daniel

Edit:

Wobei ich grad selber ein bisschen ins Zweifeln komme:

Nehmen wir mal an, millis() würde bei 500000 überlaufen (anstatt bei 4 Billion).
Der Aufruf der Funktion erfolgt bei 499998.

Somit wird in der Funktion startzeit auf 499998 gesetzt und dauer auf 5000
Mittlerweile ist dann der neue Wert von Millis bei 0, weil Millis übergelaufen ist.

würde ja nun bedeuten

0 - 499998 = - 499998

  • 499998 ist kleiner als 5000 also startet die while-Schleife.

Nun dauert es doch aber ca. 505000 Millisekunden bis "millis() - startzeit" einen Wert von mehr als 5000 erreicht hat und dann die While-Schleife nicht mehr ausgeführt wird, oder?

Oder hab ich jetzt eine Denkblockade?

While (millis() - lastMillis < irgendwas) ist der falsche Ansatz. Der blockiert.
if (millis() - lastMillis >= dauer) tu_was

ist der Weg.

Gruß Tommy

Ok...muss ich mir mal morgen bei klarem Kopf anschauen. Danke.