Features
Sign In & Sign Out
Track attendance with a 6-digit ID — typed or scanned with a barcode scanner.
Google Sheets Sync
Records export to a Google Sheet in the signed-in user's Drive, non-blocking in the background.
Optional Webcam Photos
Takes a webcam photo at each sign-in or sign-out to deter fraud. Frequency and trigger are configurable.
Late / Early Prompts
Prompts for a reason when signing out early or signing in late, with per-worksheet cutoff times.
Easy Sign In Mode
Auto-detects sign-in vs. sign-out from local state — no radio buttons needed.
Keyboardless Mode
Designed for barcode-scanner stations — configure 16-character barcodes for each action.
Who's Here
Live scrollable list of everyone currently signed in, with sign-in time. Sortable and auto-refreshing.
Themes & Scaling
Light, Dark, and Black & Gold themes with scalable fonts for any display size.
Packaged as Exe
Distributable as a single .exe file built with PyInstaller — no Python install required.
Quick Start (Executable)
If you downloaded a pre-built .exe:
- Place the
.exein its own folder —settings.jsonandtoken.jsonwill be written next to it. - Double-click the
.exeto launch. - The app opens in full-screen. The main form is greyed out and a yellow banner is shown until you sign in.
- Open Options → Google Settings and click "Sign In with Google". Your browser will open for OAuth consent. Complete the sign-in there.
- The banner disappears, the form becomes active, and the dropdown populates with your spreadsheet's worksheet names.
Quick Start (From Source)
- Install dependencies (first time only):
python dependencies.py - Run the app:
python main.py - The app opens in full-screen. The main form is greyed out and a yellow banner is shown until you sign in.
- Open Options → Google Settings and click "Sign In with Google". Your browser will open for OAuth consent. Complete the sign-in there.
- The banner disappears, the form becomes active, and the dropdown populates with your spreadsheet's worksheet names.
Requirements
- Python 3.8+
- Dependencies:
google-api-python-client,google-auth-oauthlib,gspread,opencv-python,Pillow
First-Time Setup
Sign In with Google
- Open Options → Google Settings.
- Click "Sign In with Google" — your browser opens for a one-time consent flow.
- The token is saved to
token.jsonin the app folder. Subsequent launches load it automatically; a browser is only opened again if the token expires or is revoked.
Connect a Google Sheet
The app must know which spreadsheet to write to. In Options → Google Settings → Sheets Config:
- Create a new sheet — enter a name and click Create. The app creates a spreadsheet in your Drive with the standard tab layout (Main Attendance, Build Season, IDs).
- Use an existing sheet — enter the exact spreadsheet title and click Connect. The sheet must already exist in your signed-in account's Drive.
The selected sheet name is saved to settings.json and reused on subsequent launches.
Sign In / Sign Out of Google
| Action | How |
|---|---|
| Sign in | Options → Google Settings → "Sign In with Google" |
| Sign out | Options → Google Settings → "Sign Out" |
Signing out deletes token.json. The yellow banner reappears and the form is greyed out until you sign in again.
Daily Use
- Launch the app. If previously signed in, the form activates automatically after sheets load (the dropdown briefly shows "Loading sheets…").
- Select the worksheet from the "Why are you here" dropdown (e.g. "Main Attendance", "Build Season").
- Select Sign In or Sign Out (hidden in Easy Sign In mode — direction is auto-detected).
- Type or scan a 6-digit ID into the entry field and press Enter (or click Enter).
- If the ID is new, the app prompts for a first and last name.
- A "Smile!" popup appears while the webcam captures a photo (if the camera is enabled).
- A confirmation dialog appears immediately — no waiting for Google.
Records are queued and pushed to Google Sheets/Drive in the background. The app remains fully usable while the push is in progress.
Easy Sign In Mode
When enabled (Options → App Behavior), the Sign In / Sign Out radio buttons are hidden. The app automatically determines direction from its local state: if the person is currently listed as signed in, the next scan signs them out, and vice versa.
Keyboardless Mode
Designed for barcode-scanner stations where no keyboard is attached. Configure 16-character scanner barcodes for each action (sign in, sign out, select worksheet, close popup). Enable via Options → Keyboardless Mode or activate directly after configuring bindings. Press Ctrl+E to exit keyboardless mode.
Who's Here
Click "Who's here?" in the header to open a scrollable, resizable list of everyone currently signed in, with their sign-in time. Sortable by name or time. Refreshes every 60 seconds; the Refresh button re-scans Google Sheets live.
People signed in for more than 12 hours are automatically signed out (recorded as "Didn't sign out") and removed from the list.
Camera Settings
| Setting | Effect |
|---|---|
| Camera Frequency | Probability a photo is taken per event (0.05 = 1-in-20, 1.0 = always) |
| Camera Trigger | Fire on Sign In, Sign Out, Both, or Never |
Setting the trigger to Never automatically disables the Image Link and Image Path logging fields.
Late Sign-In / Early Sign-Out Prompts
If cutoff times are configured (Options → Data Logging) and enabled for a worksheet, the app prompts for a reason when:
- A sign-in occurs after the late sign-in cutoff time (24h HH:MM).
- A sign-out occurs before the early sign-out cutoff time (24h HH:MM).
The reason is stored in the Reason column of the attendance sheet.
Sheet Structure
Every attendance spreadsheet created by the app has this layout:
Attendance worksheets (e.g. "Main Attendance", "Build Season")
| Columns A–F | — | Columns H–M |
|---|---|---|
| Sign-in block | (gap) | Sign-out block |
| ID, Name, Timestamp, Image Path, Image Link, Reason | ID, Name, Timestamp, Image Path, Image Link, Reason |
Headers are written dynamically based on which fields are enabled in Data Logging settings.
IDs worksheet
| Column A | Column B |
|---|---|
| Name | ID |
The "IDs" tab is reserved and cannot be used as an attendance target. It is populated automatically as new users register.
Settings Reference
Settings are stored in settings.json next to the executable (or script). All settings are editable via Options.
| Key | Description | Default |
|---|---|---|
ui_theme | Color theme: "Light", "Dark", "Black & Gold" | "Light" |
main_ui_scale | Font scale for the main window (0.5–2.0) | 1.0 |
whos_here_scale | Font scale for the Who's Here window (0.5–2.0) | 1.0 |
camera_frequency | Probability a photo is taken (0.05–1.0) | 1.0 |
camera_trigger | When camera fires: "in", "out", "both", "never" | "both" |
easy_signin_mode | Auto-detect sign-in vs. sign-out from local state | false |
keyboardless_mode | Enable barcode-scanner input mode | false |
keyboardless_bindings | 16-char scanner strings for each action | {} |
sheet_name | Google Spreadsheet title to write attendance to | "" |
data_logging.fields | Toggle each column: name, timestamp, image_link, image_path, reason | all true |
data_logging.worksheet_targets | Ordered list of attendance worksheet names for the dropdown | [] |
data_logging.time_cutoffs.late_signin | HH:MM after which sign-in is considered late | "15:45" |
data_logging.time_cutoffs.early_signout | HH:MM before which sign-out is considered early | "18:45" |
data_logging.cutoff_enabled_by_worksheet | Per-worksheet enable flag for cutoff prompts | {} |
To reset all settings to defaults, open Options → Reset Defaults.
For Developers
Project Structure
driveUpload.py — Google Sheets/Drive helpers, ID cache, background sync worker
google_auth.py — OAuth 2.0 sign-in/out, credential storage
camera.py — Webcam capture and gamma correction
dependencies.py — pip install helper
fonts/ — Bundled Poppins font files
images/ — Written at runtime; one folder per student (ID-Name/)
settings.json — Persisted user settings (written at runtime)
token.json — Persisted OAuth token (written after first sign-in)
Background Sync
Attendance records and new ID/name pairs are never written to Google synchronously. They are placed on attendance_queue and new_id_queue respectively. background_sync_worker (a daemon thread) drains both queues, retrying failed items after a 5-second back-off.
A periodic callback (register_api_refresh_callback) triggers a local refresh of the ID cache and Who's Here state every 8–16 Google API calls.
PyInstaller Packaging
The app supports --onefile packaging. _get_base_path() resolves sys._MEIPASS when frozen so bundled resources (fonts) are found correctly. token.json and settings.json are written next to the .exe (via _get_persistent_path()) so they survive re-extraction on each launch.
OAuth Credentials
The embedded OAuth client credentials (_B64_CLIENT_ID, _B64_CLIENT_SECRET in google_auth.py) are base64-encoded to avoid secret-scanning false positives. For desktop/installed apps Google explicitly documents that the client secret is not truly secret. Actual security comes from the user consenting in their browser.
To use your own Google Cloud project, replace the _B64_* values with your own base64-encoded client ID and secret from the Google Cloud Console (OAuth 2.0 → Desktop application type).