Micro-SD File Server mit D1 Mini - AZ-Delivery

Questo contributo descrive un server Web su uno D1 mini i contenuti di una Carta SD Micro rendono disponibili al trasferimento di dati. Siccome un lettore di mappa entra Modulo di mappa di micromemoria per l'applicazione. Il hardware è abbastanza facile. La mappa leggendo il modulo e D1 mini è collegata sopra l'allenatore SPI. Vedi il giro.

Giro:

 

Trova file STL per stampare un caso adatto su mio Profilo di Thinigiverse

 

Schizzo:

 

/*
 * Copyright (c) nel 2015, tecnologie di Majenko
 * Tutti i diritti riservati.
 * 
 * Ridistribuzione e uso in fonte e forme binarie, con o senza modifica,
 * l'ares ha permesso purché le condizioni seguenti ares d'idromele:
 * 
 * * Le ridistribuzioni di codice sorgente devono ritenere la suddetta nota sul diritto d'autore, questo
 * astuzia di condizioni e la rinuncia seguente.
 * 
 * * Le ridistribuzioni in forma binaria devono riprodurre la suddetta nota sul diritto d'autore, questo
 * astuzia di condizioni e la rinuncia seguente nella documentazione e / o
 * di altro materiale fornito la distribuzione.
 * 
 * * Né il nome di Majenko Technologies né i nomi del suo
 * i contributori possono Esser usati per approvare o promuovono prodotti derivati da
 * questo software senza permesso anteriormente scritto specifico.
 * 
 * IL SOFTWARE CHE QUESTO È PROVVISTO DAI PROPRIETARI DI DIRITTO D'AUTORE E I CONTRIBUTORI «COM'È» E
 * QUALSIASI TRENO ESPRESSO O GARANZIE IMPLICATE, COMPRESO, HANNO BISOGNO, MA LIMITATO A, L'IMPLICITO
 * GARANZIE DI COMMERCIABILITÀ E IDONEITÀ POSA PURA PER ARES PARTICOLARE
 * NEGATO. IN EVENTO NESSUN DIRITTO D'AUTORE DEVE ESSERE DI BELL'UNITÀ DI PANE O CONTRIBUTORI SOGGETTI A
 * QUALSIASI DANNI DIRETTI, INDIRETTI, SECONDARI, SPECIALI, ESEMPLARI, O CONSEGUENTI
 * (COMPRESO, NECESSITÀ MA LIMITATO A, ASSISTENTE OTTENIMENTO DI DIRETTORI DIPARTIMENTALE DI MERCI O DI SERVIZIO;
 * IL LOESS DI USO, I DATI, RICAVA BENEFICIO O; O INTERRUZIONE COMMERCIALE) COMUNQUE CAUSATO E SU
 * QUALSIASI TEORIA DI RESPONSABILITÀ, SE IN CONTRATTO, RESPONSABILITÀ SEVERA, INGIUSTIZIA O
 * (COMPRESO NEGLIGENZA O ALTRIMENTI) ALZANDOSI AD OGNI MODO DELL'USO DI QUESTO
 * SOFTWARE, ANCHE SE AVVISATO DELLA POSSIBILITÀ DI DANNO DI OCCHIATA.
 */

/* Generiamo un server Web come un punto di Accesso, i contenuti di una Carta SD Micro
 il trasferimento di dati di zuzm provvede alle necessità.
 Per la SD-carta gli SPI-spilli sono usati
 D5 = GPIO14 come un orologio
 D6 = GPIO12 come un MISO
 D7 = GPIO13 come un MOSI
 D8 = GPIO15 come un chip Scelto
  
 SSID usato = SD_Server
 la parola d'ordine = Micro
   
*/

//Server Web di cliente di biblioteca di Wifi
#include <ESP8266WiFi.H>
#include <WiFiClient.H> 
#include <ESP8266WebServer.H>
//Biblioteca sür allenatore SPI
#include <SPI.H>
//Biblioteca per sistema di SD-schedario
#include <SdFat.H>

può uint8_t chipSelect = SS;


//Sagoma per la pagina di HTML
può lavoro a giornata HTML_HEADER[] =
«<!DOCTYPE HTML>»;
«<html>»;
«<head>»;
«<meta chiamano = \«viewport \» i contenuti = \«la larghezza = la larghezza del dispositivo, la scala iniziale = 1.0, la scala massima = 1.0, user-scalable=0 \«>»;
«<title>SD-Card reader</title>»;
«<style>»;
«corpo {colore di sfondo: #d2f3eb; famiglia della serie completa di caratteri: Arial, Helvetica, Sans-grazia; Colore: #000000;font-size:12pt;}»
«</style>»;
«</head>»;
«<body><div disegna = 'il margine-left:30px; '>»;;
può lavoro a giornata HTML_END[] =
«</div></body>»;
«</html>»;;

//Variabili globali
//Autorità della biblioteca di SdFat
 SdFat sd;
 //Variabili di oggetto globali alla memoria di file ed Elenchi telefonici
 SdFile file;
 SdFile dirFile;
//Punto di accesso
può lavoro a giornata *ssid = «SD_Server»; //Nome del WLAN 
può lavoro a giornata *passaporto la Parola = «Micro»; //Parola d'ordine per il WLAN
//Bandiera per l'inizializzazione di SD-carta
bool sdinit = falso;



ESP8266WebServer server(80); //I server Web si mettono in moto su porto 80

//La funzione per determinare di ContentTypes secondo fine di file
Spago getContentType(Spago nome di file){   se(server.hasArg(«trasferimento di dati»)) ritornare «application/octet-stream»;   altro se(nome di file.endsWith(«.htm»)) ritornare «testo / html»;   altro se(nome di file.endsWith(«.html»)) ritornare «testo / html»;   altro se(nome di file.endsWith(«.css»)) ritornare «testo / css»;   altro se(nome di file.endsWith(«.js»)) ritornare «application/javascript»;   altro se(nome di file.endsWith(«.png»)) ritornare «immagine / png»;   altro se(nome di file.endsWith(«.gif»)) ritornare «immagine / gif»;   altro se(nome di file.endsWith(«.jpg»)) ritornare «immagine / jpeg»;   altro se(nome di file.endsWith(«.ico»)) ritornare «immagine / x-icona»;   altro se(nome di file.endsWith(«.xml»)) ritornare «testo / xml»;   altro se(nome di file.endsWith(«.pdf»)) ritornare «application/x-pdf»;   altro se(nome di file.endsWith(«.zip»)) ritornare «application/x-zip»;   altro se(nome di file.endsWith(«.gz»)) ritornare «application/x-gzip»;   ritornare «testo / pianura»;
}

//La funzione per mandare di un file
//Sentiero di parametro e nome di File
bool sendFile(Spago sentiero, Spago fn) {   lavoro a giornata cpath[512];   uint32_t filesize;   Spago contentType;   lavoro a giornata cname[256];   File myfile;   //Costruzione del nome di file intero    //e umspeichern in un Assortimento del Carattere   sentiero = sentiero+"/"+fn;   sentiero.toCharArray(cpath,512);   //Il file chiama il convertito in piccola lettera   //alla regolazione del tipo di file   fn.toLowerCase();   contentType = getContentType(fn);   //File aperto sulla carta SD   myfile = sd.aperto(sentiero, O_READ);   //e nel server Web streamen   server.streamFile(myfile, contentType);   //File vicino   file.vicino();   ritornare vero;

}

//Mandi una lista di file
bool sendDirectory(Spago sentiero) {   lavoro a giornata cpath[512];   uint16_t N = 0;   lavoro a giornata cname[256];   Spago subdir;   Spago genitore;   Spago nome;      sentiero.toCharArray(cpath,512);   //Proviamo ad aprire il sentiero   se (dirFile.aperto(cpath, O_READ)) {     //se l'azione è con successo ci mettiamo la lunghezza di contenuti sconosciuta     server.setContentLength(CONTENT_LENGTH_UNKNOWN);     //e mandi la Testata     server.mandare(200,  «testo / html»,HTML_HEADER);     WiFiClient cliente = server.cliente();     se (sentiero != "/") {       //se il sentiero sui Rootverzeichni non indica che aggiungiamo quel che       //Essere capace di diminuire la linea con«.» una intorno a un livello       genitore = sentiero;       //abbiamo bisogno della lista più alta       genitore.togliere(genitore.lastIndexOf("/"));       //e le forme da esso un collegamento che mandiamo al cliente       server.sendContent(«<a href = 'http://192.168.4.1/? A LEI =»);       server.sendContent(genitore);       server.sendContent(«'>..</a><br>»;);     }     //adesso le linee seguono per le entrate di lista     mentre (file.openNext(&dirFile, O_READ)) {       //all'inizio del collegamento mettiamo il sentiero       server.sendContent(«<a href = 'http://192.168.4.1/? A LEI =»);       server.sendContent(sentiero);       //Il nome di file legge       file.getName(cname,255);         nome = Spago(cname);       se (file.isDir()) {         //se l'entrata è un subelenco telefonico         //se sospendiamo questo al sentiero e chiudiamo il collegamento         subdir = "/"+nome;         server.sendContent(subdir);          server.sendContent("'>");            } altro {         //se è un file facile aggiungiamo il nome di file         server.sendContent(«&FN=»);         server.sendContent(nome);         //aggiungiamo al collegamento ancora «l'obiettivo =»» con esso il file         //in propria finestra è aperto.         //Allora chiudiamo il collegamento         server.sendContent(«'pongono come obiettivo = «>»;);       }       //alla fine il nome segue come un'etichetta per il collegamento       server.sendContent(nome);       //e la fine del collegamento così come un pasto di linea       server.sendContent(«</a><br>»;);      //File vicino      file.vicino();    }    //Dopo che tutte le entrate furono mandate, Direktory è chiuso    dirFile.vicino();    //Informi dei contenuti concludono il cliente e finiscono la connessione    server.sendContent(HTML_END);    cliente.arresto();    ritorno vero;   } altro {     ritorno falso;// errore impossibile aprire il percorso   }

}
// Questa funzione viene chiamata quando la richiesta al server web = "/"
vuoto handleRoot() {   // Inserisci il nome e il percorso del file con i valori predefiniti   stringa sentiero = "/";   stringa fn = "";   // Se la richiesta contiene argomenti appropriati   // Inserisci il percorso e il nome del file con i dati della richiesta   se (server.hasArg("DIR")) sentiero = server.cattivo("DIR");   se (server.hasArg("FN")) fn = server.cattivo("FN");   serial.stampare("Path");serial.stampare(sentiero);serial.stampare("File");serial.println(fn);   stringa nome;   // Se la scheda SD non è stata ancora inizializzata, inizializzarla   se (!sdinit) sdinit = sd.iniziare(chipselect, SD_SCK_MHZ(50));   se (sdinit) {     // Se l'inizializzazione ha avuto esito positivo, leggiamo i dati dalla scheda     se (fn=="") {       // Se non è stato fornito alcun nome file, proviamo a inviare una directory       se (!directory send(sentiero)) {         // Se non è stato possibile inviare la directory, impostiamo sdinit su false         // Dal momento che apparentemente non ci sono carte nel lettore. Inviamo un avviso al cliente         sdinit = falso;         server.trasmissione(200, "testo / html", "Nessuna scheda SD");       }     } altro {       // Altrimenti proviamo a inviare il file specificato       se (!sendfile(sentiero,fn)) {         // Se non è stato possibile inviare la directory, impostiamo sdinit su false         // Dal momento che apparentemente non ci sono carte nel lettore. Inviamo un avviso al cliente         sdinit = falso;         server.trasmissione(200, "testo / html", "Nessuna scheda SD");       }     }   } altro {     // Inizializzazione non riuscita     server.trasmissione(200, "testo / html", "Nessuna scheda SD");   }
}

// Prepara il processore
vuoto configurazione() {   serial.iniziare(115200);   serial.println();   serial.stampare("Configurazione del punto di accesso ...");   // Imposta il punto di accesso   WiFi.SofTap(ssid, password);   IPAddress MyIP = WiFi.softAPIP();   serial.stampare("Indirizzo IP AP:");   serial.println(MyIP);   // ip è sempre 192.168.4.1   // Definizione delle funzioni di risposta   server.su("/", handleRoot);   // avvia il server web   server.iniziare();   serial.println("Server HTTP avviato");
}

// loop principale
vuoto cappio() {   // Verifica la richiesta   server.cliente maniglia();
}

 

 

Spero che questo post sia stato utile e come sempre sono contento di commenti e feedback. Fino ad allora, passa un buon fine settimana!

Esp-8266Projekte für anfänger

19 commenti

Andreas Wolter

Andreas Wolter

@Andreas: die Libraries wurden teilweise komplett in den ESP Core integriert und/oder nicht weiter gepflegt. Ich würde daher versuchen, es komplett anders aufzubauen.
Wenn die Zeit es zulässt, werden wir versuchen, den Beitrag zu aktualisieren.

Grüße,
Andreas Wolter
AZ-Delivery Blog

Andreas

Andreas

Hallo,
ich habe mich heute Abend auch damit abgekämpft, diesen Sketch zum Laufen zu bringen. Auch ich bekomme die Fehlermeldung
‘operator=’ (operad types are ‘fs::File’ and ‘FsFile’)
Wenn ich es recht verstanden habe, kommt mit dem ESP8662-Library Paket auch eine FS.h, auf die dann von den anderen Libraries aus dem Paket zugegriffen wird. Und nun ist aber in unterschiedlichen Libraries der gleiche Ausdruck “File”, mit dem man die Variable “myfile” deklariert, vorhanden. Der Compiler weiß nun nicht, welche Deklaration aus welcher Library er für “File” verwenden soll. Es ist wohl ein Problem des ESP-Library-Pakets, das anscheinend auch nicht mehr gepflegt wird – jedenfalls hat ESP8266WiFi bei mir noch die Versionsnummer 1.0
Wie man das nun abstellt bzw. den Konflikt behebt, damit kenne ich mich leider zu wenig aus und bin auch aus den wenigen Foreneinträgen, die ich zu ähnlichen Problemen gefunden habe, nicht wirklich schlau geworden bzw. die Lösungscorschläge haben nicht funktioniert.

Markus

Markus

Hallo,

ich wäre auch an einer aktuellen Version interessiert. Leider sind meine eigenen Versuche bisher gescheitert :-( .

Grüße
Markus

Andreas Wolter

Andreas Wolter

aus Zeitgründen aktuell noch nicht.
Vielleicht finden SIe auch selbst eine Lösung, die wir dann hier zeigen können. Es gibt sehr viele neue und alte Bibliotheken, die zusammen funktionieren müssen.

Grüße,
Andreas Wolter

Markus

Markus

Hallo,
gibt es schon einen neuen Sketch mit der SD Bibliothek?

Grüße
Markus

Andreas Wolter

Andreas Wolter

ich habe mir das noch einmal angesehen. Es scheint, als wäre die Bibliothek und damit auch der Sketch in diesem Beitrag outdated. Wenn man den aktuellen ESP8266 Arduino Core installiert, wird dort die SD Bibliothek mit installiert. Außerdem die SDFAT Bibliothek. Beides scheint sich nicht zu vertragen. Wenn man nun noch versucht, manuell die angegebenen Bibliotheken zu installieren, geht das komplett in die Hose. Ich werde versuchen, mit der SD Bibliothek den Sketch zu aktualisieren. Das wird allerdings ein bisschen dauern.

Grüße,
Andreas Wolter
AZ-Delivery Blog

Norbert

Norbert

Danke Herr Wolter für die schnelle Antwort.
Ich habe leider immer noch keinen Erfolg.
Die entsprechenden Bibliotheken (Ihr angegebener Link) habe ich installiert.
Leider kommt beim Kompilieren In Zeile 124 : " myfile = sd.open(path, O_READ);"
der Fehler " no match for ‘operator=’ (operad types are ‘fs::File’ and ‘FsFile’)

Ich verwende Arduino IDE 1.8.15
Ich würde gern den Micro-SD File Server nachbauen!
Könnten Sie mir bitte noch einen Tipp geben wo der Fehler liegen könnte.
Leider bin ich Anfänger und kann mit den Fehlermeldungen wenig anfangen.
Ich bedanke mich für Ihre Bemühungen
und verbleibe mit freundlichen Grüßen
Norbert

Im Fehlerfenster erscheint folgendes in Rot:
C:\Users\norbe\Desktop\Stromzähler – Messwerterfassung\PC und WEB-Server\Versuch3\Versuch3.ino: In function ‘bool sendFile(String, String)’:
Versuch3:81:32: error: no match for ‘operator=’ (operand types are ‘fs::File’ and ‘FsFile’)
In file included from C:\Users\norbe\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\3.0.2\libraries\ESP8266WiFi\src/CertStoreBearSSL.h:26,
from C:\Users\norbe\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\3.0.2\libraries\ESP8266WiFi\src/WiFiClientSecureBearSSL.h:30,
from C:\Users\norbe\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\3.0.2\libraries\ESP8266WiFi\src/WiFiClientSecure.h:23,
from C:\Users\norbe\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\3.0.2\libraries\ESP8266WiFi\src/WiFiServerSecure.h:20,
from C:\Users\norbe\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\3.0.2\libraries\ESP8266WiFi\src/ESP8266WiFi.h:41,
from C:\Users\norbe\Desktop\Stromzähler – Messwerterfassung\PC und WEB-Server\Versuch3\Versuch3.ino:2:
C:\Users\norbe\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\3.0.2\cores\esp8266/FS.h:52:7: note: candidate: ‘fs::File& fs::File::operator=(const fs::File&)’
52 | class File : public Stream
| ^~~~
C:\Users\norbe\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\3.0.2\cores\esp8266/FS.h:52:7: note: no known conversion for argument 1 from ‘FsFile’ to ‘const fs::File&’
C:\Users\norbe\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\3.0.2\cores\esp8266/FS.h:52:7: note: candidate: ‘fs::File& fs::File::operator=(fs::File&&)’
C:\Users\norbe\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\3.0.2\cores\esp8266/FS.h:52:7: note: no known conversion for argument 1 from ‘FsFile’ to ‘fs::File&&’
Bibliothek ESP8266WiFi in Version 1.0 im Ordner: C:\Users\norbe\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\3.0.2\libraries\ESP8266WiFi wird verwendet
Bibliothek ESP8266WebServer in Version 1.0 im Ordner: C:\Users\norbe\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\3.0.2\libraries\ESP8266WebServer wird verwendet
Bibliothek SPI in Version 1.0 im Ordner: C:\Users\norbe\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\3.0.2\libraries\SPI wird verwendet
Bibliothek SdFat-2.1.1 in Version 2.1.1 im Ordner: C:\Users\norbe\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\3.0.2\libraries\SdFat-2.1.1 wird verwendet
exit status 1
no match for ‘operator=’ (operand types are ‘fs::File’ and ‘FsFile’)

Andreas Wolter

Andreas Wolter

Die SD-Card Bibliotheken finden Sie als Download auf der verlinkten Produktseite des SD-Card Moduls: https://cdn.shopify.com/s/files/1/1509/1638/files/Micro_Memory_Card_Arduino.rar?9306531954326920108

Wir ergänzen das im Beitrag

Andreas Wolter
AZ-Delivery Blog

Norbert Patschorke

Norbert Patschorke

Hallo,
ich möchte es gern nachbauen.
Aber ich finde nirgends die passende SDFAT-Bibliothek.
Bitte gebt mir eine Hinweis (Link).
Gruß Norbert

Lompe

Lompe

Postscriptum:

Am PC mit dem Chrome-Browser geht es auch nicht.
Auch nicht, wenn die Anzeige unsicherer Seiten zu gelassen ist.

Lompe

Lompe

Funktioniert einwandfrei auf dem WIN 10 pc im Browser (Firefox).
Aber nicht auf dem Android Smartphone wenn über den Access Point aufgerufen. Die Routinen werden abgearbeitet (Serial-Monitor der Arduino IDE zur Kontrolle) und die Seiten gesendet, aber auf dem Bildschirm des Smartphones erscheint nichts.

fritzoskar

fritzoskar

Gibt es einen funktionierenden Sketsch?
Grüße

Henkel

Henkel

Welche SDFat Library braucht man? Mit der hier geht es nicht!
https://github.com/greiman/SdFat

Bibliothek 1. ESP8266 2.6.3
Hardwareziel Wemos D1 Mini
Arduino 1.8.12
Fehlermeldungen:

In file included from L:\arduino-1.8.12\portable\sketchbook\libraries\SdFat\src/FatLib/FatLib.h:27:0,

from L:\arduino-1.8.12\portable\sketchbook\libraries\SdFat\src/SdFat.h:33, from L:\arduino-1.8.12\portable\sketchbook\ESP8266WebserverSD\ESP8266WebserverSD\ESP8266WebserverSD.ino:51:

L:\arduino-1.8.12\portable\sketchbook\libraries\SdFat\src/FatLib/ArduinoFiles.h:122:7: error: redefinition of ‘class fs::File’

class File : public FatFile, public Stream { ^

In file included from L:\arduino-1.8.12\portable\packages\esp8266\hardware\esp8266\2.6.3\libraries\ESP8266WiFi\src/CertStoreBearSSL.h:26:0,

from L:\arduino-1.8.12\portable\packages\esp8266\hardware\esp8266\2.6.3\libraries\ESP8266WiFi\src/WiFiClientSecureBearSSL.h:30, from L:\arduino-1.8.12\portable\packages\esp8266\hardware\esp8266\2.6.3\libraries\ESP8266WiFi\src/WiFiClientSecure.h:41, from L:\arduino-1.8.12\portable\packages\esp8266\hardware\esp8266\2.6.3\libraries\ESP8266WiFi\src/WiFiServerSecure.h:20, from L:\arduino-1.8.12\portable\packages\esp8266\hardware\esp8266\2.6.3\libraries\ESP8266WiFi\src/ESP8266WiFi.h:41, from L:\arduino-1.8.12\portable\sketchbook\ESP8266WebserverSD\ESP8266WebserverSD\ESP8266WebserverSD.ino:45:

L:\arduino-1.8.12\portable\packages\esp8266\hardware\esp8266\2.6.3\cores\esp8266/FS.h:52:7: error: previous definition of ‘class fs::File’

class File : public Stream ^

In file included from L:\arduino-1.8.12\portable\sketchbook\libraries\SdFat\src/FatLib/FatLib.h:28:0,

from L:\arduino-1.8.12\portable\sketchbook\libraries\SdFat\src/SdFat.h:33, from L:\arduino-1.8.12\portable\sketchbook\ESP8266WebserverSD\ESP8266WebserverSD\ESP8266WebserverSD.ino:51:

L:\arduino-1.8.12\portable\sketchbook\libraries\SdFat\src/FatLib/FatFileSystem.h: In member function ‘fs::File FatFileSystem::open(const char*, oflag_t)’:

L:\arduino-1.8.12\portable\sketchbook\libraries\SdFat\src/FatLib/FatFileSystem.h:95:13: error: ‘class fs::File’ has no member named ‘open’

tmpFile.open(vwd(), path, oflag); ^

Mehrere Bibliotheken wurden für “SdFat.h” gefunden
Benutzt: L:\arduino-1.8.12\portable\sketchbook\libraries\SdFat
Nicht benutzt: L:\arduino-1.8.12\portable\packages\esp8266\hardware\esp8266\2.6.3\libraries\ESP8266SdFat
exit status 1
Fehler beim Kompilieren für das Board LOLIN D1 R2 & mini.

Moritz

Moritz

That means i can serve files of the sd card? That would be nice even if it is slow!

jean-marie

jean-marie

Guten Abend, ich mache alle Projekte für Ihre Website.
Sie sind großartig, aber ich habe ein Problem mit der SDFAT-Bibliothek. Ich habe den Fehler “‘SdFat’ benennt keinen Typ”.
Kannst du mir helfen?
Ich habe schon im Netz gesucht aber ….
++

jm

Gerald

Gerald

Sorry, ich hatte das Programm vergessen. Ist jetzt dabei.

michael

michael

Hallo Gerald,
hast Du dafür kein Programm?
Grüße michael

michael

michael

Hallo, wo ist das Programm dazu?

Frank Eisenwiener

Frank Eisenwiener

Danke erstmal für die anregenden Projekte!

Irgendwie fehlt mir persönlich bei diesem hier aber die Software (oder habe ich was überlesen?)…

Gruß
Frank

Lascia un commento

Tutti i commenti vengono moderati prima della pubblicazione