Server/Client Problem...

Hallo,
irgendwie sehe ich mal wieder den Wald vor lauter Bäumen nicht... :~
Kann mal jemand auf den Code schaue, warum der nicht funktioniert?
Ich kann nicht per WEbbrowser auf den Arduino zugreifen.

#include <SPI.h>
#include <Ethernet.h>             // library for ethernet functions
#include <DallasTemperature.h>    // library for temperature sensors
#include <OneWire.h>              // library for the onewire bus
#include <Wire.h> 

int led = 2;

#define ONE_WIRE_BUS 7
 
OneWire oneWire(ONE_WIRE_BUS);                   // pin für Temperatursensoren
 
//DeviceAdressen der einzelnen ds1820 Temperatursensoren.
DeviceAddress sensor1 = { 0x28, 0x65, 0x35, 0xC3, 0x03, 0x00, 0x00, 0x35 };
DeviceAddress sensor2 = { 0x28, 0x03, 0xF6, 0xC2, 0x03, 0x00, 0x00, 0xA7 };

//ETHERNET-SETTINGS
byte mac[]     = { 0x5D, 0xA2, 0xFA, 0x2D, 0x76, 0x7C };    // MAC-Adresse des Arduino
byte ip[]      = { 192, 168, 178, 40 };                     // IP-Adresse des Arduino
byte gateway[] = { 192, 168, 178, 1 };                    // Gateway
byte subnet[]  = { 255, 255, 255, 0 };                    // SubNet
byte server[]  = { 192, 168, 178, 111 };                     // IP-Adresse des Servers

EthernetServer Server(80);

EthernetClient client;
char host[]    = "192.168.178.111";                      // Domain
char url[]     = "/Arduino/Temp/SaveTempToMySQL.php"; // Pfad zur PHP-Datei
char key[]     = "12345";                     // Kennwort aus PHP-Datei
char c;                                                     // Variable für Rückgabe des Servers
 
long Interval  = 5;                                        // Upload-Interval in Minuten
DallasTemperature sensors(&oneWire);                               
int numSensors;                                             // Variable zum speichern der Anzahl der Temperatur-Sensoren
 
void setup()
{
  pinMode(led, OUTPUT);      // Setzt den ledPin (Pin 2) als Ausgang
 
  Serial.begin(9600);
  Serial.flush();
  delay(200);
 
  Serial.println("Arduino TemperaturLogger");
  Serial.println("Ethernet initialisieren..."); 
 
  Ethernet.begin(mac, ip);
  Server.begin();   // start listening for clients
  Serial.print("server is at ");
  Serial.println(Ethernet.localIP());

  Interval = Interval * 1000 * 60;                            // Das in Minuten angegebene Interval in Millisekunden umrechnen
  delay(1000);                                                // warten, bis Ethernet gestartet    
  //Sensoren abfragen
  sensors.begin();
  sensors.setResolution(sensor1, 10);
  sensors.setResolution(sensor2, 10);
  Serial.println("Temperatur-Sensoren ermitteln...");
 
  numSensors = sensors.getDeviceCount();                      // Anzahl der angeschlossenen Sensoren in numSensors speichern
 
  if(numSensors > 0)                                          // Es wurde mindestens 1 Sensor gefunden                                       
  {
    Serial.print(numSensors);
    Serial.println( " Temperatur-Sensoren gefunden.");
  }         
  else                                                        // Es wurde kein Sensor gefunden
  {
    Serial.println("Keine Temperatur-Sensoren gefunden.");
  }
}
 
void loop()
{
  sensors.requestTemperatures();
  float temp1 = sensors.getTempC(sensor1);                      // Temperatur von Sensor 1 ermitteln
  float temp2 = sensors.getTempC(sensor2);                      // Temperatur von Sensor 2 ermitteln
  
  Serial.print("Temp1: ");
  Serial.println(temp1,2);
  Serial.print("Temp2: ");
  Serial.println(temp2);
 
  Daten_senden(temp1, temp2);                                 // Temperaturdaten an Server übertragen
 
  delay(700);
 
  byte maxReads = 10;   //Seconds
  while ((maxReads-- > 0) && client.connected())              // Antwort des Servers lesen
  {
    delay(1000);             
    while (client.available())
    {
      char response = client.read();
      Serial.print(response);
      digitalWrite(led, HIGH);
    }
  }
  client.stop();
  Serial.println(" ");
  Serial.println("Done.");
  client.flush();  
  delay(Interval);
  
  // Ausgabe auf Website
  EthernetClient client = Server.available();
  if (client) {
    client.println("HTTP/1.1 200 OK");
    client.println("Content-Type: text/html");
    client.println();
    client.println("<html><head>");
    client.println("<meta http-equiv='refresh' content='60'>");
    client.println("<title>Arduino Webserver</title>");
    client.println("</head>");
    client.println("<body>");
    //---Überschrift---
    client.println("
<hr />");
    client.println("<h1><div align='center'>Arduino Webserver powered by Cetax</div></h1>");
    client.println("<hr />
");
    //---Überschrift---
    client.println("Die Temperatur betraegt ");
    client.println("<h2>");
    client.println(temp1);
    client.println("&deg;C");
    client.println("</h2>");
    client.println("</BODY></HTML>");    
    delay(100);
    client.stop();//close the connection with the client
  }
  
}
 
/******************************
                              *
  Daten an Server schickenn   *
                              *
*******************************/
void Daten_senden(float T1, float T2)
{    
  if (client.connect(server, 8000)) // Verbindung zum Server aufbauen
  {
    Serial.println("Verbunden, Sende Daten...");
    client.print("GET " + String(url));
    Serial.println("GET " + String(url));
    client.print("?T1=");
    Serial.print("?T1=");
    client.print(T1);
    Serial.println(T1);
    client.print("&T2=");
    Serial.print("&T2=");
    client.print(T2);
    Serial.println(T2);
    client.print("&key=" + String(key));
    Serial.print("&key=" + String(key));
    client.println(" HTTP/1.1");
    Serial.println(" HTTP/1.1");
    client.print("Host: " + String(host));
    Serial.print("Host: " + String(host));
    client.println();
    Serial.println();
    client.println("User-Agent: Arduino");
    Serial.println("User-Agent: Arduino");
    client.println("Connection: close");
    Serial.println("Connection: close");
    client.println();
    Serial.println();
  }
  else
  {
    Serial.println(" ***** VERBINDUNG KANN NICHT HERGESTELLT WERDEN *****");
    digitalWrite(led, LOW);
  }
}

Danke Euch

Zum einen: entferne alle delay()-Aufrufe, die sind komplett unnötig.
Zum anderen: Du hast eine Kombination von Web-Client und Web-Server gemacht, aber das zeitliche Verhalten ist etwas unbestimmt.

Zudem verwendest Du bei allen konstanten Strings das F()-Makro nicht, welches diese im Flash-Speicher behält und kein kostbares RAM dafür verbraucht.

Hi,
also der Teil, in dem die Temperatur in die SQL-Datenbank funktioniert super,
nur wollte ich gern auch "mal" die aktuelle Temperatur haben.
Nur leider kommt immer ein "Er kann die Website nicht finden, wenn ich die IP des Arduinos aufrufen.

pylon:
...
Zum anderen: Du hast eine Kombination von Web-Client und Web-Server gemacht, aber das zeitliche Verhalten ist etwas unbestimmt.
...

Was meinst damit ? Wenn ich den Code ans Ende verschiebe, klappt es auch nicht.
Mache ich daraus einen eigenen Sketch, funktioniert es, nur nicht zusammen (Webclient/Server)

Wie komme ich denn an die aktuelle Temperatur?
Jemand eine Idee ?

Bei deinem eigentlichen Problem kann ich dir zwar nicht helfen aber, Ich kann dir nur dazu Raten deinen Ram zu Sparen. Denn wenn der voll läuft dann reagiert dein Arduino unkontrolliert.

Um heraus zu finden wie viel RAM frei ist nutze ich das hier:

http://www.arduino.cc/playground/Code/AvailableMemory

int freeRam () {
  extern int __heap_start, *__brkval; 
  int v; 
  return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); 
}
// Irgendwo in einer HTML Tabelle>>>

client << F("<th colspan='4'align='center'>Diagnosezeile
 Freier Speicher = "); //Wird direkt aus dem Flash gelesen 
client.print(freeRam());      // client.print wird aus dem RAM geholt
client << F(" Byte
");      // ist wieder vom Flash und belastet somit den RAM nicht

Und das Zauberwort zum Ram Sparen lautet Progmem
Dazu gibt es auch eine recht einfache Bibliothek: Flash | Arduiniana

Das ist das F()-Makro was pylon schon erwähnt hat.
Nachdem du wieder ein paar Byte RAM frei hast ist es möglich das dein Code schon Funktioniert....

Gruß derRobert

Ok.
Aber wie kommt Ihr darauf das der Ram voll läuft ?
Woran sieht man das ?

wie man das sieht?
Mit einem codeschnippsel und der Erklärung aus dem Playground.
Beides steht im Post über dir!

Wie wir darauf kommen?
Bittere Erfahrung!!!

Wenn der RAM voll ist dann macht der Arduino nicht mehr was du ihm mit deinem Programm sagst sondern völlig undefinierte Dinge. Daher ist es Ratsam zu allererst ab zu klären wie es um den Speicher steht.

Und die Menge an Serial.print und Client.print in deinem Code, Ist sehr Speicherhungrig

Und hier habe ich ebend noch was gefunden:

uwefed:
Using Flash Memory for string storage.
Ab Arduino IDE Version 1.0 wurde die F()-Syntax eingeführt.
Mit ihr kann man Strings im Flash-Speicher anstatt im RAM ablegen.
Beispiel:

Serial.println(F("This string will be stored in flash memory"));

Ähnlich funktioniert auch

#include <avr/pgmspace.h>

printf_P(PSTR("This string will be stored in flash memory"));



Dazu ist aber das Include der obengenannte Bibiothek notwendig.

http://www.arduino.cc/playground/Main/Printf

Grüße Uwe

Was meinst damit ?

Tragen wir mal Deinen loop() zeitlich zusammen:

  sensors.requestTemperatures();
  float temp1 = sensors.getTempC(sensor1);                      // Temperatur von Sensor 1 ermitteln
  float temp2 = sensors.getTempC(sensor2);                      // Temperatur von Sensor 2 ermitteln

Zwei OneWire-Temperatursensoren abrufen: ca. 1.5s

  Daten_senden(temp1, temp2);                                 // Temperaturdaten an Server übertragen

Je nach Reaktionsgeschwindigkeit des Servers unterschiedlich, aber schon die serielle Ausgabe braucht ca. 0.2s, also dürften 0.5s nicht falsch liegen.

  delay(700);

Weitere 0.7s

    delay(1000);

Mindestens eine weitere Sekunde.

long Interval  = 5;                                        // Upload-Interval in Minuten
  delay(Interval);

Hier stimmt zum Glück der Kommentar nicht, sonst wäre spätestens hier Dein Code gestorben

Dann wird getestet, ob eine Verbindung reingekommen ist, die es zu behandeln gilt. Insgesamt gehen fast 4 Sekunden verloren, bevor ein neuer Test ansteht. Mit kleinen Änderungen und dem entfernen sämtlicher unnötiger delay()s ist das schnell auf wenige Millisekunde runter.

Aber wie kommt Ihr darauf das der Ram voll läuft ?
Woran sieht man das ?

Du verwendest über 700 Zeichen konstante Strings, die Du einfach durch das F()-Makro in den Programm-Speicher (Flash) verschieben kannst. Ansonsten werden die 700 Bytes konstant im RAM belegt. Bei 2kB Gesamtspeicher darf man hier durchaus von Speicherverschwendung ausgehen.

Dann verwendest Du die String-Klasse, die erstens den Speicher fragmentiert und zweiten an einem Memory-Leak bei der Freigabe von dynamisch alloziertem Speicher leidet. Beides zusammen führt zum dringenden Rat: Verwende die ganze String-Klasse nie in einem Sketch, der über ein Hello-World-Beispiel hinausgeht.

Hallo ihr beiden,
danke für die tolle Erklärung.
Hoffe ich habe verstanden was ihr meint.
Ich werde mich mal daran machen, den Code zu säubern und so zu optimieren.
Vielen Dank.

Ich verstehe ehrlich gesagt den Sinn hinter dem Ganzen nicht. Wenn Dein Arduino eh schon in eine Datenbank mit einem PHP-fähigen Webserver logged, warum holst Du Dir die Daten nicht von dort? Während der Arduino in Richtung Datenbank schreibt, ist er eh beschäftigt und kann keine weiteren Anfragen verarbeiten. Deine Daten können also NIE aktueller sein, als das was in der DB steht. Der dortige Webserver hat sicher mehr Ressourcen, um das Loggen des Arduino UND das Ausliefern einer Webseite mit den aktuellsten Daten zu verkraften.
Das Prinzip dahinter ist KISS (Keep It Simple and Stupid)
Bei gleichzeitig Client und Server die zeitnah reagieren sollen, müßtest Du die Kommunikation "multipexen" also nicht innerhalb einer Funktion Daten senden und an einer anderen Stelle Webserver spielen, sondern alles "quasi" parallel in der loop() abhandeln. der WIZnet 5100 kann glaub ich 2 TCP-Verbindungen gleichzeitig, ich weiss aber nicht, ob die LIB das kann. Das Prinzip wäre so ähnlich wie "Blink without delay".
Oder noch anders.
Webserver und Webclient sind, sagen wir mal Objekte die "selbst wissen" wo im Ablauf (Senden, Empfangen, Verarbeiten etc.) sie gerade stehen. Z.B. durch einen internen Status. Jedes dieser "Objekte" hat sowas wie eine "next_step()" Funktion, die man aufrufen kann und wo dieses Objekt den nächsten Schritt macht. Z.B. ein Byte Senden oder Empfangen, die aktuelle Temperatur auslesen, was auch immer. Aber immer nur einen kleinen Schritt, danach kehrt die Funktion wieder zurück. Somit blockiert jede Funktion immer nur für ein par Millisekunden den Ablauf. In Pseudocode würde das in etwa so aussehen:

void setup() {
   ...

   //neues Webserver Objekt erzeugen
   Webserver server = Webserver;
   
   //Objekt initialisieren (lausche auf Port 80)
   server.init(80);


   //neues Webclient Objekt erzeugen
   Webclient client = Webclient;
   
   //Objekt initialisieren (sende an IP mit Port )
   client.init("192.168.0.1",80);

   ...

}

void loop() {
   //Webserver einen schritt machen lassen
   server.next_step();
   
   //Client einen Schritt machen lassen
   client.next_step();

  //anderer NICHT BLOCKIERENDER kurzer Code
  
}

Das ganze geht in Richtung "kooperatives" Multitasking.