ESP8266 & Arduino Mega - Webserver (als Client an vorh. AP)

Moin moin.

Ich habe vor mit einem Arduino Mega und einem ESP8266 einen simplen Webserver laufen zu lassen um übers LAN (später auch WAN) 3-4 Lampen steuern zu können. Das ganze über eine simple HTML-Maske.

Vorhanden sind:
-Arduino Mega
-ESP 8266 (mit AT-Firmware)
-USB-to-Serial Converter (sollte für diesen Zweck nicht notwendig sein)

Ich habe Probleme beim Sketch.
Bisher läuft es, dass ich den Arduino mit beigefügtem Code bespiele und dieser Sich dann mit dem ESP per Serial2 (Spannungsteiler verwendet) verbindet. Der ESP verbindet sich erfolgreich mit dem WLan und meldet dies auch an den Arduino zurück, welcher mir dies wiederum über Serial(USB) mitteilt.

Der Code springt bis in die Loop und hier weiß ich nicht weiter.

Muss der Webserver direkt auf den ESP geflasht sein und der Arduino empfängt nur den Befehl, dass (z.B.) ein Button gedrückt wurde und schaltet darauf hin einen Ausgang?

Oder kann ich dem ESP über den Arduino alle Instruktionen geben, dass dieser einen Webserver aufmacht?

Oooder kann ich quasi "nur die Antenne" des ESP nutzen und alles andere auf dem Arduino laufen lassen?
Performance ist nicht wichtig, soll ja nur 3-4 simple Relais ein-/ausschalten.

Ich hoffe, ihr könnt mich auf den richtigen Weg bringen. Danke schon mal!

Hier der Sketch bisher:

// SoftwareSerial mySerial(10, 11);       // RX, TX ; for use with Arduino Uno instead of HWSerial of the Mega 
#define SSID_client "Alice-D24"           //Set SSID of the Wifi connect TO
#define PASS_client "Multiketaminsaft24"  //And the password
#define DST_IP "220.181.111.85"           //baidu.com
boolean connectWiFi();

void setup()
   {

     // Open serial communication and wait for port to open:
     //serial 2 is to esp8266 
     Serial2.begin(9600);                   //9600 (mine), 57600, 115200. Must match flashed baudrate on ESP8266
     Serial2.setTimeout(1000);
     
     //Serial 0 is to usb
     Serial.begin(115200);

     //wait for ports to connect
     while(!Serial); 
     while(!Serial2);

     //Say Hello
     Serial.println("ESP8266 + Arduino by Linyo");
     Serial.println("Connecting to ESP8266 Module");
     
     //read serial from ESP
     while(Serial2.available()>0)
     Serial2.read();
     delay(5000);                           //Five seconds to power on the ESP-Module.
     Serial2.println("AT+RST");             //Tell ESP to give back infos
     Serial2.flush();

     //if(Serial2.find("ready"))
     if(Serial2.find("Ready")||Serial2.find("ready"))
     {
       //If ESP-Module was found
       Serial.println("Module found!");
     }
     else
     {
       //If ESP-Module was not found
       Serial.println("MODULE NOT FOUND! CHECK CONNECTIONS AND POWER SUPPLY");
       while(1);
     }
     delay(1000);

     
     //Connect to the WiFi
     boolean connected=false;
     for(int i=0;i<5;i++)
        {
       if(connectWiFi())                      //function located at bottom
          {
            connected = true;
            break;
          }
        }
     if (!connected){while(1);}
     delay(5000);
        
     //Set the single connection mode
     Serial2.println("AT+CIPMUX=0");

 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void loop() {
     Serial.println("Test");                //Test if Programm enters loop
}



//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
boolean connectWiFi()
     {
       Serial2.println("AT+CWMODE=1");
       String cmd="AT+CWJAP=\"";
       cmd+=SSID_client;
       cmd+="\",\"";
       cmd+=PASS_client;
       cmd+="\"";
       //dbgSerial.println(cmd);
       Serial2.println(cmd);
       Serial.println(cmd);
       delay(2000);
       if(Serial2.find("OK"))
       {
         //dbgSerial.println("OK, Connected to WiFi.");
         Serial.println("OK, Connected to WiFi.");
         return true;
         }else
         {
           //dbgSerial.println("Can not connect to the WiFi.");
           Serial.println("Can not connect to the WiFi.");
           return false;
         }
       }

soll ja nur ein simples Relais ein-/ausschalten.

Wenn das alles ist, dann würde ich auf den Mega verzichten.
Eine eigene Firmware auf den ESP flashen, welche den Kram erledigt.

Ok, ich korrigiere mich. 3 Lampen :smiley:

Schau in der Dokumentation der AT Befehle nach welche Sequenzen du dafür brauchst.

Eine ganz gute Beschreibung findest du hier ESP8266 - AT Command Reference · room-15

Basisanweisungen für einen Webserver sind:

 "AT+CIPMUX=1"
 "AT+CIPSERVER=1,80"
 "AT+CIPSEND=<lenOfData>"
 "AT+CIPCLOSE=<connectionNumber>"

Gibt aber sicher auch einen Haufen Beispiele.

Whandall:
Schau in der Dokumentation der AT Befehle nach welche Sequenzen du dafür brauchst.

Eine ganz gute Beschreibung findest du hier ESP8266 - AT Command Reference · room-15

Basisanweisungen für einen Webserver sind:

 "AT+CIPMUX=1"

"AT+CIPSERVER=1,80"
"AT+CIPSEND="
"AT+CIPCLOSE="



Gibt aber sicher auch einen Haufen Beispiele.

Super, Danke.
Das ist ein Anfang :slight_smile:

Auch für 3 Lampen sollte ein ESP reichen (kommt drauf an, welchen du hast).
Schau dir sonst mal die NodeMCU an. Sind einfach zu programmieren und haben einiges an Pins die du zum schalten verwenden kannst.

Grüsse
Peter

someone83:
Auch für 3 Lampen sollte ein ESP reichen (kommt drauf an, welchen du hast).
Schau dir sonst mal die NodeMCU an. Sind einfach zu programmieren und haben einiges an Pins die du zum schalten verwenden kannst.

Grüsse
Peter

Vielen Dank für den Tip, allerdings habe ich ja bereits Hardware und bin ziemlich zuversichtlich, dass die Aufgabe mit dieser zu lösen ist.
Neue Hardware zu kaufen wäre die letzte Option, denn dann fliegt der ESP in die Ecke und wird eh nicht mehr genutzt.
Außederm möchte ich eben diesen verstehen lernen.

Mir gehts weniger um die Lampen. Ich möchte das Potenzial verstehen und ausschöpfen können

legolas136:
allerdings habe ich ja bereits Hardware und bin ziemlich zuversichtlich, dass die Aufgabe mit dieser zu lösen ist.

Kannst du auch sein. :wink:

Dann spricht natürlich nichts dagegen!

Nur in Sachen Potential hat der ESP dem Mega das ein oder andere Voraus (mehr Speicher, massiv schneller).

Aber wenns ums lernen geht, bist du mit deiner Variante besser dran!

Grüsse
Peter

hi,

wenn's um's lernen geht, mach nur zu.

aber das mit der "besseren" lösung hast Du vielleicht nicht richtig verstanden:

der 8266 kann wesentlich mehr und das schneller als der mega. einziger nachteil ist, daß er weniger ausgänge hat (die Du ja nicht brauchst). für einen solchen zweck einen mega dazuzuschnallen, ist nur eine bremse.

wenn Du willst, schau mal hier. damit habe ich es sofort hinbekommen.

gruß stefan

EDIT:
PS.: es wird von GPIO2 gesprochen, das ist der, der die draufgebaute LED steuert (beim esp12e, vielleicht bei Deinem anders).
ein- und ausschalten ist vertauscht, wenn ich mich recht erinnere...

Super!

Lieben Dank für all die Antworten. Werde mich direkt daransetzen, wenn ich mich vom Wochenende erholt habe :grinning:

Eisebaer:
hi,

wenn's um's lernen geht, mach nur zu.

aber das mit der "besseren" lösung hast Du vielleicht nicht richtig verstanden:

der 8266 kann wesentlich mehr und das schneller als der mega. einziger nachteil ist, daß er weniger ausgänge hat (die Du ja nicht brauchst). für einen solchen zweck einen mega dazuzuschnallen, ist nur eine bremse.

wenn Du willst, schau mal hier. damit habe ich es sofort hinbekommen.

Stabiler HTTP 1.1 WLAN Webserver mit dem ESP8266 Microcontroller - Bastel & Reparatur Blog

gruß stefan

EDIT:
PS.: es wird von GPIO2 gesprochen, das ist der, der die draufgebaute LED steuert (beim esp12e, vielleicht bei Deinem anders).
ein- und ausschalten ist vertauscht, wenn ich mich recht erinnere...

Den hatte ich schon drauf, lief auch auf Anhieb. Zu dem Programm würde ich jetzt gerne noch eine I/O-Erweiterung mit dem Mega (Oder nem Uno) haben.

Ich habe übrigens den ESP-01

So, mal der Zeischenstand:

folgendes läuft jetzt auf den ESP8266:

/*--------------------------------------------------
HTTP 1.1 Webserver for ESP8266 
for ESP8266 adapted Arduino IDE

Stefan Thesen 04/2015

Running stable for days 
(in difference to all samples I tried)

Does HTTP 1.1 with defined connection closing.
Reconnects in case of lost WiFi.
Handles empty requests in a defined manner.
Handle requests for non-exisiting pages correctly.

This demo allows to switch two functions:
Function 1 creates serial output and toggels GPIO2
Function 2 just creates serial output.

Serial output can e.g. be used to steer an attached
Arduino, Raspberry etc.
--------------------------------------------------*/

#include <ESP8266WiFi.h>
void WiFiStart(void);
const char* ssid = "xxx";
const char* password = "xxx";

unsigned long ulReqcount;
unsigned long ulReconncount;


// Create an instance of the server on Port 80
WiFiServer server(8080);

void setup() 
{
  // setup globals
  ulReqcount=0; 
  ulReconncount=0;
  
  // prepare GPIO2
  pinMode(2, OUTPUT);
  digitalWrite(2, 0);
  
  // start serial
  Serial.begin(9600);
  delay(1);
  
  // inital connect
  WiFi.mode(WIFI_STA);
  WiFiStart();
}


void loop() 
{
  // check if WLAN is connected
  if (WiFi.status() != WL_CONNECTED)
  {
    WiFiStart();
  }
  
  // Check if a client has connected
  WiFiClient client = server.available();
  if (!client) 
  {
    return;
  }
  
  // Wait until the client sends some data
  Serial.println("new client");
  unsigned long ultimeout = millis()+250;
  while(!client.available() && (millis()<ultimeout) )
  {
    delay(1);
  }
  if(millis()>ultimeout) 
  { 
    Serial.println("client connection time-out!");
    return; 
  }
  
  // Read the first line of the request
  String sRequest = client.readStringUntil('\r');
  //Serial.println(sRequest);
  client.flush();
  
  // stop client, if request is empty
  if(sRequest=="")
  {
    Serial.println("empty request! - stopping client");
    client.stop();
    return;
  }
  
  // get path; end of path is either space or ?
  // Syntax is e.g. GET /?pin=MOTOR1STOP HTTP/1.1
  String sPath="",sParam="", sCmd="";
  String sGetstart="GET ";
  int iStart,iEndSpace,iEndQuest;
  iStart = sRequest.indexOf(sGetstart);
  if (iStart>=0)
  {
    iStart+=+sGetstart.length();
    iEndSpace = sRequest.indexOf(" ",iStart);
    iEndQuest = sRequest.indexOf("?",iStart);
    
    // are there parameters?
    if(iEndSpace>0)
    {
      if(iEndQuest>0)
      {
        // there are parameters
        sPath  = sRequest.substring(iStart,iEndQuest);
        sParam = sRequest.substring(iEndQuest,iEndSpace);
      }
      else
      {
        // NO parameters
        sPath  = sRequest.substring(iStart,iEndSpace);
      }
    }
  }
  
  ///////////////////////////////////////////////////////////////////////////////
  // output parameters to serial, you may connect e.g. an Arduino and react on it
  ///////////////////////////////////////////////////////////////////////////////
  if(sParam.length()>0)
  {
    int iEqu=sParam.indexOf("=");
    if(iEqu>=0)
    {
      sCmd = sParam.substring(iEqu+1,sParam.length());
      Serial.println(sCmd);
    }
  }
  
  
  ///////////////////////////
  // format the html response
  ///////////////////////////
  String sResponse,sHeader;
  
  ////////////////////////////
  // 404 for non-matching path
  ////////////////////////////
  if(sPath!="/")
  {
    sResponse="<html><head><title>404 Not Found</title></head><body><h1>Not Found</h1><p>The requested URL was not found on this server.</p></body></html>";
    
    sHeader  = "HTTP/1.1 404 Not found\r\n";
    sHeader += "Content-Length: ";
    sHeader += sResponse.length();
    sHeader += "\r\n";
    sHeader += "Content-Type: text/html\r\n";
    sHeader += "Connection: close\r\n";
    sHeader += "\r\n";
  }
  ///////////////////////
  // format the html page
  ///////////////////////
  else
  {
    ulReqcount++;
    sResponse  = "<html><head><title>Demo f&uumlr ESP8266 Steuerung</title></head><body>";
    sResponse += "<font color=\"#000000\"><body bgcolor=\"#d0d0f0\">";
    sResponse += "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, user-scalable=yes\">";
    sResponse += "<h1>Linyo's Smart Home Steuerung</h1>";
    //sResponse += "Funktion 1 schaltet GPIO2 und erzeugt eine serielle Ausgabe.
";
    //sResponse += "Funktion 2 erzeugt nur eine serielle Ausgabe.
";
    sResponse += "<FONT SIZE=+1>";
    sResponse += "<p>LED 1 <a href=\"?pin=FUNCTION1ON\"><button>einschalten</button></a>&nbsp;<a href=\"?pin=FUNCTION1OFF\"><button>ausschalten</button></a></p>";
    //sResponse += "<p>Funktion 2 <a href=\"?pin=FUNCTION2ON\"><button>einschalten</button></a>&nbsp;<a href=\"?pin=FUNCTION2OFF\"><button>ausschalten</button></a></p>";
    
    //////////////////////
    // react on parameters
    //////////////////////
    if (sCmd.length()>0)
    {
      // write received command to html page
      sResponse += "Kommando:" + sCmd + "
";
      
      // switch GPIO
      if(sCmd.indexOf("FUNCTION1ON")>=0)
      {
        digitalWrite(2, 1);
      }
      else if(sCmd.indexOf("FUNCTION1OFF")>=0)
      {
        digitalWrite(2, 0);
      }
    }

    /*
    sResponse += "<FONT SIZE=-2>";
    sResponse += "
Aufrufz&auml;hler="; 
    sResponse += ulReqcount;
    sResponse += " - Verbindungsz&auml;hler="; 
    sResponse += ulReconncount;
    sResponse += "
";
    sResponse += "Stefan Thesen 04/2015
";
    */
    sResponse += "</body></html>";
    
    sHeader  = "HTTP/1.1 200 OK\r\n";
    sHeader += "Content-Length: ";
    sHeader += sResponse.length();
    sHeader += "\r\n";
    sHeader += "Content-Type: text/html\r\n";
    sHeader += "Connection: close\r\n";
    sHeader += "\r\n";
  }
  
  // Send the response to the client
  client.print(sHeader);
  client.print(sResponse);
  
  // and stop the client
  client.stop();
  Serial.println("Client disonnected");
}

void WiFiStart()
{
  ulReconncount++;
  
  // Connect to WiFi network
  Serial.println();
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);
  
  WiFi.begin(ssid, password);
  
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");
  
  // Start the server
  server.begin();
  Serial.println("Server started");

  // Print the IP address
  Serial.println(WiFi.localIP());
}

Damit kann ich von extern (Portforwardind Port 8080) eine LED ein- und ausschalten.
Diese Woche geht's weiter.

hi,

ohne es kleinreden zu wollen: das ist ja der sketch aus dem link oben, oder?

gruß stefan

jep ^^
dachte, es hilft, wenn es hier auch so nochmal steht

den kannst du nun erweitern auf deine 3 Lampen. Notfalls sogar auf 4, wenn du gpio0 auch hernimmst.

So, ich bin schon eine Ecke weiter gekommen. Die Kommunikation läuft perfekt und auch stabil (über 1 Woche)

Nun möchte ich vom ESP Befehle senden. Der Teil auf dem ESP läuft, der Befehl wird laut Serial Monitor korrekt übertragen.

Ich habe mir aus dem Forum (Danke an Bohne) Code stibitzt und versuche ihn für meine Zwecke zu adaptieren.

Der ESP sendet ganz stumpf:
xLED1.ony wobei das "x" als Befehlsbeginnindikator, der "." als Trenner und das "y" als Befehlsende ausgewertet werden sollen.

Der Code auf dem Mega sieht so aus:

#define STATE_UNDEFINED 0
#define STATE_READING_KEY 1
#define STATE_READING_VALUE 2

String KEY;                                       //Dient als Name des Befehls
String KEY_VALUE;                                 //Wert des Befehls
int currentState = STATE_UNDEFINED;              //Zu Programmstart warten auf Befehle

void setup()
{
 Serial.begin(9600);                              //an PC per USB
 Serial2.begin(9600);                             //Quelle der Befehle an Serial2 (Arduino MEGA!)
}

void loop()
{
 
 char c = Serial2.read();
 
 if(currentState==STATE_UNDEFINED)
 {
   if(c == 'x')                                   //Nach befehl suchen (beginnt mit "x")
   {
     currentState = STATE_READING_KEY;
   }
 }
 else if(currentState== STATE_READING_KEY)
 {
   if(c == '.')                                   //Warten bis Befehl übertragen wurde (als Trenner dient ein ".")
   {
     currentState = STATE_READING_VALUE;     
   }
   else
   {
     KEY += c;  
   }
 }
 else if(currentState== STATE_READING_VALUE)      
 {
   if(c == 'y')                                   //Warten bis der Wert übertragen wurde wurde (mit "y")
   {
     Serial.println("Received:");
     
     Serial.print("Key = ");
     Serial.println(KEY);
     
     Serial.print("Value = ");
     Serial.println(KEY_VALUE);
     
     KEY = "";                                    //Strings resetten
     KEY_VALUE = "";                              //Strings resetten
     
     currentState = STATE_UNDEFINED;              //Warten auf neuen Befehl
     
   }
   else
   {
     KEY_VALUE += c;
   }
 }
}

Nachdem ich den Mega starte und das erste mal der oben genannte Befehl auf Serial2 empfangen wird bekomme ich jedoch:

Received:
Key = ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿLÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿEÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿDÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ1ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ
Value = ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿoÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿnÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ

Zwischen den ganzen "ÿ" sind die richtigen Strings enthalten. Aber ich versteh einfach nicht, woher dieser ganze "Müll" kommt...

Würde mich über einen Tip freuen :slight_smile:

Habs gefunden.
Hab das ganze in ein if-Statement gepackt, dasses nur durchlaufen wird, wenn Serial2.available() > 1 ist; also wenn ein ganzer char in Buffer liegt :slight_smile:

#define STATE_UNDEFINED 0
#define STATE_READING_KEY 1
#define STATE_READING_VALUE 2
char c;
String inCMD;                                     //als temporärer Speicher
String KEY;                                       //Dient als Name des Befehls
String KEY_VALUE;                                 //Wert des Befehls
int currentState = STATE_UNDEFINED;               //Zu Programmstart warten auf Befehle

void setup()
{
 Serial.begin(9600);                              //an PC per USB
 Serial2.begin(9600);                             //Quelle der Befehle an Serial2 (Arduino MEGA!)
}

void loop()
{
 
 //c = Serial2.read();
 if(Serial2.available() > 1){
  c = Serial2.read();
 
 
 
 if(currentState==STATE_UNDEFINED)
 {
   if(c == 'x')                                   //Nach befehl suchen (beginnt mit "x")
   {
     currentState = STATE_READING_KEY;
   }
 }
 else if(currentState== STATE_READING_KEY)
 {
   if(c == '.')                                   //Warten bis Befehl übertragen wurde (als Trenner dient ein ".")
   {
     currentState = STATE_READING_VALUE;     
   }
   else
   {
     KEY += c;  
   }
 }
 else if(currentState== STATE_READING_VALUE)      
 {
   if(c == 'y')                                   //Warten bis der Wert übertragen wurde wurde (mit "y")
   {
     Serial.println("Received:");
     
     Serial.print("Key = ");
     Serial.println(KEY);
     
     Serial.print("Value = ");
     Serial.println(KEY_VALUE);
     
     KEY = "";                                    //Strings resetten
     KEY_VALUE = "";                              //Strings resetten
     
     currentState = STATE_UNDEFINED;              //Warten auf neuen Befehl
     
   }
   else
   {
     KEY_VALUE += c;
   }
 }
 }
}

ÿ kommt, wenn kein Zeichen im Empfangsbuffer ist. Das ist das ASCII für 255 bzw. -1

deswegen immer mit if-Abfrage

du machst das aber immer noch zu kompliziert. Sende Zeilenumbrüche mit und Lese immer ganze Zeilen ein und werte die Zeile aus, wenn sie komplett ist.

oder du fängst an, einzulesen, wenn ein x kommt und hörst auf, wenn ein y kommt. Dann hast du auch den gesamten Befehl zum auswerten.

ElEspanol:
du machst das aber immer noch zu kompliziert. Sende Zeilenumbrüche mit und Lese immer ganze Zeilen ein und werte die Zeile aus, wenn sie komplett ist.

oder du fängst an, einzulesen, wenn ein x kommt und hörst auf, wenn ein y kommt. Dann hast du auch den gesamten Befehl zum auswerten.

Das hört sich gut an.

Nun empfange ich so etwas wie:

&key=led1&value=on&key=led2&value=off$

Wie kann ich das denn auseinandernehmen?

muss das alles mit den String funktionen indexOf und substring passieren?

Ich stelle mir das so vor, dass der "Quell-"string nach und nach zerlegt wird, aber komme einfach zu keiner Lösung, wie ich dies bewerkstelligen kann..