Rothschopf Werner

rowex ganz privat

Angebote

Der Webserver -  Aktualisieren mittes AJAX/JSON

Auf den vorhergehenden Seiten haben wir uns die prinzipielle Ausgabe einer Webseite und die Gestaltung auf einem ESP8266 angesehen. Jetzt geht es um die Aktualisierung der Webseite. Um neue Werte auf einer Webseite darzustellen könnte man diese einfach neu laden. Das geht mit entsprechenden Anweisungen in einem META-Tag ("refresh"). Hier verwende ich jedoch den Update über AJAX.

Sehr vereinfacht dargestellt: bei AJAX ruft ein Client (der Webbrowser) mittels JavaScript Daten von einem Webserver auf und aktualisert in der Folge die Webseite. Genauer: in meinem Fall werden einzelne Teile der Webseite aktualisiert.

Wir benötigen 3 Teile

  • eine HTML Seite die ein JavaScript aufruft und so aufbereitet ist, damit einzelne Teile veränderbar werden
  • ein JavaScript das neue Daten von einer Resource abholt und die Webseite ändert
  • einen Webserver der die zu aktualisierenden Daten als JSON zur Verfügung stellt

Die HTML Seite

In der HTML Seite 0.htm gibt es daher einerseits

  • im Header einen Link auf das eigentliche JavaScript (rot)
  • Im Body Tag den Aufruf einer JavaScript Funktion bei "onload" die beim Laden der Seite aufgerufen wird (blau)
  • eindeutige ID's für jene Element die mittels JavaScript aktualisert werden sollen (grün)
void handlePage()
{
String message;
message = F("<!DOCTYPE html>\n"
"<html>\n<head>\n<title>" TXT_BOARDNAME " - Board " TXT_BOARDID "</title>\n"
"<meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\">\n"
"<meta name=\"viewport\" content=\"width=device-width\">\n"
"<link rel='stylesheet' type='text/css' href='/f.css'>\n"
"<script src='j.js'></script>\n"
"</head>\n");
message += F("<body onload='GetSwitchState(0)'>\n"
"<header>\n<h1>" TXT_BOARDNAME " - Board " TXT_BOARDID "</h1>\n"
"<nav><p><a href=\"0.htm\">Home</a> <a href=\"1.htm\">[Page 1]</a> <a href=\"2.htm\">[The Webclient]</a> <a href=\"r.htm\">[Remote Module]</a> <a href=\"x.htm\">[Page X]</a></p></nav>\n</header>\n"
"<div id='cont'>\n");

if (server.uri() == "/0.htm" || server.uri() == "/") // *** HOME *** 0.htm
{
message += F("<h2>Homepage</h2>\n" // here you write your html code for your homepage. Let's give some examples...
"<p>This is an example for a webserver on your ESP8266.<p>\n"
"<p>Values are getting updated with AJAX/JSON. "
"I'm still using old style XMLHttpRequest instead of fetch-API. It's up to "
"the reader to update - but old style works fine for me ;-P</p>\n");

message += F("<h2>Values (with update)</h2>\n");
message += F("<p>Internal Voltage measured by ESP: <span id='internalVcc'>"); // example how to show values on the webserver
message += ESP.getVcc();
message += F("</span>mV</p>\n");

Für die eigentliche JavaScript Datei gibt es wieder einen Handler im setup()

server.on("/j.js", handleJs); // a javascript to handle AJAX/JSON Update of the page

sowie eine Funktion im tab "server" damit die Datei zur Verfügung gestellt werden kann.

void handleJs() {
// Output: a JavaScript
// a function in the JavaScript uses AJAX to request a JSON file from the webserver and updates the values on the page if the object names and ID are the same
String message;
message += F(" function GetSwitchState(s) {\n" // 0 call function with settimeout, 1 run only once for manual update
" nocache = '&nocache='+ Math.random() * 1000000;\n"
" var request = new XMLHttpRequest(); \n"
" request.onreadystatechange = function() {\n"
" if (this.readyState == 4) {\n"
" if (this.status == 200) {\n"
" if (this.responseText != null) {\n"
" var jo=JSON.parse(this.responseText);\n"
" for (var i in jo)\n"
" {if(document.getElementById(i)) document.getElementById(i).innerHTML=jo[i];}\n" // as long as the JSON name fits to the HTML ID value will be replaced
// add other fields here
" document.getElementById('sec').innerHTML = Math.floor(jo['ss']%60);\n" // example how to change a value in the HTML page
" if (jo['ss']>60){document.getElementById('min').innerHTML=Math.floor(jo['ss']/60%60);}\n"
" if (jo['ss']>3600){document.getElementById('hour').innerHTML=Math.floor(jo['ss']/3600%24);}\n"
" if (jo['ss']>86400){document.getElementById('day').innerHTML=Math.floor(jo['ss']/86400%7);}\n"
" if (jo['ss']>604800){document.getElementById('week').innerHTML=Math.floor(jo['ss']/604800%52);}\n");
message += F(" document.getElementById('sec').style.color = 'dimgray';\n"
" }}}\n"
" else {document.getElementById('sec').style.color = 'red';}\n"
" }\n"
" request.open('GET', 'json?p="); // request the JSON output
message += server.uri();
message += F("' + nocache, true);\n"
" request.send(null);\n"
" if (s==0) setTimeout('GetSwitchState(0)', ");
message += ajaxIntervall * 1000;
message += F(");\n"
" }");
server.send(200, "text/plain", message);
}

Das JavaScript

Das JavaScript ruft die Daten mittels "json" vom Webserver ab. Wenn die Daten einlagen gibt es zwei Varianten:

  1. Daten bei denen der Schlüssel exakt einer ID im HTML Dokument gleichen werden ausgetauscht (magenta). Unter Beibehaltung der Namenskonvention zwischen JSON und HTML-Dokument kann man "viele" Daten aus dem JSON mit einer einzigen Zeile im JavaScript aktualisieren.
  2. Daten werden aufbereitet und speziell im Dokument geändert - das passiert z.B. beim Zeitstempel: das JSON enthält die Laufzeit in Sekunden (ss) und diese wird auf Sekunden (sec), Minuten (min) etc. aufgeteilt. (blau)

Zur Laufzeitkontrolle sieht man auch kurz: Bei Start des JavaScript wird die Sekundenanzeige rot - wenn das Script ordnungsgemäß verarbeitet werden kann, wird die Sekunde wieder grau (dimgray).

Eine Anmerkung: "Heute" könnte man das ganze auch mit Fetch-API machen, XMLHttpRequest klappt aber immer noch und da ich auch ein paar alte Browser habe und dieses Script 1a läuft, habe ich mich noch für diese bewährte Variante entschieden.

Das JSON

Zuletzt dürfen wir nicht auf das JSON vergessen. Auch dafür brauchen wir wieder einen eigenen Handler im setup():

 server.on("/json", handleJson); // send data in JSON

und die entsprechende Funktion, die aber im wesentlichen auch nur eine reine Ausgabe der Schlüssel und Werte ist.

void handleJson() {
// Output: send data to browser as JSON
// after modification always check if JSON is still valid. Just call the JSON (json) in your webbrowser and check.
// Serial.println(F("D230 requested json"));
String message = "";
message = (F("{\"ss\":")); // Start of JSON and the first object "ss":
message += millis() / 1000;
message += (F(",\"internalVcc\":"));
message += ESP.getVcc();
message += (F(",\"button1\":"));
message += digitalRead(BUTTON1_PIN);
message += (F(",\"output1\":"));
message += digitalRead(OUTPUT1_PIN);
message += (F("}")); // End of JSON
server.send(200, "text/plain", message);
}

dieses Funktion generiert ein JSON in der Art:

{"ss":7785,"internalVcc":3041,"button1":1,"output1":0}

Damit haben wir nun zwei neue Komponenten (das JavaScript und das JSON) eingeführt sowie das bestehende HTML für die Aktualisierung mittels AJAX/JSON adaptiert.

Es geht weiter mit "Webserver - GPIO Schalten über Webseite".


Links


Protokoll

erstellt: 2018-09-02 | Stand: 2018-09-05