Mit der Arduino IDE kann man Programme für den ESP8266 entwickeln, die über WLAN und WEB-Browser die Anwendung steuern. Die Benutzeroberfläche und die Benutzeraktionen werden mit Hilfe von HTML definiert.
Der Vorteil dieses Konzepts liegt darin, dass man mit PC, Tablet oder Smartphone die Anwendung steuern kann. Das ist unabhängig von Betriebssystem und Gerätehardware möglich. WLAN-Fähigkeit und Web-Browser sind ohnehin so gut wie immer vorhanden und reichen völlig aus.
Hier wird gezeigt wie man mit der Arduino IDE Programme für den ESP8266 schreiben kann, die die HTML-Seiten aufbauen, an den WEB-Partner senden und die empfangenen Benutzereingaben auswerten.
HTML-Editoren können hier nicht eingesetzt werden, Die HTML-Seiten müssen Element für Element selbst definiert werden.
Hier das erste Beispiel. Es sieht so aus :

In diesem Beispielen wird nichts gesteuert. Es werden nur die Klicks auf „OK“ und „nicht OK“ gezählt. Die Besonderheit : Es wird auch ein kleines Bild dargestellt.
Das dazugehörenden Beispielprogramm mutet auf den ersten Blick ein wenig „oversized“ an, weil es viele Unterroutinen enthält, die teilweise hier nicht aufgerufen werden.
Diese Routinen werden jedoch für andere Steuerelemente benötigt. Das Programm eignet sich in der vorliegenden Form als Kopiervorlage. Es enthält die wichtigsten Unterroutinen und kann auf einfache Weise ausgebaut werden.
Coding
//---------------------------------------------------------------------
//ESP866 HTML Demo 01
//---------------------------------------------------------------------
// Author : Hubert Baumgarten
//---------------------------------------------------------------------
#include <ESP8266WiFi.h>
#ifdef __AVR__
#include <avr/power.h>
#endif
#include "bild1.c"
#define BGTDEBUG 1
//---------------------------------------------------------------------
// WiFi
byte my_WiFi_Mode = 0; // WIFI_STA = 1 = Workstation WIFI_AP = 2 = Accesspoint
const char * ssid_sta = "<your SSID>";
const char * password_sta = "<Your Password>";
const char * ssid_ap = "ESP_HTML_01";
const char * password_ap = ""; // alternativ : = "12345678";
WiFiServer server(80);
WiFiClient client;
#define MAX_PACKAGE_SIZE 2048
char HTML_String[5000];
char HTTP_Header[150];
//---------------------------------------------------------------------
// Allgemeine Variablen
int ok_count = 0;
int notok_count = 0;
int Aufruf_Zaehler = 0;
#define ACTION_OK 1
#define ACTION_NOTOK 2
int action;
//---------------------------------------------------------------------
void setup() {
#ifdef BGTDEBUG
Serial.begin(115200);
for (int i = 10; i > 0; i--) {
Serial.print("Warte ");
Serial.print(i);
Serial.println(" sec");
delay(1000);
}
Serial.println("ESP_HTML_01");
#endif
//---------------------------------------------------------------------
// WiFi starten
WiFi_Start_STA();
if (my_WiFi_Mode == 0) WiFi_Start_AP();
}
//---------------------------------------------------------------------
void loop() {
WiFI_Traffic();
delay(10);
}
//---------------------------------------------------------------------
void WiFi_Start_STA() {
unsigned long timeout;
WiFi.mode(WIFI_STA); // Workstation
WiFi.begin(ssid_sta, password_sta);
timeout = millis() + 12000L;
while (WiFi.status() != WL_CONNECTED && millis() < timeout) {
delay(10);
}
if (WiFi.status() == WL_CONNECTED) {
server.begin();
my_WiFi_Mode = WIFI_STA;
#ifdef BGTDEBUG
Serial.print("Connected IP - Address : ");
for (int i = 0; i < 3; i++) {
Serial.print( WiFi.localIP()[i]);
Serial.print(".");
}
Serial.println(WiFi.localIP()[3]);
#endif
} else {
WiFi.mode(WIFI_OFF);
#ifdef BGTDEBUG
Serial.println("WLAN-Connection failed");
#endif
}
}
//---------------------------------------------------------------------
void WiFi_Start_AP() {
WiFi.mode(WIFI_AP); // Accesspoint
WiFi.softAP(ssid_ap, password_ap);
server.begin();
IPAddress myIP = WiFi.softAPIP();
my_WiFi_Mode = WIFI_AP;
#ifdef BGTDEBUG
Serial.print("Accesspoint started - Name : ");
Serial.print(ssid_ap);
Serial.print( " IP address: ");
Serial.println(myIP);
#endif
}
//---------------------------------------------------------------------
void WiFI_Traffic() {
char my_char;
int htmlPtr = 0;
unsigned long my_timeout;
// Check if a client has connected
client = server.available();
if (!client) {
return;
}
my_timeout = millis() + 250L;
while (!client.available() && (millis() < my_timeout) ) delay(10);
delay(10);
if (millis() > my_timeout) {
#ifdef BGTDEBUG
Serial.println("Client connection timeout!");
#endif
return;
}
//---------------------------------------------------------------------
htmlPtr = 0;
my_char = 0;
while (client.available() && my_char != 'r') {
my_char = client.read();
HTML_String[htmlPtr++] = my_char;
}
client.flush();
HTML_String[htmlPtr] = 0;
#ifdef BGTDEBUG
Serial.println ("--------------------------------------------------------");
Serial.print("Remote IP - Address : ");
for (int i = 0; i < 3; i++) {
Serial.print( client.remoteIP()[i]);
Serial.print(".");
}
Serial.println(client.remoteIP()[3]);
exhibit("Remote Port ", client.remotePort());
exhibit ("Request : ", HTML_String);
#endif
Aufruf_Zaehler++;
if (Find_Start ("bild1.gif", HTML_String) > 0) {
send_bin(Bild1, BILD1_LEN, "image/gif", "bild1.gif");
return;
}
if (Find_Start ("/?", HTML_String) < 0 && Find_Start ("GET / HTTP", HTML_String) < 0 ) {
send_not_found();
return;
}
//---------------------------------------------------------------------
// Benutzereingaben einlesen und verarbeiten
//---------------------------------------------------------------------
action = Pick_Parameter_Zahl("ACTION=", HTML_String);
if ( action == ACTION_OK) ok_count++;
if ( action == ACTION_NOTOK) notok_count++;
//---------------------------------------------------------------------
//Antwortseite aufbauen
make_HTML01();
//---------------------------------------------------------------------
// Header aufbauen
strcpy(HTTP_Header , "HTTP/1.1 200 OKrn");
strcat(HTTP_Header, "Content-Length: ");
strcati(HTTP_Header, strlen(HTML_String));
strcat(HTTP_Header, "rn");
strcat(HTTP_Header, "Content-Type: text/htmlrn");
strcat(HTTP_Header, "Connection: closern");
strcat(HTTP_Header, "rn");
#ifdef BGTDEBUG
exhibit("Header : ", HTTP_Header);
exhibit("Laenge Header : ", strlen(HTTP_Header));
exhibit("Laenge HTML : ", strlen(HTML_String));
#endif
client.print(HTTP_Header);
delay(20);
send_HTML();
}
//---------------------------------------------------------------------
// HTML Seite 01 aufbauen
//---------------------------------------------------------------------
void make_HTML01() {
strcpy( HTML_String, "<!DOCTYPE html>");
strcat( HTML_String, "<html>");
strcat( HTML_String, "<head>");
strcat( HTML_String, "<title>HTML Demo</title>");
strcat( HTML_String, "</head>");
strcat( HTML_String, "<body bgcolor="#adcede">");
strcat( HTML_String, "<font color="#000000" face="VERDANA,ARIAL,HELVETICA">");
strcat( HTML_String, "<h1>HTML Demo ");
strcat( HTML_String, "<img src="bild1.gif" alt="mein Bild"></h1>");
strcat( HTML_String, "<form>");
strcat( HTML_String, "<button style= "width:120px" name="ACTION" value="");
strcati(HTML_String, ACTION_OK);
strcat( HTML_String, "">OK</button>");
strcat( HTML_String, " ");
strcat( HTML_String, "<button style= "width:120px" name="ACTION" value="");
strcati(HTML_String, ACTION_NOTOK);
strcat( HTML_String, "">nicht OK</button>");
strcat( HTML_String, "</form>");
strcat( HTML_String, "<BR>");
strcat( HTML_String, "<FONT SIZE=-1>");
strcat( HTML_String, "Aufrufzähler : ");
strcati(HTML_String, Aufruf_Zaehler);
strcat( HTML_String, " Anzahl OK : ");
strcati(HTML_String, ok_count);
strcat( HTML_String, " Anzahl NOK : ");
strcati(HTML_String, notok_count);
strcat( HTML_String, "<br>");
strcat( HTML_String, "</font>");
strcat( HTML_String, "</font>");
strcat( HTML_String, "</body>");
strcat( HTML_String, "</html>");
}
//--------------------------------------------------------------------------
void send_bin(const unsigned char * bin , int bin_len, const char * type, const char * file) {
int my_len, my_ptr, my_send;
strcpy(HTTP_Header, "HTTP/1.1 200 OKrn");
strcat(HTTP_Header, "Content-Length: ");
strcati(HTTP_Header, bin_len);
strcat(HTTP_Header, "rn");
strcat(HTTP_Header, "Content-Type: ");
strcat(HTTP_Header, type);
strcat(HTTP_Header, "rn");
strcat(HTTP_Header, "Content-Location: ");
strcat(HTTP_Header, file);
strcat(HTTP_Header, "rn");
strcat(HTTP_Header, "Connection: closern");
strcat(HTTP_Header, "rn");
#ifdef BGTDEBUG
exhibit("Header : ", HTTP_Header);
exhibit("Laenge Header : ", (unsigned long) strlen(HTTP_Header));
exhibit("Laenge Bin : ", bin_len);
#endif
client.print(HTTP_Header);
delay(20);
//---------------------------------------------------------------------
// in Portionen senden
my_len = bin_len;
my_ptr = 0;
my_send = 0;
while ((my_len - my_send) > 0) {
my_send = my_ptr + MAX_PACKAGE_SIZE;
if (my_send > my_len) {
client.write(&bin[my_ptr], my_len - my_ptr);
delay(20);
my_send = my_len;
} else {
client.write(&bin[my_ptr], MAX_PACKAGE_SIZE);
delay(20);
my_ptr = my_send;
}
}
client.stop();
}
//--------------------------------------------------------------------------
void send_not_found() {
#ifdef BGTDEBUG
Serial.println("Sende Not Found");
#endif
client.print("HTTP/1.1 404 Not Foundrnrn");
delay(20);
client.stop();
}
//--------------------------------------------------------------------------
void send_HTML() {
char my_char;
int my_len = strlen(HTML_String);
int my_ptr = 0;
int my_send = 0;
//--------------------------------------------------------------------------
// in Portionen senden
while ((my_len - my_send) > 0) {
my_send = my_ptr + MAX_PACKAGE_SIZE;
if (my_send > my_len) {
client.print(&HTML_String[my_ptr]);
delay(20);
#ifdef BGTDEBUG
Serial.println(&HTML_String[my_ptr]);
#endif
my_send = my_len;
} else {
my_char = HTML_String[my_send];
// Auf Anfang eines Tags positionieren
while ( my_char != '<') my_char = HTML_String[--my_send];
HTML_String[my_send] = 0;
client.print(&HTML_String[my_ptr]);
delay(20);
#ifdef BGTDEBUG
Serial.println(&HTML_String[my_ptr]);
#endif
HTML_String[my_send] = my_char;
my_ptr = my_send;
}
}
client.stop();
}
//----------------------------------------------------------------------------------------------
void set_colgroup(int w1, int w2, int w3, int w4, int w5) {
strcat( HTML_String, "<colgroup>");
set_colgroup1(w1);
set_colgroup1(w2);
set_colgroup1(w3);
set_colgroup1(w4);
set_colgroup1(w5);
strcat( HTML_String, "</colgroup>");
}
//------------------------------------------------------------------------------------------
void set_colgroup1(int ww) {
if (ww == 0) return;
strcat( HTML_String, "<col width="");
strcati( HTML_String, ww);
strcat( HTML_String, "">");
}
//---------------------------------------------------------------------
void strcati(char* tx, int i) {
char tmp[8];
itoa(i, tmp, 10);
strcat (tx, tmp);
}
//---------------------------------------------------------------------
void strcati2(char* tx, int i) {
char tmp[8];
itoa(i, tmp, 10);
if (strlen(tmp) < 2) strcat (tx, "0");
strcat (tx, tmp);
}
//---------------------------------------------------------------------
int Pick_Parameter_Zahl(const char * par, char * str) {
int myIdx = Find_End(par, str);
if (myIdx >= 0) return Pick_Dec(str, myIdx);
else return -1;
}
//---------------------------------------------------------------------
int Find_End(const char * such, const char * str) {
int tmp = Find_Start(such, str);
if (tmp >= 0)tmp += strlen(such);
return tmp;
}
//---------------------------------------------------------------------
int Find_Start(const char * such, const char * str) {
int tmp = -1;
int ww = strlen(str) - strlen(such);
int ll = strlen(such);
for (int i = 0; i <= ww && tmp == -1; i++) {
if (strncmp(such, &str[i], ll) == 0) tmp = i;
}
return tmp;
}
//---------------------------------------------------------------------
int Pick_Dec(const char * tx, int idx ) {
int tmp = 0;
for (int p = idx; p < idx + 5 && (tx[p] >= '0' && tx[p] <= '9') ; p++) {
tmp = 10 * tmp + tx[p] - '0';
}
return tmp;
}
//----------------------------------------------------------------------------
int Pick_N_Zahl(const char * tx, char separator, byte n) {
int ll = strlen(tx);
int tmp = -1;
byte anz = 1;
byte i = 0;
while (i < ll && anz < n) {
if (tx[i] == separator)anz++;
i++;
}
if (i < ll) return Pick_Dec(tx, i);
else return -1;
}
//---------------------------------------------------------------------
int Pick_Hex(const char * tx, int idx ) {
int tmp = 0;
for (int p = idx; p < idx + 5 && ( (tx[p] >= '0' && tx[p] <= '9') || (tx[p] >= 'A' && tx[p] <= 'F')) ; p++) {
if (tx[p] <= '9')tmp = 16 * tmp + tx[p] - '0';
else tmp = 16 * tmp + tx[p] - 55;
}
return tmp;
}
//---------------------------------------------------------------------
void Pick_Text(char * tx_ziel, char * tx_quelle, int max_ziel) {
int p_ziel = 0;
int p_quelle = 0;
int len_quelle = strlen(tx_quelle);
while (p_ziel < max_ziel && p_quelle < len_quelle && tx_quelle[p_quelle] && tx_quelle[p_quelle] != ' ' && tx_quelle[p_quelle] != '&') {
if (tx_quelle[p_quelle] == '%') {
tx_ziel[p_ziel] = (HexChar_to_NumChar( tx_quelle[p_quelle + 1]) << 4) + HexChar_to_NumChar(tx_quelle[p_quelle + 2]);
p_quelle += 2;
} else if (tx_quelle[p_quelle] == '+') {
tx_ziel[p_ziel] = ' ';
}
else {
tx_ziel[p_ziel] = tx_quelle[p_quelle];
}
p_ziel++;
p_quelle++;
}
tx_ziel[p_ziel] = 0;
}
//---------------------------------------------------------------------
char HexChar_to_NumChar( char c) {
if (c >= '0' && c <= '9') return c - '0';
if (c >= 'A' && c <= 'F') return c - 55;
return 0;
}
#ifdef BGTDEBUG
//---------------------------------------------------------------------
void exhibit(const char * tx, int v) {
Serial.print(tx);
Serial.println(v);
}
//---------------------------------------------------------------------
void exhibit(const char * tx, unsigned int v) {
Serial.print(tx);
Serial.println(v);
}
//---------------------------------------------------------------------
void exhibit(const char * tx, unsigned long v) {
Serial.print(tx);
Serial.println(v);
}
//---------------------------------------------------------------------
void exhibit(const char * tx, const char * v) {
Serial.print(tx);
Serial.println(v);
}
#endif
Der Sketch zum download:
Erläuterungen zum Programmrahmen
Im Setup wird 10 Sekunden gewarten, damit man in Ruhe den Serial-Monitor starten kann und alle Meldungen mitbekommt
Dann wird zunächst versucht sich beim lokalen WLAN anzumelden. Wenn dies fehlschlägt wird ein eigener WEB-Server gestartet.
In der Loop wird die Routine WIFI-Traffic aufgerufen, um die über WALN empfangenen Benutzereingaben zu verarbeiten und die aktuelle HTML-Seite aufzubauen und zu senden.
Die Web-Browser rufen nicht nur die HTML-Seite und die darin enthaltenen Verweise auf Grafiken usw. ab. Sie fragen z.B. auch nach einem Favoriten-Ikon. Wenn man diese Requests ignoriert, weden sie alle paar Sekunden wiederholt. Daher wird in meinem Programm auf alles was nicht bekannt ist und bedient werden kann, mit „Not found“ geantwortet. Das merkt sich der Browser und weitere Anfragen unterbleiben.
Nach einem Abruf der HTML-Seite ohne jeden Parameter (Browsereingabe z.B. http://192.168.178.41/) kommt dieser Request an.:
GET / HTTP/1.1
Zwischen dem Slash und dem HTTP stehen ggf. Eingabe-Parameter oder der Name einer Datei die, abgerufen wird. In meinem Beispiel wird eine Bilddatei verlinkt :
HTML-Beispiel :
<img src=„bild.gif“ alt=„mein Bild“>
Die Bilddatei wird nach dem Senden der HTML-Seite automatisch angefordert :
GET /bild1.gif HTTP/1.1
Die Bilddatei wurde zu einem Char-Array umgesetzt und in einer eigenen Code-Datei Bild1.c gespeichert.:
#include "arduino.h"
#define BILD1_LEN 1515
const unsigned char Bild1[] = {
0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 0x2B, 0x00, 0x28, 0x00, 0x70, 0x00, 0x00, 0x21, 0xF9, 0x04,
....
0x5B, 0xD1, 0xFD, 0xA2, 0xC8, 0x34, 0x5F, 0x01, 0x01, 0x00, 0x3B};
Diese binären Daten werden mit write übertragen. Write ist erforderlich, weil print beim ersten Auftreten eines 0x00 die Übertragung beenden würde.
Das Senden der HTML- und Binär-Daten geschieht in Portionen. Max. 2048 Bytes dürfen auf einmal geschickt werden, danach muß eine Pause von 20 mSec eingelegt werden.
Die Buttons haben die Attribute Name und Value. Beides wird beim Anklicken gesendet. So kann identifiziert werden, welcher Button angeklickt wurde.
HTML-Beispiel :
<button style=“width:200px“ name=„ACTION“ value=„1“>OK</button>
Wenn dieser Knopf angeklickt wird, kommt folgender Request :
GET /?ACTION=1 HTTP/1.1
Ich gebe die HTML-Seite auch auf dem Serialmonitor aus. Von dort kann sie mit Cut and Paste abgegriffen und z.B. zur Syntax-Prüfung in ein entsprechendes Programm übertragen werden.
Ein gute Seite zur Syntax-Prüfung im Netz ist z.B. :
http://www.dirtymarkup.com/
Das sieht so aus :

Wenn man seine Seite eingefügt hat, kann man mit Enter die Eingabe in mehrere Zeilen aufteilen. Das sieht dann so aus.

Hinweise auf Syntax-Fehler stehen ggf. am Anfang einer Zeile. Man kann den Fehler durch Aufteilen der Zeilen (Enter) einkreisen.
Es ist dringend angeraten, seine HTMLSeite zu überprüfen, um sicher zu gehen, dass sich kein Fehler eingeschlichen hat. Die verschiedenen WEB-Browser behandeln Fehler ganz unterschiedlich. Einige korrigieren bestimmte Fehler erfolgreich und alles sieht gut aus, einige nicht, und zeigen u.U. einen Scherbenhaufen (Browser in Voodoo-Mode) an.
Aufbau der HTML-Seite
Ich baue die HTML-Seite als Char-Array auf. Das benötigt weniger Speicher und läuft daher stabiler als der Aufbau mit Hilfe einer String-Variablen. Das Char-Array muß natürlich groß genug definiert sein. Es wird mit strcat zusammengesetzt. Eine eigenen Routine strcati dient zum Anfügen von Integerzahlen.
Die Benutzereingaben müssen in
<form> … </form>
eingebettet sein. Innerhalb dieses Blockes muß ein Button sein, der die Übertragung der Benutzereingaben dieses Blocks auslöst.
Auf einer HTML-Seite dürfen mehrere solcher Blöcke vorhanden sein, um z.B. die Eingaben zu strukurieren und unnötige Datenübertragungen zu vermeiden.
Wie oben bereits erwähnt, werden die Atrribute Name und Value beim Anklicken eines Button gesendet. Im Request kommen dann Name=Value an. Ich benutze bei allen Buttons immer den gleichen Namen „ACTION“ mit verschiedenen numerischen Werten in Value. Die Auswertung ist dann einfach. Mit der Routine Pick_Parameter_Zahl wird der Zahlenwert hinter „ACTION=“ ausgelesen. Der eingelesen Wert wird dann interpretiert. Das ist einfacher als verschiedenen Namen zu verwenden, die dann einzeln ausgelesen werden müssten,
Die verschieden Werte für ACTION habe ich als Kompilerkonstanten definiert z.B. ACTION_OK. Diese Konstanten verwende ich beim Aufbau der HTML-Seite und beim Interpretieren der Benutzereingaben. Das schafft Klarheit und Übersichtlichkeit und dokumentiert sich automatisch.
Dieses Anwendungsbeispiel
Hier werden nur die Anzahl Klicks auf „Ok“ und „Nicht OK“ gezählt. Das is denkbar einfach:
// Variablen
int ok_count = 0;
int notok_count = 0;
int Aufruf_Zaehler = 0;
#define ACTION_OK 1
#define ACTION_NOTOK 2
int action;
// HTML Ausgabe
strcat( HTML_String, "<button style= "width:120px" name="ACTION" value="");
strcati(HTML_String, ACTION_OK);
strcat( HTML_String, "">OK</button>");
strcat( HTML_String, " ");
strcat( HTML_String, "<button style= "width:120px" name="ACTION" value="");
strcati(HTML_String, ACTION_NOTOK);
strcat( HTML_String, "">nicht OK</button>");
strcat( HTML_String, "</form>");
strcat( HTML_String, "<BR>");
strcat( HTML_String, "<FONT SIZE=-1>");
strcat( HTML_String, "Aufrufzähler : ");
strcati(HTML_String, Aufruf_Zaehler);
strcat( HTML_String, " Anzahl OK : ");
strcati(HTML_String, ok_count);
strcat( HTML_String, " Anzahl NOK : ");
strcati(HTML_String, notok_count);
// Auswertung
action = Pick_Parameter_Zahl("ACTION=", HTML_String);
if ( action == ACTION_OK) ok_count++;
if ( action == ACTION_NOTOK) notok_count++;
2. Anwendungsbeispiel
Im folgenden Anwendungsbeispiel möchte ich zeigen, wie die wichtigsten Steuerelemente definiert und ausgewertet werden.
Textfelder
HTML-Beispiel :
<input type=„text“ style=“width:200px“ name=„VORNAME“ maxlength=„20“ value=„Bärbel“>
Das sieht so aus :

Der Request sieht so aus :
GET /?VORNAME=B%E4rbel&ACTION=4&NACHNAME=von+der+Waterkant HTTP/1.1
Die Felder sind durch ein & getrennt. Umlaute werden hexadezimal zurückgegeben. Dem Headezimalwert ist ein % vorangestellt. In diesem Beispiel wird der Buchstabe ä als %E4 codiert. Leerzeichen werden als + dargestellt. Die Routine Pick_Text bereitet die empfangenen Textfelder auf, dh. Hexcodes und + -Zeichen werden umgesetzt.
Auswertung :
if ( action == ACTION_SET_NAME) {
myIndex = Find_End("VORNAME=", HTML_String);
if (myIndex >= 0) {
Pick_Text(Vorname, &HTML_String[myIndex], 20);
}
myIndex = Find_End("NACHNAME=", HTML_String);
if (myIndex >= 0) {
Pick_Text(Nachname, &HTML_String[myIndex], 20);
}
}
Uhrzeit und Datum
HTML-Beispiel :
<input type=“time“ style=“width:100px“ name=“UHRZEIT“ value=„16:47:00“>
<input type=“date“ style=“width:100px“ name=“DATUM“ value=„2016-02-09“>
Das sieht so aus :

Der Request sieht so aus :
GET /?UHRZEIT=16%3A47%3A00&ACTION=3&DATUM=2016-02-09 HTTP/1.1
In der Uhrzeit sind die Trennzeichen : hexadezimal-codiert,. Das Datum wird in der angelsächsischen Reihenfolge Jahr, Monat Tag angegeben.
Auswertung :
if ( action == ACTION_SET_DATE_TIME) {
myIndex = Find_End("UHRZEIT=", HTML_String);
if (myIndex >= 0) {
Pick_Text(tmp_string, &HTML_String[myIndex], 8);
Uhrzeit_HH = Pick_N_Zahl(tmp_string, ':', 1);
Uhrzeit_MM = Pick_N_Zahl(tmp_string, ':', 2);
Uhrzeit_SS = Pick_N_Zahl(tmp_string, ':', 3);
}
myIndex = Find_End("DATUM=", HTML_String);
if (myIndex >= 0) {
Pick_Text(tmp_string, &HTML_String[myIndex], 10);
Datum_JJJJ = Pick_N_Zahl(tmp_string, '-', 1);
Datum_MM = Pick_N_Zahl(tmp_string, '-', 2);
Datum_TT = Pick_N_Zahl(tmp_string, '-', 3);
}
}
Auswahlfelder
HTML-Beispiel für Checkbox :
<input type=„checkbox“ name=„WOCHENTAG0“ id=„WT0“ value=„1“ checked>
<label for=„WT0“>Mo</label>
Man muß die Checkbox definieren und explizit ein Beschriftungslabel zuordnen. Das Attribut checked zeigt an, das diese Checkbox angekreuzt angezeigt werden soll. Im Request erhält man nur für angekreixte Checkboxen Name und Value. Über nicht angekreuzte Checkboxen wird geschwiegen. In meinem unternstehenden Beispiel habe ich alle 7 Wochentage aufgeführt und baue die angekreutenTage als Bit in ein 1-Byte-Datenfeld ein..
Auswertung :
Wochentage = 0;
for (int i = 0; i < 7; i++) {
strcpy( tmp_string, "WOCHENTAG");
strcati( tmp_string, i);
strcat( tmp_string, "=");
if (Pick_Parameter_Zahl(tmp_string, HTML_String) == 1)
Wochentage |= 1 << i;
}
HTML-Beispiel für Radiobutton :
<input type=“radio“ name=„JAHRESZEIT“ id=“JZ0″ value=„0“ checked>
<label for=“JZ0″>Frühling</label>
<input type=“radio“ name=„JAHRESZEIT“ id=“JZ1″ value=„1“>
<label for=“JZ1″>Sommer</label>
Man muß auch hier zunächst den Radiobutton definieren und dann explizit ein Beschriftungslabel zuordnen.
Die Gruppierung der Gruppe geschieht über das Attribut Name, das bei allen Gruppenmitgliedern den gleichen Wert hat. Genau ein Radiobutton der Gruppe darf ein checked enthalten
Auswertung :
Jahreszeit = Pick_Parameter_Zahl("JAHRESZEIT=", HTML_String);
HTML-Beispiel für Combobox :
<select name=„WETTER“ style=“width:160px“>
<option selected value=„0“>Regen</option>
<option value=„1“>Wolken</option>
</select>
Zwischen select und endselect werden die Auswahloptionen aufgeführt. Die vorgewählte Option erhält das Attribut selected.
Auswertung :
Wetter = Pick_Parameter_Zahl("WETTER=", HTML_String);
Das sieht so aus :

Der Request für alles obige sieht so aus :
GET /?WOCHENTAG1=1&WOCHENTAG2=1&WOCHENTAG3=1&ACTION=5&JAHRESZEIT=2&WETTER=2 HTTP/1.1
Slider
HTML-Beispiel :
<input type=„range“ name=„VOLUME“ min=„0“ max=„30“ value=„15“>
Das sieht so aus :

Der Request sieht so aus :
GET /?VOLUME=15&ACTION=6 HTTP/1.1
Auswertung :
if ( action == ACTION_LIES_VOLUME) {
Volume = Pick_Parameter_Zahl("VOLUME=", HTML_String);
}
Listing (ohne die oben bereits wiedergegebenen Unterroutinen)
Coding
//---------------------------------------------------------------------
//ESP866 HTML Demo 02
//---------------------------------------------------------------------
// Author : Hubert Baumgarten
//---------------------------------------------------------------------
#include <ESP8266WiFi.h>
#ifdef __AVR__
#include <avr/power.h>
#endif
#define BGTDEBUG 1
//---------------------------------------------------------------------
// WiFi
byte my_WiFi_Mode = 0; // WIFI_STA = 1 = Workstation WIFI_AP = 2 = Accesspoint
const char * ssid_sta = "<Your SSID>";
const char * password_sta = "<Your Password>";
const char * ssid_ap = "ESP_HTML_02";
const char * password_ap = ""; // alternativ : = "12345678";
WiFiServer server(80);
WiFiClient client;
#define MAX_PACKAGE_SIZE 2048
char HTML_String[5000];
char HTTP_Header[150];
//---------------------------------------------------------------------
// Allgemeine Variablen
int Aufruf_Zaehler = 0;
#define ACTION_OK 1
#define ACTION_NOTOK 2
#define ACTION_SET_DATE_TIME 3
#define ACTION_SET_NAME 4
#define ACTION_LIES_AUSWAHL 5
#define ACTION_LIES_VOLUME 6
int action;
// Vor- Nachname
char Vorname[20] = "Bärbel";
char Nachname[20] = "von der Waterkant";
// Uhrzeit Datum
byte Uhrzeit_HH = 16;
byte Uhrzeit_MM = 47;
byte Uhrzeit_SS = 0;
byte Datum_TT = 9;
byte Datum_MM = 2;
int Datum_JJJJ = 2016;
// checkboxen
char Wochentage_tab[7][3] = {"Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"};
byte Wochentage = 0;
// Radiobutton
char Jahreszeiten_tab[4][15] = {"Frühling", "Sommer", "Herbst", "Winter"};
byte Jahreszeit = 0;
// Combobox
char Wetter_tab[4][10] = {"Sonne", "Wolken", "Regen", "Schnee"};
byte Wetter;
// Slider
byte Volume = 15;
char tmp_string[20];
//---------------------------------------------------------------------
void setup() {
#ifdef BGTDEBUG
Serial.begin(115200);
for (int i = 10; i > 0; i--) {
Serial.print("Warte ");
Serial.print(i);
Serial.println(" sec");
delay(1000);
}
Serial.println("ESP_HTML_02");
#endif
//---------------------------------------------------------------------
// WiFi starten
WiFi_Start_STA();
if (my_WiFi_Mode == 0) WiFi_Start_AP();
}
//---------------------------------------------------------------------
void loop() {
WiFI_Traffic();
delay(10);
}
//---------------------------------------------------------------------
void WiFI_Traffic() {
char my_char;
int htmlPtr = 0;
int myIdx;
int myIndex;
unsigned long my_timeout;
// Check if a client has connected
client = server.available();
if (!client) {
return;
}
my_timeout = millis() + 250L;
while (!client.available() && (millis() < my_timeout) ) delay(10);
delay(10);
if (millis() > my_timeout) {
return;
}
//---------------------------------------------------------------------
htmlPtr = 0;
my_char = 0;
while (client.available() && my_char != 'r') {
my_char = client.read();
HTML_String[htmlPtr++] = my_char;
}
client.flush();
HTML_String[htmlPtr] = 0;
#ifdef BGTDEBUG
exhibit ("Request : ", HTML_String);
#endif
Aufruf_Zaehler++;
if (Find_Start ("/?", HTML_String) < 0 && Find_Start ("GET / HTTP", HTML_String) < 0 ) {
send_not_found();
return;
}
//---------------------------------------------------------------------
// Benutzereingaben einlesen und verarbeiten
//---------------------------------------------------------------------
action = Pick_Parameter_Zahl("ACTION=", HTML_String);
// Vor und Nachname
if ( action == ACTION_SET_NAME) {
myIndex = Find_End("VORNAME=", HTML_String);
if (myIndex >= 0) {
Pick_Text(Vorname, &HTML_String[myIndex], 20);
#ifdef BGTDEBUG
exhibit ("Vorname : ", Vorname);
#endif
}
myIndex = Find_End("NACHNAME=", HTML_String);
if (myIndex >= 0) {
Pick_Text(Nachname, &HTML_String[myIndex], 20);
#ifdef BGTDEBUG
exhibit ("Nachname : ", Nachname);
#endif
}
}
// Uhrzeit und Datum
if ( action == ACTION_SET_DATE_TIME) {
// UHRZEIT=12%3A35%3A25
myIndex = Find_End("UHRZEIT=", HTML_String);
if (myIndex >= 0) {
Pick_Text(tmp_string, &HTML_String[myIndex], 8);
Uhrzeit_HH = Pick_N_Zahl(tmp_string, ':', 1);
Uhrzeit_MM = Pick_N_Zahl(tmp_string, ':', 2);
Uhrzeit_SS = Pick_N_Zahl(tmp_string, ':', 3);
#ifdef BGTDEBUG
Serial.print("Neue Uhrzeit ");
Serial.print(Uhrzeit_HH);
Serial.print(":");
Serial.print(Uhrzeit_MM);
Serial.print(":");
Serial.println(Uhrzeit_SS);
#endif
}
// DATUM=2015-12-31
myIndex = Find_End("DATUM=", HTML_String);
if (myIndex >= 0) {
Pick_Text(tmp_string, &HTML_String[myIndex], 10);
Datum_JJJJ = Pick_N_Zahl(tmp_string, '-', 1);
Datum_MM = Pick_N_Zahl(tmp_string, '-', 2);
Datum_TT = Pick_N_Zahl(tmp_string, '-', 3);
#ifdef BGTDEBUG
Serial.print("Neues Datum ");
Serial.print(Datum_TT);
Serial.print(".");
Serial.print(Datum_MM);
Serial.print(".");
Serial.println(Datum_JJJJ);
#endif
}
}
if ( action == ACTION_LIES_AUSWAHL) {
Wochentage = 0;
for (int i = 0; i < 7; i++) {
strcpy( tmp_string, "WOCHENTAG");
strcati( tmp_string, i);
strcat( tmp_string, "=");
if (Pick_Parameter_Zahl(tmp_string, HTML_String) == 1)Wochentage |= 1 << i;
}
Jahreszeit = Pick_Parameter_Zahl("JAHRESZEIT=", HTML_String);
Wetter = Pick_Parameter_Zahl("WETTER=", HTML_String);
}
if ( action == ACTION_LIES_VOLUME) {
Volume = Pick_Parameter_Zahl("VOLUME=", HTML_String);
}
//---------------------------------------------------------------------
//Antwortseite aufbauen
make_HTML01();
//---------------------------------------------------------------------
// Header aufbauen
strcpy(HTTP_Header , "HTTP/1.1 200 OKrn");
strcat(HTTP_Header, "Content-Length: ");
strcati(HTTP_Header, strlen(HTML_String));
strcat(HTTP_Header, "rn");
strcat(HTTP_Header, "Content-Type: text/htmlrn");
strcat(HTTP_Header, "Connection: closern");
strcat(HTTP_Header, "rn");
#ifdef BGTDEBUG
exhibit("Header : ", HTTP_Header);
exhibit("Laenge Header : ", strlen(HTTP_Header));
exhibit("Laenge HTML : ", strlen(HTML_String));
#endif
client.print(HTTP_Header);
delay(20);
send_HTML();
}
//---------------------------------------------------------------------
// HTML Seite 01 aufbauen
//---------------------------------------------------------------------
void make_HTML01() {
strcpy( HTML_String, "<!DOCTYPE html>");
strcat( HTML_String, "<html>");
strcat( HTML_String, "<head>");
strcat( HTML_String, "<title>HTML Demo</title>");
strcat( HTML_String, "</head>");
strcat( HTML_String, "<body bgcolor="#adcede">");
strcat( HTML_String, "<font color="#000000" face="VERDANA,ARIAL,HELVETICA">");
strcat( HTML_String, "<h1>HTML Demo</h1>");
//-----------------------------------------------------------------------------------------
// Textfelder Vor- und Nachname
strcat( HTML_String, "<h2>Textfelder</h2>");
strcat( HTML_String, "<form>");
strcat( HTML_String, "<table>");
set_colgroup(150, 270, 150, 0, 0);
strcat( HTML_String, "<tr>");
strcat( HTML_String, "<td><b>Vorname</b></td>");
strcat( HTML_String, "<td>");
strcat( HTML_String, "<input type="text" style= "width:200px" name="VORNAME" maxlength="20" Value ="");
strcat( HTML_String, Vorname);
strcat( HTML_String, ""></td>");
strcat( HTML_String, "<td><button style= "width:100px" name="ACTION" value="");
strcati(HTML_String, ACTION_SET_NAME);
strcat( HTML_String, "">Übernehmen</button></td>");
strcat( HTML_String, "</tr>");
strcat( HTML_String, "<tr>");
strcat( HTML_String, "<td><b>Nachname</b></td>");
strcat( HTML_String, "<td>");
strcat( HTML_String, "<input type="text" style= "width:200px" name="NACHNAME" maxlength="20" Value ="");
strcat( HTML_String, Nachname);
strcat( HTML_String, ""></td>");
strcat( HTML_String, "</tr>");
strcat( HTML_String, "</table>");
strcat( HTML_String, "</form>");
strcat( HTML_String, "<br>");
//-----------------------------------------------------------------------------------------
// Uhrzeit + Datum
strcat( HTML_String, "<h2>Uhrzeit und Datum</h2>");
strcat( HTML_String, "<form>");
strcat( HTML_String, "<table>");
set_colgroup(150, 270, 150, 0, 0);
strcat( HTML_String, "<tr>");
strcat( HTML_String, "<td><b>Uhrzeit</b></td>");
strcat( HTML_String, "<td><input type="time" style= "width:100px" name="UHRZEIT" value="");
strcati2( HTML_String, Uhrzeit_HH);
strcat( HTML_String, ":");
strcati2( HTML_String, Uhrzeit_MM);
strcat( HTML_String, ":");
strcati2( HTML_String, Uhrzeit_SS);
strcat( HTML_String, ""></td>");
strcat( HTML_String, "<td><button style= "width:100px" name="ACTION" value="");
strcati(HTML_String, ACTION_SET_DATE_TIME);
strcat( HTML_String, "">Übernehmen</button></td>");
strcat( HTML_String, "</tr>");
strcat( HTML_String, "<tr>");
strcat( HTML_String, "<td><b>Datum</b></td>");
strcat( HTML_String, "<td><input type="date" style= "width:100px" name="DATUM" value="");
strcati( HTML_String, Datum_JJJJ);
strcat( HTML_String, "-");
strcati2( HTML_String, Datum_MM);
strcat( HTML_String, "-");
strcati2( HTML_String, Datum_TT);
strcat( HTML_String, ""></td></tr>");
strcat( HTML_String, "</table>");
strcat( HTML_String, "</form>");
strcat( HTML_String, "<br>");
//-----------------------------------------------------------------------------------------
// Checkboxen
strcat( HTML_String, "<h2>Checkbox, Radiobutton und Combobox</h2>");
strcat( HTML_String, "<form>");
strcat( HTML_String, "<table>");
set_colgroup(150, 270, 150, 0, 0);
strcat( HTML_String, "<tr>");
strcat( HTML_String, "<td><b>Wochentage</b></td>");
strcat( HTML_String, "<td>");
for (int i = 0; i < 7; i++) {
if (i == 5)strcat( HTML_String, "<br>");
strcat( HTML_String, "<input type="checkbox" name="WOCHENTAG");
strcati( HTML_String, i);
strcat( HTML_String, "" id = "WT");
strcati( HTML_String, i);
strcat( HTML_String, "" value = "1" ");
if (Wochentage & 1 << i) strcat( HTML_String, "checked ");
strcat( HTML_String, "> ");
strcat( HTML_String, "<label for ="WT");
strcati( HTML_String, i);
strcat( HTML_String, "">");
strcat( HTML_String, Wochentage_tab[i]);
strcat( HTML_String, "</label>");
}
strcat( HTML_String, "</td>");
strcat( HTML_String, "<td><button style= "width:100px" name="ACTION" value="");
strcati(HTML_String, ACTION_LIES_AUSWAHL);
strcat( HTML_String, "">Übernehmen</button></td>");
strcat( HTML_String, "</tr>");
//-----------------------------------------------------------------------------------------
// Radiobuttons
for (int i = 0; i < 4; i++) {
strcat( HTML_String, "<tr>");
if (i == 0) strcat( HTML_String, "<td><b>Jahreszeit</b></td>");
else strcat( HTML_String, "<td> </td>");
strcat( HTML_String, "<td><input type = "radio" name="JAHRESZEIT" id="JZ");
strcati( HTML_String, i);
strcat( HTML_String, "" value="");
strcati( HTML_String, i);
strcat( HTML_String, """);
if (Jahreszeit == i)strcat( HTML_String, " CHECKED");
strcat( HTML_String, "><label for="JZ");
strcati( HTML_String, i);
strcat( HTML_String, "">");
strcat( HTML_String, Jahreszeiten_tab[i]);
strcat( HTML_String, "</label></td></tr>");
}
//-----------------------------------------------------------------------------------------
// Combobox
strcat( HTML_String, "<tr><td><b>Wetter</b></td>");
strcat( HTML_String, "<td>");
strcat( HTML_String, "<select name = "WETTER" style= "width:160px">");
for (int i = 0; i < 4; i++) {
strcat( HTML_String, "<option ");
if (Wetter == i)strcat( HTML_String, "selected ");
strcat( HTML_String, "value = "");
strcati( HTML_String, i);
strcat(HTML_String, "">");
strcat(HTML_String, Wetter_tab[i]);
strcat(HTML_String, "</option>");
}
strcat( HTML_String, "</select>");
strcat( HTML_String, "</td></tr>");
strcat( HTML_String, "</table>");
strcat( HTML_String, "</form>");
strcat( HTML_String, "<br>");
//-----------------------------------------------------------------------------------------
// Slider
strcat( HTML_String, "<h2>Slider</h2>");
strcat( HTML_String, "<form>");
strcat( HTML_String, "<table>");
set_colgroup(150, 270, 150, 0, 0);
strcat( HTML_String, "<tr><td><b>Lautstärke</b></td>");
strcat( HTML_String, "<td>");
strcat( HTML_String, "<input type="range" name="VOLUME" min="0" max="30" value = "");
strcati(HTML_String, Volume);
strcat( HTML_String, "">");
strcat( HTML_String, "</td>");
strcat( HTML_String, "<td><button style= "width:100px" name="ACTION" value="");
strcati(HTML_String, ACTION_LIES_VOLUME);
strcat( HTML_String, "">Übernehmen</button></td>");
strcat( HTML_String, "</tr>");
strcat( HTML_String, "</table>");
strcat( HTML_String, "</form>");
strcat( HTML_String, "<BR>");
strcat( HTML_String, "<FONT SIZE=-1>");
strcat( HTML_String, "Aufrufzähler : ");
strcati(HTML_String, Aufruf_Zaehler);
strcat( HTML_String, "</font>");
strcat( HTML_String, "</font>");
strcat( HTML_String, "</body>");
strcat( HTML_String, "</html>");
}
Der Sketch zum download:
Weitere Details zu HTML findet man hier :
www.w3schools.com Englische Seite. Kurz und bündig.
wiki.selfhtml.org Deutsche Seite. Ausführliche Beispiele.
Das war’s. Viel Spaß beim Ausprobieren.
Hubert Baumgarten
Hallo,
ich habe eine Frage:
ich habe mit einem NodeMCU-Board und LuaLoader ein bißchen herumgespielt. Um das NodeMCU-Board mit Lua-Scripten laufen zu lassen ist die Lua-Firmware auf dem Board gespeichert.
In diesem Artikel hier werden C-Programme in der Arduino-IDE geschrieben. Wenn man diese C-Programme auf das Board lädt wird dann die Lua-Firmware überschrieben?
Könnte man das so einrichten das beides parallel laufen könnte?
viele Grüße
Stefan
Hallo,
ich wollte das Programm ausprobieren, habe mir die Library ESP8266wifi-Master von Github heruntergeladen, bekomme aber immer eine Fehlermeldung. Erst dass die passende Library nicht vorhanden ist, und wenn ich dann selbst die Library ESP8266wifi.h einfüge bekomme ich die Fehlermeldung ‚WifiServer‘ does not type a name. Kannst du mir da bitte weiterhelfen,
danke Gerhard
Hallo,
Ich hab eine frage, ich möchte auf einen Webserver Bilder einfügen wie wandle ich ein Bild in eine *.c Datei.
gruß Stefan
Hallo Stefan,
Dateien im Sourcecode als hex-array zu speichern ist nicht mehr aktuell.Besser ist es das SPIPPS-FileSystem zu nutzen.
Sehe hier
https://github.com/esp8266/arduino-esp8266fs-plugin
Hubert
Danke Hubert,
versteh ich das richtig danach kann ich das Bild ganz normal aufrufen wie in einer html seite auf dem pc
gruß Stefan
Hallo Stefan,
ganz so einfach geht das nicht. Man kann nicht vom WLAN auf das SPIFFS zugreifen.
Du musst erkennen, welche Daten angefordert wird. Dann öffnest Du die Datei, liest in Blöcken zu 2 KByte ein und sendest den Block. Wichtig zwischen den Blöcken delay (20) sonst kollabiert Dein ESP.
Viele Grüße Hubert
Wie kann man das mit dem Slider ohne übernehmen button machen?
Hallo Hubert,
das ist ein interessanter Ansatz.
Wäre es aber nicht übersichtlicher, das in eine objektorientierte Struktur zu packen?
Also eine Objektstruktur von Objekten, welche jeweils einem HTML Syntax-Konstrukt entsprechen und neben Start- und Endetag eine Objektliste enthalten, die untergeordnete Objekte aufnehmen kann.
Eine insert-Methode würde diese dann in eine Objektliste aufnehmen eine print-Methode dann am Ende iterativ durchlaufen und den gesamten Code erzeugen.
Was hältst du davon? Gibt es so was schon irgendwo?
Lohnt es sich so was zus schreiben?
Ich bin mit html leider noch wenig vertraut – wenn man aber mit dem ESP was machen will muss man da halt irgendwie durch.
Gruß
Rainer
Hallo Hubert,
ich habe schon einiges probiert, komme aber nicht weiter.
Ich möchte gerne z.B. das Datum oder die Uhrzeit automatisch vom ESP aktualisieren, ohne immer wieder eine Taste im Browser drücken zu müssen.
Habe schon was von einem refreshFrame gehört, habe aber keine Ahnung wie das gehen kann.
Hast Du das schon mal gemacht?
Falls ja, kannst Du es kurz beschreiben?
Gruß Matthias
Hallo Matthias,
das ist mit HTML lösbar. Siehe hier:
https://www.w3schools.com/tags/att_meta_http_equiv.asp
Hubert
Hallo Hubert,
komme leider erst jetzt dazu Dir zu antworten.
Funktioniert prima. Vielen Dank für die Hilfe.
Gruß Matthias
Hallo Fans,
Ich bin dabei, den sketch von Hubert Baumgarten ESP8266_HTM_01 zum Laufen zu bringen und bekomme die folgende Fehlerausschrift:
Arduino: 1.8.4 (Windows 10), Board: „Arduino/Genuino Uno“
In file included from C:\Users\Klaus\Documents\Arduino\libraries\ESP8266WiFi\src/ESP8266WiFiSTA.h:28:0,
from C:\Users\Klaus\Documents\Arduino\libraries\ESP8266WiFi\src/ESP8266WiFi.h:34,
from D:\Arduino\ESP_HTML_01\ESP_HTML_01.ino:6:
C:\Users\Klaus\Documents\Arduino\libraries\ESP8266WiFi\src/ESP8266WiFiGeneric.h:27:22: fatal error: functional: No such file or directory
#include
^
compilation terminated.
exit status 1
Fehler beim Kompilieren für das Board Arduino/Genuino Uno.
Ich habe schon ein wenig Erfahrung mit dem Arduino , habe aber wenig Erfahrung oder spezielle Kenntnisse mit der Programmierung, kann mir daher nicht erklären, wie ich den Fehler beseitigen könnte.
Die Com 6 meldet :
AT+CIPMUX=1
AT+CIPSERVER=1,80
AT+CIPSTO=0
AT+CWMODE?
AT+CWSAP?
AT+CIFSR
Es können keine AT-Kommandos gesendet werden.
Für Hilfe danke im Voraus.
Klaus
Hallo Fans,
Nachsatz zu:
Ich bin dabei, den sketch von Hubert Baumgarten ESP8266_HTM_01 zum Laufen zu bringen
#include Muß es heißen!!
^
Für Hilfe danke im Voraus.
Klaus
Nochmal mit Zeichenerläuterung:
Klaus Saare
jetzt gerade
Dein Kommentar wartet auf Freischaltung.
Hallo Fans,
Nachsatz zu:
Ich bin dabei, den sketch von Hubert Baumgarten ESP8266_HTM_01 zum Laufen zu bringen
#include (Kleiner als)functional (größer als) muß es heißen!!
^
Für Hilfe danke im Voraus.
Klaus
Hallo Klaus,
Du musst die Arduino IDE um ein Plugin für den ESP8266 erweitern. Lies den Beitrag von Luca Zimmermann : https://arduino-hannover.de/2015/04/08/arduino-ide-mit-dem-esp8266/
Dann wähle als Board Generic ESP8266.
Hubert
Hallo Hubert,
danke für den Hinweis, das werde ich so machen.
Ich werde dann berichten.
Hallo Hubert – habe die Seite schon vor einer Weile entdeckt und habe jetzt aber erst mein WEMOS D1 min board zum Laufen gebracht. Damit laufen alle beiden HTML Beispiele auf Anhieb. Nun will ich versuchen, ein paar Radio-Buttons zu installieren, mit denen ich z.B. Relais ansteuern kann. Weiterhin will ich einen Analogwert abfragen und zum Client senden. Ich werde dann berichten, wie erfolgreich ich war, oder ggf. hier einen Hilferuf loslassen. Danke für die Veröffentlichung der sehr lehrreichen Beispiele.
Gruß Peter
Hallo Fans,
Neulich hatte mir Hubert Baumgarten auf meine Frage geantwortet, ich habe alles neu eingerichtet und bekomme nun für eine andere Konfiguration den gleichen Fehler wie für ESP8266_HTML_Demo_01:
1 x ESP-12F Doit-Modul
1 x 0,93″ OLED-Bildschirm
1 x 4-Relais-Modul
die folgende Fehlerausschrift:
Arduino: 1.8.4 (Windows 10), Board: „NodeMCU 1.0 (ESP-12E Module), 80 MHz, 115200, 4M (3M SPIFFS)“
Build-Optionen wurden verändert, alles wird neu kompiliert
Archiving built core (caching) in: C:\Users\UKSAA_~1\AppData\Local\Temp\arduino_cache_132476\core\core_esp8266_esp8266_nodemcuv2_CpuFrequency_80,UploadSpeed_115200,FlashSize_4M3M_ebf600f747ad56cd21b1798c997094c7.a
Der Sketch verwendet 260403 Bytes (24%) des Programmspeicherplatzes. Das Maximum sind 1044464 Bytes.
Globale Variablen verwenden 37672 Bytes (45%) des dynamischen Speichers, 44248 Bytes für lokale Variablen verbleiben. Das Maximum sind 81920 Bytes.
warning: espcomm_sync failed
error: espcomm_open failed
error: espcomm_upload_mem failed
error: espcomm_upload_mem failed
Am sketch liegt es wohl nicht.
Für jede Hilfe im Voraus herzlichen Dank.
Hallo,
Ich hätte mal eine Frage bezüglich der Bild datei im ersten beispiel code?
wie hast du diese datei erstellt? gibt es dazu eine bestimmte Software die du nutzt? Ich finde nichts auf tante Google…
wenn ich versuche den max. Wert des Sliders über 254
zu erhöhen funktioniert das auswerten nicht mehr richtig,
leider finde ich den Fehler nicht …
Der aktueller Wert des Slider wird in meinem Beispiel in die Variable Volume eingelesen. Diese ist als Byte definiert.Für Deine Anwendung empfehle ich die Definition als unsigned int.
Hallo Hubert,
Ich versuche seit tagen einen ds18b20 einzubinden. Die Auswertung des sensors ist kein Problem! Aber das einbringen in die html Seite scheitert? Kann es sein dass hier nicht mit float gearbeitet werden kann? Hat jemand vielleicht eine Idee wie soetwas realisiert werden könnte?
Dieses Beispiel hat mir super geholfen, ich habe etwas CSS & JScript mit rein gebracht.
Eigentlich würde es jetzt super funktionieren, nur leider sprenge ich jetzt wohl irgend eine Grenze einer Variablen.
Ich hatte vermutet „HTML_String“ (char HTML_String[5000];) aber den Wert einfach höher setzen hat nicht gereicht, gibt es noch eine andere Stelle an der ich schrauben könnte?
(alternative ist noch eben den Seiteninhalt zu unterteilen)
Danke für diesen sehr hilfreichen Beitrag!
Alles Super:
Laenge Header : 85
Laenge HTML : 4770
Fehlerfall:
Laenge Header : 85
Laenge HTML : 4870
als Nachtrag habe ich mal die Werte ermittelt ab wann es bei mir zum Fehler kommt, im Fehlerfall sendet der ESP8266(12) nach dem ersten Seitenaufruf weiter LeerZeilen bis in alle Ewigkeit.
Eventuell kennt das ja schon jemand und weis was hier zu tun ist?
Hallo Hubert,
ansich funktioniert die Webseite ganz gut aber in der funktion
void WiFi_Start_STA() {
…
habe ich dann noch diese Zeile eingefügt:
WiFi.begin(ssid_sta, password_sta);
dann verbindet sich der ESP auch mit dem lokalen Router.
Außerdem zeigen verschiedene Browser die Datum/Zeit Felder falsch an.
Sonst Top!!!!!
Gruß Günter
Hi
Besten Dank für diese Ausarbeitung!
Ich versuche gerade, diverse Sensoren per ESP8266 anzeigen zu lassen (mitgeschnitten via CAN-Modul, wo einige Arduinos die Sensorwerte drauf geben) – Das klappt auch halbwegs, mit Aktualisierung, alle 3 Sekunden wird per JavaScript eine Unterseite aufgerufen, Die als Rückgabe ID=Wert Paare zurück gibt, Die vom JavaScript interpretiert in einer Tabelle aktuell gehalten werden.
(Jedes relevante Tabellenfeld hat eine eindeutige ID, Welche auch in der Rückgabe bereits vom ESP generiert wird – der JavaScript muß ’nur noch‘ getElementByID=arg[0].value=arg[1] au7sführen)
Nun wollte ich die Daten ‚graphisch‘ etwas hübscher darstellen – in HTML ASCII-Art – hier bekomme ich recht schnell, daß der ESP resettet – wohl, weil meine Datenmenge (übrigens per String zusammen geklebt) wohl die Innereien zerreißt.
Hier der Ansatz: Char-Array … klar … logisch … und dann noch, Was ich in den Tiefen des WWW ebenfalls nicht finden konnte – Übertragen in ‚kleinen Happen‘.
Junge – Du bist top!
Ob Dein Sketch Heute noch lauffähig ist, werde ich gleich herausfinden – Deine Ideen/Umsetzungen werden auf jeden Fall in mein Projekt einfließen.
MfG
PS: Ich durfte auch über HTML5 Canvas stolpern – vll. gibt’s ja doch noch Grafik vom ESP 🙂
Nachtrag: Der Sketch funktioniert Jan/2021 immer noch.
Einzig eine unbenutzte Variable tmp wird in
int Pick_N_Zahl(const char * tx, char separator, byte n)
angemeckert – Die wird sonst zur Generierung der Rückgabe benutzt – hier nicht benötigt.
Kostet aber auch Nichts – der Kompiler optimiert Die weg.
Habe nur die SSID und das zugehörige PW in einen separaten TAB (pw.h) abgelegt (und Diesen per #include „pw.h“ includiert) – so ist mein PW nicht direkt beim Vorzeigen des Sketch überall bekannt.
MfG