Real-time physiological monitoring platform for sports medicine — Athlete · Coach · Medical
Biomedical Engineering Portfolio · Alonso Martín Díez · Universidad Europea de Madrid · 2026
MedSport Monitor is a professional desktop application that centralises real-time physiological data for sports teams. It connects IoMT wearable sensors via MQTT, analyses physiological signals through a Python microservice, and surfaces the results through a multi-role JavaFX interface.
┌─────────────────────────────────────────────────────────────┐
│ MedSport Monitor │
│ │
│ ┌──────────────┐ MQTT ┌──────────────────────────┐ │
│ │ Python │ ──────────► │ JavaFX 21 Desktop App │ │
│ │ Simulator │ medsport/ │ │ │
│ │ (paho-mqtt) │ {team}/ │ ┌────────┐ ┌─────────┐ │ │
│ └──────────────┘ {athlete}/ │ │Athlete │ │ Coach │ │ │
│ {sensor} │ │ UI │ │ UI │ │ │
│ ┌──────────────┐ │ └────────┘ └─────────┘ │ │
│ │ Mosquitto │ │ ┌──────────┐ │ │
│ │ MQTT Broker │ │ │ Medical │ │ │
│ │ :1883 │ │ │ UI │ │ │
│ └──────────────┘ │ └──────────┘ │ │
│ │ │ │
│ ┌──────────────┐ HTTP │ ┌──────────────────────┐│ │
│ │ FastAPI │ ◄─────────► │ │ SQLite DB (WAL) ││ │
│ │ Analytics │ :8000 │ └──────────────────────┘│ │
│ │ (uvicorn) │ └──────────────────────────┘ │
│ └──────────────┘ │
└─────────────────────────────────────────────────────────────┘
| Capability | Details |
|---|---|
| Live sensor streaming | HR, SpO₂, GPS track, accelerometer (10 Hz), cadence via MQTT |
| Multi-role access control | Three distinct dashboards: Athlete, Coach, Medical |
| Physiological analytics | Heart zones (Karvonen), HRV, fatigue index, ACR, cardiovascular risk |
| Clinical records | SOAP notes, medical restrictions, return-to-play tracking |
| PDF reports | Generated by FastAPI + ReportLab, downloadable from the medical panel |
| Team management | Alert thresholds per team, session control, real-time chat |
| Offline mode | App works fully without Mosquitto — demo data replaces live feeds |
| Layer | Technology |
|---|---|
| Desktop UI | JavaFX 21, FXML, CSS glassmorphism |
| Language | Java 21 (JPMS modules) |
| Build | Maven 3 + Maven Wrapper (mvnw) |
| Sensor data | Eclipse Paho MQTT 1.2.5 |
| Database | SQLite via JDBC (WAL mode) |
| Authentication | PBKDF2-SHA256 (JPMS-compatible, no BCrypt native lib) |
| Simulator | Python 3.11+, paho-mqtt 2.x, NumPy, SciPy |
| Analytics API | FastAPI + uvicorn, NumPy, SciPy |
| PDF reports | ReportLab 4.x |
| MQTT broker | Eclipse Mosquitto 2.x |
| HTTP client | java.net.http (JDK built-in, no extra deps) |
| JSON | Jackson 2.x |
Important: The project must be placed at
~/Downloads/MedSport/(i.e.C:\Users\<you>\Downloads\MedSporton Windows) because the database path is resolved relative to the user home. The database is auto-created on first launch.
cd MedSport
start.batcd MedSport
chmod +x start.sh && ./start.shThe startup script handles everything automatically:
- Starts Mosquitto MQTT broker on port 1883 (graceful skip if not installed)
- Creates a Python virtual environment and installs all dependencies
- Starts the FastAPI analytics service on
:8000 - Starts the physiological simulator (6 athletes, multi-threaded, publishes every 1 s)
- Compiles and launches the JavaFX desktop application
| Requirement | Minimum | Install |
|---|---|---|
| Java | 21 | Adoptium Temurin 21 — set JAVA_HOME |
| Python | 3.11+ | python.org |
| Maven | 3.9+ | Included as Maven Wrapper — no install needed |
| Mosquitto | 2.x | Optional — app runs in demo mode without it |
# Windows
winget install EclipseFoundation.Mosquitto
# macOS
brew install mosquitto
# Ubuntu / Debian
sudo apt install mosquittoMedSport/
│
├── 📱 java-app/ # JavaFX 21 desktop application
│ ├── src/main/java/com/medsport/
│ │ ├── auth/ # Login, SessionManager, PasswordUtils
│ │ ├── controllers/
│ │ │ ├── athlete/ # Dashboard, Sessions, Performance, Team, Profile
│ │ │ ├── coach/ # Dashboard, Session, Comparison, TeamMgmt,
│ │ │ │ # Simulator, Performance
│ │ │ ├── medical/ # Dashboard, History (SOAP), Restrictions,
│ │ │ │ # Risk, Reports
│ │ │ └── shared/ # MainLayout, TeamWizard, JoinTeam, Notifications
│ │ ├── models/ # User, Team, Session, SensorReading, Alert,
│ │ │ # SoapNote, MedicalRestriction, …
│ │ ├── services/ # DatabaseService, MqttService, AlertService,
│ │ │ # SessionService, TeamService, ChatService,
│ │ │ # AnalyticsRestClient, PdfService
│ │ └── views/components/ # RippleEffect, AnimatedBackground, ViewTransition
│ └── src/main/resources/
│ ├── css/ # base.css + role themes (athlete/coach/medical)
│ ├── fxml/ # All screen layouts (login, main, per-role views)
│ └── database/ # schema.sql + seed_data.sql (loaded on first run)
│
├── 🐍 python-simulator/ # IoMT sensor simulator
│ ├── simulator.py # Entry point — multi-threaded, 6 athlete threads
│ ├── config.py # Broker settings, athlete profiles, publish intervals
│ ├── requirements.txt # paho-mqtt, numpy, scipy
│ └── physiological_models/
│ ├── heart_rate_model.py # Realistic HR with effort ramps
│ ├── spo2_model.py # SpO₂ correlated with HR zone
│ ├── gps_model.py # GPS route simulation (lat/lon/speed/alt)
│ ├── accelerometer_model.py # 3-axis accelerometer at 10 Hz
│ └── athlete_profile.py # Per-athlete biometric parameters
│
├── 📊 python-analytics/ # FastAPI microservice for advanced analytics
│ ├── main.py # API routes
│ ├── requirements.txt # fastapi, uvicorn, numpy, scipy, reportlab
│ └── analysis/
│ ├── heart_zones.py # Karvonen zone distribution + HRV
│ ├── fatigue_index.py # ACR (Acute:Chronic Ratio), fatigue classification
│ ├── radar_metrics.py # 6-axis performance polygon
│ ├── cardiovascular_risk.py # Risk score + contributing factors
│ ├── hrv_analysis.py # RMSSD, SDNN, pNN50 from HR series
│ ├── training_load.py # Team-wide load, overload flags
│ └── pdf_generator.py # ReportLab clinical PDF generator
│
├── 🗄️ database/
│ ├── schema.sql # 17-table SQLite schema (auto-run on first start)
│ └── seed_data.sql # 29 demo users, 4 teams, sessions, readings, alerts
│
├── 📄 docs/
│ └── architecture.md # Detailed architecture and design decisions
│
├── mosquitto.conf # MQTT broker config (port 1883, anonymous)
├── start.bat # Windows one-click launch
├── start.sh # macOS/Linux one-click launch
└── stop_all.bat # Windows — kill all background services
| Screen | Features |
|---|---|
| Dashboard | Live HR with animated pulse dot, SpO₂ gauge, GPS track canvas (auto-scale route), heart zone bars (Z1–Z5), speed, cadence, session clock |
| Sessions | Table of past sessions with detail panel (date, type, duration, zone breakdown, avg HR) |
| Performance | Radar chart (6 axes: Endurance · Speed · Recovery · Consistency · Load · Intensity), Acute:Chronic Ratio, analytics from FastAPI |
| Team Chat | Real-time chat via SQLite polling, chat bubbles, unread badge |
| Profile | Edit name, sport, height, weight; change password with PBKDF2 re-hash |
| Screen | Features |
|---|---|
| Dashboard | FlowPane athlete cards with live HR/SpO₂/zone, alert feed with ACK, session quick-start button |
| Session | Start/stop session, per-athlete live rows with intensity display, zone range control, session timer |
| Comparison | Dual-athlete radar overlay (blue vs green), live HR/SpO₂ side-by-side |
| Team Management | Athlete roster, HR%/SpO₂%/weekly-load alert threshold sliders, saved to DB |
| Simulator Control | MQTT connection control panel, per-athlete intensity sliders, message log with counters |
| Performance | Per-athlete radar from radar-metrics, fatigue index, ACR, team load overview |
| Screen | Features |
|---|---|
| Dashboard | Athlete status grid (live HR/SpO₂ with alarm dots), critical alert feed with ACK, active restrictions list |
| History (SOAP) | Per-athlete SOAP note list, note detail viewer, new SOAP note form (S/O/A/P + private flag) |
| Restrictions | Add Full / Partial / HR-Limited restrictions with return-to-play date; resolve active restrictions |
| Risk Analysis | Per-athlete risk score bars (live HR + seeded component), team risk radar (6 axes) |
| Reports | PDF clinical report via FastAPI (/api/reports/generate-athlete-pdf), includes SOAP notes + risk score |
| Zone | % HRR | Training Description |
|---|---|---|
| Z1 | < 60% | Active recovery |
| Z2 | 60–70% | Aerobic base |
| Z3 | 70–80% | Aerobic endurance |
| Z4 | 80–90% | Lactate threshold |
| Z5 | > 90% | VO₂max / neuromuscular |
HRmax (Tanaka formula): 208 − 0.7 × age
HRR (Heart Rate Reserve): HRmax − RestingHR
| ACR Range | Status |
|---|---|
| < 0.8 | Under-training |
| 0.8 – 1.3 | Optimal — safe training zone |
| 1.3 – 1.5 | Caution — moderate spike risk |
| > 1.5 | High risk — overload injury zone |
Calculated from a rolling 7-day vs 28-day training load window.
| Sensor | Interval | MQTT Topic |
|---|---|---|
| Heart rate (bpm) | 1.0 s | medsport/{team}/{athlete}/hr |
| SpO₂ (%) | 2.0 s | medsport/{team}/{athlete}/spo2 |
| GPS lat/lon/speed/alt | 1.0 s | medsport/{team}/{athlete}/gps_* |
| Accelerometer x/y/z | 0.1 s | medsport/{team}/{athlete}/accel_* |
| Cadence (spm) | 1.0 s | medsport/{team}/{athlete}/cadence |
The FastAPI service runs at http://localhost:8000. Interactive docs at http://localhost:8000/docs.
| Endpoint | Method | Description |
|---|---|---|
/api/health |
GET | Service health check |
/api/analysis/heart-zones |
POST | Zone distribution + HRV from HR series |
/api/analysis/fatigue-index |
POST | ACR + fatigue classification |
/api/analysis/radar-metrics |
POST | 6-axis performance polygon |
/api/analysis/cardiovascular-risk |
POST | Risk score + contributing factors |
/api/analysis/training-load |
POST | Team-wide load + overload flags |
/api/analysis/session-summary |
POST | avg/max HR, speed, zones per session |
/api/reports/generate-athlete-pdf |
POST | Clinical PDF (base64) with SOAP notes + risk |
/api/reports/generate-session-pdf |
POST | Session-specific performance PDF |
/api/reports/generate-team-epidemiology |
POST | Team injury/illness epidemiology report |
SQLite at database/medsport.db — created automatically on first launch from schema.sql + seed_data.sql.
| Table | Description |
|---|---|
users |
All accounts (id, email, password_hash, role, name) |
athlete_profiles |
Biometrics (sport, height, weight, hr_max, resting_hr, dob) |
medical_profiles |
Doctor/staff profile data |
teams |
Team config (name, sport, join code, alert thresholds) |
team_members |
Athlete–team membership links |
training_sessions |
Sessions (start/end, type, active flag) |
session_participants |
Athlete participation per session |
sensor_readings |
Raw IoMT data (type, value, timestamp) |
alerts |
Physiological alerts (severity, acknowledged, parameter) |
soap_notes |
Clinical SOAP notes (S/O/A/P, private flag, doctor) |
medical_restrictions |
Training restrictions (type, HR limit, return date, status) |
medical_records |
Pathologies, allergies, medications, blood type |
personal_records |
Athlete performance personal bests |
chat_messages |
Team chat messages |
Seed data included: 29 users · 4 teams · 20 sessions · 87 session participants · 9 alerts · 8 SOAP notes · 6 active restrictions
All accounts use the password: Demo1234!
| Name | Team | |
|---|---|---|
| Carlos Méndez | coach@demo.com |
Equipo Élite A |
| Ana García | coach2@demo.com |
Equipo Resistencia B |
| Roberto Silva | coach3@demo.com |
Equipo Velocidad C |
| Miguel Torres | coach4@demo.com |
Equipo Fuerza D |
| Name | Team | |
|---|---|---|
| Dra. Laura Vidal | doctor@demo.com |
Equipo Élite A |
| Dr. Pedro Ruiz | doctor2@demo.com |
Equipo Resistencia B |
| Dra. Marta López | doctor3@demo.com |
Equipo Velocidad C |
| Name | Team | |
|---|---|---|
| Marco Torres | athlete1@demo.com |
Equipo Élite A |
| Elena Castro | athlete2@demo.com |
Equipo Élite A |
| Diego Herrera | athlete3@demo.com |
Equipo Élite A |
| Sofía Mendoza | athlete4@demo.com |
Equipo Élite A |
| Javier Romero | athlete5@demo.com |
Equipo Élite A |
| Lucía Fernández | athlete6@demo.com |
Equipo Élite A |
| Carlos Ruiz | athlete7@demo.com |
Equipo Resistencia B |
| Ana Martín | athlete8@demo.com |
Equipo Resistencia B |
| Pablo González | athlete9@demo.com |
Equipo Velocidad C |
| Isabel Sánchez | athlete10@demo.com |
Equipo Fuerza D |
(22 athletes total across 4 teams — see database/seed_data.sql for the complete list)
listener 1883
allow_anonymous trueMAVEN_OPTS=-Dprism.order=sw -Xmx512m
-Dprism.order=sw forces software rendering, which prevents black-screen issues on systems without a compatible GPU driver.
Edit ATHLETE_PROFILES to change simulated athletes, their base HR, VO₂max, and sport type. Each profile maps to a user in the database via athlete_id.
# Windows
$env:JAVA_HOME = "C:\Program Files\Java\jdk-21"
$env:MAVEN_OPTS = "-Dprism.order=sw -Xmx512m"
cd java-app
.\mvnw.cmd javafx:runcd MedSport
source venv/bin/activate # or venv\Scripts\activate on Windows
cd python-analytics
uvicorn main:app --reload --port 8000cd MedSport
source venv/bin/activate
cd python-simulator
python simulator.py- Add a constant to
SensorReading.SensorType - Add the mapping in
SensorReading.fromString() - Add a processing branch in
DashboardController.processReading() - Add the corresponding model in
python-simulator/physiological_models/
- Create the FXML layout in
src/main/resources/fxml/{role}/ - Create the controller in
controllers/{role}/ - Add a nav button to
MainLayout.fxml - Register the handler in
MainLayoutController.configureNavForRole()
- Karvonen, M.J. et al. (1957). The effects of training on heart rate. Annals of Medicine and Experimental Biology of Finland, 35(3), 307–315.
- Tanaka, H. et al. (2001). Age-predicted maximal heart rate revisited. Journal of the American College of Cardiology, 37(1), 153–156.
- Gabbett, T.J. (2016). The training-injury prevention paradox. British Journal of Sports Medicine, 50(5), 273–280.
- Task Force of the ESC / NASPE (1996). Heart rate variability: standards of measurement, physiological interpretation, and clinical use. Circulation, 93(5), 1043–1065.
- Eclipse Paho MQTT Client. https://eclipse.dev/paho/
- Eclipse Mosquitto MQTT Broker. https://mosquitto.org/
Alonso Martín Díez · Biomedical Engineering · Universidad Europea de Madrid · 2026