Other
Google Smart Tap on the gate (Pi + Wallet Mate II)
Android / Google Wallet taps at the door use Google Smart Tap 2.x on the access-engine reader. The Pi decrypts the pass and checks the redemption value against the local member cache (and /api/access/verify as fallback).
This is separate from Apple VAS (transparent session + OSE.VAS.01 GET DATA). Both can be enabled on the same reader; the engine runs Smart Tap first, then Apple, so Android HCE is not broken by Apple’s session.
Code: access-engine/smart_tap/ (protocol ported from Google’s smart-tap-sample-app).
What “success” looks like in logs
SmartTap: redemption value: <pass-uuid-or-redemption-string>
NFC: Wallet tap detected — verifying token: <same>
Main: Access GRANTED (Wallet Local-First) …
Not success (wrong path — phone treated as a fob):
NFC: Card detected (UID: 08FA396C)
Main: Access DENIED for 08FA396C (Not found or inactive in local DB)
If wallet mode is on and the tap is a phone (ATR like 3B80800101), the engine skips UID fallback and logs:
NFC: Phone tap — wallet read did not return a pass token; skipping UID fallback (not a fob).
Prerequisites (Google + Pass Ninja + portal)
| Layer | Requirement |
|---|---|
| Google Pay & Wallet Console | Issuer / redemption setup; Collector ID; EC private key uploaded; key version noted |
| Pass class | redemptionIssuers includes your issuer; pass objects have smartTapRedemptionValue set (Pass Ninja: usually passes.id via nfc.message) |
| Pass Ninja (if used) | Google template + PASS_NINJA_API_FIELD_NFC=nfc.message on web-portal; member adds pass to Google Wallet (not only a barcode) |
| Portal | Active membership; pass synced to Pi (Sync … N active tokens cached) |
| Hardware | ACS Wallet Mate II (PICC), pcscd, member-access.service |
Collector ID on the terminal must match a collector ID on the pass in Google Wallet. Wrong ID → negotiate 9500 or get-data 9001 (no pass transmitted).
Pi configuration (device.env)
Copy from access-engine/device.env.example. Wallet-related vars:
# Required for Google Wallet taps
GOOGLE_SMART_TAP_COLLECTOR_ID=20180608 # numeric, from Google console
GOOGLE_SMART_TAP_KEY_VERSION=1 # matches uploaded key version
GOOGLE_SMART_TAP_PRIVATE_KEY_PATH=/home/porta/member-access-os/access-engine/google_smart_tap.pem
# Also required for online fallback + Apple (shared reader config)
ACCESS_VERIFY_URL=https://pass.qrtick.com/api/access/verify
ACCESS_POINT_ID=<uuid-from-portal-access-points>
APPLE_PASS_TYPE_IDENTIFIER=pass.com.example.memberaccess # Apple only
VAS_PRIVATE_KEY_PATH=/home/porta/member-access-os/access-engine/vas_private.pem
Optional: inline PEM instead of file:
GOOGLE_SMART_TAP_PRIVATE_KEY_PEM="-----BEGIN EC PRIVATE KEY-----\n..."
On boot you should see:
NFC: Wallet enabled (Apple VAS & Google Smart Tap).
If Google is missing: only collector ID set, or PEM path wrong → Wallet enabled may list Apple only or UID-only mode.
Deploy from your laptop
Pre-built device.env + keys on the Pi path; then sync code and restart:
# From repo root — adjust PI_USER / PI_HOST (Tailscale name or LAN)
PI_USER=porta PI_HOST=tyegym-gate-001 ./deploy.sh access-engine/device.env
Follow logs:
ssh porta@tyegym-gate-001 'sudo journalctl -u member-access -n 100 -f'
Or set DEPLOY_FOLLOW_LOGS=1 on deploy.
Lab provisioning only on the device: sudo ./access-engine/deploy.sh ./device.env (see on-site install runbook).
Member tap procedure (on-site)
- Member opens Google Wallet and displays the gym pass (not just the lock screen).
- Hold phone flat on the Wallet Mate 2–3 seconds.
- If multiple passes match, Google may show a carousel — member selects the gym pass and taps again.
Apple users: open pass in Apple Wallet if ECP did not auto-present (VAS: ECP not confirmed in logs).
Troubleshooting
| Symptom | Likely cause | What to check |
|---|---|---|
SmartTap: unable to authenticate (9500) | Collector ID / private key / key version mismatch vs Google console | Re-export PEM; confirm GOOGLE_SMART_TAP_* on Pi; same key registered for that collector |
SmartTap: no matching pass on device (9001) | Pass not in wallet, wrong collector on pass, or pass not opened | Pass Ninja Google install URL; redemptionIssuers; member has pass on screen |
Phone tap — … skipping UID fallback | Smart Tap ran but no token | Above + Pass Ninja NFC field on Google template |
ST2 not listed in OSE | Informational | Engine still tries SELECT Smart Tap 2 |
SmartTap: OSE label … (not AndroidPay) | Device is not presenting Google Wallet (iPhone / empty field) | Expected on iPhone; use Apple VAS path |
Access DENIED with UID hex | Old code or wallet not configured | Deploy latest access-engine/; confirm wallet enabled in logs |
Access GRANTED online but not local | Sync lag | Wait for Sync [Poll]: Auth sync complete; check facility slug / access point |
| Gate never opens, remote pulse works | Door / Shelly, not NFC | Shelly env; staff Release gate in portal |
Verify token shape: Redemption value should match passes.id (UUID) when using PASS_NINJA_API_FIELD_NFC=nfc.message. Pi cache uses that same id as serial_number during sync.
Protocol reference (for engineers)
| Step | APDU | Notes |
|---|---|---|
| 1 | SELECT OSE.VAS.01 | Detect AndroidPay; list Smart Tap 2 AID |
| 2 | SELECT A0000000476D0000111 | Smart Tap 2 (v1 AID …0101 is deprecated) |
| 3 | 90 53 NEGOTIATE | Collector signature + ECDH session keys |
| 4 | 90 50 GET DATA | Service types tried: generic 0x12, loyalty 0x03, all 0x00 |
| 5 | 90 C0 GET MORE | If status 9100 |
Implementation: access-engine/smart_tap/protocol.py → wallet_smarttap.try_smart_tap_token() → nfc_driver → main.handle_vas_token().
Related docs
member-wallet-tap-troubleshooting.md— member-facing phone wallet tap checklist (share from portal or support)member-nfc-tag-tap-troubleshooting.md— member-facing physical NFC tag / fob at the gateaccess-engine/device.env.example— env templateon-site-install-10-minute-runbook.md— golden image + site clockfleet-checkin-device-registry.md— hostname / serial registry- Google Smart Tap — communication flow
- Pass Ninja — Google NFC IDs