Refactor channel utilization functionality by removing LongFast channel support and associated UI elements. Update data fetching to focus solely on MediumFast channel, simplifying the gauge creation and legend display. Clean up unused code related to channel filtering.

This commit is contained in:
Anton Roslund
2025-11-02 12:10:26 +01:00
parent cfdd8c0cd6
commit c4318073bb
4 changed files with 27 additions and 110 deletions
+4 -33
View File
@@ -7,30 +7,6 @@ draft: false
<br/>
{{% blocks/section color="white" %}}
<style>
@media (max-width: 576px) {
#channelToolbar { top: 16px !important; }
}
</style>
<div id="channelToolbar" class="d-flex justify-content-end sticky-top" style="top: 84px;">
<div class="btn-toolbar bg-white shadow-sm rounded-3 py-2 px-2" role="toolbar" aria-label="Channel toolbar">
<div class="btn-group btn-group-sm me-2" role="group" aria-label="Channel filter">
<input type="radio" class="btn-check" name="btnchannel-nodes" id="filterChannelAll" autocomplete="off" checked>
<label class="btn btn-outline-primary" for="filterChannelAll">Alla</label>
</div>
<div class="btn-group btn-group-sm me-2" role="group" aria-label="Basic radio toggle button group">
<input type="radio" class="btn-check" name="btnchannel-nodes" id="filterChannelMediumFast" data-channel="MediumFast" autocomplete="off">
<label class="btn btn-outline-primary" for="filterChannelMediumFast">MediumFast</label>
<input type="radio" class="btn-check" name="btnchannel-nodes" id="filterChannelLongFast" data-channel="LongFast" autocomplete="off">
<label class="btn btn-outline-primary" for="filterChannelLongFast">LongFast</label>
</div>
<div data-bs-toggle="tooltip" data-bs-placement="left" title="Filtrera på kanal eller visa alla.">
<span class="badge rounded-pill bg-dark">?</span>
</div>
</div>
</div>
## Antal Enheter
<div class="container my-3 mx-0" style="max-width: 1000px;">
<div class="row text-center px-0">
@@ -60,19 +36,14 @@ Antalet meddelanden per timme senaste 7 dygnen. Grafen visar antal okrypterade m
Mätarna visar genomsnittligt kanalutnyttjande för de 10 noder som har högst kanalutnyttjande. Kanalutnyttjande (Channel Utilization) visar hur mycket av radiokanalen som är upptagen. Under 1520% är allt normalt, över 25% får Telemetri lägre prioritet, vilket kan ge längre tid mellan uppdateringar. Runt 40% stryps positionsuppdateringar. Här i EU gäller dessutom max 10% sändtid per timme som kan pausa sändningar helt.
<div class="container my-3 mx-0" style="max-width: 1000px;">
<div class="row text-center px-0">
<div class="col-md-6 mb-4">
<h5 class="text-muted">LongFast</h5>
<div id="longfastGaugeContainer" class="" style="height: 300px;">
<canvas id="longfastGauge"></canvas>
</div>
<div id="longfastLegend" class="" style="font-size: 0.85rem;"></div>
</div>
<div class="col-md-6">
<div class="row px-0 align-items-start">
<div class="col-md-6 mb-3">
<h5 class="text-muted">MediumFast</h5>
<div id="mediumfastGaugeContainer" class="" style="height: 300px;">
<canvas id="mediumfastGauge"></canvas>
</div>
</div>
<div class="col-md-6">
<div id="mediumfastLegend" class="" style="font-size: 0.85rem;"></div>
</div>
</div>
+12 -12
View File
@@ -2,15 +2,13 @@ async function channelUtilizationGauges() {
try {
await fetchNodes();
// Create gauges for both channels
await createChannelUtilizationGauge('LongFast', 'longfastGauge');
// Create gauge for MediumFast only
await createChannelUtilizationGauge('MediumFast', 'mediumfastGauge');
} catch (err) {
console.error('Error creating channel utilization gauges:', err);
// Show error on both canvases
showGaugeError('longfastGauge');
// Show error on MediumFast canvas
showGaugeError('mediumfastGauge');
}
}
@@ -160,26 +158,28 @@ function showTop10NodesLegend(channelName, top10Nodes) {
if (!legendContainer || top10Nodes.length === 0) return;
let legendHTML = '<h6 class="text-muted mb-2">Top 10 Nodes</h6>';
legendHTML += '<div class="row">';
let legendHTML = '<h5 class="text-muted mb-2">Top 10 Nodes</h5>';
legendHTML += '<ul class="list-unstyled mb-0">';
top10Nodes.forEach((node, index) => {
const utilizationColor = getUtilizationColor(node.utilizationValue);
const shortName = node.short_name || node.node_id_hex || `Node ${node.node_id}`;
const longName = node.long_name || '';
legendHTML += `
<div class="col-6 mb-1 d-flex align-items-center">
<li class="mb-2 d-flex align-items-center">
<span class="badge me-2" style="background-color: ${utilizationColor}; color: white; font-size: 0.7rem; min-width: 45px;">
${node.utilizationValue.toFixed(1)}%
</span>
<span class="text-truncate" style="font-size: 0.75rem;" title="${node.long_name || shortName}">
${shortName}
<span class="me-2" style="display:inline-block;width:7ch;font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace; font-size: 0.85rem; text-align:right; white-space:nowrap; overflow:hidden; text-overflow:clip;" title="${shortName}">[${shortName}]</span>
<span class="text-truncate" style="font-size: 0.85rem;" title="${longName || shortName}">
${longName}
</span>
</div>
</li>
`;
});
legendHTML += '</div>';
legendHTML += '</ul>';
legendContainer.innerHTML = legendHTML;
}
+11 -37
View File
@@ -9,26 +9,21 @@ async function channelUtilizationHourlyAverage() {
ctx.fillText('Loading...', canvas.width/2, canvas.height/2);
try {
// Fetch data for both channels over the last 7 days
const [mediumFastResponse, longFastResponse] = await Promise.all([
fetch('https://map.sthlm-mesh.se/api/v1/stats/channel-utilization-stats?days=7&channel_id=MediumFast'),
fetch('https://map.sthlm-mesh.se/api/v1/stats/channel-utilization-stats?days=7&channel_id=LongFast')
]);
// Fetch data for MediumFast over the last 7 days
const response = await fetch('https://map.sthlm-mesh.se/api/v1/stats/channel-utilization-stats?days=7&channel_id=MediumFast');
const allData = await response.json();
const mediumFastData = await mediumFastResponse.json();
const longFastData = await longFastResponse.json();
// Single dataset containing all points
const datasets = [];
// Create datasets for both channels
const datasets = [];
const mediumFastPoints = mediumFastData.map(entry => ({
const points = allData.map(entry => ({
x: entry.recorded_at,
y: parseFloat(entry.avg_channel_utilization)
y: entry.avg_channel_utilization
}));
datasets.push({
label: 'MediumFast',
data: mediumFastPoints,
label: 'channelutilization',
data: points,
borderColor: 'rgb(34, 197, 94)',
backgroundColor: 'rgba(34, 197, 94, 0.1)',
borderWidth: 2,
@@ -37,22 +32,6 @@ async function channelUtilizationHourlyAverage() {
fill: false,
});
const longFastPoints = longFastData.map(entry => ({
x: entry.recorded_at,
y: parseFloat(entry.avg_channel_utilization)
}));
datasets.push({
label: 'LongFast',
data: longFastPoints,
borderColor: 'rgb(15, 169, 252)',
backgroundColor: 'rgba(15, 169, 252, 0.1)',
borderWidth: 2,
tension: 0.1,
pointRadius: 0,
fill: false,
});
new Chart(ctx, {
type: 'line',
data: {
@@ -78,12 +57,7 @@ async function channelUtilizationHourlyAverage() {
},
plugins: {
legend: {
display: true,
position: 'top',
labels: {
usePointStyle: true,
padding: 20
}
display: false
},
tooltip: { mode: 'index', intersect: false },
annotation: {
-28
View File
@@ -1,20 +1,5 @@
let nodes = [];
let fetchPromise = null;
const StatusFilter = {
_channelId: null,
_subscribers: [],
getChannelId() {
return this._channelId;
},
subscribe(callback) {
if (typeof callback === 'function') this._subscribers.push(callback);
},
_notify() {
for (const cb of this._subscribers) {
try { cb(this._channelId); } catch (_) {}
}
}
};
async function fetchNodes() {
if (nodes.length > 0) return;
@@ -34,16 +19,3 @@ async function fetchNodes() {
await fetchPromise;
}
// Initialize global channel filter listeners once
document.addEventListener('DOMContentLoaded', () => {
const radios = document.querySelectorAll("input[name='btnchannel-nodes']");
if (!radios || radios.length === 0) return;
const checked = document.querySelector("input[name='btnchannel-nodes']:checked");
StatusFilter._channelId = checked ? (checked.getAttribute('data-channel') || null) : null;
radios.forEach(r => r.addEventListener('change', () => {
const channel = r.getAttribute('data-channel');
StatusFilter._channelId = channel || null;
StatusFilter._notify();
}));
});