Inhalt
Beschreibung der Anleitung
Die Tags (Karten im Scheckkartenformat oder als Schlüsselanhänger) eines RFID-Moduls werden dazu verwendet den Namen einer fiktiven Mitarbeiterin/eines fiktiven Mitarbeiters festzustellen und mit Hilfe der Standardbibliothek time.h die Zeit der Anmeldung oder der Abmeldung zu ermitteln. Diese Daten werden über WiFi an einen Browser übertragen und angezeigt. Alle 60 Sekunden wird die Anzeige automatisch aktualisiert.
Über einen Button kann die Seite auch händisch auf den neuesten Stand gebracht werden.
Ansicht im Browser
Trage unter Datei -> Einstellungen eine zusätzliche Boardverwalter-URL ein:
https://arduino.esp8266.com/stable/package_esp8266com_index.json
Wenn das Wemos D1 Mini nicht automatisch erkannt wurde, klicke auf „Wähle ein anderes Board und einen anderen Port“ und suche nach Wemos D1. Je nach Betriebssystem wird der USB-Port eine andere Bezeichnung haben.
Benötigte Bauteile
Das RFID-Kit MFC522
Das RFID-Kit MFC522 besteht aus den sogenannten Tags – Karten im Scheckkartenformat oder als Schlüsselanhänger – und dem Lesegerät. Das Lesegerät generiert einen Code wenn ein Tag vor das Lesegerät gehalten wird.
Der Schaltplan
Benötigte Bibliothek installieren
RFID-Code auslesen
Jeder Tag generiert einen individuellen Code. Damit du die Karten den Mitarbeiter*innen zuordnen kannst, musst du die Codes ermitteln und notieren.
Dazu dient dieses Programm:
#include
// Anschlüsse RFID definieren
#define SDA D8
#define RST D3
// RFID-Empfänger benennen
MFRC522 mfrc522(SDA, RST);
// vom RFID ermttelter Wert der Karte als Folge von Dezimalzahlen
String WertDEZ;
void setup()
{
Serial.begin(9600);
delay(500);
SPI.begin();
// Initialisierung des RFID-Empfängers
mfrc522.PCD_Init();
}
void loop()
{
// Wert der Karte zurücksetzen
WertDEZ = "";
// wenn eine Karte aufgelegt wird startet die Abfrage
if (mfrc522.PICC_IsNewCardPresent())
{
mfrc522.PICC_ReadCardSerial();
// Dezimalwerte der Karte in String schreiben
for (byte i = 0; i < mfrc522.uid.size; i++)
{
WertDEZ = WertDEZ + String(mfrc522.uid.uidByte[i], DEC) + " ";
}
// Wartezeit anpassen, wenn mehrere Werte gelesen werden
delay(1000);
// dezimalen Wert im Seriellen Monitor anzeigen
Serial.println("dezimaler Wert: " + WertDEZ);
}
}
Das Programm
Globale Variablen definieren und Bibliothek einbinden
Die Bibliothek time.h sorgt für die Ermittlung der aktuellen Zeit über NTP-Server. Das NTP (Network Time Protocol) ist ein Protokoll zur Synchronisierung von Uhren in Computersystemen. Im Internet existieren öffentlich zugängliche NTP-Server, die sich zur Zeitsynchronisation nutzen lassen. Hier wird ein Pool von Zeitservern verwendet. Das hat den Vorteil, dass bei einem Ausfall eines Zeitservers der nächste in der Liste benutzt wird. Die SSID des Routers und das Passwort musst du anpassen.
Wenn du weitere Mitarbeiter*innen hinzufügen willst, müssen sie im Array MitarbeiterInnen (Zeile 61) notiert werden. Gleichzeitig musst du die Größe der Arrays AnmeldeZeit und AnmeldeStatus (Zeilen 64 und 67) entsprechend erhöhen.
// Bibiotheken hinzufügen
#include
#include
#include
// Anschlüsse RFID definieren
#define SDA D8
#define RST D3
// RFID-Empfänger benennen
MFRC522 mfrc522(SDA, RST);
char Router[] = "Router_SSID";
char Passwort[] = "xxxxxxxx";
// vom RFID ermttelter Wert der Karte als Folge von Dezimalzahlen
String WertDEZ;
/*
NTP-Server aus Pool
# define Zeitserver "de.pool.ntp.org"
https://www.pool.ntp.org/zone/de
oder z.B. Zeitserver der Physikalisch-technische Bundesanstalt
# define Zeitserver "ptbtime1.ptb.de"
wenn eine statische IP-Adresse verwendet kann der Eintrag auch direkt erfolgen
NTP-Server als IP-Adresse angeben
192.53.103.108 -> Physikalisch-technische Bundesanstalt
*/
#define Zeitserver "de.pool.ntp.org"
/*
Liste der Zeitzonen
https://github.com/nayarsystems/posix_tz_db/blob/master/zones.csv
Zeitzone CET = Central European Time -1 -> 1 Stunde zurück
CEST = Central European Summer Time von
M3 = März, 5.0 = Sonntag 5. Woche, 02 = 2 Uhr
bis M10 = Oktober, 5.0 = Sonntag 5. Woche 03 = 3 Uhr
*/
#define Zeitzone "CET-1CEST,M3.5.0/02,M10.5.0/03"
// time_t enthält die Anzahl der Sekunden seit dem 1.1.1970 0 Uhr
time_t aktuelleZeit;
/*
Struktur tm wandelt die ermittelte Zeit in ein "lesbares" Format um:
tm_hour -> Stunde: 0 bis 23
tm_min -> Minuten: 0 bis 59
tm_sec -> Sekunden 0 bis 59
tm_mday -> Tag 1 bis 31
tm_mon -> Monat: 0 (Januar) bis 11 (Dezember)
tm_year -> Jahre seit 1900
tm_yday -> vergangene Tage seit 1. Januar des Jahres
tm_isdst -> Wert > 0 = Sommerzeit (dst = daylight saving time)
*/
tm Zeit;
WiFiServer Server(80);
WiFiClient Client;
// Namen der Mitarbeiter*innen
String MitarbeiterInnen[3] = { "Klaus Drolshagen", "Eva Hilger", "Claudia Kruse" };
// Anmeldestatus: false = abgemeldet
bool AnmeldeStatus[3] = { false, false, false };
// Zeit der Anmeldung/Abmeldung
String AnmeldeZeit[3];
Der setup-Teil
void setup()
{
Serial.begin(9600);
delay(500);
SPI.begin();
// Initialisierung des RFID-Empfängers
mfrc522.PCD_Init();
// Parameter für die zu ermittelnde Zeit
configTime(Zeitzone, Zeitserver);
WiFi.begin(Router, Passwort);
// Verbindung herstellen
while (WiFi.status() != WL_CONNECTED)
{
delay(200);
Serial.print(".");
}
Server.begin();
// SSID des Routers anzeigen
Serial.println();
Serial.print("Verbunden mit ");
Serial.println(WiFi.SSID());
// IP des D! anzeigen
Serial.println(WiFi.localIP());
}
Im Seriellen Monitor wird die IP-Adresse des Wemos D1 angezeigt.
Diese IP-Adresse musst du in der Adresszeile eines Browsers deiner Wahl eingeben.
Der loop-Teil
Der loop-Teil fragt als Erstes den dezimalen Wert der Karte oder des Schlüsselanhängers ab. Sie werden zur Kontrollen im Seriellen Monitor angezeigt. Für die Abfrage der Mitarbeiterin/des Mitarbeiters musst du die ermittelten Werte in den Zeilen 34, 50 und 60 gegen die ausgelesenen Werte deiner Tags austauschen.
void loop()
{
// aktuelle Zeit lesen
time(&aktuelleZeit);
// localtime_r -> ermittelte Zeit in die lokale Zeitzone setzen
localtime_r(&aktuelleZeit, &Zeit);
// Wert der Karte zurücksetzen
WertDEZ = "";
// wenn eine Karte aufgelegt wird startet die Abfrage
if (mfrc522.PICC_IsNewCardPresent())
{
mfrc522.PICC_ReadCardSerial();
// Dezimalwerte der Karte in String schreiben
for (byte i = 0; i < mfrc522.uid.size; i++)
{
WertDEZ = WertDEZ + String(mfrc522.uid.uidByte[i], DEC) + " ";
}
// Wartezeit anpassen, wenn mehrere Werte gelesen werden
delay(1000);
// dezimalen Wert im Seriellen Monitor anzeigen
Serial.println("dezimaler Wert: " + WertDEZ);
}
// Leerzeichen am Ende entfernen
WertDEZ.trim();
// Karten abfragen und Namen der Mitarbeiter*innen und Zeit zuordnen
if (WertDEZ.compareTo("195 106 18 23") == 0)
{
AnmeldeStatus[0] = !AnmeldeStatus[0];
// AnmeldeZeit zurücksetzen
AnmeldeZeit[0] = "";
// wenn Stunde < 10 -> 0 voranstellen
if (Zeit.tm_hour < 10) AnmeldeZeit[0] = "0";
AnmeldeZeit[0] = AnmeldeZeit[0] + Zeit.tm_hour + ":";
// wenn Minute < 10 -> 0 voranstellen
if (Zeit.tm_min < 10) AnmeldeZeit[0] = "0";
AnmeldeZeit[0] = AnmeldeZeit[0] + Zeit.tm_min;
}
if (WertDEZ.compareTo("227 77 233 22") == 0)
{
AnmeldeStatus[1] = !AnmeldeStatus[1];
AnmeldeZeit[1] = "";
if (Zeit.tm_hour < 10) AnmeldeZeit[1] = "0";
AnmeldeZeit[1] = AnmeldeZeit[1] + Zeit.tm_hour + ":";
if (Zeit.tm_min < 10) AnmeldeZeit[1] = "0";
AnmeldeZeit[1] = AnmeldeZeit[1] + Zeit.tm_min;
}
if (WertDEZ.compareTo("131 125 21 23") == 0)
{
AnmeldeStatus[2] = !AnmeldeStatus[2];
AnmeldeZeit[2] = "";
if (Zeit.tm_hour < 10) AnmeldeZeit[2] = "0";
AnmeldeZeit[2] = AnmeldeZeit[2] + Zeit.tm_hour + ":";
if (Zeit.tm_min < 10) AnmeldeZeit[2] = "0";
AnmeldeZeit[2] = AnmeldeZeit[2] + Zeit.tm_min;
}
Client = Server.available();
if (Client)
{
// Seite aufbauen wenn SeiteAufbauen true ist
boolean SeiteAufbauen = true;
while (Client.connected())
{
if (Client.available())
{
char Zeichen = Client.read();
if (Zeichen == '\n')
{
// wenn SeiteAufbauen den Wert true hat
if (SeiteAufbauen)
{
// HTTP-Anforderung senden
Client.println("HTTP/1.1 200 OK");
Client.println("Content-Type: text/html");
// Leerzeile zwingend erforderlich
Client.println();
/*
HTML-Seite aufbauen
die folgenden Anweisungen müssen mit print oder println gesendet werden
println "verschönert" den Quelltext
" muss mit \" maskiert werden
*/
Client.println("");
Client.println("");
Client.println("");
// alle 60 Sekunden aktualisieren mit meta-Tag
Client.println("");
Client.println(" Anmeldestatus der Mitarbeiter*innen
");
Client.println("
");
// aktuelle Zeit anzeigen
Client.println("");
// tm_mday -> Wochentag anzeigen
switch (Zeit.tm_wday)
{
case 0:
Client.print(F("Sonntag"));
break;
case 1:
Client.print(F("Montag"));
break;
case 2:
Client.print(F("Dienstag"));
break;
case 3:
Client.print(F("Mittwoch"));
break;
case 4:
Client.print(F("Donnerstag"));
break;
case 5:
Client.print(F("Freitag"));
break;
case 6:
Client.print(F("Samstag"));
break;
}
Client.print(", ");
// Tag: führende 0 ergänzen
if (Zeit.tm_mday < 10) Client.print("0");
Client.print(Zeit.tm_mday);
Client.print(".");
// Monat: führende 0 ergänzen
if (Zeit.tm_mon < 10) Client.print("0");
Client.print(Zeit.tm_mon + 1);
Client.print(".");
// tm_year + 1900
Client.print(Zeit.tm_year + 1900);
// Uhrzeit
Client.print(" Uhrzeit: ");
// Stunden
if (Zeit.tm_hour < 10) Client.print("0");
Client.print(Zeit.tm_hour);
Client.print(":");
// Minuten
if (Zeit.tm_min < 10) Client.print("0");
Client.print(Zeit.tm_min);
Client.print(":");
// Sekunden
if (Zeit.tm_sec < 10) Client.print("0");
Client.print(Zeit.tm_sec);
Client.println("
");
Client.println("
");
// Name und Anmeldestatus der Mitarbeiter*innen anzeigen
for (int i = 0; i < sizeof(MitarbeiterInnen) / sizeof(MitarbeiterInnen[0]); i++)
{
Client.println(MitarbeiterInnen[i]);
if (AnmeldeStatus[i] == true) Client.println(": angemeldet seit " + AnmeldeZeit[i] + " Uhr");
else Client.println(": abgemeldet seit " + AnmeldeZeit[i] + " Uhr");
Client.println("
");
}
Client.println("
");
Client.println(" ");
Client.println("
");
// IPs anzeigen
Client.print(F("Eigene IP: "));
Client.print(Client.remoteIP());
Client.print(F(""));
Client.print(F("
IP Klient (D1): "));
Client.print(WiFi.localIP());
Client.print(F(""));
Client.println("");
Client.println("");
Client.print("");
// HTTP-Antwort endet mit neuer Zeile
Client.println();
// Seite vollständig geladen -> loop verlassen
break;
}
// wenn new line (\n) gesendet wurde -> Seite aufbauen
if (Zeichen == '\n') SeiteAufbauen = true;
else if (Zeichen != '\r') SeiteAufbauen = false;
delay(1);
Client.stop();
}
}
}
}
}
Beispiel: Bilder und Beschriftung der Karten
Funduino - Dein Onlineshop für Mikroelektronik
-
Dauerhaft bis zu 10% Rabatt für Schüler, Studenten und Lehrkräfte
-
Mehr als 3.500 Artikel sofort verfügbar!
-
Über 8 Jahre Erfahrung mit Arduino, 3D-Druck und co.