Modify node.html to add statistics

This commit is contained in:
Pablo Revilla
2026-01-03 18:13:57 -08:00
parent e9dcca1f19
commit 924d223866
3 changed files with 159 additions and 38 deletions
+5 -1
View File
@@ -179,7 +179,11 @@
"to": "To",
"port": "Port",
"direct_to_mqtt": "Direct to MQTT",
"all_broadcast": "All"
"all_broadcast": "All",
"statistics": "Statistics",
"last_24h": "24h",
"packets_sent": "Packets sent",
"times_seen": "Times seen"
},
"packet": {
"loading": "Loading packet information...",
+5 -1
View File
@@ -164,7 +164,11 @@
"to": "A",
"port": "Puerto",
"direct_to_mqtt": "Directo a MQTT",
"all_broadcast": "Todos"
"all_broadcast": "Todos",
"statistics": "Estadísticas",
"last_24h": "24h",
"packets_sent": "Paquetes enviados",
"times_seen": "Veces visto"
},
"packet": {
+149 -36
View File
@@ -159,9 +159,13 @@
<div><strong data-translate-lang="last_update">Last Update</strong><strong>: </strong> <span id="info-last-update"></span></div>
<div>
<strong data-translate-lang="statistics">Statistics</strong><strong>: </strong>
<span id="info-stats"></span>
<span id="info-stats"
data-label-24h="24h"
data-label-sent="Packets sent"
data-label-seen="Times seen"></span>
</div>
</div>
<!-- Map. -->
@@ -216,6 +220,19 @@
<div id="chart_neighbors" style="height:380px;"></div>
</div>
<!-- Packet Histogram -->
<div id="packet_histogram_container" class="chart-container">
<div class="chart-header">
📊 <span data-translate-lang="packets_per_day">Packets per Day (Last 7 Days)</span>
<div class="chart-actions">
<button onclick="expandChart('packet_histogram')" data-translate-lang="expand">Expand</button>
<button onclick="exportCSV('packet_histogram')" data-translate-lang="export_csv">Export CSV</button>
</div>
</div>
<div id="chart_packet_histogram" style="height:380px;"></div>
</div>
<!-- Packets -->
<table class="packet-table">
@@ -246,6 +263,42 @@
<script src="https://cdn.jsdelivr.net/npm/echarts@5.5.0/dist/echarts.min.js"></script>
<script>
const PORT_COLOR_MAP = {
0: "#6c757d",
1: "#007bff",
3: "#28a745",
4: "#ffc107",
5: "#dc3545",
6: "#20c997",
65: "#6610f2",
67: "#17a2b8",
68: "#fd7e14",
69: "#6f42c1",
70: "#ff4444",
71: "#ff66cc",
72: "#00cc99",
73: "#9999ff",
74: "#cc00cc",
75: "#ffbb33",
76: "#00bcd4",
77: "#8bc34a",
78: "#795548"
};
const PORT_LABEL_MAP = {
0: "UNKNOWN",
1: "Text",
3: "Position",
4: "Node Info",
5: "Routing",
6: "Admin",
65: "Store & Forward",
67: "Telemetry",
70: "Traceroute",
71: "Neighbor"
};
/* ======================================================
NODE PAGE TRANSLATION (isolated from base)
====================================================== */
@@ -471,41 +524,6 @@ function nodeLink(id, labelOverride = null) {
====================================================== */
function portLabel(p) {
const PORT_COLOR_MAP = {
0: "#6c757d",
1: "#007bff",
3: "#28a745",
4: "#ffc107",
5: "#dc3545",
6: "#20c997",
65: "#6610f2",
67: "#17a2b8",
68: "#fd7e14",
69: "#6f42c1",
70: "#ff4444",
71: "#ff66cc",
72: "#00cc99",
73: "#9999ff",
74: "#cc00cc",
75: "#ffbb33",
76: "#00bcd4",
77: "#8bc34a",
78: "#795548"
};
const PORT_LABEL_MAP = {
0: "UNKNOWN",
1: "Text",
3: "Position",
4: "Node Info",
5: "Routing",
6: "Admin",
65: "Store & Forward",
67: "Telemetry",
70: "Traceroute",
71: "Neighbor"
};
const color = PORT_COLOR_MAP[p] || "#6c757d";
const label = PORT_LABEL_MAP[p] || `Port ${p}`;
@@ -519,6 +537,7 @@ function portLabel(p) {
`;
}
/* ======================================================
MAP SETUP
====================================================== */
@@ -1031,6 +1050,99 @@ async function loadNeighborTimeSeries() {
}
async function loadPacketHistogram() {
const DAYS = 7;
const now = new Date();
const dayKeys = [];
const dayLabels = [];
for (let i = DAYS - 1; i >= 0; i--) {
const d = new Date(now);
d.setDate(d.getDate() - i);
dayKeys.push(d.toISOString().slice(0, 10));
dayLabels.push(
d.toLocaleDateString([], { month: "short", day: "numeric" })
);
}
const url = new URL("/api/packets", window.location.origin);
url.searchParams.set("node_id", fromNodeId);
// last 7 days only (microseconds)
const sinceUs = Date.now() * 1000 - (7 * 24 * 60 * 60 * 1_000_000);
url.searchParams.set("since", sinceUs);
// modest safety limit (still applies after server-side filter)
url.searchParams.set("limit", 2000);
const res = await fetch(url);
if (!res.ok) return;
const packets = (await res.json()).packets || [];
const counts = {}; // { port: { day: count } }
const ports = new Set();
for (const pkt of packets) {
if (!pkt.import_time_us) continue;
const day = new Date(pkt.import_time_us / 1000)
.toISOString()
.slice(0, 10);
if (!dayKeys.includes(day)) continue;
const port = pkt.portnum ?? 0;
ports.add(port);
counts[port] ??= {};
counts[port][day] = (counts[port][day] || 0) + 1;
}
if (!ports.size) {
document.getElementById("packet_histogram_container").style.display = "none";
return;
}
const series = Array.from(ports)
.sort((a, b) => a - b)
.map(port => ({
name: PORT_LABEL_MAP[port] || `Port ${port}`,
type: "bar",
stack: "total",
barMaxWidth: 42,
itemStyle: {
color: PORT_COLOR_MAP[port] || "#888"
},
data: dayKeys.map(d => counts[port]?.[d] || 0)
}));
const chart = echarts.init(
document.getElementById("chart_packet_histogram")
);
chart.setOption({
animation: false,
tooltip: { trigger: "axis" },
legend: { textStyle: { color: "#ccc" } },
xAxis: {
type: "category",
data: dayLabels,
axisLabel: { color: "#ccc" }
},
yAxis: {
type: "value",
axisLabel: { color: "#ccc" }
},
series
});
window.addEventListener("resize", () => chart.resize());
}
/* ======================================================
EXPAND / EXPORT BUTTONS
@@ -1120,6 +1232,7 @@ document.addEventListener("DOMContentLoaded", async () => {
await loadPackets();
await loadTelemetryCharts();
await loadNeighborTimeSeries();
await loadPacketHistogram();
ensureMapVisible();
setTimeout(ensureMapVisible, 1000);
window.addEventListener("resize", ensureMapVisible);