# fusion_clock ACR122U Wedge Turns an ACR122U (or any PC/SC ACS reader) into a USB-HID-style keyboard wedge so the fusion_clock NFC kiosk can use it. ## Why this exists The ACR122U is a fantastic 13.56 MHz reader (better range than cheap HID readers, reads MIFARE Classic/DESFire/NTAG/FeliCa/ISO15693 — basically everything Ubiquiti UA-Pockets and most enterprise cards). **But it speaks PC/SC (CCID), not HID keyboard.** Browsers can't talk to PC/SC devices directly. This daemon bridges the gap: it polls the ACR122U over PC/SC, reads tag UIDs, and types them into the focused window as keystrokes — exactly like a USB-HID reader would. The fusion_clock kiosk page's existing keyboard listener picks them up the same way. ``` ACR122U → PC/SC → wedge.py → keystrokes → kiosk page in Chrome ``` ## Setup ### macOS ```bash brew install swig pip3 install -r requirements.txt python3 wedge.py --verbose ``` The first time the daemon tries to type a UID, macOS will pop up an **Accessibility permission** prompt. Grant it to Terminal.app (or whatever shell ran the script). This is one-time. If `pyscard` fails to install: ensure Xcode command-line tools are installed (`xcode-select --install`). ### Windows ```powershell pip install -r requirements.txt python wedge.py --verbose ``` No swig required — pyscard ships pre-built wheels on Windows. ### Linux ```bash sudo apt install pcscd pcsc-tools libpcsclite-dev swig sudo systemctl enable --now pcscd pip3 install -r requirements.txt python3 wedge.py --verbose ``` You may need to run with sudo or add your user to the `plugdev` group. ## Usage ```bash # Quiet mode — just types UIDs on tap python3 wedge.py # Verbose — prints every tap and reader event python3 wedge.py --verbose # Detect-only — prints UIDs but doesn't type them # (use this to verify the reader is working before granting Accessibility perms) python3 wedge.py --no-type --verbose ``` ## Output format UIDs are typed as colon-separated uppercase hex, followed by Enter: ``` 04:10:5B:CA:FD:22:90 ``` This matches what `FusionClockNfcKiosk._normalize_uid()` expects, so the kiosk recognizes it without any server-side translation. ## Debounce The daemon won't re-emit the same UID more than once within 2 seconds (so holding a card on the reader doesn't fire repeated clock-ins). Tap a different card, or wait 2 seconds, and the same card will re-emit. ## Running as a service For kiosk deployments, you want this to start at boot and stay running. ### macOS — LaunchAgent Create `~/Library/LaunchAgents/com.nexa.fusion-clock-acr-wedge.plist`: ```xml Label com.nexa.fusion-clock-acr-wedge ProgramArguments /usr/bin/python3 /Users/USERNAME/path/to/wedge.py RunAtLoad KeepAlive StandardOutPath /tmp/fusion-clock-wedge.log StandardErrorPath /tmp/fusion-clock-wedge.err ``` Load it: ```bash launchctl load ~/Library/LaunchAgents/com.nexa.fusion-clock-acr-wedge.plist ``` ### Windows — Task Scheduler Create a task to run `python wedge.py` at login. Or use NSSM to install it as a Windows service. ### Linux — systemd user service Create `~/.config/systemd/user/fusion-clock-wedge.service`: ```ini [Unit] Description=Fusion Clock ACR122U Wedge After=graphical-session.target [Service] ExecStart=/usr/bin/python3 /home/USER/path/to/wedge.py Restart=always [Install] WantedBy=default.target ``` Enable it: ```bash systemctl --user enable --now fusion-clock-wedge.service ``` ## Troubleshooting **"No PC/SC readers detected"** - macOS: PC/SC is built into the OS, no service to start. Just make sure the reader is plugged in. - Linux: `sudo systemctl status pcscd` — make sure it's running. - Windows: built-in. **"pyautogui can't type on macOS"** - Grant Accessibility permission to your terminal in System Settings → Privacy & Security → Accessibility. **"Reader detected but no UID on tap"** - Try `--verbose` to see error messages. - The card might not respond to the standard GET_UID APDU. Most 13.56 MHz cards do; some FeliCa variants don't. - Try `python3 wedge.py --no-type --verbose` to confirm detection works without involving the keyboard layer. **Keystrokes appearing in the wrong window** - pyautogui types into whatever window has focus. Make sure the kiosk page is focused when you tap. - This is the same behavior as a USB-HID reader — they both depend on the OS focused window. ## Future packaging This is the prototype. For client distribution we'll wrap it in: - macOS .app bundle (PyInstaller + py2app) - Windows .exe (PyInstaller) - Linux AppImage Plus autostart and an idle "no reader detected" status indicator. See parent module's todo list.