Grundlagen

Bevor wir direkt mit dem Pi und RFID anfangen, brauchen wir erstmal ein paar Grundlagen für die Funktionsweise. RFID ist kurz für radio-frequency identification oder auf Deutsch: Identifizierung mit elektromagnetischen Wellen. Mit dieser Technik können Daten von einem Transponder mithilfe eines Schreib-/Lesegeräts (wir werden die Abkürzung RFID-Reader benutzen) gelesen werden.

RFID-Reader, Blau

Wie schon gesagt, gehört zu einem RFID-System immer der RFID-Reader und ein Transponder. Ein Transponder kann dabei in vielen verschiedenen Formen und Größen kommen. Wir benutzen in diesem Fall RFID-Karte, RFID-Anhänger und NFC-Sticker (dazu später mehr). Alle davon sind Transponder. Die Transponder, die wir benutzen, sind alle gleich aufgebaut. Sie lassen sich in zwei verschiedene Komponenten aufteilen, einmal die Antenne (diese befindet sich an den Außenseiten) und dem Speicher und der Logik in der Form eines Chips in der Mitte des Transponders.

RFID-Transponder in Chipkarten Form

Die Transponder, die wir benutzen, haben keine eigene Stromversorgung, denn diese kommt durch den RFID-Reader. Wenn dieser angeschlossen ist, wird ein hochfrequentes elektromagnetisches Feld erzeugt. Und sobald sich der Transponder in diesem Feld befindet, wird er darüber mit Strom versorgt. Die Energie wird dabei durch die Antennen aufgenommen und dann an den Chip weitergegeben. Wenn die Stromversorgung sichergestellt ist, startet die Kommunikation zwischen dem RFID-Reader und dem Transponder. Die hier verwendeten Transponder können beschrieben oder gelesen werden. Der Transponder erzeugt dabei kein eigenes Feld oder Wellen, sondern manipuliert nur das vorhandene Feld mithilfe der Antennen. Dieses kann dann durch den RFID-Reader interpretiert und ausgewertet werden. Der Vorteil ist, dass der Transponder keine eigene Stromversorgung braucht und deswegen sehr klein sein kann. Der Nachteil ist, dass bei diesem Verfahren der RFID-Reader und der Transponder nicht weit von einander entfernt sein dürfen, damit die Übertragung funktioniert.

NFC

Jetzt haben wir schon viel über RFID geredet und dabei auch noch NFC erwähnt. Das steht für Near Field Communication oder auf Deutsch: Nahfeldkommunikation. NFC ist eine Unterart von RFID, die nur mit 13,56 MHz arbeitet. Wir können dies an unserem RFID-Reader benutzen, weil auch der in diesem Frequenzbereich arbeitet. NFC ist eine neuere Technik und erlaubt auch, dass zwei Geräte, wie z.B. Smartphones, miteinander kommunizieren und Daten austauschen können. Auch kontaktloses Bezahlen ist dadurch häufig möglich.

RFID am Raspberry Pi

Jetzt haben wir genug Grundlagen gehabt und wollen diese Technik nun am Pi benutzen. Dafür müssen wir zuerst den RFID-Reader an den Pi anschließen. Für die Kommunikation zwischen dem Pi und dem Reader wird das SPI-Protokoll benutzt. Wie du das einrichtest, erfährst du unter http://cw42.de/spi . Bei allen aktuellen Betriebssystem-Versionen solltest du aber über sudo raspi-config -> 5 Interfacing Options -> P4 SPI -> YES (alles bestätigen und dann neustarten) schon einfach SPI aktiviert haben.

Mifare RFID RC522 am Raspberry Pi
RC522 ModulRaspberry Pi
1 – SDAGPIO8 CE0
2 – SCKGPIO11 SCKL
3 – MOSIGPIO10 MOSI
4 – MISOGPIO9 MISO
5 – IRQ
6 – GNDGND
7 – RSTGPIO25
8 – 3.3V3.3V

Bibliotheken hinzufügen

Das Anschließen des Bauteils haben wir jetzt hinter uns und können uns nun wieder um die Software kümmern. Für die Kommunikation zwischen Pi und dem Reader wird das SPI-Kommunikationsprotokoll benutzt. Im Gegensatz zum 5510-Display, welches im Starterkit enthalten ist, senden wir diesmal nicht einfach nur Daten an den Reader, sondern müssen diese natürlich auch empfangen, um die einzelnen Karten wieder auslesen zu können. Deswegen ist die Software auch ein wenig komplizierter, aber natürlich gibt es auch dafür schon eine Bibliothek, die wir nur für unsere Zwecke anpassen müssen. Es gibt zwei verschiedene Komponenten, die wir herunterladen müssen, zuerst die Bibliothek mit der Python über die GPIO-Pins SPI kommunizieren kann:

$ git clone https://github.com/coding-world/SPI-Py.git
$ cd SPI-PY
$ sudo python setup.py install

Zunächst gehen wir wieder einen Ordner zurück:

$ cd ../

Und jetzt die Bibliothek für die Kommunikation mit dem Reader:

$ git clone https://github.com/coding-world/MFRC522-python.git
$ cd MFRC522-python

Wenn du jetzt Read.py ausführst und die RFID-Karte oder den RFID-Anhänger an den Reader am Pi hältst, solltest du folgendes sehen:

$ python Read.py
Card detected
Card read UID: 219,160,58,213
Size: 8

Wenn nichts angezeigt wird, obwohl du mit den RFID-Transpondern auch ein wenig länger (1-2 Sekunden) in der Nähe der Vorderseite bleibst, ist entweder etwas beim Anschließen falsch gelaufen oder beim Aktivieren/Installieren der Bibliotheken. Am besten versuchst du einfach erstmal alles noch mal.

Arbeiten mit RFID-Karten

Dein RFID-Reader sollte jetzt funktionieren. In diesem Teil zeigen wir dir, wie man das Read.py– und Write.py-Script so ändert, dass wir eigene Namen oder IDs auf die Karten schreiben und diese später auch wieder auslesen können.

Alle RFID-Karten haben eine eigene UUID, also eine eigene eingebaute Kennung, die auch auf der Karte gespeichert ist. Wir können aber auch noch weitere Daten auf die Karten schreiben und auslesen. So lassen sich zum Beispiel Karten für die Zeiterfassung bauen. Wenn jemand ins Büro kommt, registriert er sich mit seiner RFID-Karte. Wir steigen einfach ein. Als erstes modifizieren wir das Write.py– und Read.py-Programm, sodass wir eigene Daten auf die RFID-Speicher schreiben und lesen können.

Daten auf RFID schreiben

Unsere RFID-Karten haben 16 Sektoren. In jedem Sektor können wir eine Zahl von 1 bis 255 speichern. Wenn du das Script Read.py ausführst und eine RFID-Karte vor den Leser hältst, dann sollte die Ausgabe so aussehen:

Sector 8 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

16 Sektoren, die alle auf 0 stehen. Maschinencode ist zwar toll, aber wer kann sich das merken? Wir wollen lieber Bucchstaben speichern. Wenn wir 0 als A nehmen und B als 1 und C als 2 dann sind wir schnell durch. Dazu kommt dann noch das kleine abc, die Zahlen und Sonderzeichen. Das klingt nach viel Mühe. Zum Glück haben andere das Problem schon gelöst. Es gibt den American Standard Code for Information Interchange, kurz ASCII. Da sind alle Zeichen enthalten, die wir brauchen und das Beste ist, Python kann das übersetzen (nur auf die deutschen Umlaute und Sonderzeichen müssen wir verzichten, aber das ist ja auch nicht so schlimm 😉 ). Mehr zu ASCII gibt es auch auf https://de.wikipedia.org/wiki/American_Standard_Code_for_Information_Interchange.

Wir erstellen jetzt ein kleines Script, das eine Eingabe in ASCII-Code umwandelt. Diesen Code speichern wir dann auf eine RFID-Karte.

Erstelle eine neue Datei mit nano ASCII.py und schreibe folgenden Inhalt hinein:

name=raw_input("Gib einen Kartennamen ein: ")
if len(name)>16:
  name=name[:16]
data = [ord(x) for x in list(name)]
print data

Ok, das sieht komplizierter aus, als es ist. In der ersten Zeile holen wir uns die Eingabe des Nutzers und speichern diese in der Variablen name. Mit ran_input("Frage") können wir im Terminal dem Benutzer des Programms eine Frage stellen und die Antworten dann in einer Variable speichern und später weiterverwenden. Wir können 16 Sektoren also 16 Zahlen von 0 bis 255 speichern. Falls der Nutzer aber mehr Zeichen eingegeben hat – zum Beispiel 18 oder 20, dann ist das zu viel. In der zweiten Zeile prüfen wir das. if len(name)>16: bedeutet, wenn die Länge von name > (größer als) 16 ist, dann mache Folgendes. Die Länge ist dabei natürlich die Anzahl der Zeichen. Die Funktion len() gibt uns die Länge einer Variable aus. Das kannst du selbst testen mit:

print len("Das ist ein TEST")

Falls unsere Variable name länger ist als 16 Zeichen, dann wird der eingerückte Teil ausgeführt und zwar: name=name[:16]. Übersetzt heißt das: speichere in die Variablen name nur die ersten 16 Stellen aus der Variablen name. Mit Variable[anfangsWert:Endwert] können wir einzelne Zeichen aus einer Zeichenkette ausschneiden und ausgeben oder wieder in einer Neuen (oder der Alten) Variable speichern.

Jetzt kommt der Kern des Ganzen, das Übersetzen der Zeichen in ASCII.

data = [ord(x) for x in name]

data ist die Variable, in der nachher alle Zeichen gespeichert werden. [ord(x) for x in list(name)] besteht aus zwei Teilen. ord(x) und for x in name. Das Erste ist eine Python-Funktion, die wir auch so aufrufen können, mit print ord(“A“). Das Zweite, die for-Schleife, ist ähnlich wie die while-Schleife und lässt uns einzelne Elemente durchgehen. print ord(“A“) gibt uns den ASCII-Wert, also eine Zahl aus, bei ist das 97 . Jetzt bleibt der kryptische Teil for x in. Das bedeutet, dass es jedes Element in der Variablen name ord(x) ausführt. Das x wird dabei durch den Wert aus der Liste ersetzt. Für unser [“h“, “a“, “l“, “l“, “o“] wäre das also ord(“h“) ord(“a“) ord(“l“) usw. Das ergibt zusammen: [104, 97, 108, 108, 111].

Nun haben wir also erfolgreich die Buchstaben in ein Format umgewandelt, welches wir auf der Karte speichern können, aber dafür müssen wir das natürlich auch wirklich tun.

Um nicht alles neu schreiben zu müssen, benutzen wir als Grundlage die Write.py-Datei. Dazu kopieren wir diese erstmal in eine neue Datei.

$ cp Write.py MyWrite.py

Jetzt können wir MyWrite.py bearbeiten und immer noch auf die alte Datei zugreifen. Diese öffnen wir jetzt mit nano und fügen unter ìmport signal, also in Zeile 8 unser vorheriges Programm ein. Die Datei müsste bei dir dann so aussehen:

#!/usr/bin/env python
# -*- coding: utf8 -*-

import RPi.GPIO as GPIO
import MFRC522
import signal

name=raw_input("Gib einen Kartennamen ein: ")
if len(name)>16:
 name=name[:16]
data = [ord(x) for x in list(name)]

continue_reading = True

Dazu müssen wir noch in Zeile 56 und 77 die neuen data-Variablen auskommentieren, weil diese ansonsten unsere Variablen, die wir am Anfang definiert haben, überschreiben. Das machst du ganz einfach, indem du vor diese Zeilen eine # schreibst. Wenn du nano als deinen Editor benutzt, kannst du mit Strg/Ctrl + w einen Suchbegriff eingeben und dann mit Enter suchen, und nano springt dann zu dieser Zeile.

Sollte sich bei dir der Fehlerteufel eingeschlichen haben, kannst du mit dem folgenden Befehl das Programm mit den Änderungen herunterladen:

$ wget cw42.de/p/MyWrite.py

Führe das Script nun aus mit python MyWrite.py. Gib einen Namen oder eine ID für deine RFID-Karte ein, bestätige das mit Enter und halte dann deine RFID-Karte an den Reader.

Die Ausgabe sollte etwa so aussehen:

Sector 8 looked like this:
Sector 8 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

Data written
It now looks like this:
Sector 8 [104, 97, 108, 108, 111, 255, 255, 255, 255, 255, 
255, 255, 255, 255, 255, 255]

Die Zahlen nach Sector 8 sind unser hallo . Die 255 sind Platzhalter, die automatisch erstellt werden.

Jetzt bist du in der Lage, deine Karten mit eindeutigen Namen und IDs zu belegen. Die Karten lassen sich übrigens mehr als 10.000 Mal wieder beschreiben. Du kannst sie also jederzeit neu beschreiben!

RFID-Karte lesen

In diesem Teil werden wir die Informationen einer RFID-Karte auslesen und den ASCII-Zahlen-Code in lesbaren Code umwandeln. Bevor wir weitermachen, müssen wir dabei zuerst etwas in der Hauptdatei verändern, die wir auch zum Schreiben benutzt haben. Wenn wir die eingebauten Lese-Funktionen ausführen, werden zwar die Daten der Karten im Terminal ausgegeben, aber das bringt uns erstmal nichts, wenn wir mit diesen Daten noch etwas ausführen wollen. Deswegen bessern wir da nochmal etwas nach. Öffne die Datei MFRC522.py mit nano MFRC522.py und bei Zeile 377 fügst du folgende Zeile ein: return backData. Das sollte dann so bei dir aussehen (und natürlich nicht das Speichern vergessen): python if len(backData) == 16: print "Sector "+str(blockAddr)+" "+str(backData) return backData

Auch diese Datei kannst du dir natürlich mit folgendem Befehl herunterladen:

$ wget cw42.de/p/MFRC522.py

Als Nächstes wollen wir die Karte auslesen. Um uns da die Tipparbeit zu sparen, benutzen wir Read. py als Grundlage und kopieren den Inhalt in eine neue Datei.

$ cp Read.py MyRead.py

Dann öffnen wir MyRead.py und ändern den folgenden Programmcode:

# Check if authenticated
        if status == MIFAREReader.MI_OK:
            MIFAREReader.MFRC522_Read(8)

Vor MIFAREReader.MFRC522_Read(8) schreiben wir data =, damit das so aussieht (natürlich speichern nicht vergessen):

# Check if authenticated
        if status == MIFAREReader.MI_OK:
            data = MIFAREReader.MFRC522_Read(8)

Und warum haben wir das Ganze jetzt so gemacht? Mit MIFAREReader.MFRC522_Read(8) wird eine Funktion in der Datei MFRC522.py aufgerufen. Diese Funktion gibt normalerweise mit print den Wert auf der Karte aus. Wir haben zusätzlich das return ausgegeben. Dadurch wird der Wert nun auch übermittelt und wir können ihn in die Variable data speichern. In der Variablen data liegt nun die Liste mit den Nummern. Diese Liste wollen wir nun von ASCII wieder zurück umwandeln in lesbare Zeichen. Daher fügen wir unter dem data = MIFAREReader.MFRC522_Read(8) folgendes ein:

text = "".join(chr(x) for x in data)
print text

Jetzt müssen wir natürlich erneut die ganze data-Variable durchgehen und alle Zahlen, die ein ASCII-Code sind, wieder zurück in Zeichen umwandeln, die wir auch wirklich benutzen können. Also genau das umgekehrte Verfahren, das wir schon in die MyWrite.py-Datei gebaut haben. Dafür nutzen wir die Funktion join und chr . join zieht die Werte zusammen und chr(x) for x in data macht ein chr(x) für jeden Eintrag, also für jeden Zahlenblock wieder ein Zeichen in unserer Liste. chr() ist dabei der Gegensatz zu ord(), wir wandeln also ASCII-Zahlen in Buchstaben um. Damit wir dann nicht „h“, „a“, „l“, „l“, „o“ lesen, setzen wir das join davor. Die Ausgabe ist somit „hallo“. (Natürlich auch nur, solange du zu Beginn hallo auf die Zahlen geschrieben hast.)