Mit WiFi-Shield Textdatei von Webserver laden und Wert in Variablen speichern

Hallo Arduino-Freunde,

ich möchte mein neu erworbenes Arduino WiFi Shield gerne über PHP fernsteuern. Dafür habe ich mir folgendes überlegt:
Auf der Website, welche ich auf einem Webserver gespeichert habe, findet sich die Möglichkeit Buttons zu bedienen, die einen
Wert, in einer ebenfalls auf dem Server befindlichen TXT-Datei, ändern. Der Arduino stellt nun eine Verbindung zum Server her,
lädt alle bspw. 5 Sekunden die Textdatei herunter und liest den dort gespeicherten Wert aus. Dieser Wert wird dann in einer Variablen gespeichert und kann
dann nach belieben weiterverarbeitet werden.

Bisher funktioniert das downloaden des TXT-Files hervorragend, auch zeigt der Serial Monitor den Inhalt dieser Datei an. Das Problem besteht
nun darin, dass ich den Inhalt der Textdatei nicht in einer Variablen speichern kann.

Hier der Code (zusammen gebastelt aus den WiFi-Shield-Examples):

#include <SPI.h>
#include <WiFi.h>

char ssid[] = "Netzwerkname"; 
char pass[] = "Password";  
int keyIndex = 0;           

int status = WL_IDLE_STATUS;
WiFiClient client;
char server[] = "Internetadresse der Website";


unsigned long lastConnectionTime = 0;           // last time you connected to the server, in milliseconds
boolean lastConnected = false;                  // state of the connection last time through the main loop
const unsigned long postingInterval = 10*1000;  // delay between updates, in milliseconds

void setup() {
  
  Serial.begin(9600);
  
  while ( status != WL_CONNECTED) {
  status = WiFi.begin(ssid, keyIndex, pass);
  delay(1000);
  }
  } 


void loop() {
 while (client.available()) {
    char c = client.read();
    Serial.write(c);
  }

  // if there's no net connection, but there was one last time
  // through the loop, then stop the client:
  if (!client.connected() && lastConnected) {
    Serial.println();
    Serial.println("disconnecting.");
    client.stop();
  }
  
  // Wenn nicht verbunden und 10 Sekunden vergagen seit letzter Verbindung, neue Verbindung
  if(!client.connected() && (millis() - lastConnectionTime > postingInterval)) {
    httpRequest();
  }
  // Da nun verbunden: lastConnect
  lastConnected = client.connected();
}

// HTTP Verbindung zu Server:
void httpRequest() {
  // Wenn Verbindung zu Client besteht:
  if (client.connect(server, 80)) {
    
    // Get Request an TXT Datei
    client.println("GET /Test.txt HTTP/1.1");
    client.println("Host: Internetadresse der Website"); 
    client.println();
  
    lastConnectionTime = millis();
  } 
  else {
    // if you couldn't make a connection:
    Serial.println("connection failed");
    Serial.println("disconnecting.");
    client.stop();
  }
}

Vielen Dank für Eure Hilfe :slight_smile:

Hat niemand eine Idee? Oder ist es zu konfus formuliert ? XD

Was meinst du den genau mit "dass ich den Inhalt der Textdatei nicht in einer Variablen speichern kann"? Was liest du genau aus und in was für einem Datentyp willst du das abspeichern?

Dein Problem scheint er die Umwandlung der Datentypen zu sein. z.B. char zu Integer. Da wäre es eben wichtig zu wissen was da eigentlich übertragen/gespeichert wird.

gama:
Hat niemand eine Idee? Oder ist es zu konfus formuliert ? XD

Womit hast Du denn ein Problem?

In der Zeile
char c = client.read();
liest Du die gesendete Datei Zeichen für Zeichen aus und weist das gelesene Zeichen jeweils an die Variable "c" zu. Jedes neu gelesene Zeichen landet immer wieder in derselben Variablen c.

So what?

Kommen die Zeichen zu schnell für eine Weiterverarbeitung?

Hast Du ein Problem, eine "größere" Variable zusammenzusammeln, z.B. eine "Zeile" aus der Datei?

Oder möchtest Du aus der Textdatei irgendwas zusammensammeln (z.B. Zahlenwerte) und in numerische Variablen "umwandeln"?

Da Du die Datei bereits erfolgreich ausliest per "client.read();" und auch die gelesenen Zeichen erfolgreich zeichenweise an eine Variable zuweist ("char c =") kann ich in Deinem Beitrag irgendwie den Sinn nicht entdecken (falls einer drinsteckt).

Was meinst du den genau mit "dass ich den Inhalt der Textdatei nicht in einer Variablen speichern kann"? Was liest du genau aus und in was für einem Datentyp willst du das abspeichern?

In der Text Datei befindet sich für den Anfang mal irgendein Zahlenwert, z.B 1 oder 0.
Dieser Wert soll nun in der Variable c gespeichert werden. Wenn 1 empfangen wird soll z.B
Pin 13 auf HIGH gesetzt werden.

Ich habe nun aber meinen Fehler gefunden, ich stand die ganze Zeit auf dem Schlauch - bis gerade eben. Ich habe die if Abfrage, welche den oben beschriebenen Ablauf vollführen soll nicht in die loop gesetzt sondern in die Funktion httpRequest. Es tut mit Leid Euch mit so einem trivialen Problem belastet zu haben, aber ich kam 2 Wochen lang einfach nicht dahinter, dank Euch funktioniert es nun endlich. :slight_smile: :sweat_smile:
Dennoch habe ich eine Frage:

Hast Du ein Problem, eine "größere" Variable zusammenzusammeln, z.B. eine "Zeile" aus der Datei?

Wenn ich gerade mehrere Werte in der Datei gespeichert habe, wie kann ich diese zerlegen in einzelne Ziffern?
Besser beschrieben: wenn in meiner TXT-Datei '1001101' stehen würde und jede Ziffer einem Pin zugeordnet werden soll (also: Ziffer 1 bestimmt Status von Pin 13; Ziffer 2 von Pin 12; [...]) , wie kann jetzt z.B die dritte Ziffer (=> 0) ausgewählt werden, um den Pin 11 auf LOW zu setzen? Wie unterteile ich diesen 'Zahlenstring' in einzele Ziffern und speichere diese in mehreren Variablen oder einem Array?

Danke nochmal :slight_smile:

Am besten du liest die ganze Zeile einfach in ein char Array. Das hast du praktisch schon hier:

while (client.available())
{
    char c = client.read();
    Serial.write(c);
}

Du musst halt vorher das Array einmal anlegen. Die Länge kennst du an der Anzahl der Pins. Dann lässt du einfach in der while-Schleife einen Index mitlaufen und schreibst rein. Du musst aber unbedingt aufpassen dass der String nicht größer als das Array ist (oder sicherheitshalber den Index mit der Länge vergleichen und dann aus der Schleife springen)!

So ähnlich:

byte length = 20;
char str[length];
byte i = 0;

while (client.available() && i < length)
{
    str[i] = client.read();
    i++;
}

Dann kannst du über den Index direkt darauf abfragen. So ähnlich:

if(str[2] == '0')
{
    digitalWrite(11, LOW);
}
else
{
    digitalWrite(11, HIGH);
}

Chars zwischen 0 und 9 in Integer umwandeln geht einfach indem man minus 48 macht (oder 0x30), da '0' in ASCII den Wert 48 hat. Daher könnte auch das gehen (weil HIGH = 1 und LOW = 0 ist wenn du dir mal die defines anschaust):

digitalWrite(11, str[2] - 48);

Kürzer wird es nicht.

Ansonsten gibt es dafür die Funktionen atoi, atol und strtol (oder strtoul für unsigned long), wenn du mal längere Zahlen konvertieren willst:
http://www.cplusplus.com/reference/cstdlib/atoi/
http://www.cplusplus.com/reference/cstdlib/atol/
http://www.cplusplus.com/reference/cstdlib/strtol/
http://www.nongnu.org/avr-libc/user-manual/group__avr__stdlib.html

Wenn man die Zahlen z.B. mit Kommas oder Leerzeichen trennt, kann man mehrere umwandeln. Bei strtrol gibt es dafür den endptr Parameter, der immer auf den Terminator gesetzt wird (so dass man beim nächsten Aufruf bei endptr + 1 anfangen kann). Oder man macht diese Trennung schon beim Einlesen des Strings.

strtol hat einen Parameter über den man die Basis definieren kann. Damit könntest du also einen Binär-String in eine Zahl umwandeln. Danach müssest du aber das jeweilige Bit mit UND aus-maskieren um darauf zu testen, oder die Arduino-Funktion bitRead() verwenden. Das ist auch nicht einfacher.