React-based frontend for ESP32 dual-pulley exercise rep counter system.
- Auto Device Discovery - Automatically scans network (192.168.108.3-30) to find LEFT/RIGHT ESP32 devices
- Real-time Updates - WebSocket connections to both devices for live rep counting
- Split-Screen Display - Responsive LEFT|RIGHT layout with large rep numbers
- Gold-on-Dark Theme - Custom Material UI theme with #FFD700 gold on dark background
- Debug Panel - Toggle visibility of sensor data (position, peak, valley, phase)
- Reset Controls - Send RESET command to both devices simultaneously
- Framework: React 18 + TypeScript + Vite
- UI Library: Material UI v7.2 + Material Icons
- State Management: Zustand with persist middleware
- Data Fetching: React Query (@tanstack/react-query)
- WebSocket: react-use-websocket
npm installnpm run devOpen http://localhost:5173 in your browser.
npm run buildProduction build outputs to dist/ directory.
- Store:
stores/useRepCounterStore.ts- Device state (LEFT/RIGHT WebSocket data)
- Discovered device IPs
- Connection status
- Debug mode (persisted to localStorage)
- React Query: Device discovery via REST API
- WebSocket: Real-time rep data from ESP32 devices
useDeviceDiscovery()- Network scan + device identificationuseDeviceWebSocket(ip, deviceId)- WebSocket connection per device
App
├── QueryClientProvider
├── ThemeProvider (gold-on-dark)
└── AppContent
├── DeviceDiscovery (automatic)
└── Layout
├── Header
├── LastSetDisplay (LEFT | RIGHT previous set)
├── RepDisplay (large current reps)
├── Controls (Reset, Debug toggle)
└── DebugPanel (conditional)
The app scans 192.168.108.3-30 by default. To change the network range, edit:
// src/hooks/useDeviceDiscovery.ts
const NETWORK_BASE = '192.168.108'
const SCAN_START = 3
const SCAN_END = 30GET http://{ip}/device/- Device identity (LEFT or RIGHT)
ws://{ip}:81/- Real-time state updates- Receives JSON messages every 1 second
- Sends
"RESET"command to clear rep counters
{
"device_identity": "LEFT",
"current_reps": 5,
"last_set_reps": 10,
"position": 42,
"last_peak": 50,
"last_valley": 10,
"phase": "GOING_UP",
"total_magnets": 123
}- Ensure ESP32 devices are powered on
- Verify devices are connected to the same network
- Check that devices are in the 192.168.108.0/24 subnet
- Confirm devices respond to
http://{ip}/device/endpoint - IMPORTANT: ESP32 firmware must include CORS headers (updated in latest version)
- Check that ESP32 WebSocket server is running on port 81
- Verify firewall/network settings allow WebSocket connections
- Check browser console for connection errors
- If you see CORS errors in the browser console, you need to update the ESP32 firmware
- The latest firmware includes
Access-Control-Allow-Origin: *headers on all HTTP endpoints - Flash the updated firmware to both LEFT and RIGHT devices
Click "Show Debug" to view:
- Connection status
- Current position
- Last peak/valley values
- Movement phase
- Total magnet passes
Following Agent OS best practices:
- ✅ No
transformhover effects (uses color/shadow/opacity) - ✅ No overflow scroll for layout (responsive grid/flex)
- ✅ Single Responsibility components
- ✅ Custom hooks for logic extraction
- ✅ No
useEffect(uses library callbacks instead)