i2c fixes + server improvements

This commit is contained in:
2026-10-05 19:28:37 +02:00
parent 7094d05030
commit 02f3df8c41
9 changed files with 254 additions and 52 deletions
+46 -8
View File
@@ -35,6 +35,7 @@
<label for="range-select">Range:</label>
<select id="range-select">
<option value="today">Today</option>
<option value="24h">Last 24h</option>
<option value="week">Week</option>
<option value="month">Month</option>
<option value="all" selected>All</option>
@@ -44,6 +45,7 @@
<div id="chart-section" class="hidden chart-box">
<canvas id="chart"></canvas>
<p id="chart-info" class="desc"></p>
<p id="chart-error" class="error hidden"></p>
</div>
@@ -74,8 +76,13 @@
const refreshButton = document.getElementById('refresh-button');
const readoutsSection = document.getElementById('readouts-section');
const readoutsBody = document.getElementById('readouts-body');
const chartInfo = document.getElementById('chart-info');
let chart = null;
// Strefa czasowa przeglądarki — backend liczy "today" od północy
// w tej strefie (np. Europe/Warsaw = GMT+2 latem).
const userTz = Intl.DateTimeFormat().resolvedOptions().timeZone || 'Europe/Warsaw';
// The page must keep working (dropdown + table) even if the
// Chart.js CDN is unreachable — the chart is then simply skipped.
if (window.Chart) {
@@ -87,12 +94,38 @@
function formatTimestamp(iso) {
const d = new Date(iso);
return d.toLocaleString('pl-PL', { timeZone: 'Europe/Warsaw' });
return d.toLocaleString('pl-PL', { timeZone: userTz });
}
function formatChartLabel(iso) {
const d = new Date(iso + 'Z');
return d.toLocaleString('pl-PL', { timeZone: 'Europe/Warsaw', hour: '2-digit', minute: '2-digit', day: '2-digit', month: '2-digit', year: 'numeric' });
return d.toLocaleString('pl-PL', { timeZone: userTz, hour: '2-digit', minute: '2-digit', day: '2-digit', month: '2-digit', year: 'numeric' });
}
function chartInfoText(range) {
if (range === 'today') return `Raw measurements since local midnight (${userTz}) — no averaging.`;
if (range === '24h') return 'Raw measurements from the last 24 hours — no averaging.';
const period = range === 'week' ? 'the last 7 days'
: range === 'month' ? 'the last 30 days'
: 'all stored data';
return `Hourly averages over ${period} — each point is the mean of all measurements in that local hour (${userTz}).`;
}
// Ciśnienie jest składowane w bazie w paskalach (tak wysyła firmware),
// a wyświetlane w hektopaskalach z jednym miejscem po przecinku.
function displayValue(type, value) {
if (type === 'pressure') return Math.round(value / 10) / 10;
return value;
}
function formatTableValue(type, value) {
if (type === 'pressure') return (value / 100).toFixed(1) + ' hPa';
return value;
}
function yAxisTitle(type) {
if (type === 'pressure') return 'pressure (hPa)';
return type;
}
async function fetchJSON(url) {
@@ -143,11 +176,14 @@
try {
// fetch hourly data for chart
const hourly = await fetchJSON(`/api/sensors/${sensorId}/readouts/hourly?type=${type}&range=${range}`);
const hourly = await fetchJSON(`/api/sensors/${sensorId}/readouts/hourly?type=${encodeURIComponent(type)}&range=${encodeURIComponent(range)}&tz=${encodeURIComponent(userTz)}`);
if (!hourly.length) throw new Error('no data for this range');
const labels = hourly.map(r => formatChartLabel(r.timestamp));
const values = hourly.map(r => r.value);
const values = hourly.map(r => displayValue(type, r.value));
// Przy zakresach today/24h punktów jest dużo (~1/min),
// więc mniejsze markery żeby wykres był czytelny.
const dense = range === 'today' || range === '24h';
if (chart) chart.destroy();
const ctx = document.getElementById('chart').getContext('2d');
@@ -164,15 +200,15 @@
pointBorderColor: '#55ffff',
fill: true,
tension: 0.3,
pointRadius: 3,
pointRadius: dense ? 1.5 : 3,
}]
},
options: {
responsive: true,
plugins: { legend: { display: false } },
scales: {
x: { title: { display: true, text: 'Time (hourly avg)' } },
y: { title: { display: true, text: type } }
x: { title: { display: true, text: dense ? 'Time' : 'Time (hourly avg)' } },
y: { title: { display: true, text: yAxisTitle(type) } }
}
}
});
@@ -180,9 +216,11 @@
// The chart was created while the container was hidden,
// so force a re-measure now that it is visible.
chart.resize();
chartInfo.textContent = '> ' + chartInfoText(range);
} catch (err) {
chartError.textContent = '! Chart error: ' + err.message;
chartError.classList.remove('hidden');
chartInfo.textContent = '';
chartSection.classList.remove('hidden');
}
}
@@ -199,7 +237,7 @@
const readouts = await fetchJSON(`/api/sensors/${sensorId}/readouts?type=${type}`);
readouts.forEach(r => {
const tr = document.createElement('tr');
tr.innerHTML = `<td>${formatTimestamp(r.timestamp)}</td><td>${r.value}</td>`;
tr.innerHTML = `<td>${formatTimestamp(r.timestamp)}</td><td>${formatTableValue(type, r.value)}</td>`;
readoutsBody.appendChild(tr);
});
readoutsSection.classList.remove('hidden');