add data record, download csv

Signed-off-by: YoungSoo Shin <shinys000114@gmail.com>
This commit is contained in:
2025-12-09 14:52:07 +09:00
parent 8ba4a179db
commit 9923365184
2 changed files with 79 additions and 3 deletions

View File

@@ -141,8 +141,9 @@
<div class="card border-top-0 rounded-0 rounded-bottom"> <div class="card border-top-0 rounded-0 rounded-bottom">
<div class="card-body"> <div class="card-body">
<div class="d-flex justify-content-end mb-3"> <div class="d-flex justify-content-end mb-3">
<a class="btn btn-primary" download="datalog.csv" href="/datalog.csv" style="display: none"><i <button id="record-button" class="btn btn-success me-2"><i class="bi bi-record-circle me-1"></i>Record</button>
class="bi bi-download me-1"></i> Download CSV</a> <button id="stop-button" class="btn btn-danger me-2" style="display: none;"><i class="bi bi-stop-circle me-1"></i>Stop</button>
<button id="download-csv-button" class="btn btn-primary" style="display: none;"><i class="bi bi-download me-1"></i>Download CSV</button>
</div> </div>
<h5 class="card-title text-center mb-3">Power Metrics</h5> <h5 class="card-title text-center mb-3">Power Metrics</h5>
<div class="row"> <div class="row">

View File

@@ -30,6 +30,8 @@ import {setupEventListeners} from './events.js';
// --- Globals --- // --- Globals ---
// StatusMessage is imported directly from the generated proto.js file. // StatusMessage is imported directly from the generated proto.js file.
let isRecording = false;
let recordedData = [];
// --- DOM Elements --- // --- DOM Elements ---
const loginContainer = document.getElementById('login-container'); const loginContainer = document.getElementById('login-container');
@@ -50,6 +52,11 @@ const newUsernameInput = document.getElementById('new-username');
const newPasswordInput = document.getElementById('new-password'); const newPasswordInput = document.getElementById('new-password');
const confirmPasswordInput = document.getElementById('confirm-password'); const confirmPasswordInput = document.getElementById('confirm-password');
// Metrics Tab DOM Elements
const recordButton = document.getElementById('record-button');
const stopButton = document.getElementById('stop-button');
const downloadCsvButton = document.getElementById('download-csv-button');
// --- WebSocket Event Handlers --- // --- WebSocket Event Handlers ---
@@ -88,10 +95,15 @@ function onWsMessage(event) {
USB: sensorData.usb, USB: sensorData.usb,
MAIN: sensorData.main, MAIN: sensorData.main,
VIN: sensorData.vin, VIN: sensorData.vin,
timestamp: sensorData.timestampMs timestamp: sensorData.timestampMs,
uptime: sensorData.uptimeMs
}; };
updateSensorUI(sensorPayload); updateSensorUI(sensorPayload);
if (isRecording) {
recordedData.push(sensorPayload);
}
// Update uptime separately from the sensor data payload // Update uptime separately from the sensor data payload
if (sensorData.uptimeMs !== undefined) { if (sensorData.uptimeMs !== undefined) {
updateUptimeUI(sensorData.uptimeMs / 1000); updateUptimeUI(sensorData.uptimeMs / 1000);
@@ -233,6 +245,63 @@ function setupThemeToggles() {
}); });
} }
// --- Recording and Downloading Functions ---
function startRecording() {
isRecording = true;
recordedData = [];
recordButton.style.display = 'none';
stopButton.style.display = 'inline-block';
downloadCsvButton.style.display = 'none';
console.log('Recording started.');
}
function stopRecording() {
isRecording = false;
recordButton.style.display = 'inline-block';
stopButton.style.display = 'none';
if (recordedData.length > 0) {
downloadCsvButton.style.display = 'inline-block';
}
console.log('Recording stopped. Data points captured:', recordedData.length);
}
function downloadCSV() {
if (recordedData.length === 0) {
alert('No data to download.');
return;
}
const headers = [
'timestamp', 'uptime_ms',
'vin_voltage', 'vin_current', 'vin_power',
'main_voltage', 'main_current', 'main_power',
'usb_voltage', 'usb_current', 'usb_power'
];
const csvRows = [headers.join(',')];
recordedData.forEach(data => {
const timestamp = new Date(data.timestamp).toISOString();
const row = [
timestamp,
data.uptime,
data.VIN.voltage, data.VIN.current, data.VIN.power,
data.MAIN.voltage, data.MAIN.current, data.MAIN.power,
data.USB.voltage, data.USB.current, data.USB.power
];
csvRows.push(row.join(','));
});
const blob = new Blob([csvRows.join('\n')], { type: 'text/csv;charset=utf-8;' });
const link = document.createElement('a');
const url = URL.createObjectURL(blob);
link.setAttribute('href', url);
link.setAttribute('download', 'powermate_log.csv');
link.style.visibility = 'hidden';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
// --- Application Initialization --- // --- Application Initialization ---
@@ -263,6 +332,12 @@ function initializeMainAppContent() {
initializeVersion(); initializeVersion();
setupEventListeners(); // Attach main app event listeners setupEventListeners(); // Attach main app event listeners
logoutButton.addEventListener('click', handleLogout); // Attach logout listener logoutButton.addEventListener('click', handleLogout); // Attach logout listener
// Attach listeners for recording/downloading
recordButton.addEventListener('click', startRecording);
stopButton.addEventListener('click', stopRecording);
downloadCsvButton.addEventListener('click', downloadCSV);
connect(); connect();
// Attach user settings form listener // Attach user settings form listener