Webserver ansteuern

Hallo zusammen,
ich bin Arduinobastler in jungen Tagen und versuche mich gerade an einem Webserver, welcher im Netzwerk ansteuerbar ist und "Hallo Welt" per Klick ausgeben soll.

Sende hier mal mein bisheriges Programm.
Bitte schaue es sich mal jemand an und gebe mir Rückmeldung dazu.
(Ich erwarte nicht unbedingt eine Musterlösung. Es würde mir auch schon ein hilfreicher Denkanstoß oder Link zu einem Tutorial helfen)
Vielen Dank im Vorraus.

Magic

#include <SPI.h> //Anbindung microcontroller an Ethernet-Shield
#include <Ethernet.h>
int x;

// Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network:
byte mac[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
byte ip[] = { 192,168,1, 177 };

// Initialize the Ethernet server library
// with the IP address and port you want to use
// (port 80 is default for HTTP):
EthernetServer server(80);

void setup()
{
// start the Ethernet connection and the server:
Ethernet.begin(mac, ip);
server.begin();
pinMode(5, OUTPUT);

}

void loop()
{

if (x==1){
analogWrite(5, 200);
}

// listen for incoming clients
EthernetClient client = server.available();
if (client) {
// an http request ends with a blank line
boolean currentLineIsBlank = true;
while (client.connected()) {
if (client.available()) {
char c = client.read();
// if you've gotten to the end of the line (received a newline
// character) and the line is blank, the http request has ended,
// so you can send a reply
if (c == '\n' && currentLineIsBlank) {
// send a standard http response header
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println();
// print something, in HTML format:

client.println("");
client.println("");
client.println("Sörens Testpage");
client.println(" <input type='submit' name='buttoncolorchange' id='button' value='Farbwechsel' method='post' onclick=' alert('Hallo Welt') '/> ");

client.println("");
client.println("");

client.println("");
client.println("");

break;
}
if (c == '\n') {
// you're starting a new line
currentLineIsBlank = true;
}
else if (c != '\r') {
// you've gotten a character on the current line
currentLineIsBlank = false;
}
}
}
// give the web browser time to receive the data
delay(1);
// close the connection:
client.stop();
}

}[/table]

Hallo Magicrookie,

zu allererst: Bitte setzte den Code in den Quoteblock . Das ist deutlich übersichtlicher und man muss nicht so viel scrollen :slight_smile:

Zu deinem Code: Generell sieht das doch ganz gut aus und man kann die ein oder andere Anleihe aus ein paar Tutorials erkennen.
Ohne nun selbst den Code auf meinem Ardu aufzuspielen, kann ich dein Problem oder deine Frage nicht wirklich erkennen.
(Wahrscheinlich klappt der HTML/JavaScript Teil nicht, da ein Alert in einem gekapselten Code, speziell als JS gekennzeichnet werden muss)
SelfHTML Alert

Ansonsten gibt es gute Threads hier: Dateien von SD über Ethernet & Arduino als HTTP Client

Gruß,
trib

Falls Dein Problem ist dass Dein Browser nichts empfängt/tut obwohl Du per telnet was vom Arduino empfängst, dann setz mal explizit die Zeilenenden im HTTP-Header, z.B. statt client.println() schreib client.print('\r\n').

Und statt

client.println(" <input type='submit' name='buttoncolorchange' id='button' value='Farbwechsel' method='post' onclick=' alert('Hallo Welt') '/> ");

würde ich was wie

client.println("<a href=\"javascript:alert('Hallo Welt')\">Farbwechsel</a>");

in den body-Teil schreiben.

Danke erstmal für die flotten Antworten.
War leider eine Woche außer Gefecht gesetzt und komme jetzt erst dazu mich mit ihnen zu befassen.

Vlt. hätte ich mein Problem dabei etwas genauer erklären sollen.

Das Ansprechen des Arduino klappt. Auch die Ausgabe Hallo Welt funktioniert einwandfrei.
Jedoch möchte ich eine Aktion des Arduino mit diesem Button verknüpfen.
D.h. zb soll der Button x=1 setzen. Das habe ich bisher über onclick= " x=1; " probiert , was erstmal nahe liegend aber scheinbar falsch war.

So einfach ist das auch wieder nicht :wink:

Was in Deinem Beispiel noch fehlt:

  • Ein Button, der einfach so ins Blaue hineindefiniert wird, ist wirkungslos. Du musst ihn in ein Formular einbauen, zweckmässigerweise würde ich in diesem Fall die Get-Methode benutzen. Wie das geht, findest Du bei selfhtml http://de.selfhtml.org/. Tipp: Ein hidden-Element wirst Du auch brauchen. Was das ist steht auch bei selfhtml.

  • Den Output des Servers musst Du irgendwie speichern, damit Du ihn dann auswerten kannst. In Deinem Beispiel wird der Output zeichenweise gelesen (c). Diese Zeichen könntest Du zu einem char-Array zusammenbauen.

  • Sobald der Server die erste Request-Zeile komplett übertragen hat, musst Du sie in Deinem Programm analysieren und entsprechend reagieren, das ist dann die Stelle wo Du Deiner Variablen einen neuen Wert zuweisen kannst.

Viel Erfolg und Gruß,

Thomas

Vielen Dank @ Nachtaktiv.
Dein Beitrag hat mir sehr geholfen.
Ich verstehe nun viele Beispiele anderer Arduinonutzer , die mir warscheinlich nun weiterhelfen können.

Soweit jetzt das aktuelle Programm.
Ich kriege keine Rückgabe von der angesteuerten Homepage an den Arduino.
Vlt weiß einer von euch da weiter.

#include <SPI.h>  //Anbindung microcontroller an Ethernet-Shield
#include <Ethernet.h>
#include <WString.h>
#include <Client.h>
#include <Server.h>
int LED =4;
boolean testdiode=false;

// Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network:
byte mac[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
byte ip[] = { 192,168,1, 177 };

// Initialize the Ethernet server library
// with the IP address and port you want to use
// (port 80 is default for HTTP):
EthernetServer server(80);
String readString = String(100);      // string for fetching data from address





void setup(){
  Ethernet.begin(mac, ip);  //Start der Ethernet-Verbindung und des Servers
  server.begin();
    pinMode(4, OUTPUT); 
    Serial.begin(9600);
}

void loop(){

  // listen for incoming clients
EthernetClient client = server.available(); //Client Verbindung herstellen
  if (client) {
    // an http request ends with a blank line
    boolean currentLineIsBlank = true;
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        if (readString.length()< 100){
          readString = readString + c;
        }
        Serial.print(c);
          // if you've gotten to the end of the line (received a newline
        // character) and the line is blank, the http request has ended,
        // so you can send a reply
        if (c == '\n' && currentLineIsBlank) {
          // send a standard http response header
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println();
          // print something, in HTML format:
        }
        else if (c == '\n') {
			if(readString.indexOf("3=AN") > -1) {
			   togglediode; // verändert den status von testdiode
                        }
                        if(readString.indexOf("3=AUS") > -1) {
			   togglediode; // verändert den status von testdiode
                        }
                        

			   
          
          
           client.println("<html>");
           client.println("<head>");
            client.println("<TITLE>Sörens Testpage</TITLE>");
           client.println("</head>");
           client.println("<body>");

           
          client.println("<td align='center' bgcolor='#222222'><form method=get><input type=submit name=3 value='einschalten'></form></td>");
            
            
             if (testdiode==true) {
		     client.println("<input type=submit value=AN  name=3 style=width:200;height:100;background-color:lightgreen;/>");
		 }else {
		     client.println("<input type=submit  value=AUS name=3 style=width:200;height:100;background-color:red;>");
		 }
           

           client.println("</body>");
           client.println("</html>");



          break;
        }
        if (c == '\n') {
          // you're starting a new line
          currentLineIsBlank = true;
        }
        else if (c != '\r') {
          // you've gotten a character on the current line
          currentLineIsBlank = false;
        }
      }
    }
    // give the web browser time to receive the data
    readString=" ";
    delay(1);
    // close the connection:
    client.stop();
  }

}

void togglediode (){
   if (testdiode == false){
     testdiode=true;
     digitalWrite(LED, HIGH);
   } 
   else {
     testdiode=false;  
     digitalWrite(LED, LOW);
   }
}

Hallo,

wenn Du in Deinem Formular den Wert "einschalten" schickst und in der Auswertung dann auf "AN" oder "AUS" prüfst, kann das nicht funktionieren :wink:

if(readString.indexOf("3=AN") > -1) {

...

client.println("<td align='center' bgcolor='#222222'><form method=get><input type=submit name=3 value='einschalten'></form></td>");

Auch das Formular wird so nicht funktionieren. Der Submit-Button hat ja gar nichts zum Wegschicken. Du musst im gleichen Formular sowas definieren:

<input type="hidden" name="schalten" value="aus">

Funktioniert das denn mit den einfachen Anführungszeichen? 'einschalten' ? Ich würde schreiben "einschalten"

Viel Erfolg!

Sooo

Hab die Befehle readString.append(c); und readString.contains() durch readString = readString + c; und if(readString.indexOf("3=AN") > -1) { getauscht und
mit dm letzteren eine Abfrage gebastelt.

Und habe mit Hidden unten drunter nochmal Name und Value bestimmt.
Allerdings wenn ich nun klicke ändert sich in der Adressleiste immer noch nichts und somit kann ja auch nichts übertragen werden.
Hab mir das ganze nochmal in diversen online Beispielen angeschaut und es mit meinem Code abgeglichen. Ich sehe keinen direkten Unterschied.
Hab nun gute 8 Stunden damit zugebracht den Code ans laufen zu bekommen aber es läuft immer noch nicht.

Zu dem folgenden Code
Hier habe ich einen HTML-Code ausprobiert, welcher in einer HTML-Datei eine Rückgabe in der Adressleiste ergab, es jedoch in meinem Programm nicht tut.
Vlt kann mir jmd eine Musterlösung für mein Problem geben, denn ich verzweifle so allmählig.

Danke schonmal im Vorraus

#include <SPI.h>  //Anbindung microcontroller an Ethernet-Shield
#include <Ethernet.h>
#include <WString.h>

int LED =4;
boolean testdiode=false;

// Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network:
byte mac[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
byte ip[] = { 192,168,1, 190 };

// Initialize the Ethernet server library
// with the IP address and port you want to use
// (port 80 is default for HTTP):
EthernetServer server(80);
String readString = String(100);      // string for fetching data from address


void setup(){
  Ethernet.begin(mac, ip);  //Start der Ethernet-Verbindung und des Servers
  server.begin();
    pinMode(4, OUTPUT); 
    Serial.begin(9600);
}

void loop(){

  // listen for incoming clients
EthernetClient client = server.available(); //Client Verbindung herstellen
  if (client) {
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        if (readString.length()< 100){
          readString = readString + c;
        }
        Serial.print(c);  //oput chars to serial port
        
        if (c == '\n') {
			if(readString.indexOf("3=einschalten") > -1) {
			   togglediode; // verändert den status von testdiode
                        }
                        if(readString.indexOf("3=ausschalten") > -1) {
			   togglediode; // verändert den status von testdiode
                        }
 
           client.println("<html>");
           client.println("<head>");
            client.println("<TITLE>Sörens Testpage</TITLE>");
           client.println("</head>");
           client.println("<body>");

client.println("<td align='center' bgcolor='#222222'><form method=get><input type=submit name=3 value='einschalten'></form></td>");
client.println(" <input type=\'hidden\' >");
 client.println("<td align='center' bgcolor='#222222'><form method=get><input type=submit name=3 value='ausschalten'></form></td>");
 client.println(" <input type=\'hidden\' >");

           client.println("</body>");
           client.println("</html>");
        }
        
      }
    }
    // give the web browser time to receive the data
    readString=" ";
    delay(1);
    // close the connection:
    client.stop();
  }

}

//UNTERPROGRAMME


void togglediode (){
   if (testdiode == false){
     testdiode=true;
     digitalWrite(LED, HIGH);
   } 
   else {
     testdiode=false;  
     digitalWrite(LED, LOW);
   }
}

Also was mir erstmal auffällt ist, das Deinem Formular der "action" Parameter fehlt. Außerdem müssen die hidden-Parameter innerhalb der Tags stehen und nicht dahinter.
Im Browser sollte Dein Formular wiefolgt aussehen

<html>
<head></head>
<body>
<form action="/" method="get"><input type=submit name=3 value='einschalten'>
<input type="hidden" name="varname" value="inhalt">
</form>
<form action="/" method=get><input type=submit name=3 value='ausschalten'>
<input type="hidden" name="varname" value="inhalt">
</form>
</body>
</html>

Parameter würde ich auch nicht mit Zahlen oder Ziffern bezeichnen, sondern schon mit einem "sprechenden Namen" (z.B. "schalten=an" und "schalten=aus"), aber das ist Geschmackssache, technisch sollte das erstmal kein Problem sein.
Was passiert denn, wenn Du die URL im Browser direkt anpasst, also Deinen Parameter "3=einschalten" mit einem "?" an die aufgerufene URL anhängst?
Welche Ausgaben bekommst Du über die serielle Schnittstelle?

Hier mein aktueller Code

#include <SPI.h>  //Anbindung microcontroller an Ethernet-Shield
#include <Ethernet.h>
#include <WString.h>
#include <Client.h>
#include <Server.h>
int LED =4;
boolean testdiode=false;

// Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network:
byte mac[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
byte ip[] = { 192,168,1, 190 };

// Initialize the Ethernet server library
// with the IP address and port you want to use
// (port 80 is default for HTTP):
EthernetServer server(80);
String readString = String(100);      // string for fetching data from address





void setup(){
  Ethernet.begin(mac, ip);  //Start der Ethernet-Verbindung und des Servers
  server.begin();
    pinMode(4, OUTPUT); 
    Serial.begin(9600);
}

void loop(){

  // listen for incoming clients
EthernetClient client = server.available(); //Client Verbindung herstellen
  if (client) {
    // an http request ends with a blank line
    boolean currentLineIsBlank = true;
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        if (readString.length()< 100){
          readString = readString + c;
        }
        Serial.print(c);
          // if you've gotten to the end of the line (received a newline
        // character) and the line is blank, the http request has ended,
        // so you can send a reply
        if (c == '\n' && currentLineIsBlank) {
          // send a standard http response header
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println();
          // print something, in HTML format:
        }
        else if (c == '\n') {
			if(readString.indexOf("diode=AN") > -1) {
			   togglediode; // verändert den status von testdiode
                        }
                        if(readString.indexOf("diode=AUS") > -1) {
			   togglediode; // verändert den status von testdiode
                        }
                        

			   
          
          
           client.println("<html>");
           client.println("<head>");
            client.println("<TITLE>Sörens Testpage</TITLE>");
           client.println("</head>");
           client.println("<body>");

           
            /*
             if (testdiode==true) {
		     client.println("<input type=submit value=AN  name=3 style=width:200;height:100;background-color:lightgreen;/>");
                     client.println("<input type=\'hidden\' name='anderung' value='AUS'> ");
		 }else if (testdiode==false) {
		     client.println("<input type=submit  value=AUS name=3 style=width:200;height:100;background-color:red;/>");
                     client.println("<input type=\'hidden\' name='anderung' value='AN'> ");
		 }
           */
           
                     if (testdiode==false) {
		      client.println(" <form action='/' method='get'><input type=submit name=3 value='einschalten'> ");
                      client.println(" <input type='hidden' name='diode' value='AN'> ");
                      client.println(" </form> ");

                  
		 }
                   else if (testdiode==true) {
		     client.println(" <form action='/' method=get><input type=submit name=3 value='ausschalten'> ");
                     client.println(" <input type='hidden' name='diode' value='AUS'> ");
                      client.println(" </form> ");

  
  
		 }
           
           client.println("</body>");
           client.println("</html>");



          break;
        }
        if (c == '\n') {
          // you're starting a new line
          currentLineIsBlank = true;
        }
        else if (c != '\r') {
          // you've gotten a character on the current line
          currentLineIsBlank = false;
        }
      }
    }

    
    // give the web browser time to receive the data
    readString=" ";
    delay(1);
    // close the connection:
    client.stop();
  }

}

void togglediode (){
   if (testdiode == false){
     testdiode=true;
     digitalWrite(LED, HIGH);
   } 
   else {
     testdiode=false;  
     digitalWrite(LED, LOW);
   }
}

Wenn ich den Button "einschalten" drücke steht Folgendes in der Adressleiste
" http://192.168.1.190/?3=einschalten&diode=AN "
Jedoch bleibt der LED status unverändert.

Wenn ich auf der Seite "http://192.168.1.190/ " den Befehl "diode=AN" anhänge, passiert das selbe.

Seriell wird ausgegeben:
GET /?3=einschalten&diode=AN HTTP/1.1
GET /?3=einschalten&diode=AN HTTP/1.1

Ich vermute an dieser Stelle, das das Suchen von diode=AN im String nicht funktioniert.
Kann mir allerdings nicht erklären warum nicht.

Hallo!

Wenn Du die Funktion "togglediode" aufrufen möchtest, musst Du schreiben

togglediode(); // verändert den status von testdiode

Es wundert mich, dass sich Dein Code so überhaupt compilieren lässt :slight_smile: Zum Debuggen würde ich mir die Variable "readString" direkt vor der Auswertung anzeigen lassen:

Serial.println(readString);

Das ist mir jetzt so auf die Schnelle aufgefallen und heisst nicht, dass nicht noch weitere Fehler im Code sind :slight_smile:

Viel Erfolg!

Um zu sehen, ob der String gefunden wird, kannst Du ja die Debugausgaben direkt an die passende Stelle schreiben:

        else if (c == '\n') {
			if(readString.indexOf("diode=AN") > -1) {
                                         Serial.println("diode=AN gefunden");
			   togglediode(); // verändert den status von testdiode
                        }
                        if(readString.indexOf("diode=AUS") > -1) {
                                         Serial.println("diode=AUS gefunden");
			   togglediode(); // verändert den status von testdiode
                        }

Achso, das sich die Diode an- und ausschalten läßt, hast Du getestet, oder? Sorry für die Frage, aber manchmal ist es am Ende dann doch sowas simples.
Mario.

Danke euch beiden.
Es war ein simpler Anfängerfehler. Das Unterprogramm hatte ich ohne die Klammern aufgerufen und es konnte somit nicht starten.
Programm läuft. Super! Nach 3 Wochen Rumknobelei war es nun doch so etwas Simples.

An dieser Stelle stehe ich allerdings schon wieder vor einer neuen Herrausforderung.
Ich würde gerne die LED dimmen und dafür über ein HTML-Textfeld eine Zahl übermitteln.

Kann mir dafür vielleicht jemand einen Tipp geben nach was ich dafür genau suchen müsste, vielleicht sogar einen Link zu einem Guide oder eine eigene kurze Erklärung eines Befehls und seiner Anwendung.
Ich habe bis jetzt etwas von einem "altio" Befehl gelesen, aber wurde noch nicht sehr schlau daraus.

Vielen Dank schonmal für die kommenden Antworten!
Ich freue mich drauf weiter zu machen.

PS: Falls sich jemand für den vorerst fertigen LED-Webserver-Ansteuerungcode interessiert, schreibt mir. Ich teile und helfe gerne, nachdem mir so toll geholfen wurde.

LED dimmen geht über PWM.
Siehe http://arduino.cc/en/Tutorial/Fading. Allerdings wirst Du dann die LED an einen anderen Ausgang anschliesse müssen. Pin 4 ist kein PWM Ausgang.
Wenn es um das HTML-Formular geht, brauchst Du nur innerhalb der Formulars ein

<input type=text name=dim></input>

Der Wert hängt dann als "&dim=111" mit an der URL dran, wenn Du das Formular abschickst. Du hast dann nur noch die Aufgabe, den Wert aus der URL zu filtern und in eine Zahl umzuwandeln.
Dabei ist wichtig, das der Wertebereich von 0 bis 255 geht.
Was soll denn "altio" sein? HTML, oder C-Code? Das sagt mir nämlich gar nix.
Falls Du "atoi()" meinst, ist das die Funktion die einen String ein Integer umwandeln kann.

Ok. Analoger PIN ausgewählt.
Das Textfeld werde ich morgen mal einfügen.
Stellt sich nun die Frage wie ich genau diesen Wert aus der Adresszeile auslese und dann in eine Variable einlese.
(war wohl auch atoi() was ich gesehen hatte)

Ähm analoger Pin? Das wird nicht funktionieren. Analoge Pins können Spannungen (0-5V) "messen" (Analog-Digital Wandler) und können auch als digitale Ausgänge verwendet werden. Aber NICHT als analoge Ausgänge.
PWM-Pins sind beim Arduino die folgenden digitalen Pins (3,5,6,9,10,11). PWM "simuliert" ein analoges Signal durch schnelles an- und ausschalten der 5V (die bleiben dabei aber immer 5V). Durch die unterschiedlich lange Einschaltdauer stellt sich im zeitlichen Verlauf dann eine Art "Durchschnittswert" ein.
Verwirrenderweise wird der PWM-Wert aber mit analogWrite(PIN) auf ein digitales PIN gesetzt.

Danke :slight_smile: Habe wohl auf Grund von analogWrite() gedacht, dass es ein analoger PIN wäre.
Dennoch bleibt für mich die Frage offen wie ich nun eine übermittelte Zahl aus der Adressleiste auslese.

Schau Dir mal folgendes an:
http://www.arduino.cc/playground/Code/TextFinder
Damit kannst Du prima schon beim Lesen der Daten vom Netzwerkinterface nach bestimmten Daten suchen. TextFinder kann auch bereits den Text in eine Zahl umwandeln.

Habe mir die Librarie Textfinder nun einmal angeschaut und ihr Beispielprogramm versucht auszuführen.
(Laut in der Librarie enthaltenem Text ist diese in der Programmierumgebung 1.0 schon enthalten)

Da aber bei Verifizierung die Fehlermeldung:

Webserver_test.cpp:6:24: error: TextFinder.h: No such file or directory
Webserver_test:6: error: 'TextFinder' does not name a type

erscheint.

Habe ich die Librarie nochmal einzeln hinzugefügt.

Dennoch selber Fehler.
Zudem werde ich aus der Erklärung der Librarie auf Arduino.cc nicht wirklich schlau.