An open-source, high-performance indoor cycling training application built with the Qt framework (C++17). MaximumTrainer delivers structured interval workouts with real-time power, cadence, heart rate, and speed feedback, and controls smart trainers automatically via FTMS ERG mode. Browse and sync workouts from intervals.icu, or import your own .erg / .mrc files.
| Item | Details |
|---|---|
| Language | C++17 (≈ 95 % C++) |
| Framework | Qt 5.15.2 (Windows / Linux) · Qt 6.7.3 (macOS) |
| Build file | PowerVelo.pro (qmake) |
| Qt modules | core · gui · widgets · network · bluetooth · webenginewidgets · printsupport · concurrent |
| Trainer protocol | Bluetooth LE Fitness Machine Service (FTMS / 0x1826) for ERG resistance control |
| Sensor profiles | Heart Rate (0x180D) · Cycling Speed & Cadence (0x1816) · Cycling Power (0x1818) |
| Workout formats | .erg, .mrc (imported and converted to the native .workout XML format) |
| Workout source | Integrated TrainerDay.com browser for online workout plans |
| Device | How to wake it |
|---|---|
| Smart trainer | Start pedalling for a few seconds |
| Power meter | Start pedalling |
| Heart rate strap | Moisten the electrode contacts and put it on |
| Speed / cadence sensor | Spin the crank or wheel |
- Launch MaximumTrainer and log in.
- From the main window open Preferences → Device Connections (or press the gear icon).
- Click Scan / Add Devices. The BTLE scanner lists every nearby Bluetooth LE device.
- Select the correct profile for each sensor:
| Profile | UUID | Data provided | Smart-trainer ERG control |
|---|---|---|---|
| Heart Rate Monitor | 0x180D | Heart rate (bpm) | No |
| Cycling Speed & Cadence | 0x1816 | Speed (km/h) · Cadence (RPM) | No |
| Cycling Power | 0x1818 | Power (W) | No |
| Fitness Machine (FTMS) | 0x1826 | Speed · Cadence · Power | Yes — enables ERG mode |
Important: Select the Fitness Machine (FTMS / 0x1826) profile for your smart trainer if you want the app to set resistance automatically. Choosing a plain Power or Speed profile disables ERG control.
- Paired sensors appear with a green indicator. You can pair multiple sensors simultaneously (e.g. FTMS trainer + HR strap).
If you have no hardware — or want to test a new workout — choose Simulation in the connection dialog. The software hub emits realistic drifting values:
| Channel | Base value | Range |
|---|---|---|
| Heart rate | 140 bpm | 125–165 bpm |
| Cadence | 90 rpm | 80–100 rpm |
| Speed | 28 km/h | 23–33 km/h |
| Power | 200 W | 170–260 W |
The simulator responds to ERG load commands from the workout player, making it a full end-to-end test of the training logic without any Bluetooth hardware.
Option A — TrainerDay.com library (integrated)
- Click the Find Workouts tab in the left sidebar.
- Browse or search the TrainerDay.com catalogue directly inside the app.
- Double-click a workout to download it to your local library.
Option B — Import a custom file
- Go to File → Import Workout (or File → Import Course Folder for batch import).
- Select one or more
.ergor.mrcfiles. - MaximumTrainer converts them to its native format and adds them to your library.
Option C — Create your own
Use the built-in Workout Creator (toolbar → pencil icon) to build structured intervals with configurable power, cadence, or HR targets.
| Mode | How it works | Best for |
|---|---|---|
| ERG | App automatically adjusts trainer resistance so your actual power matches the target wattage. You control only cadence. | Structured interval workouts |
| Slope / Manual | App sends a constant incline grade to the trainer. Resistance changes naturally with speed, just like riding outdoors. | Free-riding, ramp tests, courses |
The workout dialog switches to Slope mode automatically when the current interval has no power target, or when you press Increase / Decrease Difficulty to override ERG.
Once a workout starts you will see:
- Interval countdown — time remaining in the current interval, and total workout time elapsed / remaining.
- Target vs. Actual Power graph — a QWT-based real-time plot showing the structured intervals as coloured zones and your live power overlaid on top.
- Metrics widgets — live Heart Rate · Cadence · Speed · Power · Left/Right Power Balance (if a dual-sided power meter is connected) · SpO₂ (if an oxygen sensor is connected).
- Controls — Start/Pause, Skip Interval, Adjust Difficulty (±5 % FTP increments), and Lap.
Completed workout data is saved as a FIT activity file and can be uploaded to Strava, TrainingPeaks, or SelfLoops from the post-workout screen.
Note: Screenshots showing the cross-platform UI will be added here. Contributions of high-quality screenshots on each platform are welcome — please open a pull request.
| Platform | Description |
|---|---|
| Windows | Main workout player with power graph and metrics |
| macOS | Dashboard showing the TrainerDay.com workout browser |
| Linux | App running on Ubuntu — proof of cross-platform build |
| Device Manager | BTLE scanner with multiple sensors connected |
Before running MaximumTrainer on Linux, ensure the following prerequisites are met:
BlueZ is the Linux Bluetooth stack. Install it and make sure the daemon starts automatically:
sudo apt-get install -y bluez
sudo systemctl enable --now bluetoothVerify the daemon is active:
sudo systemctl status bluetoothIf the BLE device scanner shows an empty list and no error, the most common cause is that your account is not in the bluetooth group:
sudo usermod -aG bluetooth $USERImportant: Group changes take effect only after you log out and back in (or reboot). You can apply the change to the current shell session immediately — without logging out — by running:
newgrp bluetooth
MaximumTrainer requires a Bluetooth 4.0 or newer adapter to communicate with BLE sensors and trainers. Check your adapter:
hciconfig -aLook for LMP Version: 6 (BT 4.0) or higher in the output. If hciconfig is not available, use:
bluetoothctl showThe following kernel modules must be loaded:
| Module | Purpose |
|---|---|
bluetooth |
Core BLE/Bluetooth stack |
hci_uart |
UART-attached adapters (most USB dongles) |
btusb |
USB Bluetooth adapters |
Check and load if needed:
lsmod | grep -E "bluetooth|hci_uart|btusb"
# If missing, load manually:
sudo modprobe bluetooth
sudo modprobe btusbOn most modern distributions (Ubuntu 20.04+, Fedora 36+) these modules load automatically when a Bluetooth adapter is detected.
All three platforms are built and tested automatically via GitHub Actions CI (see .github/workflows/build.yml). Use PowerVelo.pro with qmake and a standard C++ compiler.
| Dependency | Version | Platform | Notes |
|---|---|---|---|
| Qt | 5.15.2 | Windows · Linux | Core framework |
| Qt | 6.7.3 | macOS | Core framework |
| QWT | 6.2.0 | all | Plotting widgets (built from source) |
| VLC-Qt | 1.1.0 (Win) · 1.1.1 from source (Linux) | Windows · Linux | Internet radio / video player |
| SFML | 2.6.1 (Win) · system package (Linux/macOS) | all | Audio feedback |
- Windows 10 version 1703 (Creators Update) or later is required. Windows 7, 8, and 8.1 are not supported (missing WinRT BLE APIs).
- A Bluetooth 4.0+ adapter with a WDM-compatible driver.
- No special permissions or manifest entries are needed.
Required tools: Qt 5.15.2 (msvc2019_64), Visual Studio 2019+ (MSVC), 7-Zip
Environment variables — set before running qmake:
| Variable | Description | Example |
|---|---|---|
QTDIR |
Qt installation root for the target arch | C:\Qt\5.15.2\msvc2019_64 |
VLCQT_DIR |
VLC-Qt installation root (forward slashes) | C:/vlcqt |
QMAKEFEATURES |
Path to QWT features directory | C:\qwt\features |
qmake invocation:
$env:QMAKEFEATURES = "C:\qwt\features"
qmake PowerVelo.pro `
"VLCQT_INSTALL=C:/vlcqt" `
"SFML_INSTALL=C:/sfml/SFML-2.6.1"
VLCQT_INSTALLmust point to the VLC-Qt package root (containingbin/,include/,lib/). The pre-built 1.1.0 win64 MSVC package places import.libfiles directly inlib/.
SFML_INSTALLmust point to the SFML root (the directory containinginclude/andlib/).
The Windows Kit libraries (Gdi32,User32) are resolved automatically by the MSVC linker — noWINKIT_INSTALLis needed when building inside an MSVC developer command prompt.
Download links:
- Qt 5.15.2: https://www.qt.io/download
- VLC-Qt 1.1.0 (win64 MSVC): https://github.com/vlc-qt/vlc-qt/releases/tag/1.1.0
- SFML 2.6.1 (vc17 64-bit): https://github.com/SFML/SFML/releases/tag/2.6.1
- QWT 6.2.0: https://sourceforge.net/projects/qwt/files/qwt/6.2.0/
Install system packages and build VLC-Qt from source, then build the app:
sudo apt-get install -y \
qtbase5-dev qtwebengine5-dev qtconnectivity5-dev \
libqwt-qt5-dev libsfml-dev libvlc-dev libvlccore-dev \
cmake build-essential
# Build VLC-Qt 1.1.1 from source
cd /tmp && git clone --branch 1.1.1 --depth 1 https://github.com/vlc-qt/vlc-qt
cd vlc-qt && mkdir build && cd build
cmake .. -DQT_VERSION=5 -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr/local
make -j$(nproc) && sudo make install && sudo ldconfig
# Build MaximumTrainer
cd /path/to/MaximumTrainer_Redux
export PATH=/usr/lib/qt5/bin:$PATH
qmake PowerVelo.pro "INCLUDEPATH+=/usr/local/include" "LIBS+=-L/usr/local/lib"
make -j$(nproc)Uses Qt 6.7.3 with Clang. QWT is built from source (non-framework) against Qt 6. VLC-Qt is optional on macOS.
# Install Qt 6.7.3 via install-qt-action or the Qt Installer, then:
brew install sfml
# Build QWT 6.2.0 from source (non-framework, required for Qt 6)
curl -L -o /tmp/qwt.tar.bz2 "https://sourceforge.net/projects/qwt/files/qwt/6.2.0/qwt-6.2.0.tar.bz2/download"
tar -xjf /tmp/qwt.tar.bz2 -C /tmp && cd /tmp/qwt-6.2.0
sed -i.bak 's/QwtFramework//' qwtconfig.pri
qmake qwt.pro && make -j$(sysctl -n hw.logicalcpu) && sudo make install
# Build MaximumTrainer
cd /path/to/MaximumTrainer_Redux
qmake PowerVelo.pro \
"SFML_INSTALL=$(brew --prefix sfml)" \
"QWT_INSTALL=/usr/local/qwt-6.2.0"
makeBTLE sensor-data parsing is validated by a headless Qt Test suite in tests/btle/ — no real hardware required. Tests run on Ubuntu, Windows, and macOS in CI.
cd tests/btle
qmake btle_tests.pro
make -j$(nproc)
../../build/tests/btle_tests -v2Language files are used at runtime from the /language folder.
You need Qt Linguist to open and generate a new language file (.qm file).
Project now going through new revisions, with plans to enhance as an open-source interval trainer for indoor cycling & indoor rowing. backlog and work items can be found here
