Web pages visualization during workouts with realtime track

86 views
Skip to first unread message

Peret

unread,
Jun 1, 2026, 7:32:15 AMJun 1
to golden-cheetah-developers
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.

workout.png

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>

TrainBridgeExample.png
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.

Ale Martinez

unread,
Jun 1, 2026, 5:32:06 PMJun 1
to golden-cheetah-developers
Hi, I like the idea to have a user-programable real time chart inside GoldenCheetah, we could see it as a generalization of Live Map chart where the HTML code is stored in a program string like Python/R charts to enable import/export/CloudDB storage, and the JS API is extended (and documented) to provide access to all configuration and realtime data, in fact Live Map could be just an example of the new chart.
OTOH I don't like the idea to use the REST API or to provide service to external/remote programs.
Cheers, Ale.

Peret

unread,
Jun 2, 2026, 9:10:12 AMJun 2
to golden-cheetah-developers
I fully agree with you.
I am using webchannel as the real time 'link' with JS embedded in html files; websockets and API REST is discarded. No extra security concerns, ports, CORS issues, etc, are involved.

If you are ok with my plan, I will do a PR in the next days:

- As initially I was developing tha hability to use html files directly on 'Web page' chart, I would keep that, as it does not add almost any extra code and allows the use of any html file that is ready and can show data in real time directly in training; no backup nor user data storage of that file.

- Then, I am allowing to add 'Python Chart' in Train view, keeping the same features as in Trends or Activities views. For this to work, I have to distinguish those three types of charts (each one reacts to different signals), instead of a boolean value (beforehand it was Trends or Activities).

- Such python chart can work as it is: no synchronization with real time data; but it can code html in the way we are used to do:
    import tempfile
    import pathlib
    html = """
    <!DOCTYPE html>
    ...
    </html>
    """
    temp_file = tempfile.NamedTemporaryFile(mode="w+t", prefix="myhtml", suffix=".html", delete=False)
    temp_file.write(html)
    temp_file.close()
    GC.webpage(pathlib.Path(temp_file.name).as_uri())

The advantage is that python code would be stored alongside any other chart: in user configuration, and is able to import/export, etc the same as it was in Trends or Activities.

- Documentation of the real time feature for training for html usage, hability to open html files directly or via python, etc

For a second stage, once the previous is stable and we are happy with it:

- Perhaps it is useful that python scripts in training got benefit from real time telemetry, so that we could build real python script not as a mere intermediary for creating html code. I would investigate the compatibility of webchannels with python. I guess it will be posible  in a way or another.

- Far from my knoledge, but perhaps a new kind of chart 'HTML code' would be nice to avoid the 'bridge' of python to build html code, allowing direct html code

Let me know, I am happy with the possibility of having this in GC

Ale Martinez

unread,
Jun 3, 2026, 1:14:49 PMJun 3
to golden-cheetah-developers
El martes, 2 de junio de 2026 a la(s) 10:10:12 a.m. UTC-3, Peret escribió:
I fully agree with you.
I am using webchannel as the real time 'link' with JS embedded in html files; websockets and API REST is discarded. No extra security concerns, ports, CORS issues, etc, are involved.

If you are ok with my plan, I will do a PR in the next days:

- As initially I was developing tha hability to use html files directly on 'Web page' chart, I would keep that, as it does not add almost any extra code and allows the use of any html file that is ready and can show data in real time directly in training; no backup nor user data storage of that file.

This is ok as a development step, but it should be possible to embed the html code in the chart, similar to how R/Pyhton chart store R/Python code.
 
- Then, I am allowing to add 'Python Chart' in Train view, keeping the same features as in Trends or Activities views. For this to work, I have to distinguish those three types of charts (each one reacts to different signals), instead of a boolean value (beforehand it was Trends or Activities).

- Such python chart can work as it is: no synchronization with real time data; but it can code html in the way we are used to do:
    import tempfile
    import pathlib
    html = """
    <!DOCTYPE html>
    ...
    </html>
    """
    temp_file = tempfile.NamedTemporaryFile(mode="w+t", prefix="myhtml", suffix=".html", delete=False)
    temp_file.write(html)
    temp_file.close()
    GC.webpage(pathlib.Path(temp_file.name).as_uri())

The advantage is that python code would be stored alongside any other chart: in user configuration, and is able to import/export, etc the same as it was in Trends or Activities.

That could be an alternative, the advantage is flexibility since the html could be generated on-the-fly using configuration information already available in Python API, se need to specify when the Python script is executed (At workout start or before at workout selection?), disadvantage is complexity.
 
- Documentation of the real time feature for training for html usage, hability to open html files directly or via python, etc

I am referring to the JS API to get configuration and realtime data in the HTML code
 
For a second stage, once the previous is stable and we are happy with it:

- Perhaps it is useful that python scripts in training got benefit from real time telemetry, so that we could build real python script not as a mere intermediary for creating html code. I would investigate the compatibility of webchannels with python. I guess it will be posible  in a way or another.

I don't like the idea to put the Python interpreter in the realtime loop for performance and complexity reasons, while we could use Python to generate the HTML code, all the realtime behaviour should be managed by the embeded JS code, the user can compute realtime user metrics in JS for example, I think there is no need to Python there.
 
- Far from my knoledge, but perhaps a new kind of chart 'HTML code' would be nice to avoid the 'bridge' of python to build html code, allowing direct html code

Yes, that would be my first option, the Web (or Live Map) chart with the HTML code as a parameter.

Peret

unread,
Jun 16, 2026, 6:01:11 AM (8 days ago) Jun 16
to golden-cheetah-developers
Thanks for your comments, Ale. I have made a pull request with (I guess) all the proposed changes

Ale Martinez

unread,
Jun 16, 2026, 12:38:26 PM (7 days ago) Jun 16
to golden-cheetah-developers
El martes, 16 de junio de 2026 a la(s) 7:01:11 a.m. UTC-3, Peret escribió:
Thanks for your comments, Ale. I have made a pull request with (I guess) all the proposed changes

Great, you new HTML chart is pretty much what I had in mind, thank you!
I have 2 suggestions:
1) focus the PR on that chart, I am not against the changes in Python/Web charts but I would prefer them to be included in separate PRs after the initial one is merged, mainly to avoid possible regressions on existing charts specially considering we are nearing the release of v3.8
2) try to involve users on testing and feedback a the users forum, I am not a regular Train View users since I can/prefer to ride outside year around and it would be nice to have some feedback from real/heavy users.
Cheers, Ale. 

Peret

unread,
Jun 16, 2026, 2:34:28 PM (7 days ago) Jun 16
to golden-cheetah-developers
Sure! I'll do that. Thanks!

Peret

unread,
Jun 18, 2026, 3:39:29 PM (5 days ago) Jun 18
to golden-cheetah-developers
Thank you very much for merging the commit, and for recognizing the job (not sure I deserve it, but I am really honored)
Now I have some pending tasks in mind, I would like to have some feedback from you, to continue to work on this (no hurry, sorry the time to read this):

- I will document the chart, and also the webchannel API offered to JS in its current state, now that it is on master. That is for sure

- If the chart is used, I hope users will ask for telemetry data completeness, and also for more configuration data. The current code is the seed and will grow with a lot of telemetry data, that will need new pr's. Perhaps this task urgency will evolve with the users requests

- Is it worth also having HTML charts in the other views: Activities, trends,...? Would it be useful, instead of developing python scripts for html code? I mean, I am not sure of the complexity and if it is even posible: python allows to send data directly to JS inside its code, using GC object (with SIP bindings and all that stuff that I do not know much). HTML chart should 'replicate' that GC object or something like that, through a view specific webchanne, I think...
This would have benefits: charts would be flexible regarding parametrization (with the config panel), so we would not need python to pass parameters or tune the page, and perhaps creation of charts would be accesible to more people. Also, not depending that mucho on python versions, packages, etc.
Maybe not really useful, but, if you think it is interesting that approach, let me know.

- The pending changes that I removed from the PR: python charts in training, and web pages chart accessing that same web channel. They may not be really useful now, so I have those changes parked. But let me know if you want to incorporate them, it is costless to add them. They do not add almost any value, having html charts available, IMHO.

Regards

Ale Martinez

unread,
Jun 18, 2026, 6:41:27 PM (5 days ago) Jun 18
to golden-cheetah-developers
El jueves, 18 de junio de 2026 a la(s) 4:39:29 p.m. UTC-3, Peret escribió:
Thank you very much for merging the commit, and for recognizing the job (not sure I deserve it, but I am really honored)

You are welcome and I think you deserve it, you have a nice idea for a long standing issue and implemented it in a clean way.
 
Now I have some pending tasks in mind, I would like to have some feedback from you, to continue to work on this (no hurry, sorry the time to read this):

- I will document the chart, and also the webchannel API offered to JS in its current state, now that it is on master. That is for sure

- If the chart is used, I hope users will ask for telemetry data completeness, and also for more configuration data. The current code is the seed and will grow with a lot of telemetry data, that will need new pr's. Perhaps this task urgency will evolve with the users requests

I think this would be the priorities before release, ideally the JS API should allow access to all RealTimeData fields like DialWindow does in non-programable way.
 
- Is it worth also having HTML charts in the other views: Activities, trends,...? Would it be useful, instead of developing python scripts for html code? I mean, I am not sure of the complexity and if it is even posible: python allows to send data directly to JS inside its code, using GC object (with SIP bindings and all that stuff that I do not know much). HTML chart should 'replicate' that GC object or something like that, through a view specific webchanne, I think...
This would have benefits: charts would be flexible regarding parametrization (with the config panel), so we would not need python to pass parameters or tune the page, and perhaps creation of charts would be accesible to more people. Also, not depending that mucho on python versions, packages, etc.
Maybe not really useful, but, if you think it is interesting that approach, let me know.

Yes, I think to enable this chart for Activities and Trends views would be useful and a cleaner solution for Web Apps in GC than to use the REST API as proposed in  https://github.com/GoldenCheetah/GoldenCheetah/issues/4835, but to replicate the Python/R APIs can be a lot of work.
   
- The pending changes that I removed from the PR: python charts in training, and web pages chart accessing that same web channel. They may not be really useful now, so I have those changes parked. But let me know if you want to incorporate them, it is costless to add them. They do not add almost any value, having html charts available, IMHO.

Agree, lets keep this parked for now.

Cheers, Ale. 

Peret

unread,
Jun 22, 2026, 12:35:23 PM (yesterday) Jun 22
to golden-cheetah-developers
Thanks Ale, I will follow that.

I have some questions for @Joachim, as he is the developer of a big part of the workout metadata in training. I prefer this group that users', that could ge bored with code questions.

So, Joachim, probably you can solve some doubts:
I am noticing that ErgFileBase::name() is only working for erg files, is that the current behavior?
Also, I have tagged a workout, but ErgFileBase::tags() has an empty list, for erg and slp workouts, although I can see the tags in the interface. This is weird

I will try to, at least, have enough data for users to start using htmls for erg or slope workpouts.
I think there will be much to publish regarding workout info, in particular, for erg: probably the workout definition itself (as well as the full route is being published for slope workouts); we will see after this first step. And also more telemetry, of course.

I am preparing a PR, and will document tomorrow, I hope.

Thanks!

Peret

unread,
Jun 22, 2026, 12:55:45 PM (yesterday) Jun 22
to golden-cheetah-developers
Hi, @Joachim,
I don't see where or how to get configured font. Diving a bit for the code, I have found TRAIN_TELEMETRY_FONT_SCALING, that seems to be used to adjust text in dial windows or something related.I only see GC_FONT_DEFAULT as a default font (general?). I'm sorry I am not aware of all that part related to the interface.
Are you thinking of creating a new default for HTML telemetry?

Peret

unread,
7:01 AM (13 hours ago) 7:01 AM
to golden-cheetah-developers
Hello, I have added a few new data for a PR to be, I guess, more or less, fully usable.

I would like to share some concern that has been on my mind:

Regarding the data I am adding, I am taking decisions on the fly: not only functional data that is more relevant or not that relevant, but also its nomenclature (names of the json fields), the data structure (for ERG workouts I have created a sequence of milosecs and target power).
That is good at the begining, as we can have and test the functionality.

I think that we are at the point when we can change this, as there may be very few people using it (apart from Joachim and me?). Perhaps any new (and already added) field should be agreed, or at least discussed if it is a complex data, or have a strong guide to follow; not only for me (that can be risky enough), but for other developers that add data in the future.

Configuration and workout data may have more 'freedom degress', as their structure are not officially documented in GC, If I am right.
But telemetry is used and documented in a lot of places. I have not found the best place, but perhaps I should investigate in code and documentation.

I think that maintenance is relevant, and ideally, telemetry updates should not be a pain to mantain in GC, when there is a new value, or a modification of an existing one: changing labels, constants, etc in many places. If HTML chart implies an additional step to take into consideration, I would be worried.

Or maybe we do not need to worry about that yet.

Just some thoughts that you probably have a better criteria; I apreciate your opinion and if you want me to be addressed in a particular direction, let me know.



Ale Martinez

unread,
10:19 AM (9 hours ago) 10:19 AM
to golden-cheetah-developers
El martes, 23 de junio de 2026 a la(s) 8:01:29 a.m. UTC-3, Peret escribió:
Hello, I have added a few new data for a PR to be, I guess, more or less, fully usable.

I would like to share some concern that has been on my mind:

Regarding the data I am adding, I am taking decisions on the fly: not only functional data that is more relevant or not that relevant, but also its nomenclature (names of the json fields), the data structure (for ERG workouts I have created a sequence of milosecs and target power).
That is good at the begining, as we can have and test the functionality.

I think that we are at the point when we can change this, as there may be very few people using it (apart from Joachim and me?). Perhaps any new (and already added) field should be agreed, or at least discussed if it is a complex data, or have a strong guide to follow; not only for me (that can be risky enough), but for other developers that add data in the future.

Configuration and workout data may have more 'freedom degress', as their structure are not officially documented in GC, If I am right.
But telemetry is used and documented in a lot of places. I have not found the best place, but perhaps I should investigate in code and documentation.

I think that maintenance is relevant, and ideally, telemetry updates should not be a pain to mantain in GC, when there is a new value, or a modification of an existing one: changing labels, constants, etc in many places. If HTML chart implies an additional step to take into consideration, I would be worried.

Hi Miguel, telemetry data names are defined in https://github.com/GoldenCheetah/GoldenCheetah/blob/7c1290e4a611c7b45e19b921e070ca26e4faa000/src/Train/RealtimeData.cpp#L630 and documented in https://github.com/GoldenCheetah/GoldenCheetah/wiki/UG_ChartTypes_Train#telemetry, we cannot use RealTimeData::seriesName directly since the names are translated and that is not portable across translations when used in code, but we could define a new method s.t. RealTimeData::seriesSymbol which would be similar but not translated (tr() removed) and may be with the blanks replaced by _ like we do with Metadata Fields, this way the maintainance would be in one place and the names in HTLM code compatible with what the user sees in other places when using English.

Peret

unread,
12:11 PM (8 hours ago) 12:11 PM
to golden-cheetah-developers
Ok, very good idea. Thanks for that! Let me review all the HTML related code, and try to adapt, add RealTimeData::seriesSymbol(), and all the linked tasks; If you prefer, you can hold the PR that can follow those guidelines for the already included data. I still need some time, and also will delay documentation (with Joachim's .md I think it will be very quick, it is only a matter of updating it, I guess)

Ale Martinez

unread,
2:35 PM (5 hours ago) 2:35 PM
to golden-cheetah-developers
El martes, 23 de junio de 2026 a la(s) 1:11:11 p.m. UTC-3, Peret escribió:
Ok, very good idea. Thanks for that! Let me review all the HTML related code, and try to adapt, add RealTimeData::seriesSymbol(), and all the linked tasks; If you prefer, you can hold the PR that can follow those guidelines for the already included data. I still need some time, and also will delay documentation (with Joachim's .md I think it will be very quick, it is only a matter of updating it, I guess)

I merged that PR to continue testing (triggered snapshot update too), we can refactor names later before release. 
Reply all
Reply to author
Forward
0 new messages