Wie im Thread Fingerabdrucksensor bereits besprochen, gab es den Bedarf nach einem Keyboard für einen Fingerabdruck-Sensor. Also anbei eine Anleitung:
Unterstützt werden unter anderem folgende Sensoren:
ZhianTec ZFM-20, ZFM-60, ZFM-70, ZFM-100
GROW R302, R303, R305, R306, R307, R551
FPM10A
pyFingerprint installieren (über apt-get)
Zuerst müsst ihr das PM Codeworks repository hinzufügen:
~$ echo "deb http://apt.pm-codeworks.de wheezy main" | sudo tee -a /etc/apt/sources.list
~$ wget -O - http://apt.pm-codeworks.de/pm-codeworks.de.gpg | sudo apt-key add -
Nachdem man nun die lokale Repository Liste updated, kann das pyFingerprint Packet installiert werden:
Wenn ihr den Sensor über einen Serial/USB-Konverter angeschlossen habt, sollte dieser beim Raspberry Pi unter /dev/ttyUSB0
jetzt ansprechbar sein.
Fingerabdrücke verwalten
Wechselt ins Verzeichnis des Paketes
Dort finden sich ein paar Programme, die mit dem pyFingerprint-Paket mitgeliefert werden.
- example_enroll.py: Damit lässt sich ein neuer Fingerabdruck auf dem Sensor registrieren (hier bitte die Position notieren!)
- example_search.py: Damit lässt sich nach einem registrierten Finger suchen und man bekommt dessen Position, falls man diese beim registrieren nicht notiert hat.
- example_delete.py: Damit lässt sich ein Fingerabdruck wieder vom Sensor löschen
Keyboard installieren
Jenachdem wo ihr eure DoorPi installation habt, können die Pfade natürlich abweichen, meist solltet ihr das DoorPi Verzeichnis aber etwa hier finden:
/usr/local/lib/python2.7/dist-packages/DoorPi2.x/
Dort wechselt dann in das Verzeichnis doorpi/keyboard/ und legt die Datei from_fingerprint.py mit folgendem Inhalt an:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from doorpi.keyboard.AbstractBaseClass import KeyboardAbstractBaseClass, HIGH_LEVEL, LOW_LEVEL
import doorpi
import threading
import time
from pyfingerprint.pyfingerprint import PyFingerprint
import logging
logger = logging.getLogger(__name__)
logger.debug("%s loaded", __name__)
def get(**kwargs): return Fingerprint(**kwargs)
class Fingerprint(KeyboardAbstractBaseClass):
name = 'Fingerprint Reader'
def readFingerprint(self):
try:
# Sensor initialisieren
sensor = PyFingerprint(self.__port, self.__baudrate, self.__sensoraddr, self.__password)
if not sensor.verifyPassword():
logger.warning('The given fingerprint sensor password is wrong!')
return None
logger.debug('Currently used templates: ' + str(sensor.getTemplateCount()) + '/' + str(sensor.getStorageCapacity()))
# Sensor-Lesen & Event-Handling
logger.debug('readFingerprint() started for %s', self.__timeout)
while (not self._shutdown and self.__active):
# Falls der Sensor nicht permanent aktiv ist und das Aktivitätsintervall überschritten ist - Abbruch
if (self.__timeout > 0 and (time.time() > self.__timeout)):
self.__active = False
return None
if (sensor.readImage()):
# Characteristics aus dem gelesenen Fingerabdruck auslesen und hinterlegen
sensor.convertImage(0x01)
# Datenbank nach diesen Characteristics durchsuchen
result = sensor.searchTemplate()
positionNumber = result[0]
accuracyScore = result[1]
# Input-Pin entsprechend der gefundenen Position aktivieren
self.last_key = positionNumber
self.last_key_time = time.time()
logger.debug('Found template at position #' + str(positionNumber))
logger.debug('The accuracy score is: ' + str(accuracyScore))
# Finger entweder gar nicht oder nicht exakt genug erkannt.
if (positionNumber == -1) or (accuracyScore < self.__security):
# Finger unbekannt - Event ausloesen
doorpi.DoorPi().event_handler('OnFingerprintFoundUnknown', __name__)
else:
# Finger bekannt - Event ausloesen
doorpi.DoorPi().event_handler('OnFingerprintFoundKnown', __name__)
# Dem Finger zugeordnete Events auslösen
if (self.last_key in self._InputPins):
self._fire_OnKeyDown(self.last_key, __name__)
self._fire_OnKeyPressed(self.last_key, __name__)
self._fire_OnKeyUp(self.last_key, __name__)
except Exception as ex:
logger.exception(ex)
def __init__(self, input_pins, output_pins, keyboard_name, conf_pre, conf_post, *args, **kwargs):
self.keyboard_name = keyboard_name
self._InputPins = map(int, input_pins)
self._OutputPins = map(int, output_pins)
self.last_key = ""
self.last_key_time = 0
self.__timeout = 0
# Spezielle Handler fuer (Un-)bekannte Finger registrieren
doorpi.DoorPi().event_handler.register_event('OnFingerprintFoundUnknown', __name__)
doorpi.DoorPi().event_handler.register_event('OnFingerprintFoundKnown', __name__)
# Config-Eintraege lesen, falls dort vorhanden.
section_name = conf_pre + 'keyboard' + conf_post
self.__port = doorpi.DoorPi().config.get(section_name, 'port', '/dev/ttyAMA0')
self.__baudrate = doorpi.DoorPi().config.get_int(section_name, 'baudrate', 57600)
self.__sensoraddr = doorpi.DoorPi().config.get(section_name, 'address', 0xFFFFFFFF)
self.__password = doorpi.DoorPi().config.get(section_name, 'password', 0x00000000)
self.__security = doorpi.DoorPi().config.get_int(section_name, 'security', 70)
# Events für hinterlegte InputPins registrieren (damit diese auch ausgeloest werden)
for input_pin in self._InputPins:
self._register_EVENTS_for_pin(input_pin, __name__)
# Dauerbetrieb oder nur auf Kommando? (Trigger-Pin definiert?)
self.__active = (len(self._OutputPins) == 0)
self._shutdown = False
if self.__active:
logger.debug('No trigger pin defined! Running permanently')
# Thread für den eigtl Lesevorgang starten
self._thread = threading.Thread(target=self.readFingerprint)
self._thread.daemon = True
self._thread.start()
self.register_destroy_action()
def destroy(self):
if self.is_destroyed:
return
self._shutdown = True
doorpi.DoorPi().event_handler.unregister_source(__name__, True)
self.__destroyed = True
def status_input(self, tag):
return (tag == self.last_key)
def set_output(self, pin, value, log_output=True):
parsed_pin = doorpi.DoorPi().parse_string('!' + str(pin) + '!')
if parsed_pin != '!' + str(pin) + '!':
pin = parsed_pin
logger.debug('out(parsed pin = %s)', parsed_pin)
pin = int(pin)
value = int(value)
log_output = str(log_output).lower() in HIGH_LEVEL
if pin not in self._OutputPins:
return False
if log_output:
logger.debug('out(pin = %s, value = %s, log_output = %s)', pin, value, log_output)
# Aktivieren oder deaktivieren?
old_state = self.__active
self.__active = (value > 0)
# Timeout-Intervall anpassen (bei 0 stoppt der Vorgang sowohl dadurch als auch da active false wird)
self.__timeout = time.time() + value
# Falls noch kein Lesevorgang laeuft, diesen ggf. starten
if self.__active and self.__active != old_state:
# Thread fuer den eigtl Lesevorgang starten
self._shutdown = False
self._thread = threading.Thread(target=self.readFingerprint)
self._thread.daemon = True
self._thread.start()
self.register_destroy_action()
return True
Alles anzeigen
Jetzt solltet ihr - nachdem ihr DoorPi neu gestartet habt - ein funktionierendes Keyboard für Fingerabdrucksensoren haben.
Konfiguration
Zum einen, müsst ihr euch entscheiden in welchem Modus ihr den Sensor betreiben wollt. Es besteht die Möglichkeit, den Sensor im dauerhaft auszulesen, was beim Testen aber zu Problemen führte oder auf ein Event hin. Als Beispiel für letzteres käme ein Bewegungssensor oder beim ZFM-70 der Capacitiv Touch Sensor (d.h. wenn das Sensorglas berührt wird) in Betracht.
Falls ihr keinen Dauerbetrieb wollt, müsst ihr einen Output-Pin für das Keyboard definieren. Über diesen und die Aktion "out" könnt ihr den Sensor dann für eine bestimmte Zeit anschalten. Wenn kein Output-Pin definiert ist, geht der Sensor in den Dauerbetrieb.
Beispiel für eine Konfiguration (hier nicht im Dauerbetrieb) (Kommentarzeilen bitte entfernen, sonst wird DoorPi meckern)
[keyboards]
fpreader = fingerprint
# fingerprint einen Trigger-Pin setzen (hier 1 bzw FingerprintAn als Alias)
[fpreader_OutputPins]
1 = FingerprintAn
# InputPins vom fpreader bzw. Position des Fingerabdruck im Speicher des Sensors mit Aktionen belegen
[fpreader_InputPins]
1 = out:Tueroeffner, 1, 0, 20
# Variablen des Keyboard (für alle ist auch ein Default-Werte hinterlegt)
[fpreader_keyboard]
port = /dev/ttyUSB0
security = 80
Alles anzeigen
Zusätzlich kann noch die Baudrate und das Passwort sowie die Adresse des Sensors definiert werden.
Wenn man nun, wie eingangs erwähnt z.B. auf einen Bewegungsmelder reagieren will (onboardpins muss natürlich als Keyboard, zB. piface registriert sein):
# Input 0 als Bewegungsmelder zuweisen und als solchen (input) definieren
[onboardpins_InputPins]
0 = Bewegungsmelder
# auf Bewegung für 30sec den Fingerabdrucksensor anschalten
[onboardpins_InputPins.Bewegungsmelder]
10 = out:FingerprintAn,30
Zusätzlich sind noch die Events OnFingerprintFoundKnown und OnFingerprintFoundUnknown registiert, falls egal ist um welchen Finger es sich jetzt genau handelt bzw. falls man jemanden darauf hinweisen möchte, dass ihm der Zutritt verwehrt wird.
Eine Integration in die Weboberfläche habe ich noch nicht vorgenommen, könnt ihr aber gerne beitragen