Limitar graficas historicas al dia actual

main
EMOTIONS-HUNTER 4 weeks ago
parent e61284ddbc
commit bdc8c2f5ad

@ -71,6 +71,8 @@ ventana de procesamiento en vez de bloquear un segundo por sensor.
- Valores permitidos: 7, 30, 90, 365 o 0 para retencion indefinida.
- La poda conserva los nombres actuales de archivos para no romper graficas ni
exportaciones.
- Las graficas filtran visualmente el dia actual; los CSV mantienen todos los
registros disponibles dentro de la retencion configurada.
## Notificaciones

@ -119,6 +119,10 @@ expone en `GET /api/alarms`. Se registran entradas a `WARNING`, `CRITICAL` y
90, 365 o 0 para conservar indefinidamente. El recolector poda filas antiguas de
CSV sin cambiar los nombres que usa el dashboard.
Las graficas del dashboard muestran solo los datos del dia actual para evitar
saturacion visual. Los CSV conservan el periodo completo configurado por
retencion y siguen disponibles para exportacion.
## Umbrales de alarma
Los limites se guardan en `config/alarms.json`, se consultan con

@ -1,6 +1,7 @@
const POLLING_INTERVAL_MS = 1000;
const WARNING_MARGIN_RATIO = 0.1;
const MIN_READING_MAX_AGE_MS = 15000;
const DAY_IN_MS = 24 * 60 * 60 * 1000;
// Variables dinámicas para el control de históricos
let currentHistoryInterval = 10000;
@ -718,6 +719,7 @@ function parseHistoricalCsv(csvText, valueKey) {
return rows
.map((line) => splitCsvLine(line))
.map((columns) => {
const rawTimestamp = columns[timestampIndex];
const rawValue = Number(columns[valueIndex]);
if (!Number.isFinite(rawValue)) {
@ -725,13 +727,49 @@ function parseHistoricalCsv(csvText, valueKey) {
}
return {
label: formatTimestamp(columns[timestampIndex]),
timestampMs: parseTimestampMs(rawTimestamp),
label: formatTimestamp(rawTimestamp),
value: rawValue
};
})
.filter(Boolean);
}
function parseTimestampMs(rawTimestamp) {
const numericTimestamp = Number(rawTimestamp);
if (Number.isFinite(numericTimestamp)) {
if (numericTimestamp > 1000000000000) {
return numericTimestamp;
}
if (numericTimestamp > 1000000000) {
return numericTimestamp * 1000;
}
}
const parsedDate = new Date(rawTimestamp);
if (!Number.isNaN(parsedDate.getTime())) {
return parsedDate.getTime();
}
return Number.NaN;
}
function filterPointsForCurrentDay(points) {
const startOfToday = new Date();
startOfToday.setHours(0, 0, 0, 0);
const startMs = startOfToday.getTime();
const endMs = startMs + DAY_IN_MS;
return points.filter((point) =>
Number.isFinite(point.timestampMs) &&
point.timestampMs >= startMs &&
point.timestampMs < endMs
);
}
function splitCsvLine(line) {
return line
.split(",")
@ -755,22 +793,10 @@ function formatTimestamp(rawTimestamp) {
return "";
}
const numericTimestamp = Number(rawTimestamp);
if (Number.isFinite(numericTimestamp)) {
if (numericTimestamp > 1000000000000) {
return new Date(numericTimestamp).toLocaleTimeString();
}
if (numericTimestamp > 1000000000) {
return new Date(numericTimestamp * 1000).toLocaleTimeString();
}
}
const parsedDate = new Date(rawTimestamp);
const parsedMs = parseTimestampMs(rawTimestamp);
if (!Number.isNaN(parsedDate.getTime())) {
return parsedDate.toLocaleTimeString();
if (Number.isFinite(parsedMs)) {
return new Date(parsedMs).toLocaleTimeString();
}
return rawTimestamp;
@ -893,7 +919,7 @@ async function updateHistoricalTrends() {
historicalCharts.map(async (chartConfig) => ({
chartConfig,
points: currentEnabledSensorIds.has(chartConfig.sensorId)
? await readHistoricalData(chartConfig)
? filterPointsForCurrentDay(await readHistoricalData(chartConfig))
: []
}))
);

@ -145,7 +145,7 @@
<section class="trends-panel" aria-label="Tendencias históricas">
<div class="panel-heading">
<h2>Tendencias Históricas</h2>
<p>Actualización: <span id="history-interval">10 segundos</span></p>
<p>Periodo visible: hoy · Actualización: <span id="history-interval">10 segundos</span></p>
</div>
<div class="card config-card" style="margin-bottom: 20px; padding: 20px; border-left: 4px solid #9c27b0;">
<h3>Configuración de Almacenamiento</h3>

@ -32,6 +32,7 @@ test('dashboard starts live polling and exposes required controls', () => {
assert.match(dashboard, /saveNotificationConfig/);
assert.match(dashboard, /\/api\/config\/notifications/);
assert.match(dashboard, /getApiHeaders/);
assert.match(dashboard, /filterPointsForCurrentDay/);
assert.match(
dashboard,
/setInterval\(updateDashboard,\s*POLLING_INTERVAL_MS\)/

Loading…
Cancel
Save