Arduino überträgt keine Werte zur MySQL Datenbank

Hallo,

Ich habe folgendes Problem. Ich möchte Werte von meinem Arduino, in eine MySQL Datenbank einpflegen. Ich weiß es gibt schon viele Posts im Internet oder in sonstigen Foren, doch ich komme nicht mehr weiter.
Ich arbeite mit einem Arduino Uno und einem Arduino WiFi Shield. Dieser Code den ich jetzt habe sollte eigentlich nur dazu dienen zu testen, ob ich überhaupt Werte in meiner Datenbank speichern kann. Im Laufe meines späteren Projektes sollen diese Werte erst noch ausgelesen werden, von Strom- und Spannungsmessern.

Naja jedenfalls verbindet sich das Shield mit dem WLAN, es kann sich auch mit dem Server verbinden, den ich einstelle und er läuft komplett durch, bis am Ende die Verbindung wieder getrennt wird. Jedoch wenn ich dann in der Datenbank nachgucke, hat das Board, bzw die php-Datei keine Daten in die Tabelle gespeichert.

Hier mein php Code:


janrieks:
Ich muss wissen, warum keine Werte in der Datenbank gespeichert werden :confused:

Dein Arduino-Sketch sendet den HTTP-Request derzeitig offenbar nach dem Schema:

  • client.connect
  • Sende den Request
  • client.stop

Dich interessiert doch offenbar überhaupt nicht:

  • ob die Verbindung lange genug bestehen bliebt, um den Request zu verarbeiten
  • welches Ergebnis die Verarbeitung hat

Übliche Webserver, denen Du so einen Rotz von HTTP-Request vorsetzt, erkennen, dass Du die Verbindung sofort nach dem Raushauen des Requests beendest, und die beenden dann natürlich auch ihre Abarbeitung des PHP-Skripts, wenn die Verbindung von Dir gecancelt wurde.

Eine vernünftige Programmlogik würde eher mit so einer Programmlogik arbeiten:

  • client.connect
  • Sende den Request
  • Warte auf Antwort oder Timeout
  • Wenn eine Antwort kommt, werte sie aus
  • client.stop

Schaue Dir vielleicht nochmal ein Webclient-Beispielprogramm an!

Das Auswerten der Server-Logs hilft in solchen Situationen enorm. Was mir sofort auffällt, ist die Leerzeile nach der Request-Zeile (vor der Host:-Zeile). Damit dürfte die Anfrage bei normalen Hosting-Angeboten nicht einmal in Deinem Konto ankommen, sondern auf dem Default-Host landen (welcher auch immer das ist). Auch wäre es sinnvoll, wenn Du auf dem Arduino die Antwort des Servers auslesen würdest und zumindest in der Debugging-Phase auch auf der seriellen Schnittstellen ausgeben würdest.

Da sowas ähnliches mein nächstes Projekt wird, hatte ich mich schon mal etwas Informiert.

Schau mal dort rein, evtl. hift es dir weiter.

Also ich hab bei mir vom Grundsatz her die gleiche Anwendung wie du, nur mit Ethernet-Controller:

Ethernetcontroller ruft Link auf, in dem die Daten stehen, die in die MySQL-Datenbank geschrieben werden.
Mein Code:

if (client.connect(server_ip, 80)) 
{
  client << (F("GET ")) << (F("templates/terminal_communication.php?do=write&1=")) << (conSerial[1]) << (F("&2=")) << (conSerial[3]) << (F("&3=")) << (conSerial[4]) << (F("&4=")) << (conSerial[5]) << (F("&5=")) << (conSerial[6]) << (F("&6=")) << (conSerial[7]) << (F("&7=")) << (conSerial[8]) << (F("&8=")) << (conSerial[9]) << (F("&9=")) << (conSerial[10]) << (F("&10=")) << (conSerial[11]) << (F("&11=")) << (conSerial[12]) << (F("&12=")) << (conSerial[13]) << (F("&13=")) << (conSerial[14]) << endl;
  client.println(F("Authorization: Benutzername:Password"));
  client.println(F("User-Agent: Terminal-Steuergerät-Ethernet"));
  client.println(F("Connection: close"));
  client.println();
}

LG

Fipsi

janrieks:
Es muss doch mal klappen... was mache ich falsch?? :confused:

Du vergißt das URL-Encoding im GET-Request.

Ein Kaufmanns-Und '&' muss zwingend in die Prozentcodierung umgeschrieben werden, ebenso wie das Fragezeichen und die Gleichheitszeichen in der URL-Adresse.

Dein Browser macht das automatisch und wandelt die eingegebene Zeile entsprechend um.

Statt wie im Browser einzugeben:

www.messwerte-ba.de/SaveTempToMySQL.php?T1=10&T2=20

wäre die korrekte GET-Anfrage mit URL-Encoding eher sowas wie:

GET /SaveTempToMySQL.php%3FT1%3D10%26T2%3D20 HTTP/1.0

Jedoch werden immer noch keine Daten in der Datenbank gespeichert

Natürlich nicht....

Wenn du vom Server einen Status 302 erhältst, liefert er dir auch eine neue Location an die du die Anfrage senden sollst.

Tust du das?
Wohl nein.
Also kommen deine Daten auch nicht da an, wo sie sollen.

Randbemerkung:
Wenn es irgend möglich ist versuche die Kommunikation per "REST Maturity Model Level 2" aufzubauen.
Grund:
Es ist (relativ) einfach zu implementieren.
Wenn du wie bisher auf GET beim schreiben setzt, könnten dir irgendwelche Bots (Google oder so) fürchterliche Streiche spielen.

Auch wird PHP seitig eine veraltete MySQL Extension genutzt.
Diese wird sterben. Gehört schon seit Jahren nicht mehr zur Standard Installation.
Setze besser auf Mysqli oder gleich auf PDO.
Das würde dir auch das SQL Injection Problem abnehmen können, welches du wohlwollend ignorierst.

Ich bin leider nicht sehr erfahren, was das Programmieren in php-Sprache angeht... und auch mit der Internetkommunikation kenne ich mich leider nicht aus... wie sende ich denn die Daten an die neue Location die mir geliefert wird? bzw wie erkenne ich das im Programm?

Und ja, das mit mysqli habe ich auch schon gelesen, ich versuche das umzuschreiben

janrieks:
Bei HTTP 1.0 bekomme ich auch keinen Bad Request mehr, wenn ich das ganze allerdings mit

GET /SaveTempToMySQL.php%3FT1%3D10%26T2%3D20 HTTP/1.0

Ich verstehe nicht ganz, was Du damit meinst.

So wie Du programmierst, dass Du zuerst überhaupt keine Server-Rückmeldungen auswertest, und auch kein URL-Encoding in GET-Anfrage machst, wirst Du vermutlich noch mehr Fehler im Code drinhaben.

"Bad Request" steht jedenfalls dafür, dass irgendwas mit dem Request nicht stimmt. Das kann die GET-Zeile sein, aber im Prinzip kommen andere Header-Zeilen dafür genau so in Frage.

Wenn Du z.B. das senden solltest:

client.print("GET /SaveTempToMySQL.php%3FT1%3D10%26T2%3D20 HTTP/1.0");
client.println(" HTTP/1.0");

dann würde die GET-Anfrage wieder zu einem "Bad Request", weil in der GET-Zeile dann mehr als zwei Leerzeichen (weil "" HTTP/1.0" doppelt) enthalten wären.

Welches ist denn die gesamte Anfrage, die Du sendest?
Und welches die daraufhin erhaltene Rückantwort des Servers?

wie sende ich denn die Daten an die neue Location die mir geliefert wird? bzw wie erkenne ich das im Programm?

Die neue Location steht doch im Response des Servers!

Location: http://192.168.112.1:8000/index.php?zone=cpzone&redirurl=http%3A%2F%2Fwww.messwerte-ba.de%2FSaveTempToMySQL.php%3FT1%3D12%26T2%3D23

Aber warum des Server dieses sendet, kann ich nicht sagen.
Bei einem Apache würde ich sagen: Du hast das per .htaccess erzwungen.

Tipp:
HTTP 1.0 ist aus dem Rennen.
Es kennt keinen "Host:" Header. (auch wenn die meisten (aber längst nicht alle) Server diesen auswerten)

Gerade bei Strato und anderen Massenhostern liegen oft tausende von Domains hinter einer IP. Da ist der Host Header zwingend nötig um diese unterscheiden zu können. Er wird meistens schon vom Loadbalancer ausgewertet um die Anfrage im Websevercluster angemessen zu verteilen.
Also HTTP 1.1 !

Du sendest tatsächlich zwei Requests und bekommst zwei Antworten vom Server.

Du sendest:

client.println(server); // Header-Zeile mit Zeilenende
 client.println();   // Leerzeile - GENAU HIER IST DER ERSTE REQUEST ZUENDE ==> weglassen!
 client.println("Connection: close"); // Das ist ein ZWEITER REQUEST
 client.println();

Und bekommst die beiden Antworten:

  1. HTTP/1.1 302 Found
  2. HTTP/1.0 400 Bad Request

Bei HTTP 1.1 wird standardmäßig die Connection offen gehalten, was Du dann am Ende mit dem Senden von "Connection: close" offenbar wieder canceln möchtest. Aber es funktioniert nicht, weil Du vorher bereits eine Leerzeile sendest. Und das Senden einer Leerzeile ist ein Zeichen dafür, dass die erste Anfrage zuende ist. Also wird versucht, "Connection: close" als einen zweiten Request zu behandeln.

Du müßtest entweder die überflüssigerweise gesendete Leerzeile weglassen.

Oder Du sendest einen HTTP/1.0 Request und läßt das "Connection: close" auch komplett weg.

Statuscode "302" bedeutet übrigens, dass Du eine falsche URL-Adresse aufgerufen hast, von der der Server aber weiß, welches die richtige Adresse ist, die er Dir anbietet, dass Du sie in einem nachfolgenden Aufruf aufrufen kannst. Eine HTTP-Umleitung also. Und den Vorschlag mit der richtigen Adresse macht der Server in der "Location" Zeile.

Location: http://192.168.112.1:8000/index.php?zone=cpzone&redirurl=http%3A%2F%2Fwww.messwerte-ba.de%2FSaveTempToMySQL.php%3FT1%3D12%26T2%3D23

D.h. wenn Du einen 300er Statuscode bekommst, z.B. Statuscode 302 und eine Location-Zeile, dann mußt Du den Inhalt der Location-Zeile auswerten und einen neuen Request senden.

Übrigens: Das was Du da in der Location-Zeile als HTTP-Umleitungsadresse angezeigt bekommst, deutet auf eine ziemlich verquere Netzwerk-/Serverkonfiguration hin. Normal ist das nicht.

Ok, top, die leerzeile habe ich rausgelöscht und nun klappt es auch, also er bekommt keinen Bad Request mehr! also muss ich nun die location zeile praktisch auwerten und dann die daten die ich in die datenbank gespeichert haben möchte über diese adresse dahin schicken?

Und ich benutze jetzt HTTP/1.1, danke für die Info :wink:

janrieks:
Ok, top, die leerzeile habe ich rausgelöscht und nun klappt es auch, also er bekommt keinen Bad Request mehr! also muss ich nun die location zeile praktisch auwerten und dann die daten die ich in die datenbank gespeichert haben möchte über diese adresse dahin schicken?

Ja. Siehe Wikipedia zum Thema HTTP-Statuscode 302

und dann die daten die ich in die datenbank gespeichert haben möchte über diese adresse dahin schicken?

Ich möchte um ein bisschen Aufmerksamkeit bitten.
Denn wenn mich nicht alles täuscht, sendest du weiterhin GET Requests.
Und dann werden die Daten schon in der URL drin sein.

Arbeitest du mit POST, musst du den Request neu zusammenstückeln.

jurs:
Übrigens: Das was Du da in der Location-Zeile als HTTP-Umleitungsadresse angezeigt bekommst, deutet auf eine ziemlich verquere Netzwerk-/Serverkonfiguration hin. Normal ist das nicht.

Dem stimme ich zu 100% zu.

Auffällig:
Die Location URL http://192.168.112.1:8000............ liegt im lokalen/privatem Netz bei dir zuhause. Zumindest wird sie nicht von deinem DSL Router nach außen weiter gereicht. Vermutlich spielt dir ein privater Router in deinem Netz zuhause den 302 Streich.

Weiter Hinweis darauf:
Bei Massenhostings setzt Strato auf Apache und nicht wie bei den Headern angegeben auf lighttpd/1.4.35
Aktuell ist bei Strato Apache/2.2.29 (Unix)

Beweis: Auch http://messwerte-ba.de/ wird von einem Server:Apache/2.2.29 (Unix) bedient

Ja!

Der Router, welches das "Gastnetzwerk" bereitstellt hat offensichtlich intern einen lighttpd/1.4.35.
Auf diesen werden alle Anfragen gerichtet , die er dann beantwortet.
Einen Browser kümmert das nicht, er sendet einfach einen weiteren Request an die im Location Header angegebene URL. Davon bekommst du nix mit, wenn du dir die Header nicht anschaust.

Machs genauso, wie der Browser.
Prüfe den Response auf einen Status 30X und wenn gegeben, folge dem Location Header.

dann ist das doch eigentlich ein Zeichen, dass die php Datei funktioniert und ich nicht unbedingt mit mysqli arbeiten muss oder?

Alter Tipp: Sattel keine toten Pferde!

Wenn es heute noch funktioniert, dann ist das eine Gnade von Strato.
Aber ewig ziehen die das auch nicht.
Von einem Tag auf den anderen kann damit Schluss sein.
Ich kann mir nicht vorstellen, dass sie dich um Erlaubnis ersuchen ein PHP Update zu machen.

Auch ist das ein öffentlicher Server deiner Firma.
Und im Augenblick reißt du da ein "SQL Injection" Loch auf.
Stopfe es!
Das ist keine Bitte, sondern ein Kommando: Stopfe es!
Das geht auch mit der alten mysql Extension.

Zu deinem anderen Problem:

Ja die Location habe ich doch oder nicht? das ist doch die, die mir im Response angezeigt wird (also im Serial Monitor under Location)
...
Die Daten müssen also an diese Adresse. Wie werte ich die Location denn aus? ich würde jetzt einfach "copy-paste" die Location in das client.print einfügen und die Daten wie gehabt versuchen rüber zu schicken, was aber nicht funktioniert :confused:

Wenns mit dem Browser über die WLAN Verbindung geht, dann sollte es auch mit dem Arduino klappen.
Mir ist die Sicherheitsstruktur in deinem Netz nicht bekannt.
Also ein klares: KA, ob das so geht.

Ok alles klar, vielen Dank!

Dann versuche ich das mal hinzubekommen mit der Location und wenn alles steht, dann wird sich mal mit mysqli beschäftigt, bzw der Aufbereitung der php-Datei!

Am einfachsten wäre es aber ja sicherlich einfach ein Wlan-Netz zu nutzen, was nur die simple WPA2 Verschlüsselung besitzt und keine weiteren Passwörter nötig sind.... eventuell kan ich so ein Netz hier aufbauen (ist ja im moment eh nur zu Testzwecken).

Dann versuche ich das mal hinzubekommen mit der Location und wenn alles steht, dann wird sich mal mit mysqli beschäftigt, bzw der Aufbereitung der php-Datei!

Erst die Lücke zu!
Alles andere ist Wahnsinn.

Auch wenn ich dein Ansinnen verstehe, nachvollziehen kann, usw....
Aber aus eigener bitterer Erfahrung weiß ich, wie gnadenlos dumm sich solche Entscheidungen auswirken können.

Bedenke:
Du hast die URL und den Code hier öffentlich bekannt gegeben!
Millionen von Internetnutzern stehen diese Informationen zur Verfügung.

Die Absicherung ist in 5 Minuten erledigt.
Tu es einfach!

combie:
Bedenke:
Du hast die URL und den Code hier öffentlich bekannt gegeben!
Millionen von Internetnutzern stehen diese Informationen zur Verfügung.

Alles klar, hast auch wieder recht!