This project transforms an ESP32 microcontroller into a sophisticated, web-controlled timer specifically designed for badminton courts and sports facilities. It provides a clear, responsive user interface that can be accessed from any device with a web browser on the same local network.
Version: 3.1.0
The timer is ideal for clubs, training facilities, or personal use, ensuring fair and consistent timing for games, practice sessions, and automated scheduling for multiple clubs sharing court time.
- Web-Based Interface: Control the timer from any device with a web browser. No app installation required.
- Responsive UI: Works seamlessly on desktop, tablet, and mobile devices.
- Simple Start/Stop Timer: Quick manual control for practice sessions and matches.
- Real-Time Synchronization: All connected devices show the same time with 60fps smooth countdown.
- Non-Blocking Siren: External relay/siren control without freezing the interface.
- Automated Scheduling: Create weekly recurring schedules that automatically start the timer.
- Weekly Calendar View: Visual grid showing all scheduled sessions across the week.
- Club-Based Organization: Each operator manages their own club's schedules.
- Enable/Disable Toggle: Turn scheduling system on/off without deleting schedules.
- Flexible Time Slots: Minute-level precision for scheduling (e.g., Monday 18:30 for 90 minutes).
- Viewer Mode: Anyone can view the timer without credentials (no control access).
- Operator Role: Club coordinators can create schedules for their club and control the timer.
- Admin Role: Full access to user management, all schedules, and system configuration.
- Default Credentials: Admin username is
admin, password isadmin(change immediately!). - Factory Reset: Restore all settings and users to defaults.
- Add/Remove Operators: Admin can create operator accounts for different clubs.
- Password Management: Users can change their own passwords.
- Session Timeout: Automatic logout after 30 minutes of inactivity.
- Rate Limiting: Protection against rapid-fire requests (10 messages/second limit).
- Real-Time Clock: Displays current time, automatically synchronized from the internet via NTP.
- NTP Sync Indicator: Visual indicator showing time synchronization status.
- Configurable Timezone: Choose from 20 common timezones worldwide with automatic DST adjustment.
- Persistent Settings: All settings, schedules, and users saved to non-volatile memory.
- Over-the-Air (OTA) Updates: Wireless firmware updates protected by password.
- Flexible WiFi Configuration: Captive portal or hardcoded credentials.
- 🔒 Enhanced Security: SHA-256 password hashing with automatic migration from plaintext
- 🔒 HTTPS Validation: Let's Encrypt certificate validation for Hello Club API integration
- 🔒 XSS Protection: HTML escaping for all user-generated content
- 🔒 Stronger Passwords: Minimum password length increased from 4 to 8 characters
- 🌍 International Support: Configurable timezone selection (20 common timezones)
- 🔧 Reliability Improvements: Timer overflow handling, 30-second schedule checks, API retry logic
- 💾 Memory Safety: Dynamic JSON allocation to prevent stack overflow
- 🛡️ Input Validation: IANA timezone format validation, password hash verification
- ✨ Complete Authentication System: Three-tier role-based access control
- ✨ Automated Scheduling: Weekly recurring schedules with calendar view
- ✨ User Management: Add/remove operators, password changes
- ✨ NTP Sync Status: Real-time indication of time synchronization
- ✨ Session Management: 30-minute timeout with automatic viewer downgrade
- ✨ Rate Limiting: Protection against abuse
- ✨ Local Test Server: Node.js mock server for testing without hardware
- 🔧 16 Bug Fixes: All critical, high, and medium priority issues resolved
- 📚 Comprehensive Documentation: Complete code reviews, user guides, API docs
Want to try the interface before deploying to ESP32?
cd test-server
npm install
npm startOpen http://localhost:8080 and login with:
- Admin:
admin/admin - Operator:
operator1/pass123 - Viewer: Leave fields empty
See test-server/README.md for full details.
- Hardware Setup: Connect ESP32, relay module, and siren (see INSTALL_GUIDE.md)
- Configure Security: Rename
src/wifi_credentials.h.exampletosrc/wifi_credentials.hand set passwords - Build & Upload:
platformio run --target upload # Upload firmware platformio run --target uploadfs # Upload web interface
- Configure WiFi: Connect to
BadmintonTimerSetupnetwork and enter your WiFi credentials - Access Timer: Navigate to http://badminton-timer.local
- ESP32 Development Board
- 5V Single-Channel Relay Module
- External Siren or Buzzer (12V recommended)
- 5V USB Power Supply (for ESP32)
- Separate Power Supply for Siren (match siren voltage)
- Jumper Wires
See INSTALL_GUIDE.md for complete wiring diagram and assembly instructions.
-
Navigate to
src/directory and renamewifi_credentials.h.exampletowifi_credentials.h -
Edit
src/wifi_credentials.hand update:OTA_PASSWORD- Password for firmware updatesWEB_PASSWORD- Password for web interface (backward compatibility - now uses user system)
-
Change admin password after first login:
- Login as
admin/admin - Click user icon → Change Password
- Set a strong password immediately
- Login as
-
Create operator accounts:
- Login as admin
- Click user icon → Manage Users
- Add operators for each club with unique passwords (minimum 8 characters)
Example:
const char* OTA_PASSWORD = "MySecureOTA2024!";
const char* WEB_PASSWORD = "legacy"; // Not used in v3.0Security Note: The wifi_credentials.h file is ignored by git to protect your passwords. Never commit this file to a public repository.
New in v3.1: The system now supports configurable timezones for international deployment.
- Login as admin (only administrators can change timezone)
- Navigate to Settings (user icon in top navigation)
- Locate System Settings section (admin-only area)
- Select your timezone from the dropdown menu (20 common timezones available)
- Changes apply immediately - all schedules and time displays update instantly
The system includes 20 commonly-used timezones:
- Oceania: Pacific/Auckland (NZ), Australia/Sydney, Pacific/Fiji
- Asia: Asia/Tokyo, Asia/Singapore, Asia/Hong_Kong, Asia/Kolkata, Asia/Dubai
- Europe: Europe/London (UK), Europe/Paris, Europe/Berlin, Europe/Moscow
- Americas: America/New_York (EST/EDT), America/Chicago (CST/CDT), America/Denver (MST/MDT), America/Los_Angeles (PST/PDT), America/Toronto, America/Mexico_City, America/Sao_Paulo
- UTC: UTC (Universal Coordinated Time)
- Persistent Storage: Timezone setting is saved to non-volatile memory (survives reboots)
- Automatic DST: Timezones with daylight saving time automatically adjust
- Schedule Conversion: Hello Club events are converted from UTC to your local timezone
- Default Timezone: Pacific/Auckland (New Zealand) - change on first setup if deploying elsewhere
Important: Ensure timezone is set correctly before creating schedules. Changing timezone after schedules are created does not retroactively update existing schedule times.
- View timer countdown
- View current schedules
- Cannot: Control timer, create schedules, change settings
- Everything viewers can do, plus:
- Start/stop timer manually
- Create/edit/delete their own club's schedules
- View only their own club's schedules
- Change their own password
- Cannot: See other clubs' schedules, manage users, factory reset
- Everything operators can do, plus:
- View all schedules from all clubs
- Add/remove operator accounts
- Change admin password
- Perform factory reset
- Manage system settings
- Power on the ESP32
- Connect to WiFi network:
BadmintonTimerSetup - Browser should auto-open setup page (or go to
http://192.168.4.1) - Select your network, enter password, click Save
- ESP32 restarts and connects to your network
- Rename
src/wifi_credentials.h.exampletosrc/wifi_credentials.h - Edit file and set your SSID and password:
#define WIFI_SSID "YourNetworkName" #define WIFI_PASSWORD "YourNetworkPassword"
- Upload firmware - ESP32 will auto-connect, bypassing captive portal
- Login: Enter your operator username and password
- Access Schedules: Click the calendar icon in the top navigation
- Enable Scheduling: Toggle the "Automatic Scheduling" switch to ON
- Create Schedule:
- Click "Add Schedule" button
- Enter your club name
- Select day of week (Sunday-Saturday)
- Set start time (hour and minute)
- Set duration in minutes
- Click Save
- View on Calendar: Your schedule appears in the weekly grid
- Edit/Delete: Click any schedule block to edit or delete it
Admins can see and manage schedules from all clubs. Use this to:
- Resolve scheduling conflicts between clubs
- View overall court utilization
- Remove schedules if needed
When scheduling is enabled:
- ESP32 checks every minute if any schedule should trigger
- If current time matches a schedule's start time, timer automatically starts
- Timer runs for the scheduled duration
- Prevents re-triggering within 2 minutes (safety window)
Important: Ensure NTP time is synced (check the ✓ indicator next to the clock) for schedules to work correctly.
Once connected to your local network:
Recommended: http://badminton-timer.local
Alternative: Use ESP32's IP address (find in router's DHCP client list)
If badminton-timer.local doesn't work:
- Use IP Address: Find ESP32's IP in your router and use that
- Configure Static IP: Set a fixed IP for the ESP32 in your router
- Enable mDNS: Check router settings for mDNS/Bonjour support
- Try Different Browser: Some browsers have better mDNS support
Update firmware wirelessly after initial USB upload:
- OTA Hostname:
badminton-timer.local - OTA Password: Set in
src/wifi_credentials.h
In PlatformIO:
platformio run --target upload --upload-port badminton-timer.localSecurity Note: Use a strong, unique OTA password. Default is insecure and MUST be changed.
- README.md (this file) - Overview and quick start
- INSTALL_GUIDE.md - Complete hardware assembly and software installation
- USER_GUIDE.md - End-user guide for operators and admins
- ARCHITECTURE.md - System architecture and design decisions
- API.md - WebSocket API reference for developers
- CHANGELOG.md - Version history and release notes
- CODE_REVIEW_FINDINGS.md - First code review (16 issues found and fixed)
- CODE_REVIEW_ROUND_2.md - Second code review (verification and final assessment)
- test-server/README.md - Local testing server documentation
esp32-badminton-timer/
├── src/
│ ├── main.cpp # Main application with WebSocket handlers
│ ├── users.h/cpp # User authentication system
│ ├── schedule.h/cpp # Schedule management system
│ ├── timer.h/cpp # Timer logic and state machine
│ ├── siren.h/cpp # Non-blocking siren control
│ ├── settings.h/cpp # NVS persistence layer
│ ├── config.h # System configuration and constants
│ └── wifi_credentials.h # WiFi and security credentials (not in git)
├── data/
│ ├── index.html # Web interface structure
│ ├── style.css # Complete UI styling
│ └── script.js # Client-side WebSocket and UI logic
├── test-server/
│ ├── server.js # Node.js mock server for local testing
│ ├── package.json # Dependencies
│ └── README.md # Test server documentation
├── docs/
│ └── (documentation files)
├── platformio.ini # PlatformIO configuration
└── README.md # This file
Backend (ESP32):
- Arduino Framework for ESP32
- AsyncWebServer (HTTP server)
- AsyncWebSocket (bidirectional real-time communication)
- ArduinoJson (JSON serialization)
- ezTime (NTP time synchronization)
- NVS/Preferences (non-volatile storage)
- SPIFFS (filesystem for web files)
Frontend (Web Browser):
- Vanilla JavaScript (no frameworks)
- WebSocket API
- CSS Grid Layout (calendar view)
- requestAnimationFrame (smooth 60fps countdown)
- Web Audio API (sound effects)
Development:
- PlatformIO (build system)
- Node.js + Express + ws (mock server for testing)
- Git (version control)
| Metric | Value |
|---|---|
| WebSocket latency | 5-50ms (local network) |
| Timer precision | ±10ms (server-side) |
| Display update rate | 60fps (client-side) |
| Sync interval | 5 seconds |
| Session timeout | 30 minutes inactivity |
| Rate limit | 10 messages/second per client |
| Max schedules | 50 (configurable) |
| Max operators | 10 (configurable) |
| Memory usage (ESP32) | ~60KB RAM |
| Flash usage | ~1.2MB program + ~200KB SPIFFS |
- Check ESP32 has internet access
- NTP requires UDP port 123 outbound
- Wait 30 seconds after boot for first sync
- Check serial monitor for NTP errors
- Ensure "Automatic Scheduling" toggle is ON
- Verify NTP sync indicator shows ✓ (green checkmark)
- Check schedule time matches current time in your configured timezone
- Verify timezone is set correctly (Settings → System Settings)
- Wait 2 minutes after last trigger (safety cooldown)
- Verify operator account was created by admin
- Check username and password (case-sensitive)
- Try factory reset if forgotten (admin only)
- Check serial monitor for auth errors
- This is normal for admins (they see all schedules)
- Operators should only see their own club's schedules
- Check you're logged in with correct username
- Default is 30 minutes of inactivity
- Any message to server resets timeout counter
- Adjust
SESSION_TIMEOUTinmain.cppif needed
This project is production-ready as of v3.0. Contributions welcome:
- Fork the repository
- Create a feature branch
- Make your changes
- Test thoroughly (use test-server for UI changes)
- Submit a pull request
See CODE_REVIEW_ROUND_2.md for known minor issues that could be fixed.
MIT License - See LICENSE file for details
Developed by: Claude Code (Anthropic) Project Type: Open Source Language: C++ (ESP32), JavaScript (Frontend) Platform: ESP32 / Arduino Framework
For issues, questions, or feature requests:
- Check existing documentation first
- Review code review documents for known issues
- Check serial monitor output (115200 baud) for errors
- Test with local mock server to isolate hardware vs software issues
- v3.1.0 (2025-10-30) - Security hardening (SHA-256, HTTPS, XSS), configurable timezone, reliability improvements
- v3.0.0 (2025-10-30) - Authentication, scheduling, user management, NTP status, 16 bug fixes
- v2.0.0 (2025-10-29) - Modular architecture, improved timing, WebSocket sync
- v1.0.0 (Initial) - Basic timer functionality
See CHANGELOG.md for detailed version history.
Last Updated: 2025-10-30 Project Status: ✅ Production Ready Tested On: ESP32-WROOM-32