Go Down

Topic: Arduino als HTTP Client - Daten auslesen (Read 1 time) previous topic - next topic

senden9

Hallo!
Folgendes Problem: Mein Arduino ruft über HTTP eine Seite auf:
Code: [Select]
GET /alarm/ardu/?i=5 HTTP/1.0


Die Variable "i=5" wird dynamisch generiert. Dort bekommt er als Antwort z.B. folgendes zurück:
Code: [Select]
HTTP/1.0 200 OK
Vary: Cookie
Content-Type: text/html; charset=utf-8
Set-Cookie: csrftoken=219fc26c9243f30f57807b2b73b5c86e; expires=Thu, 17-Jan-2013 09:43:25 GMT; Max-Age=31449600; Path=/
Connection: close
Date: Thu, 19 Jan 2012 09:43:25 GMT
Server: lighttpd/1.4.28

63

Mich interessiert nur die letzte Zahl. In diesen Fall 63. Die Zahl kann von 0-255 gehen. Wie bekomme ich diese Zahl in eine Variable gespeichert? Den String könnte ich dann ja so umwandeln:
Code: [Select]
int ausgabe = readString.toInt();

MfG
senden9

nachtaktiv68

#1
Jan 19, 2012, 11:43 am Last Edit: Jan 19, 2012, 11:55 am by nachtaktiv68 Reason: 1
Aus dem Kopf würde ich sagen etwa so :)

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

Dabei setze ich voraus, dass die Antwort des Servers (Variable "antwort") als String-Objekt vorliegt. Ich hoffe, dass die beiden Zeilenumbrüche mit "\n\n" erkannt werden, wenn nicht probier mal "\r\n\r\n". Das "+1" musst Du evtl. auch ändern. substring gibt den String einschließlich des Zeichens an der index-Position zurück, wenn "\r\n\r\n" funktioniert, wirst Du die +1 ändern müssen.
twitter: @darktom

Joghurt

Alternativ könntest Du die Ausgabe des Servers so lange Zeichen für Zeichen durchgehen bis Du einen Zeilenumbruch gefolgt von Zahlen gefolgt von einem Zeilenumbruch findest.

Dann würdes Du mit einem 3 Byte grossen char-Array auskommen (bzw. wieviele Nummern Deine Zahl maximal haben kann plus eins) statt (in aktuellen Fall) mindestens 277 Bytes für die String-Variable zu verbraten...

Speicher ist kostbar! ;)

senden9

Hi, ich habe mich gerade am Vorschlag von Jogurt versucht. Es berietet mit Kopfzerbrechen. Hier mein Code:
Code: [Select]
int CR = 0;
int LF = 0;
unsigned int http_counter = 0;
unsigned int cr_http_counter = 0;


while(client.connected()){
    if (client.available()) {
      char c = client.read();
      if (c == 13){
        CR ++ ; //ascii Carriage Return
        cr_http_counter = http_counter;
      }
      if (c == 10 & CR & (http_counter == (cr_http_counter + 1))){
        LF ++ ; //ascii Carriage Return
      }
      http_counter ++;
    }
  }

Ich muss irgendwie Abfragen ob 2x die Sequenz CR LF kommt. Bin ich auf dem richtigen Weg? Wie gesagt es bereitet mir Kopfzerbrechen.

Joghurt

Also wenn Du wirklich sicher bis dass nur und ausschließlich eine Zahl als Nutzdatum zurück kommt und Du auch nicht mehr brauchst, dann würde ich was in der Richtung ansetzen:
Code: [Select]

// Max. Anzahl an Zahlen! 6->1, 68->2, 680->3 etc...
#define MAXLEN 2

char buffer[MAXLEN+1];
byte bufferpos = 0;
boolean invalid = false; // Falsche Zeichen in der Zeile?
long retval = -1; // Nix...

void loop() {
 while (client.connected() && retval == -1) {
   if (client.available()) {
     char c = client.read();
     if (c>='0' && c<='9' && !invalid) { // zwischen 0 und 9, also eine Zahl, und sonst nix in der Zeile
       if (bufferpos>MAXLEN) {
         Serial.println("ZU LANGE!!!"); // Zu klein dimensionierter Puffer!
         invalid = true;
       } else
         buffer[bufferpos++] = c; // Zahl merken, dann zur naechsten Speicherzelle weitergehen
     } else if (c == '\r' || c == '\n') { // CR oder LF
       buffer[bufferpos] = '\0'; // "Ganz hinten" Stringende markieren
       if (bufferpos > 0) // In der letzten Zeile waren Zahlen, also NICHT zuruecksetzen!
         retval = atoi(buffer);
       invalid = false;
     } else {
       bufferpos = 0; // Keine Zahl, also Speicher an den Anfang zuruecksetzen!
       invalid = true; // Irgendwas anderes, ein Buchstabe oder ein Sonderzeichen oder so...
     }
   }
 }
 if (retval != -1){
   // Zahl gefunde, also jetzt was damit machen...
 }
 bufferpos = 0; // Klar zum naechsten Durchgang...
 invalid = false;
 retval = -1;
}

Ist aber nicht getestet, daher ohne Gewähr... ;)

senden9

#5
Jan 23, 2012, 10:40 am Last Edit: Jan 23, 2012, 10:50 am by senden9 Reason: 1
Hallo, sorry das ich erst jetzt wieder antworte.
Leider klappt der Code nicht. Der retval bleibt -1. Laut Serial.write(c); wird die HTML Seite korrekt übertragen. nur an der Auswertung scheitert es.
Ich hier der zuständige Code:
Code: [Select]
void webserver(){
 if (client.connect()) {
   Serial.println("connected");
   client.print("GET ");
   client.print(webpraefix);
   client.print("?i=");
   client.print(expanderRead(expander1),DEC);
   client.print(" HTTP/1.0\r\n\r\n");
   Serial.print("input:");
   Serial.println(expanderRead(expander1),DEC);
 }
 else {
   Serial.println("connection failed");
 }
 while (client.connected() && retval == -1) {
   if (client.available()) {
     char c = client.read();
     Serial.write(c);
     if (c>='0' && c<='9' && !invalid) { // zwischen 0 und 9, also eine Zahl, und sonst nix in der Zeile
       if (bufferpos>MAXLEN) {
         Serial.println("ZU LANGE!!!"); // Zu klein dimensionierter Puffer!
         invalid = true;
       } else
         buffer[bufferpos++] = c; // Zahl merken, dann zur naechsten Speicherzelle weitergehen
     } else if (c == '\r' || c == '\n') { // CR oder LF
       buffer[bufferpos] = '\0'; // "Ganz hinten" Stringende markieren
       if (bufferpos > 0) // In der letzten Zeile waren Zahlen, also NICHT zuruecksetzen!
         retval = atoi(buffer);
       invalid = false;
     } else {
       bufferpos = 0; // Keine Zahl, also Speicher an den Anfang zuruecksetzen!
       invalid = true; // Irgendwas anderes, ein Buchstabe oder ein Sonderzeichen oder so...
     }
   }
 }
 if (retval != -1){
   // Zahl gefunde, also jetzt was damit machen...
   expanderWrite(retval, expander2); // Testweise in die Expandr schreiben...
     // 0 = Alles ein // 255 = alles aus
 }
 Serial.println(retval);
 Serial.println("disconnecting.");
 client.stop();
 Serial.println(retval,BIN);
 Serial.println(retval,DEC);
 Serial.println("___");

 bufferpos = 0; // Klar zum naechsten Durchgang...
 invalid = false;
 retval = -1;
}

Code: [Select]
#def.h
...

byte server_ip[] = {
 192,168,1,160}; //Server IP
#define server_port  80
char webpraefix[] = "/alarm/ardu/"; //pfad zum script

long server_rw_previous = 0;

//---HTTP-Verbinfung---//
// Max. Anzahl an Zahlen! 6->1, 68->2, 680->3 etc...
#define MAXLEN 3

char buffer[MAXLEN+1];
byte bufferpos = 0;
boolean invalid = false; // Falsche Zeichen in der Zeile?
long retval = -1; // Nix...

Für einen hilfreichen Tipp wäre ich sehr dankbar.

mkl0815

Schau Dir mal http://www.arduino.cc/playground/Code/TextFinder an. Um mir  UDP / NTP zu ersparen und da meine Wetterstation eh als Webclient arbeitet, habe ich mir eine Funktion gebaut, die den aktuellen Unix-Timestamp über einen Webrequest bekommt:
Die Ausgabe unter der URL sieht wiefolgt aus:
Quote
CURRENT TIME 1327349909

Folgender Code wertet das dann aus:
Code: [Select]

#include <Ethernet.h>
#include <TextFinder.h>
...
Client client(server, 8888);
TextFinder finder( client);
...
void getTime() {
  if (client.connect()) {
    Serial.print("connected... ");
    client.println("GET /time HTTP/1.0");
    client.println("Host: wetter.office.das-tierhausi.de");
    client.println();
  } else {
    Serial.println("connection failed");
  }
  if (client.connected()) {
    gettime = 0;
    if(finder.find("CURRENT TIME")){   
         gettime = finder.getValue(',');
         Serial.print(gettime);
         Serial.println(" seconds since 1970");         
    }
    if(gettime == 0){
      Serial.println("No time. ");
    }   
    client.stop();
    //time offset abziehen
    //damit kann immer mittels time + millis() / 1000 der aktuelle timestamp berechnet werden.
    time = gettime - millis() / 1000;
  }
}

Der "Trick" sind die beiden Zeilen "if(finder.find("CURRENT TIME")){  ", hier wird nach dem Markierungsstring gesucht, und
"gettime = finder.getValue(',');". Damit wird der nächste Wert nach dem Markierungsstring ermittelt. Das klappt bei mir hervorragend.

senden9

Die Lösung:
Code: [Select]
void webserver(){
  //snprintf(out_string, 9, "%d", expanderRead(expander2));

  if (client.connect()) {
    Serial.println("connected");
    client.print("GET ");
    client.print(webpraefix);
    client.print("?i=");
    client.print(expanderRead(expander1),DEC);
    client.print(" HTTP/1.0\r\n\r\n");
    Serial.print("input:");
    Serial.println(expanderRead(expander1),DEC);
  }
  else {
    Serial.println("connection failed");
  }
  while (client.connected() && retval == -1) {
    if (client.available()) {
      char c = client.read();
      Serial.write(c);
      if (CR_LF_counter == 4) {
        if (bufferpos>MAXLEN) {
          Serial.println("ZU LANGE!!!"); // Zu klein dimensionierter Puffer!
          invalid = true;
        }
        else
          buffer[bufferpos++] = c; // Zahl merken, dann zur naechsten Speicherzelle weitergehen
      }
      else if (c == '\r' || c == '\n') { // CR oder LF
        CR_LF_counter++;
      }
      else {
        bufferpos = 0; // Keine Zahl, also Speicher an den Anfang zuruecksetzen!
        CR_LF_counter = 0;
        //invalid = true; // Irgendwas anderes, ein Buchstabe oder ein Sonderzeichen oder so...
      }
    }
  }
  if (bufferpos > 0) // In der letzten Zeile waren Zahlen, also NICHT zuruecksetzen!
          retval = atoi(buffer);
  if (retval != -1){
    // Zahl gefunde, also jetzt was damit machen...
    expanderWrite(retval, expander2); // Testweise in die Expandr schreiben...
    // 0 = Alles ein // 255 = alles aus
  }
  Serial.println(retval);
  Serial.println("disconnecting.");
  client.stop();
  Serial.println(retval,BIN);
  Serial.println(retval,DEC);
  Serial.println("___");

  bufferpos = 0; // Klar zum naechsten Durchgang...
  invalid = false;
  retval = -1;
  CR_LF_counter = 0;
  for(int x = 0; x <= (MAXLEN + 1); x++){
    buffer[x] = '\0';
  }
}


Code: [Select]
//---HTTP-Verbinfung---//
// Max. Anzahl an Zahlen! 6->1, 68->2, 680->3 etc...
#define MAXLEN 3

char start_key[10] = "WCzS2ttsE";
char buffer[MAXLEN+1];
byte bufferpos = 0;
boolean invalid = false; // Falsche Zeichen in der Zeile?
long retval = -1; // Nix...
int CR_LF_counter;

Danke für eure Hilfe!!!

Go Up