Ich habe meinen Fingarabdruckleser des Typs ZFM-20 (auch bekannt als "Arduino fingerprint sensor") an mein DoorPi geklemmt. da es dafür (noch) kein Keyboard gibt, habe ich mir das "virtuelle Keyboard" zu Nutze gemacht um die Freigabe des Fingerabdrucklesers zu implementieren.
Was es Braucht:
- Funktionierendes DoorPi, vorkonfiguriert auf Raspberry Pi B+ oder 3 (bei mir ist der 3-er im Einsatz)
- Fingerabdruckleser des Typs ZFM-20 (ebay, AliExpress...)
- USB-TTL-Konverter (z.B. mit dem CP2102-Chip) oder einen Arduino Nano mit gebrücktem GND-Rst, so kann dieser als USB-TTL fungieren.
- wahlweise zwei LED's (grün / rot oder Dual-LED)
- Kabel, Lötkolben, Widerstände...
Vorbereitung der Hardware:
- Fingerabdruckleser in entsprechend sinnvolles Gehäuse packen
- Ich habe für die initialisierung des Lesevorganges einen Taster auf das Gehäuse gepackt. (zukünftig will ich den Leser anderweitig einbauen und die Auslösung dann über eine Lichtschranke realisieren.)
- ebenfalls fanden die beiden LED's darauf platz (diese signalisieren den Lesvorgang erfolgreich / fehlerhaft)
- PiFace Board ist von Vorteil, würde aber auch über GPIO mit entsprechenden Widerständen und Relais-Board funktionieren (war mir aber zu Umständlich)
- Wie man den Fingerabdruckleser genau anschliesst und wie die Library dafür installiert wird, könnt ihr Bastian Raschke's Webseite entnehmen, da spare ich mir das Wiederkäuen.
- Anschliessend Fingerleser gemäss Bastian's Anleitung testen.
Vorbereitung der Software:
- Die Python-Library für den Fingerabdruckleser hat ebenfalls einige Beispiele mitgeliefert:
- Mit dem Beispiel "example_enroll.py" können die Finger entsprechend eingelesen werden
- Das "example_search.py" habe ich entsprechend erweitert, damit das erfolgreiche Lesen eine Aktion in DoorPi auslöst
- Ich habe das Script abgeändert und in "finger.py" umbenannt. Anschliessend habe ich es unter "/usr/local/etc/DoorPi/scripts/" abgelegt (ausführbar machen nicht vergessen, aber das wisst ihr sicher)
Der CODE muss an diversen Stellen noch am jeweiligen System angepasst werden. Dies habe ich im Code kommentiert:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
PyFingerprint
Copyright (C) 2015 Bastian Raschke <bastian.raschke@posteo.de>
All rights reserved.
@author: Bastian Raschke <bastian.raschke@posteo.de>
@revisioned <a class="call-via-3cx" href="tcxcallto:<a class="call-via-3cx" href="tcxcallto:<a class="call-via-3cx" href="tcxcallto:20170327">20170327</a>"><a class="call-via-3cx" href="tcxcallto:20170327">20170327</a></a>"><a class="call-via-3cx" href="tcxcallto:<a class="call-via-3cx" href="tcxcallto:20170327">20170327</a>"><a class="call-via-3cx" href="tcxcallto:20170327">20170327</a></a></a> by Sven Gächter (sven@familiegaechter.ch) to interact with DoorPi to unlock Doors
"""
import hashlib
from pyfingerprint.pyfingerprint import PyFingerprint
import time , requests
import os
os.environ['http_proxy']=''
import urllib2
#Timeout for Reader unread
t_end = time.time() + 10
#print(time.time())
#print(t_end)
## Search for a finger
## Tries to initialize the sensor
try:
f = PyFingerprint('/dev/ttyUSB0', 57600, 0xFFFFFFFF, 0x00000000)
if ( f.verifyPassword() == False ):
raise ValueError('The given fingerprint sensor password is wrong!')
except Exception as e:
print('The fingerprint sensor could not be initialized!')
print('Exception message: ' + str(e))
exit(1)
## Gets some sensor information
print('Currently stored templates: ' + str(f.getTemplateCount()))
## Tries to search the finger and calculate hash
try:
print('Waiting for finger...')
## Wait that finger is read
while time.time() < t_end and ( f.readImage() == False ):
pass
## Converts read image to characteristics and stores it in charbuffer 1
f.convertImage(0x01)
## Searchs template
result = f.searchTemplate()
positionNumber = result[0]
accuracyScore = result[1]
if ( positionNumber == -1 ):
print('No match found!')
# Transaction to DoorPi: No Finger listed or too long- Timeout. // Please modify URL below with your credentials e.g: http://door:pi@doorpi:8080
r = requests.get('http://username:password@doorpi-url:port/control/trigger_event?event_name=OnKeyPressed_webservice.redled&event_source=doorpi.keyboard.from_filesystem')
r.json()
exit(0)
else:
print('Found template at position #' + str(positionNumber))
print('The accuracy score is: ' + str(accuracyScore))
# Transaction to DoorPi: Door Release OK. // Please modify URL below with your credentials e.g: http://door:pi@doorpi:8080
r = requests.get('http://username:password@doorpi-url:port/control/trigger_event?event_name=OnKeyPressed_webservice.dooropen&event_source=doorpi.keyboard.from_filesystem')
r.json()
## OPTIONAL stuff to secure the Transaction (future revisions)
##
## Loads the found template to charbuffer 1
f.loadTemplate(positionNumber, 0x01)
## Downloads the characteristics of template loaded in charbuffer 1
characterics = str(f.downloadCharacteristics(0x01))
## Hashes characteristics of template
print('SHA-2 hash of template: ' + hashlib.sha256(characterics).hexdigest())
except Exception as e:
print('Operation failed!')
print('Exception message: ' + str(e))
exit(1)
Alles anzeigen
Damit die Events von DoorPi verarbeitet werden können habe ich das "virtuelle Keyboard" aktiviert und mir folgende virtuelle Inputs erstellt (Kommentare mit "//" bitte bei allen folgenden Code's rauslöschen):
[keyboards]
onboardpins = piface
webservice = filesystem
[onboardpins_InputPins]
0 = call:11 // 1 und 2 sind die Türglocken
1 = call:12
3 = sleep:0 // Taster für den Start des Lesevorganges
4 = sleep:0 // Sabotagekontakt
[onboardpins_OutputPins]
0 = Tueroeffner // Hier hängt der öffner
5 = greenled // Wie der Name schon sagt..
6 = redled // Dito.
[webservice_InputPins] // Virtuele Inputs für die Anbindung des Fingerlesers (ohne weitere Funktion)
dooropen = sleep:0
redled = sleep:0
[webservice_keyboard]
base_path_input = /var/DoorPI/keyboard/inputs/
base_path_output = /var/DoorPI/keyboard/outputs/
bouncetime = 2000
polarity = 0
pressed_on_keydown = True
reset_input = True
Alles anzeigen
Die virtuellen Inputs lösen die folgenden Events aus:
[EVENT_OnKeyPressed_onboardpins.3]
10 = os_execute:/usr/local/etc/DoorPi/scripts/finger.py
[EVENT_OnKeyPressed_onboardpins.4]
10 = os_execute:/usr/local/etc/DoorPi/scripts/sabotage.sh
11 = break
[EVENT_OnKeyPressed_webservice.dooropen]
10 = out:Tueroeffner,1,0,3
20 = out:greenled,1,0,3
[EVENT_OnKeyPressed_webservice.redled]
10 = out:redled,1,0,1
15 = sleep:1
20 = out:redled,1,0,1
Alles anzeigen
EVENT_OnKeyPressed_onboardpins.3:
- Dieser Event wird vom Input 3 getriggert. Hier hängt der Taster zum starten des Fingerlesevorgangs dran
EVENT_OnKeyPressed_onboardpins.4
- Minimale Sicherheit: Wenn jemand das Lesergehäuse vor der Haustür öffnet, werde ich über das Script "sabotage.sh" via Telegram informiert, anschliessend stoppt DoorPi und nichts geht mehr (Vorsicht, In diesem Fall braucht's noch einen Schlüssel oder einen ssh-Zugang auf die DoorPi um neu zu starten).
EVENT_OnKeyPressed_webservice.dooropen:
- Dieser Event wird von "finger.py" angestossen, wenn der Lesevorgang erfolgreich war
- Zugleich wird die grüne LED für 3s. eingeschaltet (zeigt den erfolgreichen Lesevorgang an)
EVENT_OnKeyPressed_webservice.redled:
- Dieser Event schaltet die rote LED, wenn der Lesevorgang zu lange kein Ergebnis bringt (der Vorgang bricht nach 10s ab), oder der vorgehaltene Finger nicht verzeichnet ist.
Wenn dann alles aufgebaut ist, kann mittels Knopfdruck der Lesevorgang gestartet werden: Ist der Finger korrekt, wird die Türe freigegeben.
Das System hat noch einige leaks, so sind teilweise Wartezeiten zwischen Knopfdruck und Lesevorgang (der Leser wird zuerst initialisiert) sowie nach Abschluss des Lesevorgangs bis zum öffnen der Tür in Kauf zu nehmen.
- Das hat mit dem Verarbeiten der Events zu tun. Je nach dem was DoorPi sonst noch treibt, geht's schneller.
- Dieser Tatsache könnte mit einem DoorPi-Keyboard sicher abgeholfen werden - Leider reichen meine Python-Kenntnisse dafür (noch) nicht aus
Zum Thema Sicherheit ist vorweg zu nehmen, dies ist ein Experimental aufbau! Bitte nicht bei der nächsten Sparkasse verbauen
- Tauscht jemand den Leser mit einem baugleichen Modell mit vorgespeicherten Fingern, kann die Tür problemlos geöffnet werden. Deshalb habe ich den Sabotagekontakt vorgesehen.
- Hier würde das Speichern und Abgleichen des Hash's, welcher die Library anbietet, entgegenwirken. Da hänge ich mich dann mal dran.
Kritik und Verbesserungsvorschläge sind willkommen.