/** * logRecorder.js - Gestione registrazione dati separata * Centralizza tutte le funzioni di logging del dataset */ const path = require('path'); const { datasetInit, appendData } = require('../datasetModels/datasetCore'); let app = null; let recordingInterval = null; let isRecording = false; // Stato condiviso della registrazione const recordingState = { active: false, startTime: null, entryCount: 0, currentFile: null, stream: null }; /** * Inizializza il recorder con l'istanza di SignalK app */ function init(signalkApp) { app = signalkApp; console.log('[LogRecorder] Inizializzato'); } /** * Raccoglie i dati dai sensori SignalK */ function collectSensorData() { const getSK = (p) => { const v = app.getSelfPath(p); return v && v.value !== undefined && v.value !== null ? v.value : null; }; return { timestamp: new Date().toISOString(), // Posizione latitude: getSK('navigation.position')?.latitude ?? null, longitude: getSK('navigation.position')?.longitude ?? null, speed: getSK('navigation.speedOverGround'), heading: getSK('navigation.headingTrue'), // Batteria Trazione traction_voltage: getSK('electrical.batteries.traction.Voltage'), traction_current: getSK('electrical.batteries.traction.current'), traction_soc: getSK('electrical.batteries.traction.stateOfCharge'), traction_temperature: getSK('electrical.batteries.traction.temperature'), traction_power: getSK('electrical.batteries.traction.power'), // Batteria Servizio service_voltage: getSK('electrical.batteries.service.Voltage'), service_current: getSK('electrical.batteries.service.current'), service_soc: getSK('electrical.batteries.service.stateOfCharge'), service_temperature: getSK('electrical.batteries.service.temperature'), // Meteo (da OpenMeteo condiviso) temperature: getSK('meb.temperature'), windSpeed: getSK('meb.appleWindSpeed'), windDirection: getSK('meb.appleWindDirection'), // Onde waveHeight: getSK('meb.waves.waveHeight'), wavePeriod: getSK('meb.waves.wavePeriod'), waveDirection: getSK('meb.waves.waveDirection') }; } /** * Crea un nuovo file di log */ function createNewLogFile() { const headers = [ 'timestamp', 'latitude', 'longitude', 'speed', 'heading', 'traction_voltage', 'traction_current', 'traction_soc', 'traction_temperature', 'traction_power', 'service_voltage', 'service_current', 'service_soc', 'service_temperature', 'temperature', 'windSpeed', 'windDirection', 'waveHeight', 'wavePeriod', 'waveDirection' ]; const result = datasetInit(headers); if (result) { recordingState.currentFile = result.fileName; recordingState.stream = result.stream; console.log(`[LogRecorder] Nuovo file: ${result.fileName}`); } return result; } /** * Scrive una riga di dati nel log */ function writeLogEntry(data) { if (!recordingState.stream) return false; const values = [ data.timestamp, data.latitude, data.longitude, data.speed, data.heading, data.traction_voltage, data.traction_current, data.traction_soc, data.traction_temperature, data.traction_power, data.service_voltage, data.service_current, data.service_soc, data.service_temperature, data.temperature, data.windSpeed, data.windDirection, data.waveHeight, data.wavePeriod, data.waveDirection ]; appendData(values); recordingState.entryCount++; return true; } /** * Avvia la registrazione * @param {number} intervalMs - Intervallo in millisecondi (default 2000) */ function startRecording(intervalMs = 2000) { if (isRecording) { console.log('[LogRecorder] Registrazione già attiva'); return false; } if (!app) { console.error('[LogRecorder] App non inizializzata'); return false; } const fileResult = createNewLogFile(); if (!fileResult) { console.error('[LogRecorder] Impossibile creare file di log'); return false; } recordingState.active = true; recordingState.startTime = Date.now(); recordingState.entryCount = 0; isRecording = true; recordingInterval = setInterval(() => { const data = collectSensorData(); writeLogEntry(data); }, intervalMs); console.log(`[LogRecorder] Registrazione avviata (ogni ${intervalMs}ms)`); return true; } /** * Ferma la registrazione */ function stopRecording() { if (!isRecording) { console.log('[LogRecorder] Nessuna registrazione attiva'); return false; } if (recordingInterval) { clearInterval(recordingInterval); recordingInterval = null; } if (recordingState.stream) { recordingState.stream.end(); } const duration = Date.now() - recordingState.startTime; console.log(`[LogRecorder] Registrazione fermata. Durata: ${Math.round(duration / 1000)}s, Entries: ${recordingState.entryCount}`); recordingState.active = false; recordingState.stream = null; isRecording = false; return { duration, entries: recordingState.entryCount, file: recordingState.currentFile }; } /** * Riavvia la registrazione (nuovo file) */ function restartRecording(intervalMs = 2000) { stopRecording(); return startRecording(intervalMs); } /** * Ottiene lo stato corrente della registrazione */ function getStatus() { return { isRecording, active: recordingState.active, startTime: recordingState.startTime, entryCount: recordingState.entryCount, currentFile: recordingState.currentFile, runningTime: isRecording ? Date.now() - recordingState.startTime : 0 }; } /** * Verifica se la registrazione è attiva */ function isActive() { return isRecording; } module.exports = { init, startRecording, stopRecording, restartRecording, getStatus, isActive, collectSensorData };