Local software stack for pen-driven learning sessions with hardware signal ingestion, automatic play/pause control, screenshot capture, calibration, analytics, and live dashboards.
- Session management:
- Start/stop sessions by subject
- Track writing time vs watching time
- Compute live and final focus score
- Hardware signal processing:
- Accept
PLAY,PAUSE,SHOT,PRESSURE:<value>signals - Supports two hardware input paths:
- Serial device input (
pyserial) - ESP HTTP polling input (
/dataendpoint)
- Serial device input (
- Accept
- Automatic playback control:
- Triggers keyboard play/pause key on
PLAY/PAUSEwhen enabled
- Triggers keyboard play/pause key on
- Screenshot workflow:
- Capture screenshots manually or from
SHOTsignal - Store metadata in JSON and files under date/subject folders
- Capture screenshots manually or from
- Calibration:
- Manual calibration endpoint
- Auto calibration (baseline phase + writing phase)
- One-time setup calibration lock after successful auto setup
- Live monitoring and debugging:
- Device status and ESP adapter status endpoints
- Debug log stream for device, calibration, screenshot, and control events
- WebSocket event broadcasting for real-time UI refresh
- Subject management:
- Add/list subjects
- Auto-add subject on session start if missing
frontend/(served athttp://localhost:8000):- Live device status and ESP adapter status
- Start/stop session
- Add subject
- Simulate
PLAY/PAUSE - Capture screenshot
- Auto calibration controls and status
- Session history, screenshot list, debug feed
frontend-react/(served by Vite athttp://localhost:5173):- Live backend integration (no fixed mock timer)
- Dashboard controls:
- Start/stop session
- Add subject
- Simulate
PLAY/PAUSE - Capture screenshot
- Start auto calibration
- Session history, screenshot viewer, debug panel
- Polling + WebSocket updates from backend
- Backend framework: FastAPI
- Event backbone:
EventBus+ async event handlers - Persistence: JSON collections in
data/ - Main modules:
backend/main.py: app lifecycle, API routes, event wiringbackend/device/service.py: serial input service + signal ingestionbackend/device/esp_http_service.py: ESP HTTP polling adapterbackend/session/manager.py: active session state/time accountingbackend/input/controller.py: keyboard trigger abstractionbackend/screenshot/service.py: screenshot capture and metadatabackend/calibration/service.py: manual + auto calibration flowbackend/health/monitor.py: disconnect timeout monitoringbackend/debug/service.py: in-memory rolling debug logs
data/sessions.json: session historydata/screenshots.json: screenshot metadatadata/subjects.json: subject listdata/calibration.json: calibration recordsscreenshots/YYYY-MM-DD/<Subject>/: captured images
- Create and activate virtual environment:
python3 -m venv .venv
source .venv/bin/activate- Install backend dependencies:
pip install -r requirements.txt-
Optional: create/edit
.envat repo root (/home/pritha/ptt/.env). -
Load environment variables:
set -a && source .env && set +a- Start backend:
uvicorn backend.main:app --reload --port 8000- Open classic frontend:
http://localhost:8000
cd frontend-react
npm install
npm run devOpen http://localhost:5173.
Default API behavior:
- In Vite dev on port
5173, frontend targetshttp://localhost:8000 - Override with
VITE_API_BASE_URL
Set:
SMART_PEN_SERIAL_PORT=/dev/ttyUSB0
SMART_PEN_BAUDRATE=115200The backend reads serial lines and ingests supported signals.
Set:
SMART_PEN_ESP_ENABLED=true
SMART_PEN_ESP_URL=http://<ESP_IP>/data
SMART_PEN_ESP_TIMEOUT_SECONDS=2
SMART_PEN_ESP_POLL_INTERVAL_SECONDS=0.2The ESP adapter polls endpoint text and forwards normalized signals to the same ingestion pipeline.
Debounce behavior for ESP polling:
- Repeated
PLAY/PAUSEvalues are suppressed unless state changes - Repeated
SHOTvalues fire only once until a non-SHOTvalue arrives
SMART_PEN_SERIAL_PORTSMART_PEN_BAUDRATE(default115200)SMART_PEN_TIMEOUT_SECONDS(default12)SMART_PEN_RECONNECT_SECONDS(default3)SMART_PEN_DEBUG_LOG_CAPACITY(default300)SMART_PEN_ENABLE_KEYBOARD_CONTROL(defaultfalse)SMART_PEN_PLAY_PAUSE_KEY(defaultspace)SMART_PEN_ESP_ENABLED(defaultfalse)SMART_PEN_ESP_URLSMART_PEN_ESP_TIMEOUT_SECONDS(default2)SMART_PEN_ESP_POLL_INTERVAL_SECONDS(default0.2)
POST /session/startPOST /session/stopGET /session/activeGET /sessions
GET /device/statusGET /device/esp/statusPOST /device/signal
POST /screenshotGET /screenshots
POST /calibratePOST /calibrate/auto/startGET /calibrate/auto/status
GET /subjectsPOST /subjects
GET /debug/logs- WebSocket:
/ws/events
PLAYPAUSESHOTPRESSURE:<number>
Examples:
PRESSURE:412.6pressure:327
- Screenshot capture requires GUI access and
pyautoguisupport. - Keyboard control is disabled by default for safety.
- If hardware is unavailable, you can still test via
POST /device/signalor frontend simulate buttons. - Legacy standalone
script.pywas the original prototype loop. Integrated runtime is now the backend services.