mirror of
https://github.com/pablorevilla-meshtastic/meshview.git
synced 2026-08-06 17:02:48 +02:00
225 lines
7.0 KiB
HTML
225 lines
7.0 KiB
HTML
{% extends "base.html" %}
|
|
|
|
{% block css %}
|
|
#packet_details {
|
|
height: 95vh;
|
|
overflow: auto;
|
|
}
|
|
|
|
.main-container, .container {
|
|
max-width: 900px;
|
|
margin: 0 auto;
|
|
text-align: center;
|
|
}
|
|
|
|
.card-section {
|
|
background-color: #272b2f;
|
|
border: 1px solid #474b4e;
|
|
padding: 15px 20px;
|
|
margin-bottom: 20px;
|
|
border-radius: 10px;
|
|
transition: background-color 0.2s ease;
|
|
}
|
|
|
|
.card-section:hover {
|
|
background-color: #2f3338;
|
|
}
|
|
|
|
.section-header {
|
|
font-size: 16px;
|
|
margin: 0;
|
|
font-weight: 500;
|
|
color: #fff;
|
|
}
|
|
|
|
.main-header {
|
|
font-size: 22px;
|
|
margin-bottom: 20px;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.chart {
|
|
height: 400px;
|
|
margin-top: 15px;
|
|
}
|
|
{% endblock %}
|
|
|
|
{% block head %}
|
|
<script src="https://cdn.jsdelivr.net/npm/echarts@5.5.0/dist/echarts.min.js"></script>
|
|
{% endblock %}
|
|
|
|
{% block body %}
|
|
<div class="main-container">
|
|
<h2 class="main-header">Mesh Statistics - Hourly Packet Counts (Last 24 Hours)</h2>
|
|
|
|
<!-- Overall hourly packets -->
|
|
<div class="card-section">
|
|
<p class="section-header">Packets per Hour - All Ports</p>
|
|
<div id="chart_hourly_all" class="chart"></div>
|
|
</div>
|
|
|
|
<!-- Hourly charts by portnum -->
|
|
<div class="card-section">
|
|
<p class="section-header">Packets per Hour - Text Messages (Port 1)</p>
|
|
<div id="chart_portnum_1" class="chart"></div>
|
|
</div>
|
|
|
|
<div class="card-section">
|
|
<p class="section-header">Packets per Hour - Position (Port 3)</p>
|
|
<div id="chart_portnum_3" class="chart"></div>
|
|
</div>
|
|
|
|
<div class="card-section">
|
|
<p class="section-header">Packets per Hour - Node Info (Port 4)</p>
|
|
<div id="chart_portnum_4" class="chart"></div>
|
|
</div>
|
|
|
|
<div class="card-section">
|
|
<p class="section-header">Packets per Hour - Telemetry (Port 67)</p>
|
|
<div id="chart_portnum_67" class="chart"></div>
|
|
</div>
|
|
|
|
<div class="card-section">
|
|
<p class="section-header">Packets per Hour - Traceroute (Port 70)</p>
|
|
<div id="chart_portnum_70" class="chart"></div>
|
|
</div>
|
|
|
|
<div class="card-section">
|
|
<p class="section-header">Packets per Hour - Neighbor Info (Port 71)</p>
|
|
<div id="chart_portnum_71" class="chart"></div>
|
|
</div>
|
|
|
|
<!-- Daily packets chart -->
|
|
<div class="card-section">
|
|
<p class="section-header">Packets per Day - All Ports (Last 14 Days)</p>
|
|
<div id="chart_daily_all" class="chart"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
async function fetchStats(period_type, length, portnum = null) {
|
|
try {
|
|
let url = `/api/stats?period_type=${period_type}&length=${length}`;
|
|
if (portnum !== null) {
|
|
url += `&portnum=${portnum}`;
|
|
}
|
|
const res = await fetch(url);
|
|
if (!res.ok) {
|
|
console.error(`Failed to fetch ${period_type} stats portnum ${portnum}:`, res.status, res.statusText);
|
|
return [];
|
|
}
|
|
const json = await res.json();
|
|
return json.data || [];
|
|
} catch (err) {
|
|
console.error('Error fetching stats:', err);
|
|
return [];
|
|
}
|
|
}
|
|
|
|
// Chart references
|
|
let chartHourlyAll = null;
|
|
let chartPortnum1 = null;
|
|
let chartPortnum3 = null;
|
|
let chartPortnum4 = null;
|
|
let chartPortnum67 = null;
|
|
let chartPortnum70 = null;
|
|
let chartPortnum71 = null;
|
|
let chartDailyAll = null;
|
|
|
|
function renderChart(domId, data, type, color, isHourly) {
|
|
const el = document.getElementById(domId);
|
|
if (!el) return;
|
|
|
|
const chart = echarts.init(el);
|
|
switch(domId) {
|
|
case 'chart_hourly_all': chartHourlyAll = chart; break;
|
|
case 'chart_portnum_1': chartPortnum1 = chart; break;
|
|
case 'chart_portnum_3': chartPortnum3 = chart; break;
|
|
case 'chart_portnum_4': chartPortnum4 = chart; break;
|
|
case 'chart_portnum_67': chartPortnum67 = chart; break;
|
|
case 'chart_portnum_70': chartPortnum70 = chart; break;
|
|
case 'chart_portnum_71': chartPortnum71 = chart; break;
|
|
case 'chart_daily_all': chartDailyAll = chart; break;
|
|
}
|
|
|
|
const periods = data.map(d => {
|
|
const p = (d && (d.period || d.period === 0)) ? d.period.toString() : '';
|
|
if (isHourly) {
|
|
if (p.includes(' ')) return p.split(' ')[1];
|
|
return p.slice(-5) || p;
|
|
}
|
|
return p;
|
|
});
|
|
|
|
const counts = data.map(d => (d.count ?? d.packet_count ?? 0));
|
|
|
|
const option = {
|
|
backgroundColor: '#272b2f',
|
|
tooltip: { trigger: 'axis' },
|
|
grid: { left: '6%', right: '6%', bottom: '18%' },
|
|
xAxis: {
|
|
type: 'category',
|
|
data: periods,
|
|
axisLine: { lineStyle: { color: '#aaa' } },
|
|
axisLabel: { rotate: 45, color: '#ccc' }
|
|
},
|
|
yAxis: {
|
|
type: 'value',
|
|
axisLine: { lineStyle: { color: '#aaa' } },
|
|
axisLabel: { color: '#ccc' }
|
|
},
|
|
series: [{
|
|
data: counts,
|
|
type: type,
|
|
smooth: type === 'line',
|
|
itemStyle: { color: color },
|
|
areaStyle: type === 'line' ? {} : undefined
|
|
}]
|
|
};
|
|
|
|
chart.setOption(option);
|
|
}
|
|
|
|
async function init() {
|
|
// Overall hourly packets
|
|
const hourlyAllData = await fetchStats('hour', 24);
|
|
renderChart('chart_hourly_all', hourlyAllData, 'bar', '#03dac6', true);
|
|
|
|
// Hourly packets by portnum in parallel
|
|
const portnums = [1, 3, 4, 67, 70, 71];
|
|
const colors = ['#ff5722', '#2196f3', '#9c27b0', '#ffeb3b', '#795548', '#4caf50'];
|
|
const domIds = [
|
|
'chart_portnum_1',
|
|
'chart_portnum_3',
|
|
'chart_portnum_4',
|
|
'chart_portnum_67',
|
|
'chart_portnum_70',
|
|
'chart_portnum_71'
|
|
];
|
|
|
|
const allData = await Promise.all(portnums.map(pn => fetchStats('hour', 24, pn)));
|
|
|
|
for (let i = 0; i < portnums.length; i++) {
|
|
renderChart(domIds[i], allData[i], 'bar', colors[i], true);
|
|
}
|
|
|
|
// Daily packets (all ports, last 14 days)
|
|
const dailyAllData = await fetchStats('day', 14);
|
|
renderChart('chart_daily_all', dailyAllData, 'line', '#66bb6a', false);
|
|
}
|
|
|
|
window.addEventListener('resize', () => {
|
|
if (chartHourlyAll) chartHourlyAll.resize();
|
|
if (chartPortnum1) chartPortnum1.resize();
|
|
if (chartPortnum3) chartPortnum3.resize();
|
|
if (chartPortnum4) chartPortnum4.resize();
|
|
if (chartPortnum67) chartPortnum67.resize();
|
|
if (chartPortnum70) chartPortnum70.resize();
|
|
if (chartPortnum71) chartPortnum71.resize();
|
|
if (chartDailyAll) chartDailyAll.resize();
|
|
});
|
|
|
|
init();
|
|
</script>
|
|
{% endblock %}
|