Hier biete ich eine Vielzahl an Informationen und Projekten rund um den WLAN-fähigen Mikrocontroller.
Zu den vorgestellten Projekten gehört unter anderem eine NFC-Stempeluhr, die auf Basis des ESP8266 entwickelt wurde und es ermöglicht, die Arbeitszeiten von Mitarbeitern einfach und schnell zu erfassen.
Auch eine Ultraschall-Oltankmessung, die mit Hilfe des ESP8266 realisiert wurde, wird in der Kategorie vorgestellt. Mit diesem Projekt kann man den Füllstand von Tanks oder Behältern automatisch überwachen.
Ein weiteres spannendes Projekt, das in der Kategorie vorgestellt wird, ist ein Solartracker, der ebenfalls auf Basis des ESP8266 realisiert wurde. Mit diesem Projekt lässt sich eine Solarzelle automatisch ausrichten, um die maximale Menge an Sonnenlicht einzufangen und die Energieeffizienz zu maximieren.
Die Kategorie „ESP8266“ bietet somit eine umfangreiche Sammlung an Projekten und Tutorials, die sich an Anfänger und Fortgeschrittene in der Welt der Mikrocontroller-Programmierung richten.
Meine Zisterne sollte Füllstandsanzeige erhalten, die mittels ESP8266 über mein Wlan abrufbar ist. Analog meines Beitrags Öltanküberwachung Mqtt ESP8266 Ultraschall, habe ich mit selbem Prinzip eine Füllstandanzeige für die Zisterne konstruiert. Der Aufbau ist prinzipiell identisch. Allerdings gab es bei diesem Anwendungsfall einige Besonderheiten.
Das WLAN Signal des ESP8266 ist aus einer 3 m tief im Erdreich vergrabenen Betonzisterne nicht mehr zu messen. Eine Montage neben der Zisterne im Freien wäre möglich gewesen, wollte ich für mich aber vermeiden.
Ich setzte das Ultraschall-Modul AJ-SR04M ein. In der Anleitung steht, dass der Sensor eine Temperaturabhängigkeit besitzt und die analoge Messleitung ist definitiv zu kurz für die Strecke ins Haus. So muss die Messung in der Nähe des Sensors erfolgen.
Daraus ergaben sich folgende Probleme für mich
Wie bekomme die Stromversorgung in die Zisterne
Wie bekomme ich die Messdaten aus der Zisterne.
Lösungsansatz
Mein Lösungsansatz ist es, den ESP8266 im Haus zu installieren und den Sensor mit Ultraschall-Modul AJ-SR04M im Einstiegsschacht der Zisterne anzubringen. Zusätzlich habe ich hier noch eine Steckdose für eine spätere Tauchpumpe angebracht.
Signal und Spannungsversorgung AJ-SR04M zu ESP8266
In meinem Fall sind es vom Haus bis zur Zisterne 5 m Kabelweg. Ich verwende ein geschirmtes 4 x 0,22 mm² Kabel, dass ich im Erdreich, geschützt mit Wellrohr, zusammen mit der Spannungsversorgung für die Steckdose, eingebracht habe. Bei dieser Länge von Leitung ist der Spannungsabfall sehr gering. Sodass ich keine Bedenken hatte, dass der Sensor unter einer zu geringen Spannungsversorgung zu leiden hat. Der AJ-SR04M kann in einem Spannungsbereich von 3,0V bis 5,5V betrieben werden.
Das gilt aber nur für die Spannungsversorgung. Das Signal der Messleitung von AJ-SR04M zu ESP8266 kann hier recht schnell an seine Grenzen kommen. In meinem Fall erhielt ich für meine Entfernung nach einem Testlauf verlässliche Daten.
Das muss aber nicht immer klappen und vielleicht ist zu überlegen, ob die Entfernung eine andere Art der Kommunikation benötigt. RS-232 oder MAX323 zum Beispiel. Dabei könnte dann auch eine höhere Versorgungsspannung genutzt werden, die dann auf die benötigten 3,0V bis 5,5V verringert werden.
Je nach Projekt lässt sich die Leitung und die einzelnen Komponenten außerhalb des Erdreichs testen. Das wäre zu empfehlen.
Ich habe einen Graben zwischen Haus und Zisterne ausgehoben und das Wellrohr mit beiden Leitungen in 60 cm Tiefe vergraben. Für die Einführung in die Zisterne konnte ich einen Ziegel entfernen. Mit einer Bohrung durch die Hauswand waren die Kabel schnell ins Innere gebracht. Der Durchbruch wieder ordnungsgemäß verschlossen werden.
Anbringung Ultraschall-Sensor
Den Ultraschallsensor des AJ-SR04M habe ich in einem ca. 1,20 m langen Aluminiumrohr eingesteckt und das Kabel am anderen Ende herausgeführt. Damit konnte ich die Distanz zwischen Schachtwand und Wasseroberfläche so verkürzen, dass mein Sensor ca. 20 cm über der Wasseroberfläche hängt. Der AJ-SR04M benötigt einen Mindestabstand von ca. 20 cm. Das ist dem Datenblatt zu entnehmen. Auch die Abstrahlung der Signale gilt es zu berücksichtigen. Ist der Sensor zu weit an der Schachtwand, wird das Signal von der Schachtwand reflektiert. Bei der Auswahl des Aluminiumrohrs habe ich den Durchmesser des Sensors berücksichtigt. Zwei Schellen halten das Rohr an Ort und Stelle.
Zisterne-Ultraschall-Fuellstand-Sensor-Rohr
Anbringung AJ-SR04M Messplatine
Die Messplatine habe ich im wasserdichten Steckdosengehäuse untergebracht. So könnte ich den Sensor austauschen, falls dieser irgendwann erneuert werden müsste. Die zusätzliche Steckdose habe ich für eine spätere Tauchpumpe vorgesehen. Da die AJ-SR04M Messplatine von beiden Seiten angeschlossen wird, konnte ich die feste Verkabelung zum Haus im Inneren des Gehäuses unterbringen und den steckbaren Sensor von der Vorderseite anbringen.
Die Spannungsversorgung habe ich direkt an den ESP8266 angeschlossen. Die Datenleitungen sind an PIN D6 und D7 angeschlossen. Bei meinem ESP möchte ich den externen Antennenanschluss verwenden. Mein Kellerraum schirmt sehr gut Wlan Signale ab. Die zusätzliche Antenne verbessert den Empfang und die Sendeleistung. Diese Komponenten habe ich in einer Aufputzdose neben dem Durchbruch angebracht. Die Stromversorgung habe ich über ein handelsübliches Microusb Ladekabel hergestellt.
Ich sammle die Sensordaten meiner verschiedenen Projekte auf einem zentralen Server. Dafür übertrage ich die Messergebnisse per WLAN und MQTT. Den Source dazu habe ich auch im Projekt Öltanküberwachung Mqtt ESP8266 Ultraschall angefügt.
Aussicht
Ich verwende die Messdaten aus meiner Zisterne aktuell nur zur Anzeige und speichere die Daten für mögliche „historische“ Rückschlüsse.
Möglich wäre natürlich auch, die Daten direkt als Webseite vom ESP8266 abzurufen.
Als Trockenlaufschutz für eine Tauchpumpe
Als Leckageschutz, um Undichtigkeiten der Zisterne zu erkennen
In diesem Beitrag zeige ich wie ich meine Öltanküberwachung mit Hilfe von Ultraschall und dem Mikrocontroller ESP8266 umgesetzt habe. Ultraschall wird genutzt, um den Füllstand des Öltanks zu messen, während der ESP8266 die Daten erfasst und via MQTT (Message Queuing Telemetry Transport) an einen Empfänger überträgt.
Durch die Verwendung von MQTT können die Daten problemlos an einen Empfänger, Server oder IoT Device übertragen werden, wo die Daten in Echtzeit überwacht und / oder gespeichert werden können.
Achtung: Der Umgang mit brennbaren Flüssigkeiten ist gefährlich. Ich weise auf den Haftungsausschluss am Ende meines Berichts hin. Die ist ein rein informativer Beitrag. Keine Nachbauanleitung.
Prinzip
Ultraschallsensor
Das Prinzip der Messung mit Ultraschall im Öltank beruht auf der Laufzeitmessung von Schallwellen. Der Ultraschallsensor AJ-SR04M sendet dabei Schallwellen aus, die an der Oberfläche des Öls reflektiert werden. Die reflektierten Schallwellen werden vom Sensor erfasst und die Laufzeit der Schallwellen wird gemessen. Aus dieser Laufzeit kann dann der Abstand zwischen Sensor und Öl-Oberfläche berechnet werden. Da sich der Füllstand im Tank ändert, ändert sich auch der Abstand zwischen Sensor und Öl-Oberfläche, was zur Folge hat, dass sich die Laufzeit der Schallwellen verändert. Daraus ergibt sich eine Änderung des Abstandes und somit des Füllstandes im Tank.
Ultraschall Sensor AJ-SR04M
Mikrocontroller ESP8266 und MQTT
Der ESP8266 ist ein Mikrocontroller, der die Daten des Ultraschallsensors empfangen und verarbeiten kann. Dazu wird der Mikrocontroller mit dem Ultraschallsensor verbunden und es wird ein Programm erstellt, das die Daten des Sensors auswertet und in eine für den Empfänger lesbare Form bringt. Hierbei können zum Beispiel Messwerte oder ein Status-Update übertragen werden.
Die Auswertung der Daten im ESP8266 erfolgt dann in der Regel über ein Programm, das auf dem Mikrocontroller ausgeführt wird. In diesem Programm werden die Daten des Sensors ausgelesen, verarbeitet und ggf. auch gespeichert. Hierbei können verschiedene Methoden zur Datenverarbeitung genutzt werden, wie zum Beispiel die Berechnung von Durchschnittswerten oder die Überwachung von Schwellwerten. Anschließend können die Daten über das Wi-Fi-Modul des ESP8266 an einen Empfänger via MQTT übertragen werden, um sie zu visualisieren oder weitere Aktionen auszulösen.
Der Schaltplan zeigt die verwendeten Komponenten. Hauptsächlich ist der ESP8266 und der Ultraschallsensor AJ-SR04M wichtig. Der ESP ist durch die Pin Header J1 und J2 dargestellt. Die Pin Header J3 stellen den AJ-SR04M dar.
Ich erstelle meine Platinen und Schaltpläne gerne mit Pin Headern, da ich auf den fertigen Platinen, dann die Komponenten auswechseln oder wiederverwenden kann.
Zusätzlich verwende ich hier einen 5V Spannungsregler U1, da die Energieversorgung und deren Spannung zum Zeitpunkt der konzeption noch nicht fest lag. Die Spannungsversorgung (Batteriefach, Netzteil) wird hier an die Pin Header J5 angeschlossen.
Der Widerstand R1 470 Ohm dient der Spannungsüberwachung der Energieversorgung an J5. Je nach Energiequelle muss dieser gegebenenfalls angepasst werden. Die Spannungsüberwachung kann auch vernachlässigt werden, wenn das Projekt an einer festen Spannungsquelle wie einem Netzteil versorgt wird oder beim Ausbleiben der Messwerte die Öltanküberwachung überprüft wird. In meinem Fall verwende ich später möglicherweise eine Batteriebox. Da ist es für mich interessant die sinkende Spannung der Batterien zu überwachen um abzuschätzen, wann die Öltanküberwachung ausfallen wird.
Über den Pin Header J4 steuere ich, dass der ESP8266 aus dem Deep Sleep wieder erwachen kann. Soll die Software angepasst werden, muss hier nur ein USB Stecker für das Update eingesteckt werden und der Jumper vom Pin Header J4 entfernt werden.
Platine Ultraschall Sensor mit ESP8266
Platine ESP8266 AJ-SR04M Ultraschall Sensor
Aus dem Schaltplan, den ich mithilfe von Fritzing erstellt habe, layoutete ich meine Platine. Dabei versuche ich auf eine platzsparendes Layout zu setzten. Dies ist nicht immer leicht, da die Bedienbarkeit oder Erreichbarkeit der Schnittstellen, Jumper oder Buttons für mich auch eine wichtige Rolle spielt. Kreuzungen der Leiterbahnen sind nur durch weitere Schichten auf der Leiterplatte PCB möglich. Im heutigen Produktionsprozess nicht mehr unbedingt ein Kostenfaktor, dennoch möchte ich gerne darauf verzichten. Zu komplex ist das Projekt nun aus meiner Sicht auch nicht.
So wurde hier der Ultraschallsensor AJ-SR04M, der mit einem abgewinkelten Pin Header angeliefert wurde, senkrecht auf die Platine gestellt. Die Besonderheit bei der Platine des Ultraschallsensors ist, dass die Komponenten der Platine beidseitig angebracht sind. Der Anschluss des Ultraschallmesskopfs ist auf der Unterseite.
Beim ESP8366 war es mir wichtig den USB Anschluss und den Reset-Button gut zugänglich zu haben.
Hergestellt wurde meine Platine von Aisler, die praktischerweise direkt in der Fritzing Software angeknüpft sind.
Zuerst erstellte ich mit Hilfe von Foren und anderen Bloggern eine Funktion um die Messung der Entfernung über den Ultraschallsensor AJ-SR04M zu bewerkstelligung. Ich baue eine Serielle Kommunikation zwischen ESP8266 und dem Ultraschallmodul auf.
Das oben beschriebene Messprinzip wird mit folgenden Funktionen durchgeführt. Ich wiederhole meine Messungen und berechne den Mittelwert der plausiblen Messwerte, um Schwankungen oder Messfehlern vorzubeugen. Es ist darauf zu achten, dass die Laufzeiten der Schallwellen jeder Messung sich nicht überschneiden.
Wenn die Entfernung zwischen Ultraschallsensor und Öloberfläche bestimmt wurde, sende ich die Daten mittels ESP8266 -> MQTT -> WIFI an meinen Server. Dieser nimmt die Daten entgegen, speichert diese ab und errechnet Füllmengen.
Die Ermittlung der Daten und das übertragen der Daten ist für mich ausreichend als Aufgabe für den ESP8266. Diese Aufgabe überlasse ich absichtlich dem Server. Der ESP8266 kann natürlich deutlich mehr. Es wäre auch möglich die Füllmengen direkt ausrechnen zu lassen oder die Daten über einen installierten Webserver direkt im Lan oder WAN anzuzeigen.
In meinem Fall wollte ich wenig energieraubende Aufgaben an den ESP8266 abgeben. Dieser ist schon mit WLAN und Ultraschallsensor beschäftigt. Nach erfolgreicher Messung und übertragung der Daten mittels MQTT geht der ESP8266 für 30 Minuten in den Deep Sleep um Energie zu sparen. Die Loop-Funktion bleibt in diesem Fall leer.
Zusammengebaut
Zusammengebaut und mit einem Batteriefach als Spannungsversorgung habe ich das Projekt bei mir im Heizraum aufgebaut. Bei der Anbringung des Sensors sollte die Beschreibung des Herstellers berücksichtigt werden. Es kann Sein, dass Reflektionen der Tankwände die Messwerte verfälschen oder unbrauchbar machen. In meinem Fall ist der Sensor z.B. für kurze Distanzen ungeeignet und misst erst ab einer Entfernung von 20 cm mit einer Genauigkeit von 1-2 cm. In meinem Fall aber ausreichend.
ChrisBue Öltanküberwachung Ultraschall im EinsatzChrisBue Öltanküberwachung Ultraschall HeizraumChrisBue Öltanküberwachung Ultraschall mit BatterieboxUltraschall Sensor Öltank
Resümee
Ich muss hier anmerken, dass der Öltank schon älter ist und auch diese Öffnung sowie die „Sensorbefestigung“ nicht optimal sind. Dennoch sind die Messergebnisse doch sehr beeindruckend.
Die Energieversorgung möchte ich noch einmal überarbeiten und auch ein dauerhaft geschlossenes Gehäuse wäre sinnvoll.
Ein weiteres Projekt, bei dem der Ultraschallsensor AJ-SR04M und ein ESP8266 zum Einsatz kommen habe ich hier verlinkt. Beide Projekte sind vergleichbar. Jedes hatte aber kleine, unterschiedliche Herausforderungen.
Achtung: Ich weise hier ausdrücklich darauf hin, dass der Nachbau und/oder Einbau auf eigene Gefahr geschieht. Ich weise ebenfalls ausdrücklich darauf hin, dass ich für durch den Nach- und/oder Einbau der beschriebenen Projekte entstandene Personen oder Sachschäden keine Haftung übernehme.
Heute stelle ich meine NFC-Stempeluhr auf Basis eines ESP8266 Mikrocontrollers vor, die eine einfache und effektive Zeiterfassungslösung für jeden bietet. Durch das Scannen von NFC-Tags können Mitarbeiter schnell und einfach ein- und ausstempeln, während die Daten automatisch in einer Datenbank gespeichert werden.
Zielsetzung
Das Ziel dieses Projekts NFC ESP8266 besteht darin, eine eigene NFC-basierte Stempeluhr auf Basis des ESP8266 Mikrocontrollers zu entwickeln. Durch das Scannen von NFC-Tags sollen Mitarbeiter/Kollegen einfach und schnell ein- und ausstempeln können. Die Daten werden automatisch an einen Server gesendet, in einer Datenbank gespeichert und können für die Zeiterfassung genutzt werden. Zusätzlich zur Hardware soll auch die Software für den ESP8266 Microcontroller erstellt werden.
Umsetzung
Ich habe für die Realisierung meiner NFC-basierten Stempeluhr auf Basis des ESP8266 Mikrocontrollers eine eigene Platine entworfen und hergestellt. Dies ermöglichte mir eine optimale Anordnung der Komponenten und eine saubere Verdrahtung. Allerdings ist es nicht unbedingt notwendig, eine eigene Platine herzustellen, um dieses NFC ESP8266 Projekt umzusetzen. Es gibt viele Alternativen wie z.B. Lochrasterplatinen oder Prototyping-Shields, die es Ihnen ermöglichen, die Hardwarekomponenten auf einfache Weise zu verbinden. Letztendlich hängt die Wahl der Platine davon ab, wie anspruchsvoll das Projekt ist und welche Komponenten verwendet werden.
Als erstes musste ich den Schaltplan erstellen. Hierfür verwendete ich das das kostenlose Layout-Tool Fritzing verwenden. Ich plaziete die Komponenten, einschließlich des ESP8266 Mikrocontrollers, des NFC-Lesegeräts, der NEO LED WS2812, des Summers und des Jumpers auf dem virtuellen Breadboard. Anschließend verknüpfte ich die Komponenten miteinander, um den Schaltplan zu erstellen.
In meinem Schaltplan verwende ich das RFID RC522 Modul von Funduino. Das Pinout von anderen Herstellern dieser fertigen Module kann variieren. In meinem Fall habe ich noch einen anderen Anbieter gefunden, der lediglich die Abfolge der Pins geändert hat.
Als Stromversorgung für mein Projekt verwende ich die USB Schnittstelle, die auf dem ESP8266 Wemos D1 bereits integriert ist. Darüber kann ich die Spannungen 5V und 3,3 Volt für meine Schaltung entnehmen.
Über einen Jumper-Schalter möchte ich den ESP8266 in zwei Modi versetzen können. Einmal um die Kommunikation zum WLan am Aufstellort herzustellen und um den ESP8266 dann in seinen Arbeitsbetrieb zu versetzten.
Die NEO LED WS2812 und der Summer dienen der Benutzerinteraktion, indem sie den Benutzer über erfolgreiche oder fehlgeschlagene Aktionen informieren.
Hinweis: In meinem Schaltplan ist eine RGB LED verbaut. Da zum Zeitpunkt der Erstellung ich keinen NEO LED WS2812 Plan zur Verfügung hatte, der das DIP Lochmuster der WS2812 darstellt.
Platine
Nachdem ich das Design abgeschlossen hatte, habe ich die Platine über die Plattform Aisler herstellen lassen. Aisler ist ein Online-Service, der benutzerdefinierte Platinenherstellung anbietet. Ich habe das Design meiner Platine hochgeladen und konnte innerhalb weniger Tage eine professionell gefertigte Platine erhalten.
Die Verwendung von Aisler bot mir eine effiziente Möglichkeit, meine Platine herzustellen, ohne dass ich eigene Ausrüstung oder Erfahrung mit der Herstellung von Platinen haben musste. Die fertige Platine passte perfekt zu meinem Design und konnte nahtlos in das Projekt integriert werden.
Insgesamt war die Verwendung von Fritzing und Aisler eine großartige Möglichkeit, meine eigene Platine für das NFC Stempeluhr ESP8266 DIY Projekt zu erstellen und sicherzustellen, dass das Projekt auch für mich als Laie umgesetzt werden konnte.
Die Software für das NFC Stempeluhr ESP8266 DIY Projekt wurde mit der Arduino Integrated Development Environment (IDE) erstellt. Arduino ist eine Open-Source-Plattform, die häufig für die Entwicklung von Mikrocontroller-basierten Projekten wie diesem verwendet wird.
In der Arduino IDE konnte ich den ESP8266 Mikrocontroller programmieren und die verschiedenen Komponenten des Projekts steuern. Ich habe die notwendigen Bibliotheken und Sketche verwendet, um sicherzustellen, dass die NFC-Lese- und Schreibfunktionen sowie die LED und der Summer korrekt funktionieren.
Darüber hinaus habe ich auch die WLAN-Verbindung des ESP8266 programmiert, die es ermöglicht, die Stempeluhr über das lokale Netzwerk zu verbinden und die erfassten Arbeitszeiten auf einem Server zu speichern.
Konfigurationsmodus über Jumper-Schalter
Um die WLAN-Verbindung des NFC Stempeluhr ESP8266 DIY Projekts zu konfigurieren, wurde ein spezieller Konfigurationsmodus implementiert. Der Konfigurationsmodus wird gestartet, indem ein physischer Jumper-Schalter auf der Platine betätigt wird.
Sobald der Konfigurationsmodus gestartet ist, wird der ESP8266 zu einem Access Point (AP) und erzeugt ein WLAN-Signal. Dieses WLAN-Signal kann vom Benutzer erkannt werden, der sich dann mit dem Access Point verbindet.
Nachdem der Benutzer mit dem Access Point verbunden ist, kann er eine spezielle Webseite aufrufen, auf der er die SSID und das Passwort des vorhandenen WLAN-Netzwerks eingeben kann, mit dem er sich verbinden möchte.
Sobald der Benutzer die entsprechenden Informationen eingegeben hat, speichert der ESP8266 die WLAN-Verbindungsinformationen und verwendet sie bei zukünftigen Verbindungen mit dem Netzwerk.
Durch die Verwendung dieses Konfigurationsmodus können Benutzer die WLAN-Verbindung des NFC Stempeluhr ESP8266 DIY Projekts auf einfache Weise konfigurieren, ohne dass sie zusätzliche Hardware oder komplexe Software-Konfigurationen benötigen.
Normalbetrieb
Im Normalbetrieb erfasst die NFC Stempeluhr ESP8266 DIY die Stempelzeit von Benutzern, die ihre NFC-Karte oder ihr NFC-Tag an die Stempeluhr halten. Die NFC-Lesefunktion wird von einem NFC-Lesemodul bereitgestellt, das an den ESP8266 Mikrokontroller angeschlossen ist.
Wenn ein Benutzer seine NFC-Karte oder seinen NFC-Tag an die Stempeluhr hält, erkennt das NFC-Lesemodul die Karte oder den Tag und liest die darauf gespeicherten Informationen. Die Stempeluhr sendet die gelesenen Informationen an den Server. Dieser vergleicht die Daten mit einer Liste von Benutzern und speichert den Zeitpunkt der Aktion als Arbeitszeit in einer Datenbank.
Die URL des Servers und ein paar wenige Parameter lassen sich über die Oberfläche einstellen.
Netzwerk Konfigurationsparameter
ssid -> Name des WLan Netzwerks
pass ->Passwort zum WLan Netzwerk
IP -> eigene IP Adresse
gateway -> Netzwerkdateway
subnet -> Subnetzmaske
DNS -> Adresse des DNS-Servers
Dynamische Parameter
mac -> MAC-Adresse der NFC Stempeluhr
card -> ID der Karte, die an das NFC Lesegerät gehalten wurde
pass -> Ein Schlüssel der in MD5 übertragen wird zur Berechtigung der Anfrage
url -> Anfrage URL Server.
Die Stempeluhr gibt außerdem Feedback an den Benutzer durch die Verwendung einer LED und eines Summer.
#include <SPI.h>
#include <MFRC522.h>
#include <Adafruit_NeoPixel.h>
#include <EEPROM.h>
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <ESP8266HTTPClient.h>
#include <MD5Builder.h>
// System Status
int configMode = 0; // Einstellung
int systemStatus = 0; // 0 = OK , 1 = Error, 2 = Notice
int statusCount = 0; // Zähler für LEDs
// Webserver
const char* config_mode_ssid = "NFC-CardClock"; // Enter SSID here
const char* config_mode_password = "start123"; //Enter Password here
IPAddress config_mode_local_ip(192,168,1,1);
IPAddress config_mode_gateway(192,168,1,1);
IPAddress config_mode_subnet(255,255,255,0);
ESP8266WebServer server(80);
typedef struct{
char ssid[32];
char pass[64];
IPAddress ip;
IPAddress gateway;
IPAddress subnet;
IPAddress dns;
char url[400];
char urlpost[400];
char urlpass[100];
} network;
network user_network;
struct URL {
String protocol = "";
String host = "";
String port = "";
String path = "";
} url;
// Prüft ob alle notwendigen eingegebenen Werte übertragen wurden.
byte user_checkup;
// Buzzer
int freqDeep=2200; // Hz
int freqNormal=2400; // Hz
int freqHeight=2550; // Hz
int buzzPin=16;
// Button
int buttonPin=4;
// NeoPixel
int neoLedPin=5;
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(1, neoLedPin, NEO_RGB + NEO_KHZ400);
MFRC522 mfrc522(15, 0);
MD5Builder _md5;
void setup() {
// Terminal
Serial.begin(115200);
delay(10);
yield();
// Neoleds
pixels.begin();
pixels.clear();
pixels.setPixelColor(0, pixels.Color(255, 255, 0));
pixels.show();
delay(10);
Serial.println();
Serial.println("Init System");
Serial.println();
// Card Reader
SPI.begin(); // Init SPI bus
mfrc522.PCD_Init(); // Init MFRC522
Serial.println("MFRC522 Card Reader details");
mfrc522.PCD_DumpVersionToSerial(); // Show details of PCD - MFRC522 Card Reader details
Serial.println();
// EEPROM
EEPROM.begin(sizeof(user_network));
EEPROM.get(0, user_network);
EEPROM.commit();
// Prüfen ob Config Mode
pinMode(buttonPin, INPUT_PULLUP);
configMode = digitalRead(buttonPin);
// CONFIG MODE
if(configMode == 0){
Serial.println("Config Mode -> Soft-AP");
String ssid_config_mode = config_mode_ssid + String( WiFi.macAddress() );
WiFi.softAPConfig(config_mode_local_ip, config_mode_gateway, config_mode_subnet);
Serial.println(WiFi.softAP(ssid_config_mode, config_mode_password) ? "Ready" : "Failed!");
server.on("/", handle_Config_Mode_OnConnect);
server.on("/config", handle_Config_Mode_Config);
server.on("/clearconfig", handle_Config_Mode_Clear_Config);
// NORMAL MODE
} else {
// ACCESS POINT vergessen.
WiFi.softAPdisconnect(true);
WiFi.disconnect();
Serial.println("Normal Mode -> wLan Network");
delay(200);
// Konfiguration aus EEPROM
// für Server verwenden
Serial.print("Connecting to ");
Serial.println(user_network.ssid);
// eigene IP
// DNS Server
// Gateway
// Subnet
WiFi.config(user_network.ip, user_network.dns, user_network.gateway, user_network.subnet);
// Verbindung zum wLan aufbauen.
WiFi.begin(user_network.ssid, user_network.pass);
delay(500);
while (WiFi.status() != WL_CONNECTED) {
Serial.print(".");
delay(500);
}
Serial.println("WiFi connected");
WiFi.setAutoReconnect(true);
WiFi.persistent(true);
server.on("/", handle_Normal_Mode_OnConnect);
}
server.onNotFound(handle_NotFound);
server.begin();
Serial.println("HTTP server started");
soundSystemStart();
}
void loop() {
delay(50);
statusCount++;
systemStatusControll();
// Webserver Client bedienen
server.handleClient();
// Ab hier ConfigMode
// im config mode keine Karten annehmen
if(configMode == 0){
systemStatus = 2;
// Look for new cards
if ( mfrc522.PICC_IsNewCardPresent()) {
// Select one of the cards
if ( mfrc522.PICC_ReadCardSerial()) {
soundWrong();
}
}
return;
}
// *********************
// Ab hier Normalbetrieb
// *********************
// Look for new cards
if ( mfrc522.PICC_IsNewCardPresent()) {
// Select one of the cards
if ( mfrc522.PICC_ReadCardSerial()) {
String cardId = "";
for (byte i = 0; i < mfrc522.uid.size; i++) {
// Abstand zwischen HEX-Zahlen und führende Null bei Byte < 16
cardId += String(mfrc522.uid.uidByte[i] < 0x10 ? "0" : "");
cardId += String(mfrc522.uid.uidByte[i], HEX);
}
int result = httpRequest(cardId);
// 200 Kommen
// 202 Gehen
// 204 Kein User gefunden
if( result == 200 ){
soundWork();
} else if(result == 202 ){
soundGoHome();
} else {
soundWrong();
}
}
}
}
int httpRequest(String cardId){
WiFiClientSecure client;
HTTPClient http;
// Daten an Server senden
Serial.println("URL:");
Serial.println( user_network.url );
int output = 0;
int attempts = 0;
parseURL(user_network.url, &url);
Serial.println("Host:");
Serial.println( url.host );
IPAddress IPresult;
IPAddress testIpAdress;
if(testIpAdress.fromString(url.host)){
Serial.println("Host is IP Adress:");
Serial.println( url.host );
Serial.println("No DNS needed");
} else {
while ( ( output = WiFi.hostByName( url.host.c_str(), IPresult, (uint32_t) 2000 ) ) != 1 && ( attempts < 5) ){
delay(1000);
attempts++;
}
if(output != 1){
Serial.println("Host konnte nicht ermittelt werden. DNS fehlgeschlagen.");
return -1;
}
Serial.println("IP from DNS:");
Serial.println( ipToString( IPresult) );
}
http.begin(client, user_network.url );
http.addHeader("Content-Type", "application/x-www-form-urlencoded");
// Create String for Post
String post = user_network.urlpost;
post.replace("{pass}", user_network.urlpass);
post.replace("{card}", cardId);
post.replace("{mac}", String( WiFi.macAddress() ) );
Serial.println("Post:");
Serial.println(post);
int httpCode = http.POST(post);
Serial.println("Response httpCode:");
Serial.println(httpCode);
http.end();
return httpCode;
}
void systemStatusControll(){
// Alles OK
if(systemStatus == 0){
if(statusCount == 75){
long rssi = 0;
switch (WiFi.status()){
case WL_NO_SSID_AVAIL:
Serial.println("Configured SSID cannot be reached");
break;
case WL_CONNECTED:
Serial.println("Connection successfully established");
rssi = WiFi.RSSI();
Serial.println( String( WiFi.macAddress() ) + " RSSI: " + rssi );
break;
case WL_CONNECT_FAILED:
Serial.println("Connection failed");
break;
}
pixels.setPixelColor(0, pixels.Color(0, 0, 255));
pixels.show();
statusCount = 0;
}
// Error
} else if( systemStatus == 1){
if(statusCount == 3){
pixels.setPixelColor(0, pixels.Color(255, 0, 0));
pixels.show();
statusCount = 0;
}
// Notice
} else if( systemStatus == 2){
if(statusCount == 3){
pixels.setPixelColor(0, pixels.Color(255, 255, 0));
pixels.show();
statusCount = 0;
}
}
delay(30);
pixels.clear();
pixels.show();
}
void soundOK() {
pixels.setPixelColor(0, pixels.Color(0, 255, 0));
pixels.show();
tone(buzzPin, freqNormal, 350);
delay(350);
noTone(buzzPin);
pinMode(buzzPin, INPUT);
delay(1000);
}
void soundSystemStart() {
pixels.setPixelColor(0, pixels.Color(0, 0, 255));
pixels.show();
tone(buzzPin, freqNormal, 150);
delay(200);
tone(buzzPin, freqNormal, 150);
delay(150);
noTone(buzzPin);
pinMode(buzzPin, INPUT);
delay(1000);
}
void soundWork() {
pixels.setPixelColor(0, pixels.Color(0, 255, 0));
pixels.show();
tone(buzzPin, freqNormal, 250);
delay(250);
noTone(buzzPin);
pinMode(buzzPin, INPUT);
delay(1000);
}
void soundGoHome() {
pixels.setPixelColor(0, pixels.Color(0, 255, 0));
pixels.show();
tone(buzzPin, freqNormal, 250);
delay(300);
noTone(buzzPin);
delay(150);
tone(buzzPin, freqNormal, 250);
delay(250);
noTone(buzzPin);
pinMode(buzzPin, INPUT);
delay(1000);
}
void soundWrong() {
pixels.setPixelColor(0, pixels.Color(255, 0, 0));
pixels.show();
tone(buzzPin, freqNormal, 2000);
delay(1000);
noTone(buzzPin);
pinMode(buzzPin, INPUT);
delay(1000);
}
void handle_NotFound(){
server.send(404, "text/plain", "Not found");
}
void handle_Normal_Mode_OnConnect() {
long rssi = WiFi.RSSI();
Serial.println( String( WiFi.macAddress() )+ " RSSI: " + rssi );
server.send(200, "text/html", String( WiFi.macAddress()) + " RSSI: " + rssi );
}
void handle_Config_Mode_OnConnect() {
server.send(200, "text/html", sendHtmlConfigMode(""));
}
void handle_Config_Mode_Clear_Config() {
// EEPROM löschen ->ganze konfig weg!!!
for (int i = 0 ; i < sizeof(user_network) ; i++) {
EEPROM.write(i, 0);
}
EEPROM.commit();
Serial.println("Konfig gelöscht. Speicher überschrieben.");
server.send(200, "text/html", sendHtmlConfigMode(""));
}
void handle_Config_Mode_Config(){
// INIT checkup
user_checkup = 0;
for (int i = 0; i < server.args(); i++) {
if(server.argName(i) == "ssid"){
server.arg(i).toCharArray(user_network.ssid, 32);
bitSet(user_checkup, 0);
Serial.println(server.argName(i));
Serial.println(server.arg(i));
}
if(server.argName(i) == "pass"){
server.arg(i).toCharArray(user_network.pass, 64);
bitSet(user_checkup, 1);
Serial.println(server.argName(i));
Serial.println("*********");
}
if(server.argName(i) == "ip"){
user_network.ip.fromString(server.arg(i));
bitSet(user_checkup, 2);
Serial.println(server.argName(i));
Serial.println(server.arg(i));
}
if(server.argName(i) == "gateway"){
user_network.gateway.fromString(server.arg(i));
bitSet(user_checkup, 3);
Serial.println(server.argName(i));
Serial.println(server.arg(i));
}
if(server.argName(i) == "subnet"){
user_network.subnet.fromString(server.arg(i));
bitSet(user_checkup, 4);
Serial.println(server.argName(i));
Serial.println(server.arg(i));
}
if(server.argName(i) == "dns"){
user_network.dns.fromString(server.arg(i));
bitSet(user_checkup, 5);
Serial.println(server.argName(i));
Serial.println(server.arg(i));
}
if(server.argName(i) == "url"){
server.arg(i).toCharArray(user_network.url, 400);
bitSet(user_checkup, 6);
Serial.println(server.argName(i));
Serial.println(server.arg(i));
}
if(server.argName(i) == "urlpost"){
server.arg(i).toCharArray(user_network.urlpost, 400);
bitSet(user_checkup, 7);
Serial.println(server.argName(i));
Serial.println(server.arg(i));
}
if(server.argName(i) == "urlpass"){
// MD5 umwandeln vor dem abspeichern
String stringMD5 = md5(server.arg(i));
stringMD5.toCharArray(user_network.urlpass, 100);
Serial.println(server.argName(i));
Serial.println("*********");
}
}
// Prüfen ob alle Daten
// Übertagen wurden
// 8 bit 11111111 = 255
if(user_checkup == 255){
Serial.println( "Länge der Daten: "+ String( sizeof(user_network) ) );
// EEPROM löschen
for (int i = 0 ; i < sizeof(user_network) ; i++) {
EEPROM.write(i, 0);
}
EEPROM.commit();
// Write to EEPROM
EEPROM.put(0, user_network);
EEPROM.commit();
server.send(200, "text/html", sendHtmlConfigMode("<span style=\"color: green;\">Daten gesetzt.</span>"));
return;
}
server.send(200, "text/html", sendHtmlConfigMode(""));
}
String sendHtmlConfigMode(String message){
// read EEPROM
EEPROM.get(0, user_network);
String s = "<!DOCTYPE html>";
s += "<html>\n";
s += "<head>";
s += "<meta charset=\"utf-8\"/>";
s += "</head>";
s += "<body>";
s += "<h1>Config \"NFC-CardClock\" => " + String(WiFi.macAddress()) + "</h1>\n";
s += "<b>" + message + "</b><br />";
s += "<form method=\"post\" action=\"/config\">";
s += "<h2>ssid</h2>\n";
s += "<input type=\"text\" name=\"ssid\" value=\""+ String(user_network.ssid) +"\" required></input><br />";
s += "<h2>pass</h2>\n";
s += "<input type=\"password\" name=\"pass\" value=\"\" required></input><br />";
s += "<h2>ip</h2>\n";
s += "<input type=\"text\" name=\"ip\" value=\"" + ipToString(user_network.ip) + "\" pattern=\"^([0-9]{1,3}\\.){3}[0-9]{1,3}$\" required></input><br />";
s += "<h2>gateway</h2>\n";
s += "<input type=\"text\" name=\"gateway\" value=\""+ipToString(user_network.gateway)+"\" pattern=\"^([0-9]{1,3}\\.){3}[0-9]{1,3}$\" required></input><br />";
s += "<h2>subnet</h2>\n";
s += "<input type=\"text\" name=\"subnet\" value=\""+ipToString(user_network.subnet)+"\" pattern=\"^([0-9]{1,3}\\.){3}[0-9]{1,3}$\" required></input><br />";
s += "<h2>DNS</h2>\n";
s += "<input type=\"text\" name=\"dns\" value=\""+ipToString(user_network.dns)+"\" pattern=\"^([0-9]{1,3}\\.){3}[0-9]{1,3}$\" required></input><br />";
s += "<h2>URL-Server</h2>\n";
s += "<p>Über die Variablen {mac}, {card} und/oder {pass} lassen sich Werde in der URL dynamisch einsetzen. Maximal können 400 Zeichen.<br><br>Bei Verwendung von {pass} wird das Passwort mit MD5 umgewandelt. Maximal können für {pass} 100 Zeichen verwendet werden.</p>\n";
s += "<input type=\"text\" name=\"url\" value=\""+ String(user_network.url) +"\" maxlength=\"400\" required></input><br />";
s += "<h3>POST</h3>\n";
s += "<input type=\"text\" name=\"urlpost\" value=\""+ String(user_network.urlpost) +"\" maxlength=\"400\" required></input><br />";
s += "<h3>{pass}</h3>\n";
s += "<input type=\"text\" name=\"urlpass\" value=\"\" maxlength=\"100\"></input><br />";
s += "<br /><input type=\"submit\" value=\"save\"><br />";
s += "</form></body><html>";
return s;
}
String md5(String str) {
_md5.begin();
_md5.add(String(str));
_md5.calculate();
return _md5.toString();
}
String ipToString(IPAddress ip){
String s="";
for (int i=0; i<4; i++)
s += i ? "." + String(ip[i]) : String(ip[i]);
return s;
}
void parseURL(String urlString, URL* url) {
// Assume a valid URL
enum URLParseState {PROTOCOL, SEPERATOR, HOST, PORT, PATH} state = PROTOCOL;
url->protocol = "";
url->host = "";
url->port = "";
url->path = "/";
for (int i = 0; i < urlString.length(); i++) {
switch(state)
{
case PROTOCOL: if (urlString[i] == ':') state = SEPERATOR;
else url->protocol += urlString[i];
break;
case SEPERATOR: if (urlString[i] != '/') {
state = HOST;
url->host += urlString[i];
}
break;
case HOST: if (urlString[i] == ':') state = PORT;
else {
if (urlString[i] == '/') state = PATH;
else url->host += urlString[i];
}
break;
case PORT: if (urlString[i] == '/') state = PATH;
else url->port += urlString[i];
break;
case PATH: url->path += urlString[i];
}
}
}
Zusammengebaut
Einzelteile NFC StempeluhrESP8266 Erweiterung mit AntenneErweitert mit Funkantenne NFC StempeluhrLeuchte blau NFC StempeluhrLeuchte Gelb NFC StempeluhrVorbereitungen Montage NFC StempeluhrVorbereitungen Montage 2 NFC StempeluhrAußenbereichmontage 1 NFC StempeluhrAußenbereichmontage 2 NFC StempeluhrRFID Tag oder Karte NFC Stempeluhr
Resümee
Das Projekt der NFC Stempeluhr ESP8266 DIY hat sich in den letzten zwei Jahren erfolgreich im Feldeinsatz bewährt. Die Kombination aus NFC-Lesemodul und ESP8266 Mikrocontroller ermöglicht eine einfache und effiziente Erfassung von Arbeitszeiten.
Es besteht jedoch immer die Möglichkeit, das Projekt weiter zu verbessern. Durch den Einsatz einer externen Antenne kann die Verbindungsqualität zum Wlan verbessert werden.
Eine HTTPS-Verschlüsselung bei der Übertragung der Daten an den Server kann die Sicherheit erhöhen und die Daten vor unerlaubtem Zugriff schützen.
Die Speicherung der Stempelzeiten bei Netzwerkausfall kann ebenfalls nützliche sein.
Insgesamt hat die NFC Stempeluhr ESP8266 DIY in den letzten Jahren ihre Nützlichkeit und Effektivität bewiesen und bietet weiterhin Raum für Verbesserungen und Anpassungen.