Go Down

Topic: Ethernet Shield als Server und Client gleichzeitig? (Read 4839 times) previous topic - next topic

kduin

Hallo,

kann man das Ethernet-Shield als Server und Client gleichzeitig benutzen?

Ich will für unseren Pool ein Arduino verwenden, dass Regelmäßig Messdaten (z.B. Wassertemperatur) an einen Webserver sendet, der die Daten in seiner Datenbank speichert. (Betrieb als Client)
Gleichzeitig will ich aber auch, dass ich ans Arduino Kommandos schicken kann, auf welche es umgehend reagiert. (Betrieb als Server)

Beispielschema:
Arduino sendet Messdaten alle x Minuten als Client -> Webserver speichert Daten in -> Datenbank  (-> User kann Daten jederzeit über Browser vom Webserver aufrufen)

UND

Webbrowser Knopfdruck auf "Pumpe an" -> Webserver leitet Kommando an Arduino weiter -> Arduino empfängt als Server das Kommando und führt es aus.


mkl0815

Ich denke das geht prinzipiell. Letztendlich kannst Du Dich am Sketch von Cetax orientieren: http://arduino.cc/forum/index.php/topic,102817.0.html
Nur das Du halt in dem "ich warte bis eine Sekunde rum ist" Teil des Codes eine Minute wartest und dann statt die Timer runter zu zählen einfach dem Webserver die Daten schickst.
Oder Du behältst die Timer-Funktionalität und baust den "Daten senden" Teil zusätzlich mit einem Minuten-Takt ein.
Problematisch könnte eine "Racecondition" werden, wenn der Arduino gerade an den Webserver sendet und deshalb nicht direkt auf ein ankommendes Kommando reagiert. Allerdings ist TCP recht geduldig und das Senden dürfte nicht so lange dauern, das Du in einen Timeout der ankommenden Verbindung läufst. Wenn das Senden im schlimmsten Fall 500ms dauert, sollte das gesendete Kommando trotzdem noch ankommen.

Plan B wäre, den Arduino nur als Client laufen zu lassen. Du könntest z.B. alle 10 Sekunden den gleichen Webserver, dem Du die Messdaten schickst, auch über eine andere URI nach neuen Kommandos fragen und diese dann ausführen. Somit brauchst Du nicht Client und Server, sondern nur den Client-Code.

Mario.

kduin

Hallo,

wie soll ich den Code denn umschreiben?

Dort wird doch nur die Client-Funktion benutzt?



Quote
Plan B wäre, den Arduino nur als Client laufen zu lassen. Du könntest z.B. alle 10 Sekunden den gleichen Webserver, dem Du die Messdaten schickst, auch über eine andere URI nach neuen Kommandos fragen und diese dann ausführen. Somit brauchst Du nicht Client und Server, sondern nur den Client-Code.

Das kam mir auch schon in den Sinn, aber das braucht so viel Traffic und das ganze Programm wird dadurch schwerfälliger.
Außerdem will ich ja direkt schalten, nicht mit Wartezeit.

Eisebaer

Quote
Das kam mir auch schon in den Sinn, aber das braucht so viel Traffic und das ganze Programm wird dadurch schwerfälliger.
Außerdem will ich ja direkt schalten, nicht mit Wartezeit.


hi, kduin,

diese probleme kannst Du vermeiden, wenn Du den Arduino nur als webserver laufen läßt:
einem webserver kannst Du befehle schicken, z.b. von einem anderen webserver auf Deinem computer, genauso kannst Du aber auch daten abfragen. Du mußt ja nicht den arduino die zeit bestimmen lassen, wann er die temperatur mißt, sondern kannst ja z.b. alle 10 minuten vom compu aus eine abfrage an den arduino webserver stellen.
also ein:

http://192.168.1.100?befehl=HEIZUNG_AN
der arduino kann in der antwort etwa den erfolgsfall melden

http://192.168.1.100?befehl=SENDE_TEMPERATUR
und die antwort ist die temperatur.

oder Du läßt den computer komplett außen vor. der arduino kann das alles auch ganz allein
als webserver, wenn Du die temperaturdaten dauerhaft speichern willst, nimmst Du halt die sd-karte.

Gruß stefan

mkl0815

@Eisbaer: Den Arduino als Webserver zu verwenden geht zwar, ist aber nicht immer eine gute Lösung. Spätestens wenn die Webseite komplexer wird und verschiedene Abläufe / Abfragen / Formulare umgesetzt werden müssen, kommt man schnell an die Grenzen des Arduino, vor allem was den Speicher angeht.


Hallo,

wie soll ich den Code denn umschreiben?

Dort wird doch nur die Client-Funktion benutzt?

Nein, im Code von Cetax läuft der Arduino als Server. Er wartet auf eine ankommende Verbindung auf Port 23. Allerdings nicht als Webserver, das bedeutet, das kein HTTP verwendet wird, sondern nur ein viel einfacheres Protokoll, das mit wenigen Bytes auskommt und man keine aufwändige Stringverarbeitung benötigt, um die Daten aus einer Abfrage zu filtern.
Die Idee von Eisbaer, den Arduino nur als Server zu verwenden (nur eben nicht als Webserver) ist vermutlich sogar die beste Lösung. Du brauchst dann nur den Code von Cetax um einen weiteren "Befehl" zu erweitern, mit dem Dein (externer) Webserver alle 10 Minuten die Temperatur abfragt. Der Code zum Auslesen eines digitalen Pins ist ja schon vorhanden, Du mußt nur den Code zum Abfragen des Temperatur-Sensors ergänzen und den großen Switch-Case Block ein neues Kommando beibringen.
Der Trick liegt dann darin, das Du einen Webserver (z.B. XAMPP) auf einem Rechner hast, der in der Lage ist, in regelmäßigen Abständen ein Script auszuführen, um die Messdaten abzufragen und der gleichzeitig die Webseite hostet, über die Du Deine Steuerung per Browser bedienen kannst.

Eisebaer

hi, forum,

Quote
Den Arduino als Webserver zu verwenden geht zwar, ist aber nicht immer eine gute Lösung. Spätestens wenn die Webseite komplexer wird und verschiedene Abläufe / Abfragen / Formulare umgesetzt werden müssen, kommt man schnell an die Grenzen des Arduino, vor allem was den Speicher angeht.


diese aussage hör ich immer wieder. und sie ist richtig, wenn es wirklich um komplexe anwendungen geht. kduin hat aber nicht vor, amazon auf einem arduino zu hosten, sondern er will alle paar minuten eine temperatur holen und ab und zu einen befehl schicken. um sicher zu gehen, kann ja der fragende compu auf antwort warten, bevor er nochmal was wegschickt (mit timeout). allerdings, mkl0815, hast Du recht, daß Deine lösung in diesem fall einfacher sein kann, wenn man ohnehin einen compu dauernd an hat. das hat aber nichts mit fehlender leistungsfähigkeit des arduino-webservers zu tun.

gruß stefan

TriB

Das sehe ich genauso wie Eisebaer!
Selbst nutze ich den Ardu als Server & Client und es funktioniert wunderbar. Nicht gerade das schnellste was es so gibt auf dem Markt, aber bedienbar.

Hier gibt es alle nötigen Infos:
Funkschalter in Webserver einbinden
Oder hier auch auf der ersten Seite ein paar Infos zu Hardware:   
Arduino fernsteuern dank Webserver mit Ajax

Gruß,
Thomas

JO3RI

Hi, I'll answer this in English.

In your main loop, make a void webserver and a void webclient. They will alternate if you put your webserver start within the void (same for the client) and not in the setup. Don't use delays.

I did this to get a tweet from the internet and then use it to show on a webpage shown by the arduino.
http://www.JO3RI.be

Nederlandstalige sectie - http://arduino.cc/forum/index.php/board,77.0.html -

mkl0815


Das sehe ich genauso wie Eisebaer!
Selbst nutze ich den Ardu als Server & Client und es funktioniert wunderbar. Nicht gerade das schnellste was es so gibt auf dem Markt, aber bedienbar.

Es hat ja auch keiner behauptet, das es nicht geht. Aber spätestens wenn Du Deine Arduino-Webseite nicht nur mehr vom lokalen Netz aus ansprechen willst, sondern über einen offenen Port auf dem Router den Arduino von extern steuern willst, kommst Du schon aus Sicherheitsgründen an die Grenzen.
Für https ist der Arduino definitiv zu schwach und der RAM dürfte dafür auch kaum reichen. Selbst ein HTTP-Auth oder eine in die Anwendung integrierte Passwortabfrage die halbwegs sicher ist (also nicht immer ein Klartext-Passwort in der URL als Parameter) ist auf dem Arduino schon ein ziemlicher Aufwand. Dazu kommt, das der WIZnet 5100 Ethernet Chip nur 2 TCP-Verbindungen parallel bedienen kann, wenn ich das recht in Erinnerung habe. Damit ist ein Denial of Service super einfach, es reicht schon einige Male den Reload-Button des Browsers zu klicken. Ich meine mich zu erinnern, das es dazu hier auch mal einen Thread gab, wo der Reload ein Problem war.
Mario.

kduin

Hi,

eure Ideen sind im Ansatz gut, aber ich will das Arduino ja laufen lassen, ohne irgend einen cronjob im hintergrund zu haben.

Ich glaube JO3RI's ansatz ist der treffende...

Hi, I'll answer this in English.

In your main loop, make a void webserver and a void webclient. They will alternate if you put your webserver start within the void (same for the client) and not in the setup. Don't use delays.

I did this to get a tweet from the internet and then use it to show on a webpage shown by the arduino.

Hi and thanks for your reply.
What do you mean with void webserver and client?
Can you show me a chematic example?


JO3RI

Oké, sorry to continue in English.

I used this in a project of mine: CastDuino. More on this you can read at: http://www.jo3ri.be/a/jo3ri.be/jo3ri/arduino/projects/castduino

So what I did was use webserver and webclient alternating like this: (this in only partial code)

Code: [Select]
void setup()
{
  Ethernet.begin(mac, ip, dns, gateway, subnet);
  server.begin();
  delay(3000); // we wait 3 sec to get the shield up and running
}

void loop()
{
  WebServer(); // in this void we will present our webpage(s) => web server
  SetTime(); // in this void we will get the time from an NTP server => web client
  CheckTwitter(); // in this void we will get a twitter feed => other web client
}

void WebServer(){
  EthernetClient client = server.available();
  if (client) {
    TextFinder finder(client,1); // number of seconds to wait for the next character before aborting the find and get methods.
    byte type = 0;
    while (client.connected()) {
      if (client.available()) {
        // GET, POST, or HEAD
        if(finder.getString("","/", buffer2,sizeof(buffer2)))
        {
          if(strcmp(buffer2, "GET ") == 0 )
            type = 1;
          else if(strcmp(buffer2,"POST ") == 0)
            type = 2;
          // look for the page name
          if(finder.getString( "", "/", buffer2, sizeof(buffer2)))
          {
            if(strcasecmp(buffer2, "showjobs") == 0)
              PageJobs(client, finder, type == 2);
            else if(strcasecmp(buffer2, "setslave") == 0)
              PageSetup(client, finder, type == 2);
            else if(strcasecmp(buffer2, "setupeth") == 0)
              PageConfigEth(client, finder, type == 2);
            else
              PageStandard(client);
          }
        }
        break;
      }
    }
    // give the web browser time to receive the data
    delay(1);
    client.stop();
  }
}

void SetTime(){
  if (UseTimeServer == true){
    unsigned long currentMillis = millis();
    if((currentMillis - previousMillis > (Interval *3600000)) || (TimeUpdate == true)) {
      TimeUpdate = false;
      previousMillis = currentMillis;
      sendNTPpacket(TimeServer); // send an NTP packet to a time server
      // wait to see if a reply is available
      delay(1000); 
      if ( Udp.parsePacket() ) {
        // We've received a packet, read the data from it
        Udp.read(packetBufferNTP,NTP_PACKET_SIZE);  // read the packet into the buffer
        //the timestamp starts at byte 40 of the received packet and is four bytes,
        // or two words, long. First, esxtract the two words:
        unsigned long highWord = word(packetBufferNTP[40], packetBufferNTP[41]);
        unsigned long lowWord = word(packetBufferNTP[42], packetBufferNTP[43]);
        unsigned long secsSince1900 = highWord << 16 | lowWord;
        byte DTS = 0;

        const unsigned long seventyYears = 2208988800UL - (TimeOffset * 3600L) - (DayLightSaving * 3600L);
        unsigned long epoch = secsSince1900 - seventyYears;
        setTime(epoch);
        // now that we have time set, we will have to I2C it to the output ATMEGA
        buffer[0] = epoch >> 24;
        buffer[1] = epoch >> 16;
        buffer[2] = epoch >> 8;
        buffer[3] = epoch;
        Wire.beginTransmission(4); // transmit to device #4
        Wire.write('T');        // first send a 'T' so I2C slave knows we are sending time
        for (byte i = 0;i<4;i++){
          Wire.write(buffer[i]);
        }
        Wire.endTransmission();    // stop buffering and start transmitting
      }
    }
  }
}

void CheckTwitter(){
  unsigned long currentMillis = millis();
  if((currentMillis - TwitterMillis > 600000) || (TimeUpdate == true)) {
    TimeUpdate = false;
    TwitterMillis = currentMillis;
    String TwitterName; //We will get the twittername out of the twittercommand in the TXTjob
    String SearchString ="<title>";
    if (buffer[0] == '#' && buffer[1] == 'T'  && buffer[2] == '#'){
      // first let's get the name out of the twitter command.
      for (byte i = 3; i <19; i++){
        if (buffer[i] != 0x03){
          TwitterName[i-3] = buffer[i];
        }
      }
      if (client.connect("api.twitter.com", 80)) {
        TextFinder  finder( client,2 );
        // make HTTP GET request to twitter:
        client.print("GET /1/statuses/user_timeline.rss?screen_name=");
        client.print(TwitterName);
        client.println("&count=1 HTTP/1.1");
        client.println("HOST: api.twitter.com");
        client.println();
        while (client.connected()) {
          if (client.available()) {
            SearchString = SearchString + TwitterName + ": ";
            byte charsize = SearchString.length() + 1;
            char StartHere[charsize];
            char EndHere[] = "</title>";
            SearchString.toCharArray(StartHere,charsize);
            if((finder.find("<item>")&&(finder.getString(StartHere,EndHere,buffer,140)!=0)))
            break;
          }
        }
        delay(1);
        client.stop();
      }
      // don't make this less than 30000 (30 secs), because you can't connect to the twitter servers faster (you'll be banned)
      // off course it would be better to use the "Blink without delay", but I leave that to you.
    }
  }
}


Ok, so what the actual code of castduino does is (only small part is shown here):
- receives text over UDP from another arduino (web client)
- shows the webpage embedded in the code (web server)
- sets time from a NTP server every 6 hours (web client)
- checks day, hour, minutes
- if correct day, hour, minute, it fill's a buffer with a text or tweet
- gets a twitter feed (web client)
- sends the text or tweet buffer over I2C to an other arduino that makes is show on a dot matrix.

And all this keeps repeating (so fast => 16 mhz) you won't really notice. and what does it mean?
I can check my embedded website, fill out forms, commit them, while time updates, text scrolls and tweet updates keep going on.

Hope it helps.
http://www.JO3RI.be

Nederlandstalige sectie - http://arduino.cc/forum/index.php/board,77.0.html -

Go Up