ESP8266 von Anfang an

BAXL

Moderator
Mitarbeiter
In diesem Thema möchte ich, wie in einer Art Blog, meine Bemühungen dokumentieren, den ESP8266 zu verstehen und anwenden zu können.

Der ESP8266 ist sehr einfach ausgedrückt ein kleiner Mikrokontroller, der einmal die reine Verarbeitungseinheit CPU beinhaltet und mit einer kleinen 2,4 GHz Antenne über WLAN mit der Aussenwelt kommunizieren kann. Der Programmspeicher ist je nach Modell ein kleiner Extrachip oder in dem Blechgehäuse integriert. Die Bezeichnung ESP8266 hat sich dabei zu einem Synonym für eine Vielzahl von fertigen Platinen entwickelt, an die man sehr einfach eine externe Beschaltung, wie z.B. digitale Sensoren, anschließen kann und der idR. auch einen Micro-USB Anschluß besitzt, über den man diese Baugruppe bequem per PC programmieren und abfragen kann. Das verhält sich so ähnlich wie beim Arduino, den es ebenfalls in vielen Erscheinungsformen gibt.

Der ESP8266 quasi nackt



Der ESP8266 ganz minimalistisch mit nur wenigen Anschlußpins


Und hier als Entwicklerplatine bereits mit USB-Stecker und auf Pfostenstecker herausgeführte Anschlüsse




Und nochmal im Vergleich



Der offensichtlichste Unterschied zwischen den beiden Familien sind die Leistungsfähigkeit, zur Verfügung stehender Speicher, die WLAN-Fähigkeit und dass beim ESP8266 nur ein analoger Eingang vorhanden ist, der ADC0. Ansonsten hat man mehrere digitale Ein/Ausgänge, die sich GPIO nennen und nur mit 3,3 V zurechtkommen und nicht wie bei vielen Adruinos, mit 5V. Außerdem haben nicht alle digitalen Ports bereits intern vorhandene Pull-Up oder Pull Down Widerstände. Einige schon, doch das ist ein Thema für sich.



Beiden gemein ist die Möglichkeit sie über die Arduino Programmierumgebung programmieren zu können. Der ESP8266 erfeut sich zudem bei den Freunden für Heimautomatisierung größter Beliebtheit.



Vom ESP8266 habe ich zuerst von einem Kollegen gehört, der darüber in höchsten Tönen geschwärmt hat und mir von alternativen Betriebsystem und Programmierumgebungen usw. erzählte. Das hat mich Anfangs sehr verwirrt und ich habe nur Bahnhof verstanden.

Nähert man sich diesem Modul aber etwas langsamer und behutsamer, fällt auf, dass man es bei der Programmiereung eigentlich wie einen Arduino händeln kann. Er kennt so ziemlich dieselben Befehle und das Überspielen eines Programms geht genau so schnell.

Lässt man die WLAN-Fähigkeit außen vor, hat man quasi einen Arduino.

Um damit tatsächlich arbeiten zu können und die WLAN-Fähigkeit nutzen zu können, sollte man in einfachen Schritten vorgehen.

Man benötigt im einfachsten Fall ein ESP8266 Modul, das möglichst angelötete Pins besitzt und einen Micro-USB Anschluß. Dann sollte man sich die Arduino-Programmierumgebung auf dem PC installieren und der Programmierumgebung diesen neuen "Prozessortyp" bekannt machen. Wie das geht, dazu gibt es jede Menge Seiten, die das sehr gut erklären. Zum Beispiel auf heise.de.

Nicht zu vergessen sei die Installation eines passenden USB-Treibers, damit der PC den ESP auch "sehen" und bedienen kann. Den Treiber findet man unter dem Namen CH340, oder man guckt gleich beim Makershop.

Damit hat man eigentlich die erste Hürde überwunden und kann mit dem ersten Simpelprogramm starten, das in der Regel das Blinkenlassen der auf dem Bord angebrachten blauen LED ist.

Das erstmal das Wichtigste für den Anfang. Sobald ich anfange damit zu fummeln schreibe ich mehr, dabei gehe ich wieder absichtlich nicht auf alle möglichen Feinheiten ein und konzentriere mich darauf, alles so einfach wie möglich zu halten, aber die wichtigsten Sachen nicht zu unterschlagen. Es gibt unzählige Seiten, da schreiben Leute, die viel besser sind als ich und viel mehr davon verstehen, leider setzen die bei ihren Erklärungen nicht selten ein gewissen Wissen in vielen Bereichen voraus, oder die Kenntnis, was verschiedene Abkürzungen bedeuten.
 
Zuletzt bearbeitet:

BAXL

Moderator
Mitarbeiter
Es gibt weitere zarte Erkenntnisse, die zumindest bei der Programmierung der Digitalausgänge wichtig werden können. Beim Arduino steuern wir die Digitalausgänge mit der Zahl an, deren Nummer der Pin trägt. D.h. bei D3 wäre es die 3, bei D4 die 4...D9 die 9 usw..

Beim ESP8266 sieht das anders aus. Da werden die Ausgänge mit GPIO1 bis GPIO(irgendwas) bezeichnet, wobei sogar einige Nummern ausgelassen werden. Das ist verwirrend. Die Pinbezeichnungen von Platinen haben aber wieder eine durchgehende Nummerierung von D0 bis D10. In der Programmierumgebung setzt man dann für die Pinbezeichnung in den Befehlen die Bezeichnungen D0, D1, D2 usw..

Ok, das war zu schwierig. Beispiel:

Ausgabebefehl für einen Arduino, mit dem der Digitalausgang D5 eingeschaltet wird:

digitalWrite( 5, HIGH);

Beim ESP8266 haben wir den GPIO5, der aber auf den Pin D1 herausgeführt wird, da heißt das dann:

digitalWrite(D1, HIGH);

obwohl es sich um den GPIO5 handelt. Ganz wichtig, das D muß vor der Zahl stehen!


Zuordnung der Belegung der Digitale Pins zum GPIO

D0
- GPIO16 / LED_BUILTIN Kann sein
D1 - GPIO5
D2
- GPIO4
D3
- GPIO0
D4
- GPIO2 / LED_BUILTIN Kann auch sein
D5
- GPIO14
D6
- GPIO12
D7
- GPIO13
D8
- GPIO15
D9
- GPIO3
D10
- GPIO1

Man sollte bei der Borddoku nachsehen an welchem Port die BuiltIn LED angeschlossen ist.
 
Zuletzt bearbeitet:

BAXL

Moderator
Mitarbeiter
Heute sind die drei bestellten ESP8266 D1 mini eingetroffen. Natürlich wollte ich zuerst prüfen, ob die Dinger leben. Dazu habe ich mir ein Beispiesketch aus dem Internet besorgt und in die Arduino IDE geladen. In dem Sketch soll die auf dem Board verbaute blaue LED im Sekundentakt blinken.

Nun kam das erste Problem, welches Board stelle ich ein. Nach einiger Suche und Rumfummelei habe ich herausgefunden, dass man das "LOLIN(WEMOS) D1 R2 & mini" einstellen muß.

Nochmal schnell den Sketch kompiliert und hochladen lassen. Es gab keine Fehlermeldung. Trotzdem blinkte die LED nicht. Nach einer weiteren Suche bin ich dahinter gekommen, dass in dem Beispielprogramm der falsche Digitalport eingestellt war. Es war nicht D0, sondern D4. Hätte ich das Beispielprogramm geladen, welches beim Installieren des Boardtreibers mitinstalliert wurde, hätte es sofort geklappt, weil man dort einfach als Angabe in pinMode() LED_BUILTIN eingesetzt hatte. In der Dokumentation vom Lieferanten bin ich dann auf die Fehlerursache gestoßen. Der Digitalport für die Builtin-LED ist der Pin D4!

Also nochmal das erste Sketch ausprobiert, welches dann auch funktionierte. Hurra, die LED blinkt nun vor sich hin.

#define LED D4

void setup() {
pinMode(LED, OUTPUT); // Port aus Ausgang schalten
}

void loop() {
digitalWrite(LED, LOW); //Led port ausschalten
delay(1000); //1 Sek Pause
digitalWrite(LED, HIGH); //Led port einschlaten
delay(1000);
}

void setup() {
// initialize digital pin LED_BUILTIN as an output.
pinMode(LED_BUILTIN, OUTPUT);
}

// the loop function runs over and over again forever
void loop() {
digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level)
delay(1000); // wait for a second
digitalWrite(LED_BUILTIN, LOW); // turn the LED off by making the voltage LOW
delay(1000); // wait for a second
}

Beide Sketches funktionieren :)

Der nächste Schritt wird es sein, den ESP seiner eigentlichen Bestimmung zuzuführen, nämlich der Kommunikation per WLAN, ansonsten kann man für so triviale Sachen, wie LEDs blinken lassen, auch einen einfachen Arduino nehmen.

Zum Größenvergleich habe ich das ESP8266 D1 mini neben eine Briefmarke gehalten:

 
Zuletzt bearbeitet:

BAXL

Moderator
Mitarbeiter
Im Moment bin ich am verzweifeln. Meine kleinen ESP-Freunde schaffen es offenbar, sich in mein lokales WLAN "einzuwählen". Wenn ich den ESP per USB am PC habe, wird mir im seriellen Monitor artig die IP-Adresse angezeigt und ich kann im Browser am Smartphone über http://<IP-Adresse> kontakt zum ESP aufnehmen.

#include <ESP8266WiFi.h> // stellt die WiFi Funktion zur Verfügung
WiFi.begin(ssid, passwort); // die beiden Strings kann man sich selbst ausdenken

while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print(".");
// solange noch keine Verbindung hergestellt wurde lassen wir uns in 0,5s Abständen einen Punkt anzeigen
}


Wenn man dem ESP keine statische IP-Adresse vergeben will oder kann, muß man die DNS-Funktion nutzen, d.h., dass dem ESP bei jedem Anmelden eine IP-Adresse vom WLAN zugewiesen wird. Diese Adresse kann sich aber im Laufe der Zeit mal ändern, dann erreicht man den ESP nicht mehr über die IP-Adresse und man muß irgendwie die neue IP-Adresse herausfinden.

#include <ESP8266WebServer.h> // ermöglicht die Erreichbarkeit
ESP8266WebServer server(80); // Objekt für den Webserver bereitstellen und Port festlegen Standard ist 80


Es soll aber eine Möglichkeit geben, dass dieses Problem behebt. Diese Funktion nennt sich mDNS und bedeutet wohl soviel, dass man dem ESP in seinem Programm einen Namen gibt, meinetwegen "BAXLSESP" oder so. Damit soll es dann möglich sein, ohner die aktuelle IP-Adresse zu kennen, einfach http://BAXLSESP.local einzugeben und man bekommt auch kontakt zum ESP. Tja, und das klappt trotz aller Bemühungen nicht.

#include <ESP8266mDNS.h> // verhindert Probleme bei sich ändernder IP-Adresse

Wenn sich so ein ESP in meiner Fritz Box anmeldet, dann sehe ich irgendeinen andern Namen mit ESP davor, aber nicht den, den ich im Programm vergeben habe.
Ich weiß nicht auf wievielen Seiten ich schon gesucht habe, wie oft ich das Listing aus dem YT-Video abgetippt habe und ich habe auch von anderen Seiten Listings ausprobiert - ohne Erfolg. Über die IP-Adresse komme ich immer dran, aber über diesen Alias-Namen geht es nicht. :(
 
Zuletzt bearbeitet:

BAXL

Moderator
Mitarbeiter
Ich glaube ich habe die Ursache, aber keine Lösung. Damit das funktioniert, muss der WLAN Router aus dem Namen eine IP Adresse machen. Das nennt sich DNS Rebinding. Diese Funktion ist bei meinen WLAN Routern deaktiviert. Der Grund dafür ist, dass das ein Sicherheitsloch im WLAN hervorrufen kann, was Angreifern die Möglichkeit für einen Einbruch ins Homenetz ermöglicht.

AVM macht das per default

Ergo muss ich mir was Neues einfallen lassen.
Ich habe da was von APs gelesen, kann das aber noch nicht erklären. Also dranbleiben.
 
Zuletzt bearbeitet:

Joungmerlin

Mitglied
Wenn die Teile Wlan bzw. Netzwerk fähig sind müssen die doch ne feste MAC Adresse haben.
Demnach musst du doch nur den MAC Adressen im DHCP vom Router feste IP Adressen zuordnen.

Schon hat sich dein Problem in Luft aufgelöst.
 

BAXL

Moderator
Mitarbeiter
Da hast Du im Prinzip Recht, dazu muß der entsprechende Router allerdings immer verfügbar sein. Das kann ich aber nicht immer garantieren, darum wird es auf einen Access Point, kurz AP hinauslaufen.

Wenn hier im Thema nicht, wie bei den Arduinos gewohnt, von mir in relativ kurzen Taktzeiten Posts kommen, dann liegt das daran, dass ich im Internet herumsuche und viel lese. Allmählich beginne ich zu verstehen, das reicht aber noch nicht aus, um sinnvoll weiterzumachen, oder gar erklärende Posts zu schreiben. Besonders die Erstellung einer "Internet"-Seite, wenn der ESP aufgerufen wird, ist für mich noch wie ein Schnittmuster. Die Befehle sehen sehr kryptisch aus, wenn man sich damit nicht auskennt.


Hier ist mal so ein Beispiel, was ich mir aus den vielen Quellen "besorgt" habe. Wo auch immer html oder http steht wird es sehr unübersichtlich. Für einen Webseitenprofi sicherlich kalter Kaffee, dafür würde der sich aber die Ohren bei der Hardwareprogrammierung brechen. Und, man muß nicht in allem ein Experte sein.

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

String html1 = "<!DOCTYPE html>\r\n<html>\r\n<head>\r\n\
<meta content=\"text/html; charset=ISO-8859-1\" http-equiv=\"content-type\">\r\n\
<title>WebSchalter</title>\r\n<form action=\"";
// String((val)?"/1.html":"/0.html")
String html2 = "\">\r\n<input value=\"ON/OFF\" style=\"";
String html3 = " width:5em;height:3em; font-size: 16px;\" type=\"submit\"></form>\r\n</head>\r\n<body>\r\n</body>\r\n</html>";
String Temp = "";

const char htmlFrame[] = "<!DOCTYPE html><html><head><meta charset=\"utf-8\">\r\n\
<title>IP Steckdose</title></head><body><h1>IP Steckdose</h1>\
<script type=\"text/javascript\">setInterval(refreshIframe2, 3000);\r\n\
function refreshIframe2(){ var frame = document.getElementById(\"Frame2\");\r\n frame.src = frame.src;}</script>\r\n\
<iframe id=\"Frame2\" src=\"/\" name=\"IP Relais\" height=\"300\" width=\"300\" frameBorder=\"0\"></iframe></body></html>";


ESP8266WebServer server(80); // Serverport hier einstellen
int val = 1; //Schaltzuschtand 1 ist Aus, 0 ist Ein
int i; //Variable fuer Adresse in EEPROM

void Ereignis_SchalteON() // Wird ausgefuehrt wenn "http://<ip address>/1.html" aufgerufen wurde
{
val = 0; // Relais Aus
digitalWrite(0, val); // GPIO0
Temp = html1 + String((val) ? "/1.html" : "/0.html");
Temp += html2 + String((val) ? "BACKGROUND-COLOR: DarkGray;" : "BACKGROUND-COLOR: Chartreuse;") + html3;
server.send(200, "text/html", Temp);
}

void Ereignis_SchalteOFF() // Wird ausgefuehrt wenn "http://<ip address>//0.html" aufgerufen wurde
{
val = 1; // Relais Ein
digitalWrite(0, val); // GPIO0
Temp = html1 + String((val) ? "/1.html" : "/0.html");
Temp += html2 + String((val) ? "BACKGROUND-COLOR: DarkGray;" : "BACKGROUND-COLOR: Chartreuse;") + html3;
server.send(200, "text/html", Temp);
}

void Ereignis_Index() // Wird ausgeuehrt wenn "http://<ip address>/" aufgerufen wurde
{
Temp = html1 + String((val) ? "/1.html" : "/0.html");
Temp += html2 + String((val) ? "BACKGROUND-COLOR: DarkGray;" : "BACKGROUND-COLOR: Chartreuse;") + html3;
server.send(200, "text/html", Temp);
}

void Ereignis_Frame() // Wird ausgefuehrt wenn "http://<ip address>/frame" aufgerufen wurde
{
server.send(200, "text/html", htmlFrame );
}

void setup() // Wird 1 Mal beim Start ausgefuehrt
{
char ssid[32] = "1234\0"; //Variable fuer Wlan Name
char passphrase[64] = "567890\0"; //Variable fuer Passwort

digitalWrite(0, 1); // warscheinlich ueberfluessig
pinMode(0, OUTPUT); // GPIO0 als Ausgang konfigurieren
digitalWrite(0, 1); // Anfangszustand 1 (Relais ausgeschaltet)
pinMode(2, INPUT_PULLUP); // GPIO2 als Eingang mit Pullup konfigurieren

Serial.begin(115200); // Serielle schnittstelle initialisieren
Serial.println("\r\n"); // Lehere Zeile ausgeben
EEPROM.begin(64); // EEPROM initialisieren mit 64 Byts
sprungmarke: // Hier landen wir wenn EEPROM leer

// Eeeprom einlesen
for (i = 0; i < 32; i++) ssid = EEPROM.read(i);
for (i = 32; i < 64; i++) passphrase[i - 32] = EEPROM.read(i);

// Wenn EEPROM leer
if (ssid[0] == 255)
{
Serial.println("SSID nicht konfiguriert\r\n") ;
Serial.println("Weiter mit \"Enter\"\r\n") ;
while (!Serial.available())yield(); //Warte bis Seriell etwas reinkommt
InputEEPR();
goto sprungmarke;
}
// Wlan-Zugang konfigurieren
WiFi.mode(WIFI_STA); // modus
WiFi.begin(ssid, passphrase);
WiFi.printDiag(Serial); // Wlan Daten seriell ausgeben

while (WiFi.status() != WL_CONNECTED)// Warten auf verbindung
{
delay(500);
Serial.print(".");
if (Serial.available()) InputEEPR(); //Ausgand wenn Seriell etwas empfangen
} // dann Wlan Name und Passwort eingeben

Serial.println(""); // Wenn verbunden
Serial.print("Verbunden mit ");
Serial.println(ssid);
Serial.print("IP address: ");
Serial.println(WiFi.localIP());// Aktuelle IP des ESP8266-servers zeigen

//Bechandlung der Ereignissen anschlissen
server.on("/", Ereignis_Index);
server.on("/1.html", Ereignis_SchalteON);
server.on("/0.html", Ereignis_SchalteOFF);
server.on("/frame", Ereignis_Frame);

server.begin(); // Starte den Server
Serial.println("HTTP Server gestartet");
}

void InputEEPR() // Unterprogramm zum eingeben der Wlan-Daten
{
String Text = "";
char inser;

inser = Serial.read();
if (inser == 13) // Wenn "Enter" bet?tigt, 27 esc
{
Serial.println("Input SSID: ");
for (i = 0; i < 32; i++) // SSID maximal 32 Byte
{
while (!Serial.available()) yield(); //warte bis etwas empfangen wird
inser = Serial.read();
Serial.write(inser); //Echo

if (inser == '\r') // Wenn zeile abgeschlossen ist
{
EEPROM.write(i, '\0'); //Stringende setzen
break; // for Schleife verlassen
} else EEPROM.write(i, inser);//nechste Zeichen in EEPROM speichern
}
Serial.println("\r\nOK");

Serial.println("Input Passwort: ");
for (i = 32; i < 64; i++) // Passwort maximal 32 Byte
{
while (!Serial.available()) yield(); //warte bis etwas empfangen wird
inser = Serial.read();
Serial.write(inser);
if (inser == '\r') // Wenn zeile abgeschlossen ist
{
EEPROM.write(i, '\0'); //Stringende setzen
break; // for schleife verlassen
} else EEPROM.write(i, inser);//nechste Zeichen empfangen
}
EEPROM.commit(); // EEPROM Schreiben
Serial.println("\r\nOK");
Serial.println("Bitte ESP8266 neu starten");
}
}


void loop() //Hautprogramm
{
if (Serial.available()) InputEEPR();// Wenn Seriell etwas empfangen
server.handleClient(); // Serwerereignisse abarbeiten

if (!digitalRead(2)) // Wenn Taster an GPIO2 betaetigt wurde
{
val = !val; // Schaltzstand ?endern
digitalWrite(0, val); // Schaltzstand an denn GPIO2 ausgeben
while (!digitalRead(2))server.handleClient(); //Warten bis der Taster losgelassen wird
}
}
 
Zuletzt bearbeitet:

Joungmerlin

Mitglied
Öhhhmmmm...

Ein Access Point?

Du weißt schon, daß der keine IP Adressen vergibt.
Ein reiner Access Point hat keinen DHCP Server. Diesen hat nur ein nicht eingeschränkter Router.

Man kann quasi jeden Router zu nem AP kastrieren in dem man diesem einfach ne feste IP Adresse verpasst und den DHCP Server deaktiviert.
 

BAXL

Moderator
Mitarbeiter
Warum sollte ein ESP denn auch IP Adressen vergeben? Ich will damit ja keine FritzBox o.ä. nachbilden oder gar ersetzen. Der ESP hat primär die Aufgabe etwas zu messen oder zu schalten und wenn gerade kein WLAN in der Nähe ist muss er eben seine eigene Verbindung anbieten. Aber trotzdem danke dass Du mich auf dieses wichtige Detail aufmerksam gemacht hast.
 
Top Bottom