Kiosk QR decoded to a bare https://www.parksmarter.com/home/processQR (no zone) — even the official app rejects code-less URL QRs. Now: parse processQR?code= URLs, detect bare app-link QRs and prompt for the printed Zone ID, and add manual Zone ID entry. Lookups try getMetersByScannerCode then getMetersByZoneName (DSB13 maps to zone 113150). Fixes scanning real stickers, which previously passed the URL to the API. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|---|---|---|
| .gitea/workflows | ||
| app | ||
| docs | ||
| parksmarter-client | ||
| .gitignore | ||
| package-lock.json | ||
| package.json | ||
| README.md | ||
BigBrainParking
An unofficial, de-Googled client for the ParkSmarter (IPS Group) parking system, built to run on GrapheneOS with UnifiedPush notifications and distributed via Obtainium — no Google Play Services, no Firebase, no app store.
Monorepo layout
bigbrainparking/
├── parksmarter-client/ # Zero-dep TypeScript API client (reverse-engineered, live-verified)
├── app/ # Expo / React Native app (BigBrainParking)
└── .gitea/workflows/ # CI: build signed APK -> publish release for Obtainium
parksmarter-client— the API layer. All ~40 endpoints, the custom-header auth model, and response models (most verified against production). Runs anywhere; the app imports it directly. See its own README for the API details.app— the phone app. React Native (Expo prebuild), MapLibre maps, VisionCamera QR scanning, expo-secure-store token storage, local session-expiry reminders, and UnifiedPush wiring.
Features
| Feature | Status | Notes |
|---|---|---|
| Phone + password login | ✅ wired | tokens in OS keystore |
| Map of nearby meters (clickable, zoom, live GPS) | ✅ wired | MapLibre + OpenFreeMap tiles (no key) |
| "Near my last location" proximity search | ✅ wired | caches last GPS fix |
| QR kiosk scan → meter lookup | ✅ wired | on-device VisionCamera |
| Save / share kiosks | ✅ wired | local (no server favorites API exists) |
| Active / past sessions | ✅ wired | list views |
| Start a paid session | 🟡 gated | flow wired to postStartParkingSession, disabled pending review (real charge) |
| Session-expiry reminders | ✅ wired | local notifications — no FCM needed |
| UnifiedPush (ntfy) | 🟡 partial | endpoint registration done; server→ntfy bridge still needed (see below) |
Build & run (dev)
Requires Node 20, JDK 17, Android SDK, and a GrapheneOS device (or any Android device) with USB debugging.
npm install # installs both workspaces
npm run build --workspace parksmarter-client # compile the client
cd app
npx expo prebuild --platform android # generate native project
npx expo run:android # build + install a dev client
The app talks to prod (apiv2.parksmarter.com) by default — change extra.psEnvironment
in app/app.json to point elsewhere.
Notifications on GrapheneOS
Session-expiry reminders are scheduled locally from each session's end time, so they
need no push infrastructure and work fully offline of Google. app/src/notifications/
also wires UnifiedPush (distributor: ntfy) for any genuinely server-initiated push —
but note the ParkSmarter backend only pushes via FCM, so server push requires a small
FCM→ntfy bridge (a service holding an FCM token that forwards to your ntfy topic, then
registered via PUT /api/Device). Until that exists, local reminders cover the main case.
Distribution via Obtainium (self-hosted)
Tag a release and CI builds a signed APK and publishes it to this repo's releases; your
phone's Obtainium tracks the repo and offers updates. See
docs/DISTRIBUTION.md for the full server + CI + keystore setup.