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. - Valores permitidos: 7, 30, 90, 365 o 0 para retencion indefinida.
- La poda conserva los nombres actuales de archivos para no romper graficas ni - La poda conserva los nombres actuales de archivos para no romper graficas ni
exportaciones. exportaciones.
- Las graficas filtran visualmente el dia actual; los CSV mantienen todos los
registros disponibles dentro de la retencion configurada.
## Notificaciones ## 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 90, 365 o 0 para conservar indefinidamente. El recolector poda filas antiguas de
CSV sin cambiar los nombres que usa el dashboard. 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 ## Umbrales de alarma
Los limites se guardan en `config/alarms.json`, se consultan con Los limites se guardan en `config/alarms.json`, se consultan con

@ -1,6 +1,7 @@
const POLLING_INTERVAL_MS = 1000; const POLLING_INTERVAL_MS = 1000;
const WARNING_MARGIN_RATIO = 0.1; const WARNING_MARGIN_RATIO = 0.1;
const MIN_READING_MAX_AGE_MS = 15000; const MIN_READING_MAX_AGE_MS = 15000;
const DAY_IN_MS = 24 * 60 * 60 * 1000;
// Variables dinámicas para el control de históricos // Variables dinámicas para el control de históricos
let currentHistoryInterval = 10000; let currentHistoryInterval = 10000;
@ -718,6 +719,7 @@ function parseHistoricalCsv(csvText, valueKey) {
return rows return rows
.map((line) => splitCsvLine(line)) .map((line) => splitCsvLine(line))
.map((columns) => { .map((columns) => {
const rawTimestamp = columns[timestampIndex];
const rawValue = Number(columns[valueIndex]); const rawValue = Number(columns[valueIndex]);
if (!Number.isFinite(rawValue)) { if (!Number.isFinite(rawValue)) {
@ -725,13 +727,49 @@ function parseHistoricalCsv(csvText, valueKey) {
} }
return { return {
label: formatTimestamp(columns[timestampIndex]), timestampMs: parseTimestampMs(rawTimestamp),
label: formatTimestamp(rawTimestamp),
value: rawValue value: rawValue
}; };
}) })
.filter(Boolean); .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) { function splitCsvLine(line) {
return line return line
.split(",") .split(",")
@ -755,22 +793,10 @@ function formatTimestamp(rawTimestamp) {
return ""; return "";
} }
const numericTimestamp = Number(rawTimestamp); const parsedMs = parseTimestampMs(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);
if (!Number.isNaN(parsedDate.getTime())) { if (Number.isFinite(parsedMs)) {
return parsedDate.toLocaleTimeString(); return new Date(parsedMs).toLocaleTimeString();
} }
return rawTimestamp; return rawTimestamp;
@ -893,7 +919,7 @@ async function updateHistoricalTrends() {
historicalCharts.map(async (chartConfig) => ({ historicalCharts.map(async (chartConfig) => ({
chartConfig, chartConfig,
points: currentEnabledSensorIds.has(chartConfig.sensorId) 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"> <section class="trends-panel" aria-label="Tendencias históricas">
<div class="panel-heading"> <div class="panel-heading">
<h2>Tendencias Históricas</h2> <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>
<div class="card config-card" style="margin-bottom: 20px; padding: 20px; border-left: 4px solid #9c27b0;"> <div class="card config-card" style="margin-bottom: 20px; padding: 20px; border-left: 4px solid #9c27b0;">
<h3>Configuración de Almacenamiento</h3> <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, /saveNotificationConfig/);
assert.match(dashboard, /\/api\/config\/notifications/); assert.match(dashboard, /\/api\/config\/notifications/);
assert.match(dashboard, /getApiHeaders/); assert.match(dashboard, /getApiHeaders/);
assert.match(dashboard, /filterPointsForCurrentDay/);
assert.match( assert.match(
dashboard, dashboard,
/setInterval\(updateDashboard,\s*POLLING_INTERVAL_MS\)/ /setInterval\(updateDashboard,\s*POLLING_INTERVAL_MS\)/

Loading…
Cancel
Save