This commit is contained in:
sebseb7
2025-12-23 06:59:23 +01:00
parent 1b56e2cc42
commit eec45ee379
5 changed files with 105 additions and 40 deletions

View File

@@ -1218,30 +1218,43 @@ app.get('/api/history', (req, res) => {
break; break;
} }
// Calculate time modifiers using offset in seconds // Calculate absolute start/end times (in seconds)
const nowMs = Date.now();
let startTsSec, endTsSec;
if (range === 'today') {
// align to midnight local time
const d = new Date(nowMs);
d.setHours(0, 0, 0, 0);
const midnightMs = d.getTime();
// "1 Tag" = 24h aligned to midnight
startTsSec = (midnightMs / 1000) - (off * 24 * 3600);
endTsSec = startTsSec + (24 * 3600);
} else {
// Rolling window
let durationSec; let durationSec;
if (range === 'week') durationSec = 7 * 24 * 3600; if (range === 'week') durationSec = 7 * 24 * 3600;
else if (range === 'month') durationSec = 30 * 24 * 3600; else if (range === 'month') durationSec = 30 * 24 * 3600;
else durationSec = 24 * 3600; // day else durationSec = 24 * 3600; // day
const endOffsetSec = off * durationSec; const endMs = nowMs - (off * durationSec * 1000);
const startOffsetSec = (off + 1) * durationSec; const startMs = endMs - (durationSec * 1000);
const endMod = `-${endOffsetSec} seconds`; startTsSec = Math.floor(startMs / 1000);
const startMod = `-${startOffsetSec} seconds`; endTsSec = Math.floor(endMs / 1000);
}
// Select raw data
// Select raw data
const stmt = db.prepare(` const stmt = db.prepare(`
SELECT strftime('%s', timestamp) as ts, temp_c, humidity, fan_speed SELECT strftime('%s', timestamp) as ts, temp_c, humidity, fan_speed
FROM readings FROM readings
WHERE dev_name = ? AND port = ? WHERE dev_name = ? AND port = ?
AND timestamp >= datetime('now', ?) AND timestamp >= datetime(?, 'unixepoch')
AND timestamp < datetime('now', ?) AND timestamp < datetime(?, 'unixepoch')
ORDER BY timestamp ASC ORDER BY timestamp ASC
`); `);
const rows = stmt.all(devName, parseInt(port, 10), startMod, endMod); const rows = stmt.all(devName, parseInt(port, 10), startTsSec, endTsSec);
if (rows.length === 0) return res.json({ start: 0, step: bucketSize, temps: [], hums: [], levels: [] }); if (rows.length === 0) return res.json({ start: 0, step: bucketSize, temps: [], hums: [], levels: [] });
@@ -1320,27 +1333,38 @@ app.get('/api/outputs/history', (req, res) => {
const { range, offset = 0 } = req.query; const { range, offset = 0 } = req.query;
const off = parseInt(offset, 10) || 0; const off = parseInt(offset, 10) || 0;
// Calculate duration in seconds // Calculate absolute start/end times (in seconds)
const nowMs = Date.now();
let startTsSec, endTsSec;
if (range === 'today') {
const d = new Date(nowMs);
d.setHours(0, 0, 0, 0);
const midnightMs = d.getTime();
startTsSec = (midnightMs / 1000) - (off * 24 * 3600);
endTsSec = startTsSec + (24 * 3600);
} else {
let durationSec; let durationSec;
if (range === 'week') durationSec = 7 * 24 * 3600; if (range === 'week') durationSec = 7 * 24 * 3600;
else if (range === 'month') durationSec = 30 * 24 * 3600; else if (range === 'month') durationSec = 30 * 24 * 3600;
else durationSec = 24 * 3600; // day else durationSec = 24 * 3600; // day
const endOffsetSec = off * durationSec; const endMs = nowMs - (off * durationSec * 1000);
const startOffsetSec = (off + 1) * durationSec; const startMs = endMs - (durationSec * 1000);
const endMod = `-${endOffsetSec} seconds`; startTsSec = Math.floor(startMs / 1000);
const startMod = `-${startOffsetSec} seconds`; endTsSec = Math.floor(endMs / 1000);
}
const stmt = db.prepare(` const stmt = db.prepare(`
SELECT timestamp, dev_name, port, state, level SELECT timestamp, dev_name, port, state, level
FROM output_log FROM output_log
WHERE timestamp >= datetime('now', ?) WHERE timestamp >= datetime(?, 'unixepoch')
AND timestamp < datetime('now', ?) AND timestamp < datetime(?, 'unixepoch')
ORDER BY timestamp ASC ORDER BY timestamp ASC
`); `);
const rows = stmt.all(startMod, endMod); const rows = stmt.all(startTsSec, endTsSec);
// Compress: Group by "Dev:Port" -> [[ts, state, level], ...] // Compress: Group by "Dev:Port" -> [[ts, state, level], ...]
const compressed = {}; const compressed = {};

View File

@@ -28,9 +28,19 @@ class Dashboard extends Component {
const { range, offset } = this.state; const { range, offset } = this.state;
const nowMs = Date.now(); const nowMs = Date.now();
let startMs, endMs;
if (range === 'today') {
const d = new Date(nowMs);
d.setHours(0, 0, 0, 0);
const midnightMs = d.getTime();
startMs = midnightMs - (offset * 24 * 3600 * 1000);
endMs = startMs + (24 * 3600 * 1000);
} else {
const durationSec = (range === 'week' ? 7 * 24 * 3600 : (range === 'month' ? 30 * 24 * 3600 : 24 * 3600)); const durationSec = (range === 'week' ? 7 * 24 * 3600 : (range === 'month' ? 30 * 24 * 3600 : 24 * 3600));
const endMs = nowMs - (offset * durationSec * 1000); endMs = nowMs - (offset * durationSec * 1000);
const startMs = endMs - (durationSec * 1000); startMs = endMs - (durationSec * 1000);
}
const dateOpts = { month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit' }; const dateOpts = { month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit' };
const dateRangeLabel = `${new Date(startMs).toLocaleString([], dateOpts)} - ${new Date(endMs).toLocaleString([], dateOpts)}`; const dateRangeLabel = `${new Date(startMs).toLocaleString([], dateOpts)} - ${new Date(endMs).toLocaleString([], dateOpts)}`;
@@ -71,6 +81,12 @@ class Dashboard extends Component {
> >
{t('dashboard.hours24')} {t('dashboard.hours24')}
</Button> </Button>
<Button
onClick={() => this.setRange('today')}
color={range === 'today' ? 'primary' : 'inherit'}
>
1 Tag
</Button>
<Button <Button
onClick={() => this.setRange('week')} onClick={() => this.setRange('week')}
color={range === 'week' ? 'primary' : 'inherit'} color={range === 'week' ? 'primary' : 'inherit'}

View File

@@ -80,11 +80,19 @@ class EnvChart extends Component {
}; };
const nowMs = Date.now(); const nowMs = Date.now();
const durationSec = (this.props.range === 'week' ? 7 * 24 * 3600 : (this.props.range === 'month' ? 30 * 24 * 3600 : 24 * 3600)); let startMs, endMs;
// Use offset to calculate exact window if (this.props.range === 'today') {
const endMs = nowMs - ((this.props.offset || 0) * durationSec * 1000); const d = new Date(nowMs);
const startMs = endMs - (durationSec * 1000); d.setHours(0, 0, 0, 0);
const midnightMs = d.getTime();
startMs = midnightMs - ((this.props.offset || 0) * 24 * 3600 * 1000);
endMs = startMs + (24 * 3600 * 1000);
} else {
const durationSec = (this.props.range === 'week' ? 7 * 24 * 3600 : (this.props.range === 'month' ? 30 * 24 * 3600 : 24 * 3600));
endMs = nowMs - ((this.props.offset || 0) * durationSec * 1000);
startMs = endMs - (durationSec * 1000);
}
const options = { const options = {
animation: false, animation: false,

View File

@@ -70,11 +70,19 @@ class LevelChart extends Component {
: { suggestedMin: 0, suggestedMax: 10, ticks: { stepSize: 1 } }; : { suggestedMin: 0, suggestedMax: 10, ticks: { stepSize: 1 } };
const nowMs = Date.now(); const nowMs = Date.now();
const durationSec = (this.props.range === 'week' ? 7 * 24 * 3600 : (this.props.range === 'month' ? 30 * 24 * 3600 : 24 * 3600)); let startMs, endMs;
// Use offset to calculate exact window if (this.props.range === 'today') {
const endMs = nowMs - ((this.props.offset || 0) * durationSec * 1000); const d = new Date(nowMs);
const startMs = endMs - (durationSec * 1000); d.setHours(0, 0, 0, 0);
const midnightMs = d.getTime();
startMs = midnightMs - ((this.props.offset || 0) * 24 * 3600 * 1000);
endMs = startMs + (24 * 3600 * 1000);
} else {
const durationSec = (this.props.range === 'week' ? 7 * 24 * 3600 : (this.props.range === 'month' ? 30 * 24 * 3600 : 24 * 3600));
endMs = nowMs - ((this.props.offset || 0) * durationSec * 1000);
startMs = endMs - (durationSec * 1000);
}
const options = { const options = {
animation: false, animation: false,

View File

@@ -88,10 +88,19 @@ class OutputChart extends Component {
const gruvboxColors = ['#fb4934', '#b8bb26', '#fabd2f', '#83a598', '#d3869b', '#8ec07c', '#fe8019', '#928374']; const gruvboxColors = ['#fb4934', '#b8bb26', '#fabd2f', '#83a598', '#d3869b', '#8ec07c', '#fe8019', '#928374'];
const nowMs = Date.now(); const nowMs = Date.now();
const durationSec = (range === 'week' ? 7 * 24 * 3600 : (range === 'month' ? 30 * 24 * 3600 : 24 * 3600)); let startMs, endMs;
const endMs = nowMs - ((this.props.offset || 0) * durationSec * 1000); if (range === 'today') {
const startMs = endMs - (durationSec * 1000); const d = new Date(nowMs);
d.setHours(0, 0, 0, 0);
const midnightMs = d.getTime();
startMs = midnightMs - ((this.props.offset || 0) * 24 * 3600 * 1000);
endMs = startMs + (24 * 3600 * 1000);
} else {
const durationSec = (range === 'week' ? 7 * 24 * 3600 : (range === 'month' ? 30 * 24 * 3600 : 24 * 3600));
endMs = nowMs - ((this.props.offset || 0) * durationSec * 1000);
startMs = endMs - (durationSec * 1000);
}
// Generate datasets // Generate datasets
const datasets = Object.keys(groupedData).map((key, index) => { const datasets = Object.keys(groupedData).map((key, index) => {