Compare commits
2 Commits
e15cbcbdd6
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
| c416eb8cef | |||
| 99bba1b59a |
+45
-74
@@ -10,98 +10,69 @@ from pynput.keyboard import Controller
|
|||||||
|
|
||||||
from card_reader import read_card
|
from card_reader import read_card
|
||||||
|
|
||||||
GET_UID = [0xFF, 0xCA, 0x00, 0x00, 0x00]
|
|
||||||
|
|
||||||
class NfcReaderService:
|
class NfcReaderService:
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
self._is_running = True
|
self._is_running = True
|
||||||
self._last_uid = None
|
self._last_uid = None
|
||||||
self._keyboard = Controller()
|
self._keyboard = Controller()
|
||||||
self._last_write = datetime.min
|
self._last_write = datetime(1900, 1, 1)
|
||||||
|
|
||||||
def run(self) -> None:
|
def run(self) -> None:
|
||||||
print("Reader ready.")
|
print("Reader ready.")
|
||||||
|
|
||||||
while self._is_running:
|
while self._is_running:
|
||||||
try:
|
try:
|
||||||
self._poll_card()
|
time.sleep(0.1)
|
||||||
|
card_request = CardRequest(timeout=None)
|
||||||
|
print("Waiting for card...")
|
||||||
|
card_service = card_request.waitforcard()
|
||||||
|
connection = card_service.connection
|
||||||
|
print("Connected to card!")
|
||||||
|
|
||||||
|
try:
|
||||||
|
connection.connect(CardConnection.T1_protocol)
|
||||||
|
|
||||||
|
GET_UID = [0xFF, 0xCA, 0x00, 0x00, 0x00]
|
||||||
|
uid, sw1, sw2 = connection.transmit(GET_UID)
|
||||||
|
|
||||||
|
if sw1 != 0x90:
|
||||||
|
raise CardConnectionException("UID read failed")
|
||||||
|
|
||||||
|
uid_hex = toHexString(uid)
|
||||||
|
|
||||||
|
if uid_hex == self._last_uid:
|
||||||
|
connection.disconnect()
|
||||||
|
time.sleep(0.5)
|
||||||
|
self._last_uid = None
|
||||||
|
continue
|
||||||
|
|
||||||
|
self._last_uid = uid_hex
|
||||||
|
|
||||||
|
user_id = read_card(connection)
|
||||||
|
if user_id is not None:
|
||||||
|
now = datetime.now()
|
||||||
|
if now - self._last_write > timedelta(seconds=2):
|
||||||
|
self._keyboard.type(str(user_id))
|
||||||
|
self._last_write = now
|
||||||
|
|
||||||
|
except (CardConnectionException, NoCardException):
|
||||||
|
pass
|
||||||
|
|
||||||
|
finally:
|
||||||
|
try:
|
||||||
|
connection.disconnect()
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
time.sleep(0.5)
|
||||||
|
|
||||||
except (KeyboardInterrupt, SystemExit):
|
except (KeyboardInterrupt, SystemExit):
|
||||||
self.stop()
|
self.stop()
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
print(f"[ERROR] Unexpected failure: {e}")
|
|
||||||
time.sleep(1)
|
|
||||||
|
|
||||||
def _poll_card(self) -> None:
|
|
||||||
card_request = CardRequest(timeout=1)
|
|
||||||
|
|
||||||
try:
|
|
||||||
card_service = card_request.waitforcard()
|
|
||||||
except NoCardException:
|
|
||||||
self._last_uid = None
|
|
||||||
return
|
|
||||||
|
|
||||||
connection = card_service.connection
|
|
||||||
|
|
||||||
try:
|
|
||||||
connection.connect(CardConnection.T1_protocol)
|
|
||||||
|
|
||||||
uid_hex = self._read_uid(connection)
|
|
||||||
if uid_hex is None:
|
|
||||||
return
|
|
||||||
|
|
||||||
# Card still present and unchanged -> ignore
|
|
||||||
if uid_hex == self._last_uid:
|
|
||||||
return
|
|
||||||
|
|
||||||
self._last_uid = uid_hex
|
|
||||||
|
|
||||||
self._handle_card(connection)
|
|
||||||
|
|
||||||
except (CardConnectionException, NoCardException) as e:
|
|
||||||
print(f"[CARD ERROR] {e}")
|
|
||||||
|
|
||||||
finally:
|
|
||||||
try:
|
|
||||||
connection.disconnect()
|
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
|
|
||||||
def _read_uid(self, connection) -> Optional[str]:
|
|
||||||
uid, sw1, sw2 = connection.transmit(GET_UID)
|
|
||||||
|
|
||||||
if sw1 != 0x90:
|
|
||||||
raise CardConnectionException("UID read failed")
|
|
||||||
|
|
||||||
return toHexString(uid)
|
|
||||||
|
|
||||||
def _handle_card(self, connection) -> None:
|
|
||||||
user_id = read_card(connection)
|
|
||||||
|
|
||||||
if user_id is None:
|
|
||||||
return
|
|
||||||
|
|
||||||
now = datetime.now()
|
|
||||||
|
|
||||||
# debounce keyboard output
|
|
||||||
if now - self._last_write < timedelta(seconds=2):
|
|
||||||
return
|
|
||||||
|
|
||||||
self._send_to_keyboard(user_id)
|
|
||||||
self._last_write = now
|
|
||||||
|
|
||||||
def _send_to_keyboard(self, user_id: str) -> None:
|
|
||||||
try:
|
|
||||||
self._keyboard.type(f"{user_id}\n")
|
|
||||||
except Exception as e:
|
|
||||||
print(f"[KEYBOARD ERROR] {e}")
|
|
||||||
|
|
||||||
def stop(self) -> None:
|
def stop(self) -> None:
|
||||||
print("Stopping NFC service.")
|
|
||||||
self._is_running = False
|
self._is_running = False
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
service = NfcReaderService()
|
service = NfcReaderService()
|
||||||
service.run()
|
service.run()
|
||||||
|
|||||||
@@ -4,6 +4,14 @@ This repository contains the tooling around NFC readers/writers.
|
|||||||
|
|
||||||
Currently supported NFC Device: ACR 1252U
|
Currently supported NFC Device: ACR 1252U
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
Make sure you have the apt packages `python3-dev` and `libpcsclite-dev` installed before installing the dependencies from `requirements.txt`.
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
The root path of the installation (next to `NfcReaderService.py`) needs to contain the `hmac_key.txt`. The correct key can be retrieved from sys admin.
|
||||||
|
|
||||||
## Tools:
|
## Tools:
|
||||||
|
|
||||||
- card_reader
|
- card_reader
|
||||||
@@ -17,6 +25,6 @@ Currently supported NFC Device: ACR 1252U
|
|||||||
## Intended usage
|
## Intended usage
|
||||||
|
|
||||||
Start `NfcReaderService` on terminals where LAN team needs to verify guest identity, EZGG LAN manager then reads user ID from clipboard.
|
Start `NfcReaderService` on terminals where LAN team needs to verify guest identity, EZGG LAN manager then reads user ID from clipboard.
|
||||||
`NfcReaderService` may be used as part of a systemd unit, to automate the startup process.
|
`NfcReaderService` may be used as part of a systemd unit, to automate the startup process. See service file for additional info.
|
||||||
|
|
||||||
Run `card_writer` when preparing tickets.
|
Run `card_writer` when preparing tickets.
|
||||||
+11
-3
@@ -1,10 +1,15 @@
|
|||||||
|
# THIS IS A USER-LEVEL SERVICE
|
||||||
|
# ~/.config/systemd/user
|
||||||
|
# systemctl --user daemon-reload
|
||||||
|
# systemctl --user enable nfc-reader.service
|
||||||
|
# systemctl --user start nfc-reader.service
|
||||||
|
|
||||||
[Unit]
|
[Unit]
|
||||||
Description=NFC Reader Service
|
Description=NFC Reader Service
|
||||||
After=network.target
|
After=graphical-session.target
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
Type=simple
|
Type=simple
|
||||||
User=ezgg
|
|
||||||
WorkingDirectory=/opt/nfc
|
WorkingDirectory=/opt/nfc
|
||||||
|
|
||||||
ExecStart=/opt/nfc/venv/bin/python /opt/nfc/NfcReaderService.py
|
ExecStart=/opt/nfc/venv/bin/python /opt/nfc/NfcReaderService.py
|
||||||
@@ -14,5 +19,8 @@ RestartSec=2
|
|||||||
|
|
||||||
Environment=PYTHONUNBUFFERED=1
|
Environment=PYTHONUNBUFFERED=1
|
||||||
|
|
||||||
|
Environment=DISPLAY=:0
|
||||||
|
Environment=XAUTHORITY=%h/.Xauthority
|
||||||
|
|
||||||
[Install]
|
[Install]
|
||||||
WantedBy=multi-user.target
|
WantedBy=default.target
|
||||||
|
|||||||
Reference in New Issue
Block a user