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;
}
}
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.
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
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...
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.
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.
/*--------------------------------------------------
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ür 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> <a href=\"?pin=FUNCTION1OFF\"><button>ausschalten</button></a></p>";
//sResponse += "<p>Funktion 2 <a href=\"?pin=FUNCTION2ON\"><button>einschalten</button></a> <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ähler=";
sResponse += ulReqcount;
sResponse += " - Verbindungszä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.
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...
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
#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;
}
}
}
}
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..