MySQL DB Eintrag auslesen ? [gelöst]

Hallo allerseits,
wer kann mir helfen, einen Wert aus einer MySQL-DB auszulesen ?

Wie ich reinschreibe,habe ich hinbekommen,aber wie lese ich einen Wert aus ?
Mit PHP klappt (PHP Code ist fertig) das, aber wie binde ich das in den Arduino ein ?

Ein PHP-Skript wird dann ausgeführt, wenn es vom Server abgerufen wird. Also solltest du auf der Basis vom Beispiel "WebClient" (IDE) eben so einen Abruf per HTTP-Get auslösen. An die URL werden die Parameter gehängt. Daraufhin wird dir dann ein haufen Text zugeschickt, den du irgendwie parsen musst ... ist eine reine Fleißarbeit, nichts Sensationelles. Evtl. wird der Speicher knapp - du solltest auf jeden fall so sparsam wie möglich vom Server aus antworten ...

Hi,
ok ... :~ Ich verstehe nur Bahnhof :blush:

Ich schau mir mal das Beispiel "WebClient" an ...

Beschreib doch einfach kurz erstmal was genau Du machen willst?
Theoretisch liest Du aus der DB über Dein PHP-Script genauso, wie Du auch reinschreibst. Nur das halt das was der Webserver zurückschickt halt auch wichtig ist.

Wenn Du z.B. über die URL "http://1.2.3.4/write_db.php?time=1357338439&temp1=23.2&temp2=12.4&data=wefsdvsdver32wdadwer" mit dem PHP-Script "write_db.php" die vom Arduino mit dem Aufruf übergebenen Daten in die Datenbank schreibst, kannst Du auf die gleiche Weise auch Daten lesen.
Z.B. "http://1.2.3.4/read_db.php?time=1357338439"
Es gibt dann also auf Deinem Webserver ein Script "read_db.php", da den Parameter "time" auswertet und z.B. "select * from data where time=1357338439" an die Datenbank schickt. Die DB liefert dann die Daten time, temp1, temp2 und data zurück (das ist nur als Beispiel zu sehen, welche Daten das am Ende sind, musst Du wissen :wink: ). Das könnte das PHP-Scrip z.B. in einen String packen, den dann der Arduino aus der HTTP-Verbindung die er mit dem "http://1.2.3.4/read_db.php?time=1357338439" Request aufgemacht hat, liest. Im Arduino musst Du dann die übermittelten Daten wieder auseinander nehmen und sinnvoll verarbeiten.

Das ist das ganze Geheimnis :slight_smile:

Bei der konkreten Umsetzung Deiner speziellen Anwendung können wir dann helfen, wenn wir wissen was Du genau machen willst.

Mario.

Hallo Mario XD
freue mich und wünsche ein Frohes Neues.

Also, ich speichere den Stand meines Gaszählers in eine DB.
Am Arduino ist ein Reedkontakt und jeder Impuls wird mit Uhrzeit und Datum gespeichert.

Mir geht es darum, das wenn mal der Strom ausfällt, der letzte Stand des Gaszählers gespeichert wird.
Wie ich den letzten Stand mit PHP abfrage, klappt. Der PHP Code ist fertig.

Wenn bedarf ist geb ich dir den Sketch und den PHP Code.
Hier ist der Sketch(unsauber, aber klappt erstmal)

/* 
 * Reedkontakte  zählen 
 */   
#include <Wire.h> 
#include <LiquidCrystal_I2C.h>
#include <SPI.h>
#include <Ethernet.h>             // library for ethernet functions

//ETHERNET-SETTINGS
byte mac[]     = { 0x5D, 0xA2, 0xFA, 0x2D, 0x76, 0x8C };    // MAC-Adresse des Arduino
byte ip[]      = { 192, 168, 178, 41 };                     // 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

EthernetClient client;
char host[]    = "192.168.178.111";                      // Domain
char url[]     = "/Arduino/Gas/insert1.php"; // Pfad zur PHP-Datei
char key[]     = "12345";      

LiquidCrystal_I2C lcd(0x27,16,2);  // set the LCD address to 0x27 for a 16 chars and 2 line display
byte hoch3[8] = { B01110, B00010, B00110, B00010, B01110, B00000, B00000, B00000 };

int PowerLED = 3;    // rote kontroll LED
int ReedPin = 8;     // Schalter ist mit Pin 8 verbunden 
int val;               // Variable für den Pin Zustand 
int buttonState;       // Variable für den letzten Schalterzustand 
int buttonPresses = 0; // Wie oft ist der Schalter gedrückt
float ZStand = 900295;      // Zählerstand bei Anschluss Reedkontakt
float ZStandNeu;

void setup() 
{ 
   lcd.init(); // initialize the lcd
   lcd.backlight();
   lcd.createChar(0, hoch3);
   lcd.setCursor(8,1);
   lcd.print("m");
   lcd.setCursor(9,1);
   lcd.write(0);
   lcd.setCursor(0, 0);
   lcd.print(F("Impuls-Zaehler"));
   pinMode(PowerLED, OUTPUT);   
   pinMode(ReedPin, INPUT);             // Schalter-Pin ist Input   
   Serial.begin(9600);                    // Start der seriellen Kommunikation mit 9600bps
   digitalWrite(ReedPin,HIGH);
   Serial.println(F("Programm gestartet..."));
   Ethernet.begin(mac, ip);
   Serial.println(F("Ethernet initialisieren...")); 
   delay(5000); 
   client.connect(server, 8000);               // Verbindung zum Server aufbauen
   buttonState = digitalRead(ReedPin);  // Anfangszustand lesen
   if (client.connected()) 
   {
     Serial.print(F("Verbunden ...(setup)"));
   }
   
}

void loop()
{
  val = digitalRead(ReedPin); // Eingabewert lesen und in val speichern 
     if(client.connected())
    {
     Serial.println(F("Connected ..."));
       if (val != buttonState) { // Der Zustand des Schalters hat sich verändert 
       if (val == LOW) { // Ist der Schalter gedrückt? 
       buttonPresses++; // Inkrementieren der Variablen buttonPresses
       ZStandNeu = ZStand + buttonPresses;
       Serial.print(F("Zählerstand ")); 
       Serial.print(ZStandNeu/100);
       Serial.print(F(" m"));
       Serial.println(char(179));    // 179 = m³
       digitalWrite(PowerLED, LOW);
       lcd.clear();
       lcd.setCursor(8,1);
       lcd.print(F("m"));
       lcd.setCursor(9,1);
       lcd.write(0);
       lcd.setCursor(0, 0);
       lcd.print(F("Gas-Zaehler"));
       lcd.setCursor(0, 1);
       lcd.print(ZStandNeu/100);
       float gz = ZStandNeu/100;  
       Daten_senden(gz);
       delay(1000);
       client.flush();
       client.stop(); 
       }
       do 
       {
         Serial.println(F("Warte 3 sec..."));
         delay(3000);
       } while ( !digitalRead(ReedPin) );
         client.connect(server, 8000);
      } 
      } else {
       Serial.println(F(" ***** VERBINDUNGSAUFBAU NICHT MÖGLICH *****1"));
       digitalWrite(PowerLED, HIGH);
       lcd.clear();
       lcd.setCursor(5, 0);
       lcd.print(F("Fehler!"));
       lcd.setCursor(0, 1);
       lcd.print(F("Keine Verbindung"));
       client.flush();
       client.stop();
       Serial.println(F("Warte 3 sec..."));
       while (client.connect(server, 8000));
       delay(5000);
       float gz = ZStandNeu/100;
       if(gz >= 0)
       {
         client.connect(server, 8000);
         delay(1000);
         digitalWrite(PowerLED, LOW);
       lcd.clear();
       lcd.setCursor(8,1);
       lcd.print(F("m"));
       lcd.setCursor(9,1);
       lcd.write(0);
       lcd.setCursor(0, 0);
       lcd.print(F("Gas-Zaehler"));
       lcd.setCursor(0, 1);
       lcd.print(ZStandNeu/100);
         Daten_senden(gz);
         Serial.println(gz);
         delay(1000);
         client.flush();
         client.stop(); 
         delay(500);
       }
       if(gz <=0);
       {
         client.connect(server, 8000);
         delay(1000);
      }
      }
      
buttonState = val; // Den Zustand merken  
}

void Daten_senden(float T1)
{
   if (client.connected()) 
   {
    Serial.println(F("Verbunden, Sende Daten..."));
    client.print("GET " + String(url));
    Serial.println("GET " + String(url));
    client.print(F("?T1="));
    Serial.print(F("?T1="));
    client.print(T1);
    Serial.println(T1);      
    client.print("&key=" + String(key));
    Serial.print("&key=" + String(key));
    client.println(" HTTP/1.1");
    Serial.println(F(" HTTP/1.1"));
    client.print("Host: " + String(host));
    Serial.print("Host: " + String(host));
    client.println();
    Serial.println();
    client.println("User-Agent: Arduino");
    Serial.println(F("User-Agent: Arduino"));
    client.println("Connection: close");
    Serial.println(F("Connection: close"));
    client.println();
    Serial.println();
   }
   else
   {
       Serial.println(F(" ***** VERBINDUNGSAUFBAU NICHT MÖGLICH *****"));
       digitalWrite(PowerLED, HIGH);
       lcd.clear();
       lcd.setCursor(5, 0);
       lcd.print(F("Fehler!"));
       lcd.setCursor(0, 1);
       lcd.print(F("Keine Verbindung"));
       delay(5000);
   } 
}

Und hier der PHP-Teil zum schreiben:

<?php

define("KEY","12345");
 
include("db-config.php");
 
if(isset($_GET['key']))
{
  if($_GET['key'] == KEY)
  {
    if(isset($_GET['T1']))
    {
      $GZ = mysql_real_escape_string($_GET['T1']);
      $DATUM = date("Y-m-d H:i:s");
 
      $result = mysql_query("INSERT INTO Gas (datumzeit, GZStand)
              VALUES('".$DATUM."', '".$GZ."') ") or die(mysql_error());
 
      if(mysql_affected_rows() == 1)
      {
        $result = "Gaswert gespeichert";
      } else $result = "Fehler beim speichern der Daten in der MySQL-Datenbank";
    } else $result = "Kein Wert übergeben";
  } else $result = "Falscher Key";
} else $result = "Kein Key übergeben";
 
print_r($result);
?>

Und hier der PHP-Teil zum Lesen:

<?php
/***********************************************************************************
  Autor:   Stefan Blinkmann                                                        *
  Kontakt: stefan@blinkmann.com                                                    *
                                                                                   *
  PROJEKT: Ausgabe des durch den ARDUINO zuletzt generierten Gaswert               *
                                                                                   *
***********************************************************************************/
 
include("db-config.php");

$q_data  = mysql_query("SELECT DATE_FORMAT(datumzeit,'%d.%m.%Y') AS DATUM, DATE_FORMAT(datumzeit,'%H:%i') AS ZEIT, GZStand FROM Gas ORDER BY datumzeit DESC LIMIT 1") or die(mysql_error());
if(mysql_num_rows($q_data) > 0)
{
  $r_data = mysql_fetch_array($q_data);
  $DATUM  = $r_data['DATUM'];
  $GZ  = number_format($r_data['GZStand'], 2, '.', '');
  $ZEIT   = $r_data['ZEIT'];
}
else
{
  $E = 1;
  $M = "Es wurden kein Gaswerte in der Datenbank gefunden!";
}
?>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  <meta name="viewport" content="user-scalable=yes, width=device-width">
  <meta http-equiv="refresh" content="30; URL=http://192.168.178.111:8000/Arduino/Gas/last.php">
  <title>ARDUINO - Aktueller Gasverbrauch</title>
</head>
<body>
 
<?php
//Wenn Daten in der Datenbank gefunden wurden, diese ausgeben
if(!isset($E))
{
?>
  <table>
  <tbody>
<th colspan="3">Letzter gespeicherter Gaszaehlerwert</th>
    <tr bgcolor="#66CC99">
      <TD align="center">Datum</TD>
      <TD align="center">Zeit</TD>
      <TD align="center">GZ-Stand</TD>
    </tr>

    <tr bgcolor="#CCCC66">
      <td align="center">&nbsp;<?php echo $DATUM ;?>&nbsp;</td>
      <td align="center">&nbsp;<?php echo $ZEIT ;?>&nbsp;</td>
      <td align="right">&nbsp;<?php echo $GZ;?>&nbsp;m³&nbsp;</td>
    </tr>
  </tbody>
</tableborder="1">

<?php           
}
else
{
// Meldung ausgeben wenn noch keine Daten in der Datenbank stehen
  echo $M;
}
?>
  </body>
</html>

Ich wollte den Stand Ursprünglich in den Eeprom schreiben,
aber da sagte jemand (Ich glaube Uwe) das der begrenzte Speicherzüglen hat,
wenn ich das richtig verstanden habe.

Danke Euch für die Hilfe

Guten Morgen Cetax,

ich hab mal kurz über den Code geschaut. Was mir als erstes auffällt ist, das Du den connect zum Server schon im setup() und an verschiedenen Stellen in loop() machst. Das ist ungünstig. Grundsätzlich sollten Dinge immer genau dort gemacht werden, wo sie gebraucht werden. In Deinem Fall wäre das client.connect(server,8000) am besten im Daten_senden() aufgehoben. Warum? Weil es nur da gebraucht wird. Im Grunde kannst Du nie 100%ig vorhersagen, wann das Daten_senden() von loop() aus aufgerufen wird und wieviel Zeit seit dem letzten client.connect() vergangen ist. Es kann daher leicht passieren, das Dein Webserver die Verbindung bereits wieder abgebaut hat (timeout).

Das nächste was auffällt sind die vielen dealy() in Deinem Code. Wozu sind die da? Damit besteht immer die Gefahr, das Du einzelne Zählimpulse verpasst. Auch ist der Aufbau Deines Programms etwas seltsam. Wenn Du das client.connect() in das Daten_Senden() verlagerst, kannst Du Dir den großen if-else Block im das client.connected() sparen und Dein Programm wird schon mal übersichtlicher. Du musst dann auch nicht mehr an verschiedenen Stellen im Code das client.connect(server,8000) aufrufen.
Der wichtigste Teil Deines Codes ist das Zählen der Impulse. Das passiert nur am Anfang von loop() mit dem "val = digitalRead(ReedPin);". Daher solltest Du sehen das Du einen Durchlauf von loop() so schnell wie möglich hinter dich bringts. Wie lang ist denn ein Impuls Deines Gaszählers? Also der Übergang von HIGH zu LOW zu HIGH? Ich vermute das der Wert abhängig ist, wieviel Gas aktuell verbraucht wird. Aber ein Durchlauf von loop() darf nie länger sein als die kürzeste Pause zwischen zwei Impulsen, sonst passiert es, das Du im ersten Durchlauf den Wechsel von HIGH zu LOW als Zählimpuls mitbekommst. Dann schaltet der EIngang wieder auf HIGH. Nun braucht deine loop() so lange, das der nächste Zählimpuls kommt und der Eingang schon wieder LOW ist. Loop() prüft den Eingang und sieht LOW, buttonState ist aber immer noch LOW vom letzten Impuls, daher "denkt" loop() es wäre der gleiche Impuls, weil Du den zwischenzeitlichen Wechsel verpasst hast. Somit verlierst Du Zählimpulse.

Zum Daten lesen aus der DB schreibe ich später noch was, das waren erstmal die Dinge die mir aufgefallen sind.

Mario.

Hallo Mario,
also habe jetzt mal auf dein anraten eine radikal Kur gemacht... XD

Das ist jetzt der neue Sketch :

/* 
 *
 * Impulse vom Gaszähler zählen 
 * 
 */   
#include <Wire.h> 
#include <LiquidCrystal_I2C.h>
#include <SPI.h>
#include <Ethernet.h>             // library for ethernet functions

//ETHERNET-SETTINGS
byte mac[]     = { 0x5D, 0xA2, 0xFA, 0x2D, 0x76, 0x8C };    // MAC-Adresse des Arduino
byte ip[]      = { 192, 168, 178, 41 };                     // 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

EthernetClient client;
char host[]    = "192.168.178.111";                      // Domain
char url[]     = "/Arduino/Gas/insert1.php"; // Pfad zur PHP-Datei
char key[]     = "ch5fn7sb";      

LiquidCrystal_I2C lcd(0x27,16,2);  // set the LCD address to 0x27 for a 16 chars and 2 line display
byte hoch3[8] = { B01110, B00010, B00110, B00010, B01110, B00000, B00000, B00000 };

int PowerLED = 3;    // rote kontroll LED
int ReedPin = 8;     // Schalter ist mit Pin 8 verbunden 
int val;               // Variable für den Pin Zustand 
int buttonState;       // Variable für den letzten Schalterzustand 
int buttonPresses = 0; // Wie oft ist der Schalter gedrückt
float ZStand = 900295;      // Zählerstand bei Anschluss Reedkontakt
float ZStandNeu;

void setup() 
{ 
   lcd.init(); // initialize the lcd
   lcd.backlight();
   lcd.createChar(0, hoch3);
   lcd.setCursor(8,1);
   lcd.print("m");
   lcd.setCursor(9,1);
   lcd.write(0);
   lcd.setCursor(0, 0);
   lcd.print(F("Impuls-Zaehler"));
   pinMode(PowerLED, OUTPUT);   
   pinMode(ReedPin, INPUT);             // Schalter-Pin ist Input   
   Serial.begin(9600);                    // Start der seriellen Kommunikation mit 9600bps
   digitalWrite(ReedPin,HIGH);
   Serial.println(F("Programm gestartet..."));
   Ethernet.begin(mac, ip);
   Serial.println(F("Ethernet initialisieren...")); 
   delay(5000);
   buttonState = digitalRead(ReedPin);  // Anfangszustand lesen   
}

void loop()
{
  val = digitalRead(ReedPin); // Eingabewert lesen und in val speichern
      if (val != buttonState) { // Der Zustand des Schalters hat sich verändert 
       if (val == LOW) { // Ist der Schalter gedrückt? 
       buttonPresses++; // Inkrementieren der Variablen buttonPresses
       ZStandNeu = ZStand + buttonPresses;
       Serial.print(F("Zählerstand ")); 
       Serial.print(ZStandNeu/100);
       Serial.print(F(" m"));
       Serial.println(char(179));    // 179 = m³
       digitalWrite(PowerLED, LOW);
       lcd.clear();
       lcd.setCursor(8,1);
       lcd.print(F("m"));
       lcd.setCursor(9,1);
       lcd.write(0);
       lcd.setCursor(0, 0);
       lcd.print(F("Gas-Zaehler"));
       lcd.setCursor(0, 1);
       lcd.print(ZStandNeu/100);
       float gz = ZStandNeu/100;  
       Daten_senden(gz);
       delay(1000);
       client.flush();
       client.stop(); 
       }
      } 
            
buttonState = val; // Den Zustand merken  
}

void Daten_senden(float T1)
{
   if (client.connect(server, 8000)) 
   {
    Serial.println(F("Verbunden, Sende Daten..."));
    client.print("GET " + String(url));
    Serial.println("GET " + String(url));
    client.print(F("?T1="));
    Serial.print(F("?T1="));
    client.print(T1);
    Serial.println(T1);      
    client.print("&key=" + String(key));
    Serial.print("&key=" + String(key));
    client.println(" HTTP/1.1");
    Serial.println(F(" HTTP/1.1"));
    client.print("Host: " + String(host));
    Serial.print("Host: " + String(host));
    client.println();
    Serial.println();
    client.println("User-Agent: Arduino");
    Serial.println(F("User-Agent: Arduino"));
    client.println("Connection: close");
    Serial.println(F("Connection: close"));
    client.println();
    Serial.println();
   }
   else
   {
       Serial.println(F(" ***** VERBINDUNGSAUFBAU NICHT MÖGLICH *****"));
       digitalWrite(PowerLED, HIGH);
       lcd.clear();
       lcd.setCursor(5, 0);
       lcd.print(F("Fehler!"));
       lcd.setCursor(0, 1);
       lcd.print(F("Keine Verbindung"));
       delay(5000);
   } 
}

Jetzt muss nur noch der Code für die SQL-DB eingefügt werden. :grin:

ICh habe mal einen Anfang versucht, aber das ist glaub ich völlig falsch...

void httpRequest()
{
  if (client.connect(server, 8000)) {
    Serial.println("connecting...");
    // send the HTTP PUT request:
    client.println("GET /read.php HTTP/1.1");
    client.println("Host: 192.168.178.111");
    client.println("User-Agent: arduino-ethernet");
    client.println("Connection: close");
    client.println();
  } else {
    // if you couldn't make a connection:
    Serial.println("connection failed");
    Serial.println("disconnecting.");
    client.stop();
  }
}

die read.php sieht so aus:

<?php
 
include("db-config.php");

$q_data  = mysql_query("SELECT DATE_FORMAT(datumzeit,'%d.%m.%Y') AS DATUM, DATE_FORMAT(datumzeit,'%H:%i') AS ZEIT, GZStand FROM Gas ORDER BY datumzeit DESC LIMIT 1") or die(mysql_error());
if(mysql_num_rows($q_data) > 0)
{
  $r_data = mysql_fetch_array($q_data);
  $DATUM  = $r_data['DATUM'];
  $GZ  = number_format($r_data['GZStand'], 2, '.', '');
  $ZEIT   = $r_data['ZEIT'];
}
echo $GZ;

?>

$GZ enthält den letzten Gasstand.

Hallo Cetax,

das sieht doch schon recht gut aus. Das delay(1000) in der loop() wozu ist das gut? Auch das delay(5000) bei einem gescheiterten Verbindungsaufbau im Daten_Senden() bringt nicht viel, da Du ja eh kein zweites Mal versuchts zu senden, hier besteht nur die Chance einen Zählimpuls zu verpassen.
Der HTTP-Request ist schon mal gar nicht so schlecht, nur mußt Du die vom PHP-Script gelieferten Daten auch einlesen und ggf. mit atoi() oder atol() noch von einem String in eine Zahl umwandeln. Ich würde für den Zählerstand auch kein float verwenden, da diese Art der Zahlendarstellung ab einer bestimmten Größe der Zahl mit Ungenauigkeiten rechnet. Damit hat irgendwann ein "ZStandNeu = ZStandNeu + 1" keinen Einfluss mehr. Verwende als Datentyp lieber ein "unsigned long", das kann bis 4,2 Mrd. zählen, was für Deinen Zähler reichen sollte, da Du ja gerade bei 900.000 bist.
Mario.

Hallo,
habe das jetzt al alles abgekürzt und geändert.
Aber, magst mir noch was schreiben ? XD

mkl0815:
...
Zum Daten lesen aus der DB schreibe ich später noch was, das waren erstmal die Dinge die mir aufgefallen sind.

Mario.

Cetax:
Aber, magst mir noch was schreiben ? XD

Hab ich doch :astonished: ???
Mein letzter Kommentar

Der HTTP-Request ist schon mal gar nicht so schlecht, nur mußt Du die vom PHP-Script gelieferten Daten auch einlesen ...

Bezog sich doch auf die Funktion "void httpRequest()". Hast Du die denn mal ausprobiert? Was passiert denn, wenn Du mit "client.read()" anfängst Daten aus der Verbindung zu lesen, nachdem Du den HTTP-Request abgeschickt hast?
Darauf bezog sich auch mein Hinweis, "unsigned long" statt des float für den Zähler zu verwenden. Da Du "diskrete" Impulse zählst, macht ein float wenig Sinn und bei "unsigned long" hast Du genügend Spielraum für große Zahlen.
Mario.

Hi,
jepp habe ich gelesen (deinen letzte bzw.vorletzten Komentar),
dachte nur da kommt noch etwas Code zum Testen... :wink:

Ok, mache mich heute abend mal ran... Mal sehen wie weit ich komme.

Danke Dir erstmal. XD

Hallo,
also sieht garnicht so schlecht aus für den Anfang, ich habe jetzt erstmal einen Sketch geschrieben,
der sich nur auf den Request beschränkt, um zu sehen was alles ankommt.

Hier der Sketch:

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

byte mac[] = { 0x00, 0xAB, 0xCB, 0xCD, 0xDE, 0x02 };
IPAddress ip(192,168,178,140);
IPAddress server(192,168,178,111);
EthernetClient client;
char host[]    = "192.168.178.111";                      // Domain
char url[]     = "/Arduino/Gas/read.php"; // Pfad zur PHP-Datei

unsigned long GZStand;

void Daten_senden(){

if (client.connect(server, 8000)) {
    Serial.println(F("Verbunden, Sende Daten..."));
    client.print("GET " + String(url));
    Serial.println("GET " + String(url));
    client.print(F("?GZStand="));
    Serial.print(F("?GZStand="));
    client.print(GZStand);
    Serial.println(GZStand);      
    client.println(" HTTP/1.1");
    Serial.println(F(" HTTP/1.1"));
    client.print("Host: " + String(host));
    Serial.print("Host: " + String(host));
    client.println();
    Serial.println();
    client.println("User-Agent: Arduino");
    Serial.println(F("User-Agent: Arduino"));
    client.println("Connection: close");
    Serial.println(F("Connection: close"));
    client.println();
    Serial.println();
  } else {
    // if you couldn't make a connection:
    Serial.println("connection failed");
    Serial.println("disconnecting.");
  }

}

void setup() 
{
Serial.begin(9600);
Serial.print("Setup LAN ... ");
// give the Ethernet shield a second to initialize:
delay(1000);
Ethernet.begin(mac, ip);
Serial.println("ok");
delay(1000);
Daten_senden();
}

void loop()
{
if (client.available()) {
char c = client.read();
Serial.print(c);
}

// if the server's disconnected, stop the client:

if (!client.connected()) {
Serial.println();
Serial.println("disconnecting.");
client.stop();
delay(100000);
}
}

Und Serial ist das zu sehen:

Setup LAN ... ok
Verbunden, Sende Daten...
GET /Arduino/Gas/read.php
?GZStand=0.00
 HTTP/1.1
Host: 192.168.178.111
User-Agent: Arduino
Connection: close

HTTP/1.1 200 OK
Date: Wed, 09 Jan 2013 21:44:26 GMT
Server: Apache/2.2.21 (Unix) PHP/5.3.6
X-Powered-By: PHP/5.3.6
Vary: Accept-Encoding
Content-Length: 7
Connection: close
Content-Type: text/html

9013.06
disconnecting.

Also mit d

char c = client.read();
Serial.print(c);

bekomme ich eine Ausgabe (9013.06) , aber mit

 client.print(GZStand);
    Serial.println(GZStand);

kommt nur "?GZStand=0.00" das raus.

Nun brauche ich mal wieder Hilfe, wie und wo muss ich denn nun atoi bzw. atol einsetzten?
Und woher weiß ich, ob die Ausgabe als String vorliegt?

Ich habe da was im Netz gefunden, wäre das etwas ?

int ausgabe = atoi(antwort.substring((antwort.indexOf("\n\n") + 1));

Schon dicht dran, aber ein kleines Verständnisproblem gibt es wohl doch noch.
Dein Arduino will Informationen von Deinem Webserver haben, daher ruft er eine URL auf ( "http://192.168.178.111:8000/Arduino/Gas/read.php"). Über diesen Aufruf wird Dein PHP-Script aktiviert, welches den aktuellen Zählerstand aus der Datenbank liest und als Antwort (quasi als Webseiten-Ersatz) schickt. Soweit zur Theorie.
Du hast jetzt aber zusätzlich in die URL einen Parameter "?GZStand=" eingebaut, der aber leider völlig unnütz ist. Mit einem solchen Parameter kann Dein Arduino Daten AN den Webserver schicken, aber KEINE bekommen. Du wunderst Dich, das die Ausgabe immer "GET /Arduino/Gas/read.php?GZStand=0.00" liefert. Aber wie soll denn was anderes dabei rauskommen? Deine Variable ist doch beim Aufruf noch "0.0", weil Du ja noch gar keine Daten bekommen hast, die kommt ja erst nachdem der Webserver die URL bekommen hat. Daher lass den Parameter einfach weg. Ebenso wie die Verwendung der String-Klasse. ( ]:slight_smile: - Zeug ... BÖSE ]:smiley: )
Statt

    client.print("GET " + String(url));
    Serial.println("GET " + String(url));

einfach

    client.print("GET ");
    client.print(url);
    Serial.print("GET ");
    client.print(url);

Man kann einen C-String auch direkt ausgeben. Das erspart die in diesem Fall unnötige Verwendung der String-Klasse (und nicht nur an dieser Stelle).

Die Daten einlesen machst Du ja schon Zeichenweise. Abgesehen davon, das die Struktur etwas seltsam ist. Wie bereits geschrieben sollten Sachen die zusammen gehören auch zusammen in einer Funktion stehen. Aktuell dient loop() dazu die einzelnen Zeichen einzulesen und auszugeben.

void loop()
{
if (client.available()) {
char c = client.read();
Serial.print(c);
}

Der Trick ist jetzt, die einzelnen Zeichen einzulesen und in einem Puffer zu sammeln, den man dann in eine Zahl umwandeln kann.

char[10] buffer = "";
int index = 0;
while (client.available()) {
    buffer[index++] = client.read();
} 
buffer[index] = 0 // NULL-Terminierung
Serial.print("Antwort :  ");
Serial.println(buffer);

Das Umwandeln würde deutlich besser gehen, wenn Du wie auch schon geschrieben ein long Integer statt eines float verwenden würdest. Ich verstehe sowieso nicht, warum Du den genauen Zählwert "ZStand" erst durch 100 teilst, um dann den float Wert in die Datenbank zu schreiben. Den Wert für die Ausgabe durch 100 zu teilen, sehe ich ein. Aber speichern sollte man möglichst das was man misst.
Mario.

Um zu zeigen was ich mit dem float meine, schau Dir mal folgendes Programm an:

void setup() {
  
  Serial.begin(9600);
  
  float num = 10.0;
  
  for(int i=1; i<10;i++) {
     Serial.print(num,2);
     Serial.print(" + 1.0 = ");
     Serial.println(num + 1.0 ,2);
     num = num * 10;
  }
}

void loop() {
}

Ausgabe :

10.00 + 1.0 = 11.00
100.00 + 1.0 = 101.00
1000.00 + 1.0 = 1001.00
10000.00 + 1.0 = 10001.00
100000.00 + 1.0 = 100001.00
1000000.00 + 1.0 = 1000001.00
10000000.00 + 1.0 = 10000001.00
100000000.00 + 1.0 = 100000000.00
1000000000.00 + 1.0 = 1000000000.00

Fällt Dir an den letzten beiden Zeilen was auf? Das gleiche würde bei hinreichend großem Zählerstand in Deinem Programm passieren, wenn Du einen weiteren Zählimpuls addieren willst. Das ist der Nachteil von Fließkommazahlen. Je größer sie werden, desto ungenauer rechnen sie.
Mario.

Nur mal schnell erzählt, warum ich float benutze bzw. habe.
Der Zählerstand ist 9013,46m³ und wenn ich float beutzte wird er auch so in die DB eingetragen.
Aber wenn ich unsigned long verwende, wird die Zahl so 901346 eingetragen, sprich ohne Punkt/Komma.
Und da ich nicht weiß (und auch noch nicht geschaut habe) wie ich das ändern kann, benutze ich float.

Werde das aber auf jedenfall ändern, habe das schon verstanden, warum man nicht float nimmt. 8)

Und vielen Dank für deine Super Hilfe, werde mich heute abend ran machen, alles um zu setzen.
Bis später....

So, da bin ich wieder... =(
Ich verstehe nicht wie ich das umsetzten soll,ich habe jetzt folgenden Sketch:

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

byte mac[] = { 0x00, 0xAB, 0xCB, 0xCD, 0xDE, 0x02 };
IPAddress ip(192,168,178,140);
IPAddress server(192,168,178,111);
EthernetClient client;


char host[]    = "192.168.178.111";                      // Domain
char url[]     = "/Arduino/Gas/read.php"; // Pfad zur PHP-Datei

unsigned long GZStand=0;

void setup() 
{
Serial.begin(9600);
Serial.print("Setup LAN ... ");
// give the Ethernet shield a second to initialize:
delay(1000);
Ethernet.begin(mac, ip);
Serial.println("ok");
delay(1000);
Daten_senden();
}


void loop()
{
 char buffer[10] = "";
 int index = 0;
 
if (client.available()) 
{
  delay(100);
  while (client.available()) 
  {
    buffer[index++] = client.read();
}
}
buffer[index] = 0; // NULL-Terminierung
Serial.print("Antwort :  ");
Serial.println(buffer);
}


void Daten_senden(){

if (client.connect(server, 8000)) {
    Serial.println(F("Verbunden, Sende Daten..."));

    client.print("GET ");
    client.print(url);
    Serial.print("GET ");
    Serial.print(url);   
    client.println(" HTTP/1.1");
    Serial.println(F(" HTTP/1.1"));
    client.print("Host: ");
    client.print(host);
    Serial.print("Host: ");
    Serial.print(host);
    client.println();
    Serial.println();
    client.println("User-Agent: Arduino");
    Serial.println(F("User-Agent: Arduino"));
    client.println("Connection: close");
    Serial.println(F("Connection: close"));
    client.println();
    Serial.println();
  } else {
    // if you couldn't make a connection:
    Serial.println("connection failed");
    Serial.println("disconnecting.");
  }  

}

bei dem DAS rauskommt :

Setup LAN ... ok
Verbunden, Sende Daten...
GET /Arduino/Gas/read.php HTTP/1.1
Host: 192.168.178.111
User-Agent: Arduino
Connection: close

Antwort :  
.6
Vary: Accept-Encoding
Content-Length: 7
Connection: close
Content-Type: text/html

9015.08HTTP/1.1 200 OK
Date: Thu, 10 Jan 2013 21:15:27 GMT
Server: Apache/2.2.21 (Unix) PHP/5.3.6
X-Powered-By: PHP/5.3.6
Vary: Accept-Encoding
Content-Length: 7
Connection: close
Content-Type: text/html

9015.08
Setup LAN ... ok
connection failed
disconnecting.
Antwort :  
Antwort :  
Antwort :  
Antwort :  
Antwort :  
Antwort :  
Antwort :  
Antwort :  
Antwort :  
Antwort : 
...

Ich verstehe nicht wie der Aufbau der Loop aussehen muss, damit da der DB Eintrag zu sehen ist :blush:
Please Help...

Hallo Cetax,

Du machst es Dir schon wieder viel zu kompliziert. Einfach mal einen Schritt zurück treten und überlegen was Du am Ende umsetzen willst und was Du bisher Du bisher schon hast (deinen eigentlichen Gaszähler-Sketch).

Du hast in Deinem eigentlichen Programm eine Funktion Daten_senden(), mit deren Hilfe Du über einen HTTP Request vom Arduino Daten an den Webserver schickst, damit dieser die übermittelten Daten in die Datenbank schreibt.
Was Du nun noch brauchst ist eine Funktion z.B. Daten_laden() mit deren Hilfe Du über einen HTTP Request Daten vom Webserver an den Arduino schickst, die der Websrveraus der Datenbank gelesen hat.
Fällt Dir die Ähnlichkeit der letzten beiden Sätze auf? Warum ist das so? Weil die Anforderungen an beide Funktionen sehr ähnlich sind. Du bist sogar schon selbst drauf gekommen, denn Du hast ja einen Teil der Daten_Senden() Funktion in den neuen Test-Sketch übernommen. Leider nicht ganz konsequent. Da Du einen Teil wieder in setup() und in die loop() ausgelagert hast.

Ich gebe mal die Struktur des Testprogramms vor und Du füllst es mit dem was Du quasi schon hast:

void setup() {
  // IP Konfiguration setzen
  // Serielle Konsole initialisieren

}

void loop() {
  // http-request senden und in variable speichern

  // 10 sekunden warten
}

//achtung wir liefern ein char* (c-String zurück)
char* daten_laden() {
    // puffer initialisieren mit leerem string
    // zaehlindex auf 0 setzen

   // connect to server

   // connected?

   //wenn connected, request senden

        // solange zeichen vorhanden sind, das aktuelle zeichen in puffer schreiben und zaehlindex erhoehen

        // wenn keine zeichen mehr vorhanden, dann puffer am letzten (schon erhoehten) index auf \0 setzen (c-String ende)

    // puffer per return zurückliefern    
}

Der Trick ist also, wie schon beim Daten_senden() die ganze Funktionalität in die daten_laden() funktion zu packen. Auch wenn es erstmal nur ein Testprogramm ist, denn wenn alles was Du braucht in der Funktion steckt, brauchst Du die am Ende nur noch in Deinen eigentlichen Sketch kopieren.

Sobald die Funktion läuft, kümmern wir uns dann um das Umwandeln in eine Zahl.

Mario.

Hallo Mario,
also ich habe versucht, das zuverstehen was du geschrieben hast und es versucht umzusetzen. :blush:

Der Sketch kompiliert ohne Fehler durch und ich sehe im Serial-Monitor auch was, aber nicht den Gasstand. :frowning:

Hier der Sketch:

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

byte mac[] = { 0x00, 0xAB, 0xCB, 0xCD, 0xDE, 0x02 };
IPAddress ip(192,168,178,140);
IPAddress server(192,168,178,111);
EthernetClient client;


char host[]    = "192.168.178.111";                      // Domain
char url[]     = "/Arduino/Gas/read.php"; // Pfad zur PHP-Datei

unsigned long GZStand=0;
char* returnvalue = 0;



void setup() {
  // IP Konfiguration setzen
  // Serielle Konsole initialisieren
  Serial.begin(9600);
  Serial.print("Setup LAN ... ");
  delay(1000);
  Ethernet.begin(mac, ip);
  Serial.println("ok");
}

void loop() {
  // http-request senden und in variable speichern
  daten_laden();
  
  // 10 sekunden warten
  delay(10000);
}

//achtung wir liefern ein char* (c-String zurück)
char* daten_laden() {
    char buffer[10] = ""; // puffer initialisieren mit leerem string
    int index = 0;        // zaehlindex auf 0 setzen
    
   client.connect(server, 8000);   // connect to server
        
   
   if (client.available()) // connected?
   {
    char c = client.read();
    Serial.print(c);
   }
       
   //wenn connected, request senden
    if (client.connected()) {
    Serial.println(F("Verbunden, Sende Daten..."));

    client.print("GET ");
    client.print(url);
    Serial.print("GET ");
    Serial.print(url);   
    client.println(" HTTP/1.1");
    Serial.println(F(" HTTP/1.1"));
    client.print("Host: ");
    client.print(host);
    Serial.print("Host: ");
    Serial.print(host);
    client.println();
    Serial.println();
    client.println("User-Agent: Arduino");
    Serial.println(F("User-Agent: Arduino"));
    client.println("Connection: close");
    Serial.println(F("Connection: close"));
    client.println();
    Serial.println();
  }

  // solange zeichen vorhanden sind, das aktuelle zeichen in puffer schreiben und zaehlindex erhoehen
  buffer[index++] = client.read();
  
  // wenn keine zeichen mehr vorhanden, dann puffer am letzten (schon erhoehten) index auf \0 setzen (c-String ende)
  buffer[index] = 0; // NULL-Terminierung
  
  // puffer per return zurückliefern    
  returnvalue=buffer;
}

Ich weiß auch nicht wie ich das "unsigned long GZStand=0;" einbinden soll.
Eigentlich doch hier , oder ?

void loop() {
  // http-request senden und in variable speichern
  daten_laden();
  
  // 10 sekunden warten
  delay(10000);
}

Und hier die Ausgabe:

Setup LAN ... ok
Verbunden, Sende Daten...
GET /Arduino/Gas/read.php HTTP/1.1
Host: 192.168.178.111
User-Agent: Arduino
Connection: close

HVerbunden, Sende Daten...
GET /Arduino/Gas/read.php HTTP/1.1
Host: 192.168.178.111
User-Agent: Arduino
Connection: close

T/. 0 K
ae r,1 a 032:62

Ich habe irgendwo was falsches Eingegeben, aber ich sehe nicht wo... :~

Nehmen wir doch mal die daten_laden() Funktion auseinander und schauen was sie macht und was sie eigentlich machen sollte:

char* daten_laden() {

definiert eine Funktion die einen Zeiger auf einen C-String zurück liefert. Das ist schon mal ok.

    char buffer[10] = ""; // puffer initialisieren mit leerem string
    int index = 0;        // zaehlindex auf 0 setzen
    
   client.connect(server, 8000);   // connect to server

definiert ein Array für 10 Zeichen (bzw. 9 Zeichen, wenn wir einen C-String mit \0 Terminierung draus machen) und einen Zählindex.
Außerdem wird die Server-Verbnidung hergestellt. Alles richtig bisher.

Nun wird es aber zum ersten Mal seltsam.

  if (client.available()) // connected?
   {
    char c = client.read();
    Serial.print(c);
   }

Hier wird ein Zeichen aus der gerade aufgebauten Verbindung gelesen, wenn vorhanden. Aber warum? Wir haben noch keine Daten an den Server geschickt, wieso sollten wir hier also Daten bekommen?
Zumal das Zeichen nur gelesen und auf der Seriellen Konsole ausgegeben wird, es wird aber nicht verarbeitet. Diese Code-Schnippsel kann also komplett weg.

   //wenn connected, request senden
    if (client.connected()) {
    Serial.println(F("Verbunden, Sende Daten..."));

    client.print("GET ");
    client.print(url);
    Serial.print("GET ");
    Serial.print(url);   
    client.println(" HTTP/1.1");
    Serial.println(F(" HTTP/1.1"));
    client.print("Host: ");
    client.print(host);
    Serial.print("Host: ");
    Serial.print(host);
    client.println();
    Serial.println();
    client.println("User-Agent: Arduino");
    Serial.println(F("User-Agent: Arduino"));
    client.println("Connection: close");
    Serial.println(F("Connection: close"));
    client.println();
    Serial.println();
  }

Hier wird der Request an den Webserver geschickt. Sehr schön, weil ohne böse String-Klasse :slight_smile: Und an drei Stellen sogar mit dem F() Macro um Speicher zu sparen. Sehr schön und ausbaufähig.

  // solange zeichen vorhanden sind, das aktuelle zeichen in puffer schreiben und zaehlindex erhoehen
  buffer[index++] = client.read();
 
  // wenn keine zeichen mehr vorhanden, dann puffer am letzten (schon erhoehten) index auf \0 setzen (c-String ende)
  buffer[index] = 0; // NULL-Terminierung

Hier wird dann ein und NUR EIN Zeichen aus der Verbindung gelesen und in den Puffer geschrieben. Dabei wird gleichzeitig der Wert von index um 1 erhöht (das macht das ++ hinter derm index).
Anschliessend wird unter dem neuen Index der Wert 0 gesetzt. Du hast damit einen C-String mit einem Zeichen gebaut, nämlich dem ersten Zeichen das der Webserver schickt. Es sollte also in Deinem Puffer dann die erste Ziffer der erwarteten Zahl stehen. Den Code um alle Zeichen einzulesen hatte ich aber schon gegeben und Du hast ihn in Deinem vorherigen Code sogar schon verwendet, nur das er da in der loop() steckte.

char[10] buffer = "";
int index = 0;
while (client.available()) {
    buffer[index++] = client.read();
} 
buffer[index] = 0 // NULL-Terminierung
Serial.print("Antwort :  ");
Serial.println(buffer);

Es fehlt also die WHILE-Schleife um das buffer[index++] = client.read();, dann sollten schon alle Zeichen gelesen werden.

Nun zur letzten Zeile

returnvalue=buffer;

Das funktioniert zwar, ist aber umständlich. Wir haben die Funktion daten_laden() ja als char* daten_laden() definiert. Das bedeutet, das diese Funktion einen Rückgabewert hat. Den sollten wir dann auch verwenden. Z.B. so:

  return buffer;

Damit sparen wir uns die Variable "returnvalue"

Ansonsten sehe ich in Deinem Code keinerlei Ausgabe bei der die empfangenen Zeichen auch ausgegeben werden. Ohne Ausgabe sieht man aber nix.

Die Ausgabe kommt dann in die loop() :

void loop() {
  // http-request senden und in variable speichern
  char* zaehlerstand = daten_laden();
  Serial.print("\n\nAntwort : ");
  Serial.println(zaehlerstand);
  // 10 sekunden warten
  delay(10000);  
}

Das "unsigned long GZStand=0;" ist zur Zeit noch unwichtig, da es ja zunächst darum geht, das wir den Zählerstand als String bekommen. Erst wenn das klappt, machen wir uns Gedanken wie wir daraus eine Zahl machen.
Aber das ist der nächste Schritt. Aktuelle kümmern wir uns nur um die Rückgabe des Webservers.

Nachdem ich den Code nun "zerpflückt" habe, versuch Du den mal mit den von mir geschriebenen Hinweisen wieder zusammen zu setzen. Ich denke dann bist Du schon wieder ein Ganzes Stück weiter.

Mario.

ahh, ok.
habe es jetzt so zusammen gesetzt, das da was "Rauskommt"...

Hier der Sketch:

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

byte mac[] = { 0x00, 0xAB, 0xCB, 0xCD, 0xDE, 0x02 };
IPAddress ip(192,168,178,140);
IPAddress server(192,168,178,111);
EthernetClient client;

char host[]    = "192.168.178.111";                      // Domain
char url[]     = "/Arduino/Gas/read.php"; // Pfad zur PHP-Datei

unsigned long GZStand=0;
char* returnvalue = 0;


void setup() {
  // IP Konfiguration setzen
  // Serielle Konsole initialisieren
  Serial.begin(9600);
  Serial.print("Setup LAN ... ");
  delay(1000);
  Ethernet.begin(mac, ip);
  Serial.println("ok");
}

void loop() {
  // http-request senden und in variable speichern
  char* zaehlerstand = daten_laden();
  Serial.print("\n\nAntwort : ");
  Serial.println(zaehlerstand);
  // 10 sekunden warten
  delay(10000);  
}


//achtung wir liefern ein char* (c-String zurück)
char* daten_laden() {
    char buffer[10] = ""; // puffer initialisieren mit leerem string
    int index = 0;        // zaehlindex auf 0 setzen
 
   client.connect(server, 8000);   // connect to server
    Serial.println(F("Verbinde ..."));    

   //wenn connected, request senden
   if (client.connected()) {
    client.print("GET ");
    client.print(url);
    client.println(" HTTP/1.1");
    client.print("Host: ");
    client.print(host);
    client.println();
    client.println("User-Agent: Arduino");
    client.println("Connection: close");
    client.println();
   }


while (client.available()) {
    buffer[index++] = client.read();   // solange zeichen vorhanden sind, das aktuelle zeichen in puffer schreiben und zaehlindex erhoehen
}

buffer[index] = 0;    // wenn keine zeichen mehr vorhanden, dann puffer am letzten (schon erhoehten) index auf \0 setzen (c-String ende)
return buffer;        // puffer per return zurückliefern

}

Ich habe mich mal an atoi versuch, aber da scheiterts mal wieder am verständnis, wo ich das eintragen muss.
Sofern atoi das richtige ist.

char buffer[10] = "123";
int index;

index = atoi(buffer);
Serial.println(index);