Arduino als Webserver einrichten und Webpage von SD-Karte laden

Arduino + Ethernet ShieldIn diesem Beitrag möchte ich zeigen, wie man einen Arduino als Webserver einrichtet, wie man ein Webformular von der, auf dem Ethernet Shield integrierten Micro-SD-Karte lädt und wie man über dieses Webformular Pins des Arduino steuern kann.

Für dieses Beispiel benötigen Sie auf jeden Fall einen Arduino, ein Ethernet-Shield und eine Micro-SD-Karte die in den Slot auf dem Ethernet Shield geschoben wird.

 

Arduino-Sketch

void setup()

Dieses Sketch stellt beim starten oder nach einem Reset eine Ethernet-Verbindung her und startet den Server, der über die in Zeile 7 angegebene IP aufgerufen wird. Danach wird die SD-Karte initialisiert. War diese Initialisierung erfolgreich, dann wird nach der Datei index.htm gesucht, die sich im Root-Verzeichnis auf der SD-Karte befinden muss.

void loop()

In der Funktion loop werden zwei Sachen abgearbeitet. Einerseits wird beim aufrufen der Server IP eine Website angezeigt und andererseits wird ständig auf Anfragen gelauscht die über diese Webseite gesendet werden.

Eine Anfrage wird dann empfangen, wenn Sie im Webbrowser den Server aufrufen indem Sie die oben angegebene ip aufrufen und anschließend einen Port am Arduino schalten indem Sie in dem zu sehenden Webinterface einen Button anklicken um einen Verbraucher ein- bzw. auszuschalten.



Wenn Sie auf einen der Buttons klicken, wird eine Anfrage wie „/?pinD6=1″ an den Arduino gesendet. D steht in diesem Fall für Digital. Möglich wäre auch die Angabe eines A für das schalten eines analogen Pins. Die Zahl hinter diesem Buchstaben steht für die PinNr auf dem Arduino. Die 1 hinter dem = Zeichen bedeutet dass dieser Pin auf HIGH oder bei Angabe einer 0 auf LOW geschaltet wird. Die Angabe „/?pinD6=1″ schaltet also den Digitalen Pin 6 auf HIGH.

Der Arduino durchsucht nun die Anfrage und schaut nach dem Teilstring „pin“. Wenn dieser gefunden wurde. werden die einzelnen Bestandteile der Anfrage in „typ“, „pin“ und „val“ gespeichert. Danach wird je nach empfangenen Typ entweder ein Digitaler oder ein Analoger Ausgang auf dem Arduino geschaltet.

#if ARDUINO > 18
#include <SPI.h> // Für Arduino Version größer als 0018
#endif
#include <Ethernet.h>
#include <TextFinder.h>
#include <SD.h>

byte mac[] = { 0x5A, 0xA2, 0xDA, 0x0D, 0x56, 0x7A }; // MAC-Adresse des Ethernet-Shield
byte ip[]  = { 192, 168, 2, 102 };                   // IP zum aufrufen des Webservers
byte sdPin = 4;                                      // Pin der SD-Karte

EthernetServer server(80);                           // Server port

File webFile;

void setup()
{  
  Ethernet.begin(mac, ip); // Client starten
  server.begin();          // Server starten
  Serial.begin(9600);
  Serial.println("ARDUINO - STEUERUNG");

  Serial.println("Initialisiere SD-Karte...");
  if (!SD.begin(sdPin)) 
  {
    Serial.println(" - Initialisierung der SD-Karte fehlgeschlagen!");
    return;
  }
  Serial.println(" - SD-Karte erfolgreich initialisiert.");

  if (!SD.exists("index.htm")) 
  {
    Serial.println(" - Datei (index.htm) wurde nicht gefunden!");
    return;
  }
  Serial.println(" - Datei (index.htm) wurde gefunden.");

  Serial.println();
  Serial.println("Verbraucher schalten");
}

void loop()
{
  EthernetClient client = server.available(); // Auf Anfrage warten

  if(client)
  {
    /*****************************************
      Ausgänge über das Webformular steuern  *
    *****************************************/
    TextFinder finder(client);

    if(finder.find("GET"))
    {
      while(finder.findUntil("pin", "\n\r"))
      {
        char typ = client.read();
        int  pin = finder.getValue();
        int  val = finder.getValue();

        if(typ == 'D')
        {
          pinMode(pin, OUTPUT);
          digitalWrite(pin, val);
          Serial.print(" - D"+String(pin));
        }
        else if(typ == 'A')
        {
          analogWrite(pin, val);
          Serial.print(" - A"+String(pin));
        }
        else Serial.print(" - Falscher Typ");

        if(val==1) Serial.println(" ein"); else Serial.println(" aus");
      }
    }

    /************************
      Webformular anzeigen  *
    ************************/
    boolean current_line_is_blank = true;       // eine HTTP-Anfrage endet mit einer Leerzeile und einer neuen Zeile

    while (client.connected()) 
    {
      if (client.available())                   // Wenn Daten vom Server empfangen werden
      {
        char c = client.read();                 // empfangene Zeichen einlesen
        if (c == '\n' && current_line_is_blank) // wenn neue Zeile und Leerzeile empfangen
        { // Standard HTTP Header senden
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println("Connection: close");
          client.println();

          // Website von SD-Karte laden
          webFile = SD.open("index.htm");  // Website laden
          if (webFile)
          {
            while(webFile.available())
            {
              client.write(webFile.read()); // Website an Client schicken
            }
            webFile.close();
          }
          break;
        }
        if (c == '\n') 
        {
          current_line_is_blank = true;
        } 
        else if (c != '\r') 
        {
          current_line_is_blank = false;
        }
      }
    }
    delay(1);
    client.stop();
  }
}

 

ArduinoWebServerPage

test.htm

Diese Datei kopieren Sie einfach ins Root-Verzeichnis auf der SD-Karte. Die SD-Karte können Sie anschließend in den Micro-SD-Slot auf dem Ethernet-Shield stecken.

<!DOCTYPE html>
<html>
<head>
  <title>Arduino Steuerung</title>
  <style type="text/css">
    h2 { margin-bottom:5px; }
  </style>
</head>
<body>

  <h1>Heizungssteuerung</h1>

  <h2>Digital Pin3:</h2>
  <a href="/?pinD3=1" target="ifr">Ein</a>
  <a href="/?pinD3=0" target="ifr">Aus</a>
  <br>
  <br>        
  <h2>Digital Pin6:</h2>
  <a href="/?pinD6=1" target="ifr">Ein</a>
  <a href="/?pinD6=0" target="ifr">Aus</a>

  <iframe name="ifr" style="display:none;" width="0" height="0"></iframe>
</body>
</html>



reichelt elektronik – Elektronik und PC-Technik

Über Enrico S.

Programmierer, Webdesigner, Grafiker, Blogger, Screencaster, Arduino- und eMobility Enthusiast. nefilim3006 ist auch bei Google+ vertreten

29 Kommentare zu “Arduino als Webserver einrichten und Webpage von SD-Karte laden

  1. Vielen Dank für diese Erklärung.

    Die Übertragung via PHP an den Arduino verstehe ich.
    Diese Schaltung habe ich mir eben nachgebaut und das läuft.
    Aber um eine echte Heizungsanlage z.B. Umlaufpumpen bzw. alle Geräte mit 230 V zu steuern bedarf es einer echten Statusabfrage mit einem Rückkanal I/O auf der PHP-Seite, sonst wird kann es im Ernstfall richtig Gefährlich werden. Leider habe ich das auch noch nicht raus, wie man den Status via PHP abfragen kann.

    … Zum üben ist der Blog wirklich Gut !

  2. Was genau meinst Du?
    Ich denke eh, das man sicherheitsrelevante Dinge nicht direkt vom Internet aus steuern dürfen sollte. Man kann ja einen Wert über die Website an den Arduino senden der diesen prüft und gegebenenfalls schaltet. Immer mit ein paar Sicherheitsabfragen wie maxTemp, minTemp. Das müsste man eben noch im Arduino deklarieren.

  3. Moin!

    bei mir läuft es noch nicht ganz rund

    ich bekomme
    ARDUINO – STEUERUNG
    Initialisiere SD-Karte…
    – SD-Karte erfolgreich initialisiert.
    – Datei (index.htm) wurde gefunden.

    Verbraucher schalten

    Ich kann auch die Index.htm im Browser anschauen… aber nichts anderes.
    eine index2.htm oder test.htm zeigt vom Inhalt immer die index.htm an

    wenn ich deine test.htm gleich als index.htm speichere geht es… ich kann dann halt keine andere htlm datei ansehen

    Unterschiede zu deiner Hardware? ich habe einen mega2560 mit einem ethernet-shield 5.0

    Ach ja :-) und die Buttons in bunt hätte ich auch gerne

    Gruß
    Thomas

  4. Das passt schon so. Ein Arduino ist ja kein Browser, woher soll er also wissen welche Seite er aufrufen soll? Das muss natürlich erst mal programmiert werden. Die Buttons kannst du ganz einfach in der html Datei mit CSS anpassen. Auch dazu gibt es hier ein Tutorial.

  5. >woher soll er also wissen welche Seite er aufrufen soll?
    hmm „er“ braucht es ja nicht wissen. Es reicht ja wenn ich es weis :o)
    durch “ webFile = SD.open(„index.htm“);“ wird ja festgelegt dass die Index.htm angezeigt werden soll.
    Ich dachte dass das wie bei einem klassischen Webserver nur initial gilt und ich auch auf andere html Dateien zugreifen kann die ich zuvor auf die Karte lege…
    …so dass mit http://meineIP/wunschseite.htm auch andere Seiten als index.htm in meinem Browser aufgerufen werden können.

    gibts da auch ein Turorial? bei einem Mega mit vielen I/O und Aufruf auf einem Minibildschirm eines Smartphone wünsche ich mir etwas mehr Diversität :o)

    Gruß
    Thomas

  6. Ja da hast Du Recht, es reicht wenn Du das weißt nur dann musst damit leben dass er nur die index.htm anzeigt,

    Du kannst auf beliebig viel Dateien zugreifen wenn Du Deine SD-Karte in den Rechner steckst. Der Arduino kann es nicht weil der weiß ja nichts von den anderen Dateien wenn Du ihn nur die index.htm öffnen lässt.

    Sicher gibt’s da eine ganze Menge an Tutorials zu. Auf dieser Seite gibt’s noch keins.
    Nur als Tipp. Versuchs mal damit.


    //Webpage senden
    if ((HTTP_req.indexOf("GET / ") > -1) || (HTTP_req.indexOf("GET /index.htm") > -1))
    {
    webFile = SD.open("index.htm");
    }
    else if (HTTP_req.indexOf("GET /page2.htm") > -1)
    {
    webFile = SD.open("page2.htm");
    }

    Vielleicht schaffst es ja dass Du damit etwas mehr „Diversität“ rein bekommst.

  7. Ja sicher geht das, ist ja nichts anderes wie wenn man über eine Weboberfläche eine LED oder ein Relais ansteuert.

  8. Hallo,
    schöne Anleitung allerdings funktioniert es bei mir noch nicht ganz, ich habe den Arduino Code auf den Arduino geladen, den Html code in das Root Verzeichnis einer Micro SD Karte geladen. Doch wenn ich diese Webpage jetzt aufrufen will, erscheint nur ein weisser Bildschirm, woran kann das liegen?
    gruß David

  9. Die SD Karte ist in FAT 16 Formatiert und die Datei heisst „Arduino Web“.

  10. Heißt die Datei „Arduino Web“ oder „Arduino.Web“?

    Auf die Spezifikationen von fat16 achten.
    8.3 Dateinamensformat
    max 65.536 Einträge möglich
    davon max 512 Dateien im Rootverzeichnis
    eine Datei darf max 2GB groß sein.

  11. Die entsprechende Stelle im loop einfach durch das hier erweitern.


    if (c == '\n' && currentLineIsBlank)
    {
    client.println(F("HTTP/1.1 200 OK"));
    client.println(F("Content-Type: text/html"));
    client.println(F("Connection: keep-alive"));
    client.println();

    if (StrContains(HTTP_req, "GET / ") || StrContains(HTTP_req, "GET /index.htm")) webFile = SD.open("index.htm");
    else if (StrContains(HTTP_req, "GET /page2.htm")) webFile = SD.open("page2.htm");
    else if (StrContains(HTTP_req, "GET /page3.htm")) webFile = SD.open("page3.htm");
    else if (StrContains(HTTP_req, "GET /page4.htm")) webFile = SD.open("page4.htm");

    if (webFile)
    {
    while(webFile.available())
    {
    client.write(webFile.read());
    }
    webFile.close();
    }
    }


    char StrContains(char *str, char *sfind)
    {
    char found = 0;
    char index = 0;
    char len;

    len = strlen(str);

    if (strlen(sfind) > len) {
    return 0;
    }
    while (index < len) { if (str[index] == sfind[found]) { found++; if (strlen(sfind) == found) { return 1; } } else { found = 0; } index++; } return 0; }

  12. Thak you, but when I upload this code to Arduino i got the error: ‚HTTP_req‘ was not declared in this scop. Please help me, what am I doing wrong ? This is the code:

    #if ARDUINO > 18
    #include // Für Arduino Version größer als 0018
    #endif
    #include
    #include
    #include

    byte mac[] = { 0x5A, 0xA2, 0xDA, 0x0D, 0x56, 0x7A }; // MAC-Adresse des Ethernet-Shield
    byte ip[] = { 192, 168, 2, 102 }; // IP zum aufrufen des Webservers
    byte sdPin = 4; // Pin der SD-Karte
    EthernetServer server(80); // Server port
    File webFile;

    void setup()
    {
    Ethernet.begin(mac, ip); // Client starten
    server.begin(); // Server starten
    Serial.begin(9600);
    Serial.println(„ARDUINO – STEUERUNG“);

    Serial.println(„Initialisiere SD-Karte…“);
    if (!SD.begin(sdPin))
    {
    Serial.println(“ – Initialisierung der SD-Karte fehlgeschlagen!“);
    return;
    }
    Serial.println(“ – SD-Karte erfolgreich initialisiert.“);

    if (!SD.exists(„index.htm“))
    {
    Serial.println(“ – Datei (index.htm) wurde nicht gefunden!“);
    return;
    }
    Serial.println(“ – Datei (index.htm) wurde gefunden.“);

    Serial.println();
    Serial.println(„Verbraucher schalten“);
    }

    void loop()
    {
    EthernetClient client = server.available(); // Auf Anfrage warten

    if(client)
    {
    /*****************************************
    Ausgänge über das Webformular steuern *
    *****************************************/
    TextFinder finder(client);

    if(finder.find(„GET“))
    {
    while(finder.findUntil(„pin“, „\n\r“))
    {
    char typ = client.read();
    int pin = finder.getValue();
    int val = finder.getValue();

    if(typ == ‚D‘)
    {
    pinMode(pin, OUTPUT);
    digitalWrite(pin, val);
    Serial.print(“ – D“+String(pin));
    }
    else if(typ == ‚A‘)
    {
    analogWrite(pin, val);
    Serial.print(“ – A“+String(pin));
    }
    else Serial.print(“ – Falscher Typ“);

    if(val==1) Serial.println(“ ein“); else Serial.println(“ aus“);
    }
    }

    /************************
    Webformular anzeigen *
    ************************/
    boolean current_line_is_blank = true; // eine HTTP-Anfrage endet mit einer Leerzeile und einer neuen Zeile

    while (client.connected())
    {
    if (client.available()) // Wenn Daten vom Server empfangen werden
    {
    char c = client.read(); // empfangene Zeichen einlesen
    if (c == ‚\n‘ && current_line_is_blank) // wenn neue Zeile und Leerzeile empfangen
    {
    client.println(F(„HTTP/1.1 200 OK“));
    client.println(F(„Content-Type: text/html“));
    client.println(F(„Connection: keep-alive“));
    client.println();

    if (StrContains(HTTP_req, „GET / „) || StrContains(HTTP_req, „GET /index.htm“)) webFile = SD.open(„index.htm“);
    else if (StrContains(HTTP_req, „GET /page2.htm“)) webFile = SD.open(„page2.htm“);
    else if (StrContains(HTTP_req, „GET /page3.htm“)) webFile = SD.open(„page3.htm“);
    else if (StrContains(HTTP_req, „GET /page4.htm“)) webFile = SD.open(„page4.htm“);

    if (webFile)
    {
    while(webFile.available())
    {
    client.write(webFile.read());
    }
    webFile.close();
    }
    }

    char StrContains(char *str, char *sfind)
    {
    char found = 0;
    char index = 0;
    char len;

    len = strlen(str);

    if (strlen(sfind) > len) {
    return 0;
    }
    while (index < len) {
    if (str[index] == sfind[found]) {
    found++;
    if (strlen(sfind) == found) {
    return 1;
    }
    }
    else {
    found = 0;
    }
    index++;
    }

    return 0;
    }

  13. Hallo,
    Die Beschreibung hört sich sehr interessant an.
    Da ich mich für den Nachbau noch eine Micro SD Karte besorgen muss, wollte ich fragen ob es es eine Beschrenkung in der Speichergröße gibt. Die „kleinen“ Karten z.B. 2GB gibt es ja kaum noch zu kaufen. Habt Ihr da irgendwelche Informationen?
    Turtle 247

  14. Hallo,
    gibt es auch die Möglichkeit, den Html Code direkt in den Code mit einzubinden, also ohne eine SD Karte?

    Gruß

    Turtle 247

  15. Klar gibt es die Möglichkeit, allerdings wirst Du da nicht weit kommen weil der Speicher des Arduino dann sehr schnell voll ist und nichts mehr funktionieren wird.

  16. Es gibt eine Beschränkung. Die Größe der SD Karte sollte bis 32GB funktionieren.
    Ich selber habe 32GB SD Karten ohne Probleme verwendet.

  17. Toll, bei mir geht es und es macht lust auf mehr,
    Beim Versuch auf dem Arduino gleichzeitig ein i2c Display anzusteuern bin ich aber gescheitert. Sobald ein “ lcd.print(„Webserver gestartet“); “ ausgeführt wird, ist die Website nicht mehr erreichbar.

    Was mache ich falsch?

    Mein kompletter Code sieht jetzt so aus:

    #if ARDUINO > 18
    #include // Für Arduino Version größer als 0018
    #endif
    #include
    #include
    #include

    //JS Display
    #include
    #include

    LiquidCrystal_I2C lcd(0x3F,20,4); // set the LCD address to 0x3F for a 20 chars and 4 line display

    //JS Display END

    byte mac[] = { 0x5A, 0xA2, 0xDA, 0x0D, 0x56, 0x7A }; // MAC-Adresse des Ethernet-Shield
    byte ip[] = { 192, 168, 178, 222 }; // IP zum aufrufen des Webservers
    byte sdPin = 4; // Pin der SD-Karte

    EthernetServer server(80); // Server port

    File webFile;

    void setup()
    {
    Ethernet.begin(mac, ip); // Client starten
    server.begin(); // Server starten
    Serial.begin(9600);
    Serial.println(„ARDUINO – STEUERUNG“);

    Serial.println(„Initialisiere SD-Karte…“);
    if (!SD.begin(sdPin))
    {
    Serial.println(“ – Initialisierung der SD-Karte fehlgeschlagen!“);
    return;
    }
    Serial.println(“ – SD-Karte erfolgreich initialisiert.“);

    if (!SD.exists(„index.htm“))
    {
    Serial.println(“ – Datei (index.htm) wurde nicht gefunden!“);
    return;
    }
    Serial.println(“ – Datei (index.htm) wurde gefunden.“);

    Serial.println();
    Serial.println(„Verbraucher schalten“);

    //JS Display
    lcd.init(); // initialize the lcd
    lcd.init();
    // Print a message to the LCD.
    lcd.backlight();
    lcd.setCursor(0,0);
    lcd.print(„Webserver gestartet“);
    // lcd.setCursor(0,1);
    // lcd.print(„IP 192.168.178.222″);

    //JS Display END
    }

    void loop()
    {
    EthernetClient client = server.available(); // Auf Anfrage warten

    if(client)
    {
    /*****************************************
    Ausgänge über das Webformular steuern *
    *****************************************/
    TextFinder finder(client);

    if(finder.find(„GET“))
    {
    while(finder.findUntil(„pin“, „\n\r“))
    {
    char typ = client.read();
    int pin = finder.getValue();
    int val = finder.getValue();

    if(typ == ‚D‘)
    {
    pinMode(pin, OUTPUT);
    digitalWrite(pin, val);
    Serial.print(“ – D“+String(pin));
    }
    else if(typ == ‚A‘)
    {
    analogWrite(pin, val);
    Serial.print(“ – A“+String(pin));
    }
    else Serial.print(“ – Falscher Typ“);

    if(val==1) Serial.println(“ ein“); else Serial.println(“ aus“);
    }
    }

    /************************
    Webformular anzeigen *
    ************************/
    boolean current_line_is_blank = true; // eine HTTP-Anfrage endet mit einer Leerzeile und einer neuen Zeile

    while (client.connected())
    {
    if (client.available()) // Wenn Daten vom Server empfangen werden
    {
    char c = client.read(); // empfangene Zeichen einlesen
    if (c == ‚\n‘ && current_line_is_blank) // wenn neue Zeile und Leerzeile empfangen
    { // Standard HTTP Header senden
    client.println(„HTTP/1.1 200 OK“);
    client.println(„Content-Type: text/html“);
    client.println(„Connection: close“);
    client.println();

    // Website von SD-Karte laden
    webFile = SD.open(„index.htm“); // Website laden
    if (webFile)
    {
    while(webFile.available())
    {
    client.write(webFile.read()); // Website an Client schicken
    }
    webFile.close();
    }
    break;
    }
    if (c == ‚\n‘)
    {
    current_line_is_blank = true;
    }
    else if (c != ‚\r‘)
    {
    current_line_is_blank = false;
    }
    }
    }
    delay(1);
    client.stop();
    }
    }

  18. you can have the Sketch html correct? I can not see the colored buttons, but only the terms ein aus.
    Thank You

    Sie können die Skizze html korrigieren? Ich kann nicht sehen die farbigen Tasten, aber nur die Begriffe ein aus.
    Danke

  19. Hallo,
    sehr gute Beschreibung.
    Habe mit CSS die Button toll hinbekommen. Die CSS Styles jedoch in das html File integrieren müssen. Eine Speicherung in ein externen CSS File auf die SD Karte hat nicht geklappt. Ist soweit auch nicht schlimm.
    Rufe ich die seite im Heimnetz direkt über die IP Nummer auf werden alle Button (12 Stück) angezeigt. über das Internet werden teilweise nur 3 – 6 angezeigt. Wie kann ich das ändern?
    Gruss
    Qtreiber

  20. Hallo Enrico!
    Sieht echt gut aus und hat auf Anhieb funktioniert. Ich finde auch klasse, das ich nur auf der HTML- Seite ändern muss, wenn ich weitere Digitalausgänge setzen möchte! Da ich Anfänger bin, habe ich noch folgende Probleme: 1.) Wenn ich (oder ein anderer Benutzer) auf die Webseite zugreife, sollte der aktuelle Status des jeweiligen Ausgangs (rot oder grün für aus oder ein) angezeigt werden. Unter Firefox 36.0.4 kriege ich leider keine farbige Anzeige wie auf oben auf Deinem Bild.; dasselbe im Internet Explorer. 2.) Welcher Code muss im Sketch hinzugefügt werden, wenn ich ausserhalb meines WLAN/ LAN über die Fritzbox zugreifen möchte? Ich hoffe, Du kannst mir bei beiden Dingen die fehlenden Codezeilen zur Verfügung stellen; ich hab schon auf vielen Arduino- Seiten gesucht und viele Sketches ausprobiert und bin langsam am Verzweifeln weil mir keiner richtig helfen konnte.

    Danke + viele Grüße

    Peter

  21. Hallo!

    Was total sinnvoll wäre wenn man eine Art htaccess Passwortschutz gegen ungewünschten Zugriff einbauen könnte.
    Bin zB gerade daran einen kleinen Webserver zu reallisieren der von „aussen“ erreichbar ist, damit ich mein Einfahrtstor jederzeit für Lieferanten aufmachen kann per Tastendruck.
    Jetzt sollte das natürlich nicht für jeden so einfach zugänglich sein und mein Tor auch nicht die ganze Zeit auf und zu gehen ;-)

    Hat wer eine Idee wie ich eine halbwegs sichere User/Password Abfrage integrieren kann?

    lg

  22. Hallo, ich arbeite mich gerade in die Materie ein und es funktioniert gut!
    Ich habe die index.htm nach meinen Wünschen verändert. Leider schaffe ich es nicht, Grafiken (z.B. für AUS und EIN) anzuzeigen.
    Sicher stimmt der Pfad nicht, ich habe aber keine Idee, wie der lauten muss, damit die Grafiken, die ich auch im root-Verzeichnis der Karte sind, angezeigt werden.

    Hat da jemand einen Tipp für mich?

Kommentar verfassen