Server Client als Kombination nutzen

Hallo Forum,
leider merke ich immer mehr meine Grenze im Verstehen und Kombinieren mehrer Lösungen. Ich habe es geschafft im lokalen Netzwerk Daten an mein Arduino zu senden und diese auszuwerten. Ausserdem habe ich es geschafft Werte vom Arduino in meine DB (irgendwo im Internet) abzu speichern. Doch, wenn ich den Spaß jetzt kombinieren möchte, gelingt mir das nicht so recht.
Ich würde mich mal wieder über eure Hilfe freuen.

#include <SPI.h>
#include <Ethernet.h>

// MAC und IP Konfiguration
byte mac[] = { 0xDE, 0xAD, 0xBC, 0xAF, 0xFE, 0xED };
IPAddress ip(192,168,*,***);
IPAddress gateway(192,168,*, *);
IPAddress subnet(255, 255, 255, 0);

// warten auf port 23
EthernetServer server(23);
char serverName[] = "www.hemitheconyx-caudicinctus.de";
EthernetClient client;

int pin = 13;
int statusPin13 = 0;

void setup() {
  //Ethernet initialisieren
  Ethernet.begin(mac, ip, gateway, subnet);
  // Server starten
  server.begin();
  Serial.begin(9600);
  
}

void loop() {
 pinLeuchten();
 webInput();
}

void pinLeuchten()
{
  if (statusPin13 == 0)
  {
    digitalWrite(pin,LOW);
  }
  else
  {
    digitalWrite(pin,HIGH);
  }
}

void webInput()
{
  // auf eine eingehende Verbindung warten
 client = server.available();
  //wenn verbindung, dann 3 bytes lesen; 
  if (client) {
    char command =client.read();
    byte pinnumber =client.read();
    byte pinvalue =client.read();
    if(command == 'O')
    {
      
      if (statusPin13 != 0)
      {
        //Setze Datenbankquery ab!!!
        Serial.println("bin in der Schleife == 1");
        dbQuery(pin,0);
      }
      statusPin13 = 0;
      Serial.println("Pin13 ausgeschaltet");
    }
    if(command == 'S')
    {
       if (statusPin13 != 1)
       {
        //Setze Datenbankquery ab!!!
        Serial.println("bin in der Schleife == 0");
        dbQuery(pin,1);
       }
      statusPin13 = 1;
      Serial.println("Pin 13 angeschaltet");
    }
    //Kommando auswerten
    client.stop();
  }
}

void dbQuery(int pin, int statuslevel)
{
  Serial.print("bin gestartet");
   if (Ethernet.begin(mac) == 0) {
   Serial.println("Failed to configure Ethernet using DHCP");
  // no point in carrying on, so do nothing forevermore:
  while(true);
  }
  //give the Ethernet shield a second to initialize:
  delay(1000);
  Serial.println("connecting...");

  // if you get a connection, report back via serial:
  
  if(client.connect(serverName, 80))
  {
    if (statuslevel == 1)
    {
    Serial.println("bin connected");
    client.println("GET /hc_arduino_php/hc_status.php?pin=13&status=1 HTTP/1.0");
    client.println("Host: www.hemitheconyx-caudicinctus.de");
    client.println();
    Serial.println("habe alles ausgeführt");      
    }
    else
    {
    Serial.println("bin connected");
    client.println("GET /hc_arduino_php/hc_status?pin=13&status=0 HTTP/1.0");
    client.println("Host: www.hemitheconyx-caudicinctus.de");
    client.println();
    Serial.println("habe alles ausgeführt");
    }
  }
  else
  {
    Serial.println("bin doch gar nicht verbunden");
  }
  client.stop();  
}

Sollte jemand von euch den Code austesten auf www.hemitheconyx-caudicinctus.de/hc_arduino_php/output.php kann überprüft werden ob sich der Wert von 0 auf 1 ändert.

Irgendwie kommt mir ein Teil vom Code bekannt vor :)

Dein Problem ist, das Du die Variable "client" global definierst und zweimal parallel verwendest, denn innerhalb der Funktion die als Webserver Daten empfängt rufts Du die Funktion dbQuery() auf. Dort wird zusätzlich das Ethernetshield nochmal initialisiert, was sicher bei schon bestehenden Verbindungen keine gute Idee ist. Als Fausregel gilt -> Initialisierungen gehören in die setup() Funktion, nicht in die loop() (seltene Ausnahmen sicher ausgenommen). Innerhalb von dbQuery() wird dann client.connect(serverName, 80) aufgerufen und damit die Verbdindung die client bereits aus webInput() hat überschrieben. Ich würde hier zumindest schon mal mit 2 verschiedenen Variablen arbeiten.

Ja der Code sollte dir durchaus bekannt vorkommen im Header steht auch dein name mit drinnen, damit ich nicht vergesse von wem unteranderem was kommt*G*.Wenn ich die Initailisierung im Setup mache gelingt es nicht, aber ich probiere es nachher nochmal aus. mfg balli

Naja, nicht einfach nur die 2. Initialisierung auch ins setup() kopieren. Was Du in Deinem Code machst ist im setup() die Ethernet-Lib mit einer festen IP konfigurieren, was ja auch Sinn macht, wenn Du den Arduino direkt ansprechen willst, ohne zu raten. Dann stellt Du aber plötzlich bei der 2. Initialisierung auf DHCP um. Ich hab jetzt nicht genau geschaut, aber eigentlich brauchst Du die zweite Initialisierung nicht. Es würde vermutlich sogar reichen in dbQuery() eine lokale client Variable zu definieren, auch wenn das kein guter Stil ist und zu Verwirrungen führen kann. Also sowas wie:

void dbQuery(int pin, int statuslevel)
{
  EthernetClient httpclient;

  
  if(httpclient.connect(serverName, 80))
...
}

Natürlich musst Du überall in der Funktion dann httpclient verwenden.

Die if/else Block kannst Du Dir auch recht einfach sparen:

/** 
  * statt diesem hier:
if (statuslevel == 1)
    {
    Serial.println("bin connected");
    client.println("GET /hc_arduino_php/hc_status.php?pin=13&status=1 HTTP/1.0");
    client.println("Host: www.hemitheconyx-caudicinctus.de");
    client.println();
    Serial.println("habe alles ausgeführt");      
    }
    else
    {
    Serial.println("bin connected");
    client.println("GET /hc_arduino_php/hc_status?pin=13&status=0 HTTP/1.0");
    client.println("Host: www.hemitheconyx-caudicinctus.de");
    client.println();
    Serial.println("habe alles ausgeführt");
    }
**/
//einfach
    Serial.println("bin connected");
    client.print("GET /hc_arduino_php/hc_status.php?pin=13&status=");
    client.print((char)status+'0');
    client.println(" HTTP/1.0");
    client.println("Host: www.hemitheconyx-caudicinctus.de");
    client.println();
    Serial.println("habe alles ausgeführt");

Der Trick steckt in client.print((char)status+'0'); Versuch mal rauszufinden, was da passiert :-)

Das Rausfinden werde ich jetzt machen,aber vorab noch meine geänderte Version:

#include <SPI.h>
#include <Ethernet.h>

// MAC und IP Konfiguration
byte mac[] = { 0xDE, 0xAD, 0xBC, 0xAF, 0xFE, 0xED };
IPAddress ip(192,168,1,177);
IPAddress gateway(192,168,1, 1);
IPAddress subnet(255, 255, 255, 0);

// warten auf port 23
EthernetServer server(23);
char serverName[] = "www.hemitheconyx-caudicinctus.de";
EthernetClient client_in;
EthernetClient client_out;

int pin = 13;
int statusPin13 = 0;

void setup() {
  
  Serial.begin(9600);
  
  //Ethernet initialisieren
   Ethernet.begin(mac, ip, gateway, subnet);
  //give the Ethernet shield a second to initialize:
  delay(1000);
  Serial.println("connecting...");
  
  // Server starten
  server.begin();
  
  
}

void loop() {
 pinLeuchten();
 webInput();
}

void pinLeuchten()
{
  if (statusPin13 == 0)
  {
    digitalWrite(pin,LOW);
  }
  else
  {
    digitalWrite(pin,HIGH);
  }
}

void webInput()
{
  // auf eine eingehende Verbindung warten
 client_in = server.available();
  //wenn verbindung, dann 3 bytes lesen; 
  if (client_in) {
    char command =client_in.read();
    byte pinnumber =client_in.read();
    byte pinvalue =client_in.read();
    if(command == 'O')
    {
      
      if (statusPin13 != 0)
      {
        //Setze Datenbankquery ab!!!
        Serial.println("bin in der Schleife == 1");
        dbQuery(pin,0);
      }
      statusPin13 = 0;
      Serial.println("Pin13 ausgeschaltet");
    }
    if(command == 'S')
    {
       if (statusPin13 != 1)
       {
        //Setze Datenbankquery ab!!!
        Serial.println("bin in der Schleife == 0");
        dbQuery(pin,1);
       }
      statusPin13 = 1;
      Serial.println("Pin 13 angeschaltet");
    }
    //Kommando auswerten
    client_in.stop();
  }
}

void dbQuery(int pin, int statuslevel)
{
  Serial.println("bin gestartet");
  
//Verbindung als Client aufbauen - Ziel Homepage
  client_out.connect(serverName, 80);
  // if you get a connection, report back via serial:
  
  if(client_out.connected())
  {
    if (statuslevel == 1)
    {
    Serial.println("bin connected");
    client_out.println("GET /hc_arduino_php/hc_status.php?pin=13&status=1 HTTP/1.0");
    client_out.println("Host: www.hemitheconyx-caudicinctus.de");
    client_out.println();
    Serial.println("habe alles ausgeführt");      
    }
    else
    {
    Serial.println("bin connected");
    client_out.println("GET /hc_arduino_php/hc_status?pin=13&status=0 HTTP/1.0");
    client_out.println("Host: www.hemitheconyx-caudicinctus.de");
    client_out.println();
    Serial.println("habe alles ausgeführt");
    }
  }
  else
  {
    Serial.println("bin doch gar nicht verbunden");
  }
  client_out.stop();  
}

Ich lande in der Funktion db_query jetzt immer in der Schleife “bin doch gar nicht verbunden”

Die fehlt der DNS Server. Bei DHCP wird der in der Regel vom Router mit den IP-Adress Daten mit vergeben. Wenn Du dem Arduino eine feste IP gibst, dann must Du auch einen DNS Server mit angeben, falls Du wie in Deinem Fall ein FQDN wie "www.hemitheconyx-caudicinctus.de" verwenden willst.

Siehe auch http://arduino.cc/en/Reference/EthernetBegin Hier speziell den Aufruf Ethernet.begin(mac, ip, dns, gateway, subnet); Als DNS kannst Du einefach die 8.8.8.8 nehmen, das ist der DNS Server von Google, der ist eigentlich immer erreichbar.

Okay, ich dachte ich muss den DNS-Server nur verwenden wenn ich von Aussen auf den Arduino will. Ich bin aber jetzt dennoch sicher, weil ich keine Portweiterleitung im Router aktiviert habe oder irre ich mich da?

//einfach
    Serial.println("bin connected");
    client.print("GET /hc_arduino_php/hc_status.php?pin=13&status=");
    client.print((char)status+'0');
    client.println(" HTTP/1.0");
    client.println("Host: www.hemitheconyx-caudicinctus.de");
    client.println();
    Serial.println("habe alles ausgeführt");

Also der Code läuft nicht ohne weiteres, weil status bereits vordefiniert ist. Alternativ habe statusPin13 eingegeben und dass dann nicht das gewünschte passiert ist mir fast klar. Mh,ich kann es mir fast nicht zusammen reimen was passiert. Worauf bezieht sich denn das "status", ich denke damit meinst du den zustand von Pin 13 oder?

mfg balli

Ballibum: Okay, ich dachte ich muss den DNS-Server nur verwenden wenn ich von Aussen auf den Arduino will. Ich bin aber jetzt dennoch sicher, weil ich keine Portweiterleitung im Router aktiviert habe oder irre ich mich da?

Es ist genau anders herum. Dein Arduino braucht einen DNS Server, wenn er einen anderen Server im Netz erreichen will, von dem er nicht die IP-Adresse, sondern nur den Namen hat. Du verwendest "www.hemitheconyx-caudicinctus.de" als Servernamen, den Du ansprechen willst. Der Name nützt deinem Arduino aber nix, weil er eine IP braucht. In Deinem Fall wäre das die 85.25.245.16. Um aus dem Namen eine IP zu machen muss der Aruino einen Nameserver fragen, genau das ist dann die 8.8.8.8 (goolge-DNS -- nicht zu verwechseln mit der Google-Suchseite :-) )

Wenn Dein Arduino vom Internet aus erreichbar sein soll, muss derjenige der ihn erreichen soll den "Namen" des Arduino auflösen können. Z.B. sowas wie "mein-arduino.dyndns.org", das würde dann auf die akutelle IP Deines Routers aufgelöst werden, der dann per weitergeleitetem Port die ankommende Anfrage an Deinen Arduino durchreicht. Für diesen Vorgang braucht der Arduino selbst keinen DNS Server, er wird ja von außen aktiv angesprochen.

Das kann man eigentlich ganz gut mit einem Telefon und der Telefonauskunft vergleichen. Wenn Du (quais als Arduino) von zu Hause (dein Netzwerk) jemanden draußen anrufen willst, von dem Du nur den Namen/Adresse (Server-Adresse) hast, rufst Du erst die Telefonauskunft an und fragst nach dessen Nummer (IP), damit Du ihn direkt anrufen kannst. Dafür brauchst Du aber die Nummer (IP) der Telefonauskunft (DNS-Dienst). Nur der Name der Telefonauskunft nützt dir auch nix, weil Du ja dann trotzdem keine Nummer hast. Daher werden DNS-Server auch immer nur als IP konfiguriert und nicht als Namen.

Wenn Dich jemand anrufen will, braucht der dann wieder die Nummer der Telefonauskunft (DNS), weil er ja Deine Telefonnummer rausbekommen muss, um Dich anzurufen. Du selbst (als Arduino) sitzt nur am Telefon und wartest das jemand anruft (client_in = server.available();). Dafür brauchst Du die Auskunft nicht, weil Du selbst ja keine Nummer rausfinden musst.

Sorry für den Märchentext, aber mir gefiel das Beispiel beim Schreiben immer besser :-)

Was den Code angeht, der nicht funktioniert. Der war ohne Testen geschrieben. Vermutlich musst Du nur folgendes ändern client.print((char)status+'0'); in client.print((char)(status+'0')); Damit wird die Operation (status + '0') auf ein einzelnes Zeichen gecastet. Es ist eine simple Umwandlung vom int-Wert 0 oder 1 (oder einer beliebigen Ziffer / nicht Zahl) in das entsprechende ASCII Zeichen 0 oder 1 (oder andere Ziffer). Mario.

Also der Text ist echt prima, wenn ich ein Tutorial zu dem Thema schreibe werde ich die Erläuterung mit Sicherheit zittieren. Und nachdem du das ganze so schön bildlich erklärt hast ist es mir auch durchaus bewusst geworden, es kann ja gar nicht anders funktionieren. Vielen Dank dafür.

Zum Code: Ich denke es funktioniert vorallem nicht weil "status" vordefiniert ist, es ist auf jeden Fall gehighlightet und wird als Fehler markiert... Das passiert auch, wenn ich int status irgendwo definiere, einfach weil status schon belegt ist. Ich bin gerade am suchen, was status bewirkt.

mfg balli

Ok, blödsinn. Mein Fehler ...

Serial.println("bin connected");
    client.print("GET /hc_arduino_php/hc_status.php?pin=13&status=");
    client.print((char)(statuslevel+'0'));
    client.println(" HTTP/1.0");
    client.println("Host: www.hemitheconyx-caudicinctus.de");
    client.println();
    Serial.println("habe alles ausgeführt");

Ich habe mich von Deinem HTML-Parameter "status" dazu verleiten lassen anzunehmen, das auch die C-Variable status heisst. Sie heisst aber statuslevel. Damit sollte es gehen.

Okay, das werde ich heute abend austesten und dann sicherlich in Erfahrung bringen, dass der Status geändert wird. vielen Dank.