2020 Update: DIY Raspberry Pi Stechuhr mit NFC (Teil 3)

Zwei Jahre ist es nun her, dass die Raspberry Pi Stechuhr in unserem Dresdner Büro im täglichen Einsatz ist. Im Laufe der Zeit hat sich, danke an Robert für das Feedback, etwas im Setup-Prozess geändert. Das nehmen wir zum Anlass, um unsere Raspberry Pi Stechuhr auf den Stand der Technik in 2020 zu heben.

Zur Erinnerung - die ersten beiden Teile findet ihr hier:

Was hat sich verändert?

Nun, im Grundaufbau der NFC Raspberry Pi Stechuhr hat sich eine kleine, dafür umso mehr entscheidende Stelle geändert. Wir nutzten ein Firefox Add-On, um selbigen per Telnet fernzusteuern. Das war von Anfang an ein Workaround - funktionierte aber tadellos. Bis folgendes passierte:

Ende Januar 2020 entfernte Mozilla alle Firefox-Extensions die Remote-Code ausführten.

Dieser Schritt, aus sicherheitstechnischen Gründen vollkommen nachvollziehbar, führte zwangsläufig zur Löschung des in unserem Setup genutzten Remote-Control Add-Ons. Also hieß es eine stabilere Lösung finden :)

Installation des Raspberry Pi

An der Hardware hat sich für uns seit dem letzten Artikel nichts verändert. Dagegen ändert sich Im Bereich Software sehr viel in zwei Jahren.

Als OS nutzen wir nun Raspbian Buster with Desktop. Dies lässt sich einfach mit dem Apple Pi Backer oder einem anderen Programm dafür auf eine SD-Karte spielen. Die SD-Karte einfach in den Pi einstecken und los geht's.

Zur Konfiguration wird im Terminal folgender Befehl ausgeführt:

sudo raspi-config

Anschließend kann im Tool das SPI (unter Interfacing Options => SPI) und SSH (optional) eingeschaltet werden.

Für die Ausführung des neuen Skripts müssen folgende Befehle zur Installation von Chromium, den Treibern zum Steuern von Chromium und die Steuer-API installiert werden.

sudo apt-get update && sudo apt-get install sudo apt-get install chromium-browser chromium-chromedriver pip3 install -U selenium

Zur Verwendung von SPI in Python muss noch die Extension für Python installiert werden. Da dies nicht ohne Weiteres möglich ist, erfolgt die Installation händisch wie folgt: 

cd ~ git clone https://github.com/lthiery/SPI-Py.git cd SPI-Py sudo python3 setup.py build && sudo python3 setup.py install

Die Skripte

Aus Kompatibilitätsgründen musste mit dem Wechsel auf Python3 auch das Skript zur Kommunikation mit dem NFC Reader ausgetauscht werden. Hier ist der Link zum neuen Skript. Dabei handelt es sich um einen Fork des alten Skriptes mit kleineren Anpassungen, um es mit Python3 kompatibel zu machen.

Statt wie bisher den Browser per Telnet fernzusteuern, nutzen wir nun eine API um den Browser direkt zu steuern. Dies hat den Vorteil dass es deutlich sicherer ist und (hoffentlich) länger unterstützt wird.

#!/usr/bin/env python # -*- coding: utf8 -*- import RPi.GPIO as GPIO import MFRC522 import signal import datetime import platform import sys import time import threading from selenium import webdriver def main(): # start browser, might take a while browser = initBrowser() continue_reading = True last_uid = [0, 0, 0, 0, 0] time_to_delete = 0 # Capture SIGINT for cleanup when the script is aborted def end_read(signal, frame): global continue_reading continue_reading = False GPIO.cleanup() if browser is not None: browser.quit() sys.exit(0) # Hook the SIGINT and SIGTERM signal.signal(signal.SIGINT, end_read) signal.signal(signal.SIGTERM, end_read) # Create an objecet of the class MFRC522 MIFAREReader = MFRC522.MFRC522() # This loop keeps checking for chips. If one is near it will get the UID and authenticate while continue_reading: (status, TagType) = MIFAREReader.MFRC522_Request(MIFAREReader.PICC_REQIDL) # If a card is found if time_to_delete != 0 and time_to_delete < datetime.datetime.now(): time_to_delete = 0 last_uid = [0, 0, 0, 0, 0] navigate(browser, 'https://sandstorm.de') # Get the UID of the card (status, uid) = MIFAREReader.MFRC522_Anticoll() # If we have the UID, continue if status == MIFAREReader.MI_OK: if last_uid != uid: uid_strings = [] for part in uid: uid_strings.append(str(hex(part)).replace('0x', '')) # we only use the first 4 entries uid_strings.pop(4) uid_string = '-'.join(uid_strings) last_uid = uid time_to_delete = datetime.datetime.now() + datetime.timedelta(0, 5) url = "https://www.your-url.de/workingtime/dongle/toggle.html?rfidToken=" + uid_string navigate(browser, url) # start the browser in fullscreen and open the default page def initBrowser(): options = webdriver.ChromeOptions() options.add_argument('--kiosk') browser = webdriver.Chrome(options=options) global_browser = browser browser.get('https://sandstorm.rocks/') return browser # small funktion to change current page in browser def navigate(browser, url): if browser is None: print('navigation not available') else: browser.get(url) if __name__ == '__main__': main()

Die beiden Skripte befinden sich bei uns im Ordner `/utl` und lassen sich nach Anpassung des folgenden Services bei Bedarf ohne Probleme auch in einem anderen Ordner ablegen.

Achtung: der ausführende Nutzer muss die notwendigen Rechte haben, um die Skripte ausführen zu dürfen.

cd /utl chmod +x timeClock.py chmod +x MFRC522.py

Autostart

Wie bisher, überlassen wir das automatische Starten des Skripts dem systemd von Rasbpian. Eine Änderung ist allerdings, dass dies nun pro Nutzer und nicht mehr systemweit konfiguriert wird. Die Konfiguration des Dienstes sieht wie folgt aus:

[Unit] Description=Python Sandstorm time clock After=network.target PartOf=graphical-session.target [Service] Type=simple ExecStart=python3 /utl/timeClock.py Restart=on-failure RestartSec=10 KillMode=process [Install] WantedBy=default.target

Diese Datei heißt bei uns `frankWalter.service` und befindet sich im Ordner `~/.config/systemd/user`

Um das Ganze nun zu starten, muss nur der Service gestartet werden:

systemctl --user enable frankWalter.service

Geschafft!

Wir hoffen sehr, dass euch das Update gefällt! Für weitere Fragen stehen wir euch gern zur Verfügung!