Hello, I am developing a functionality to be able to show html files for workout sessions.
It is an extension of current hability to open a web page or an html file (web page chart), but adding a way for that page to track real time telemetry, that is the basic need to track any training session:
A regular and independent html file with embedded Javascript, not based on a server backend (the usual web page), can show real time telemetry metrics, as well as any graph, map, or whatever you can came up with in its design, with the added value that it will track current data in training session.
That can change completely the look of a workout session: instead of tiles with metrics and graphics already predefined (really nice, indeed, but changes of the look are not completely flexible), we can insert html views with all their graphical possibilities.
In Activities view there exist great possibilities using python and R integrations in GC; you can build nice graphs, and also html views directly created with python on the fly. Training views lack such hability. It is understandable, as a real time 'channel' can be difficult to implement embedded in python engine, probably.
I have based the development in a real time web I built for real time track of athletes in a competition. I liked its look and thought that would be nice to have it in GC training sessions. It was only a matter of changing the source of real time time data.
The architecture could be based on websockets for real time data and and API REST for configuration data, as it was in my 'real world' project; or it could use QtWebChannel technology, more close to GC paradigm.
This last seemed better for integration in GC, as it is already used in some parts (live map IIRC), and avoids the need of opening ports, a local web server, etc.
On the other hand, with websockets data could be accesible outside GC, so that sessions could be followed remotely, but I think that doesn't make up for the architectural implications. And it can be implemented afterwards, almost easily, if desired, changing the webchannel development, as the functionality and behaviour would be identical.
The development is not ready yet, but close to; it could incorporate other requirements, changes, etc, if there is interest on it.
The webchannel has some funcions to be invoked by the JS embedded in html (config data mainly: getConfig() and getPlannedRoute()), as well as signals that can be fetched by the JS for real time telemetry (telemetry(), plannedRouteChanged(), stateChanged())
- As an initial guess, getConfig() provides a JSON structure like this (with sample data):
{
// Maxims for dials:
"max_speed_kmh": 60,
"max_power_w": 250,
//
Default, if no power zones
"max_hr_bpm": 200, //
Default, if no HR zones
"mapbox_token": "pk.xxx",
"power": {
"cp": 290,
"ftp": 285,
"wprime": 20000,
"pmax": 900,
"aetp": 220,
"zoneLows": [0, 160, 200, 240, 280, 320, 360],
"zoneNames": ["Z1", "Z2", "Z3", "Z4", "Z5", "Z6", "Z7"]
},
"hr": {
"lthr": 170,
"aethr": 150,
"restHr": 50,
"maxHr": 190,
"zoneLows": [0, 115, 140, 155, 170, 180],
"zoneNames": ["Z1", "Z2", "Z3", "Z4", "Z5"],
"zoneTrimps": [0.9, 1.1, 1.2, 2.0, 5.0]
}
}
("mapbox_token" is a specific need for the map I use in a html; it would be removed, probably) -> Although this will arise a new debate about what if some developed html requires very specific data (as the date or previuos activity, or total elevation gain,...): there always exist the possibility to send data based on an external requirement file or environment variables...
- Telemetry data currently contains:
{"timestamp":..., "lat":..., "lon":..., "alt":..., "slope":..., "speed_kmh":..., "hr_bpm":..., "power_w":..., "cadence_rpm":..., "distance_km":...}
I am attaching a screenshot of a training session using two html files I am testing, along with current telemetry data fields using tiles; they are tests, only to show capabilities of the development. I have to say that I neither know JavaScript nor html, but using AI is easy to create nice pages, as these are the case.

html only needs to be able to 'connect' to the webchannel, that as long as it is integrated in the same process (no external server nor different processes, it is GC who runs its internal browser through Qt), it is a trivial task. Following is a basic html that can be watched in GC, and its output during a workout.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>GoldenCheetah Minimal WebChannel Example</title>
<!-- Include the standard Qt WebChannel transport script provided by GoldenCheetah -->
<script src="qrc:///qtwebchannel/qwebchannel.js"></script>
<style>
body {
font-family: sans-serif;
padding: 20px;
background-color: #f4f4f9;
color: #333;
}
.container {
background: #fff;
padding: 20px;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
max-width: 600px;
margin: 0 auto;
}
pre {
background: #eee;
padding: 10px;
border-radius: 4px;
overflow-x: auto;
}
.telemetry-data {
font-size: 1.2em;
margin: 10px 0;
}
.val {
font-weight: bold;
color: #0056b3;
}
</style>
</head>
<body>
<div class="container">
<h1>GC WebChannel Bridge Test</h1>
<p>This is a minimal example showing how to connect an HTML file to GoldenCheetah using <strong>QtWebChannel</strong>.</p>
<h2>1. Configuration Data</h2>
<p>Data retrieved from <code>window.gc.getConfig()</code>:</p>
<pre id="config-display">Waiting for connection...</pre>
<h2>2. Real-Time Telemetry</h2>
<p>Data received via <code>window.gc.telemetry.connect(...)</code>:</p>
<div class="telemetry-data">Speed: <span id="telemetry-speed" class="val">0.0</span> km/h</div>
<div class="telemetry-data">Power: <span id="telemetry-power" class="val">0</span> W</div>
<div class="telemetry-data">Heart Rate: <span id="telemetry-hr" class="val">0</span> bpm</div>
<div class="telemetry-data">Distance: <span id="telemetry-distance" class="val">0.00</span> km</div>
<h2>3. Training State</h2>
<p>Status: <strong id="telemetry-state">Stopped</strong></p>
</div>
<script>
// Function to initialize logic once QWebChannel is ready
function initializeBridge() {
if (!window.gc) {
document.getElementById("config-display").innerText = "Error: window.gc object not found.";
return;
}
// 1. Fetch configuration
// We use Promise.resolve in case the C++ method returns a promise in newer Qt versions
Promise.resolve(window.gc.getConfig())
.then(function(configStr) {
console.log("Config received:", configStr);
// Pretty-print the JSON string
try {
var jsonObj = JSON.parse(configStr);
document.getElementById("config-display").innerText = JSON.stringify(jsonObj, null, 2);
} catch (e) {
document.getElementById("config-display").innerText = configStr;
}
})
.catch(function(error) {
document.getElementById("config-display").innerText = "Error fetching config: " + error;
});
// 2. Listen to real-time telemetry (emitted ~1Hz)
if (window.gc.telemetry) {
window.gc.telemetry.connect(function(payload) {
// Parse payload if it's a string
var data = typeof payload === 'string' ? JSON.parse(payload) : payload;
document.getElementById("telemetry-speed").innerText = (data.speed_kmh || 0).toFixed(1);
document.getElementById("telemetry-power").innerText = data.power_w !== undefined ? Math.round(data.power_w) : "0";
document.getElementById("telemetry-hr").innerText = data.hr_bpm !== undefined ? Math.round(data.hr_bpm) : "0";
document.getElementById("telemetry-distance").innerText = (data.distance_km || 0).toFixed(2);
});
}
// 3. Listen to state changes (Start, Pause, Stop)
if (window.gc.stateChanged) {
window.gc.stateChanged.connect(function(state) {
document.getElementById("telemetry-state").innerText = state.toUpperCase();
});
}
}
// Standard setup to connect to Qt WebChannel
if (typeof QWebChannel !== 'undefined') {
new QWebChannel(qt.webChannelTransport, function(channel) {
// Attach the C++ 'gc' object to the global window
window.gc = channel.objects.gc;
initializeBridge();
});
} else {
document.getElementById("config-display").innerText = "QWebChannel not available. Please open this file inside GoldenCheetah.";
}
</script>
</body>
</html>

I am querying the interest and the posible benefits and drawbacks in developers forum better than users', as the technical implications can be a go/no go for the project. Performance could be an issue, although I heve not noticed any problem, and the map view html has a lot of code that manages many controls that come from the original project.
I have not created a PR for the same reason. If it is not of interest, it is not worth making a PR. This is a query to know your opinion as users and the developers of the system.
Anyway, thanks for your time, I wish it is good for the project.