Migra dal codice salvato in locale al codice condiviso
This commit is contained in:
350
plugin/datasetModels/graphsCore.js
Normal file
350
plugin/datasetModels/graphsCore.js
Normal file
@@ -0,0 +1,350 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const ARCHIVE_FILE = path.join(__dirname, 'hourly_archive.json');
|
||||
|
||||
// Cache dati OpenMeteo condivisi (evita chiamate duplicate)
|
||||
let sharedWeatherData = {
|
||||
forecast: null,
|
||||
waves: null,
|
||||
units: null, // Unità di misura globali
|
||||
lastUpdate: null,
|
||||
updateInterval: 2 * 60 * 1000 // 2 minuti
|
||||
};
|
||||
|
||||
// Archivio dati orari
|
||||
let hourlyArchive = {
|
||||
temperature: [],
|
||||
windSpeed: [],
|
||||
windDirection: [],
|
||||
waveHeight: [],
|
||||
wavePeriod: [],
|
||||
waveDirection: [],
|
||||
humidity: [],
|
||||
pressure: []
|
||||
};
|
||||
|
||||
/**
|
||||
* Carica l'archivio da file
|
||||
*/
|
||||
function loadArchive() {
|
||||
try {
|
||||
if (fs.existsSync(ARCHIVE_FILE)) {
|
||||
const data = fs.readFileSync(ARCHIVE_FILE, 'utf8');
|
||||
const parsed = JSON.parse(data);
|
||||
// Valida struttura archivio
|
||||
if (parsed && typeof parsed === 'object') {
|
||||
hourlyArchive = {
|
||||
temperature: Array.isArray(parsed.temperature) ? parsed.temperature : [],
|
||||
windSpeed: Array.isArray(parsed.windSpeed) ? parsed.windSpeed : [],
|
||||
windDirection: Array.isArray(parsed.windDirection) ? parsed.windDirection : [],
|
||||
waveHeight: Array.isArray(parsed.waveHeight) ? parsed.waveHeight : [],
|
||||
wavePeriod: Array.isArray(parsed.wavePeriod) ? parsed.wavePeriod : [],
|
||||
waveDirection: Array.isArray(parsed.waveDirection) ? parsed.waveDirection : [],
|
||||
humidity: Array.isArray(parsed.humidity) ? parsed.humidity : [],
|
||||
pressure: Array.isArray(parsed.pressure) ? parsed.pressure : []
|
||||
};
|
||||
console.log('[GraphsCore] Archivio caricato');
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('[GraphsCore] Errore caricamento archivio:', error.message);
|
||||
// Resetta archivio se corrotto
|
||||
hourlyArchive = {
|
||||
temperature: [], windSpeed: [], windDirection: [],
|
||||
waveHeight: [], wavePeriod: [], waveDirection: [],
|
||||
humidity: [], pressure: []
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Salva l'archivio su file
|
||||
*/
|
||||
function saveArchive() {
|
||||
try {
|
||||
fs.writeFileSync(ARCHIVE_FILE, JSON.stringify(hourlyArchive, null, 2));
|
||||
} catch (error) {
|
||||
console.error('[GraphsCore] Errore salvataggio archivio:', error.message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Aggiorna i dati meteo condivisi
|
||||
* @param {object} forecastData - Dati forecast da OpenMeteo
|
||||
* @param {object} wavesData - Dati onde da OpenMeteo
|
||||
*/
|
||||
function updateSharedWeatherData(forecastData, wavesData) {
|
||||
if (forecastData) {
|
||||
sharedWeatherData.forecast = forecastData;
|
||||
}
|
||||
if (wavesData) {
|
||||
sharedWeatherData.waves = wavesData;
|
||||
}
|
||||
|
||||
// Aggiorna unità se disponibili
|
||||
if (forecastData?.units || wavesData?.units) {
|
||||
sharedWeatherData.units = {
|
||||
forecast: forecastData?.units || sharedWeatherData.units?.forecast || {},
|
||||
waves: wavesData?.units || sharedWeatherData.units?.waves || {}
|
||||
};
|
||||
}
|
||||
|
||||
sharedWeatherData.lastUpdate = Date.now();
|
||||
}
|
||||
|
||||
/**
|
||||
* Ottiene i dati meteo condivisi
|
||||
* @returns {object} Dati meteo attuali
|
||||
*/
|
||||
function getSharedWeatherData() {
|
||||
return {
|
||||
forecast: sharedWeatherData.forecast,
|
||||
waves: sharedWeatherData.waves,
|
||||
units: sharedWeatherData.units,
|
||||
lastUpdate: sharedWeatherData.lastUpdate,
|
||||
isValid: sharedWeatherData.lastUpdate &&
|
||||
(Date.now() - sharedWeatherData.lastUpdate) < sharedWeatherData.updateInterval * 2
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Ottiene le unità di misura globali
|
||||
*/
|
||||
function getUnits() {
|
||||
return sharedWeatherData.units || {
|
||||
forecast: {
|
||||
temperature: '°C',
|
||||
humidity: '%',
|
||||
pressure: 'hPa',
|
||||
windSpeed: 'km/h',
|
||||
windDirection: '°'
|
||||
},
|
||||
waves: {
|
||||
waveHeight: 'm',
|
||||
wavePeriod: 's',
|
||||
waveDirection: '°'
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Formatta un valore con la sua unità
|
||||
*/
|
||||
function formatValue(value, unitKey, category = 'forecast') {
|
||||
if (value === null || value === undefined) return 'n/d';
|
||||
const units = getUnits();
|
||||
const unit = units[category]?.[unitKey] || '';
|
||||
return `${value}${unit}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifica se i dati condivisi sono ancora validi
|
||||
*/
|
||||
function isWeatherDataValid() {
|
||||
if (!sharedWeatherData.lastUpdate) return false;
|
||||
return (Date.now() - sharedWeatherData.lastUpdate) < sharedWeatherData.updateInterval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Archivia un punto dati orario
|
||||
*/
|
||||
function archiveHourlyData(data) {
|
||||
if (!data || typeof data !== 'object') {
|
||||
console.warn('[GraphsCore] archiveHourlyData: dati non validi');
|
||||
return;
|
||||
}
|
||||
|
||||
const timestamp = new Date().toISOString();
|
||||
const maxPoints = 168; // 7 giorni di dati orari
|
||||
|
||||
const addPoint = (arr, value) => {
|
||||
if (value === null || value === undefined || Number.isNaN(value)) return;
|
||||
arr.push({ timestamp, value });
|
||||
if (arr.length > maxPoints) arr.shift();
|
||||
};
|
||||
|
||||
addPoint(hourlyArchive.temperature, data.temperature);
|
||||
addPoint(hourlyArchive.windSpeed, data.windSpeed);
|
||||
addPoint(hourlyArchive.windDirection, data.windDirection);
|
||||
addPoint(hourlyArchive.waveHeight, data.waveHeight);
|
||||
addPoint(hourlyArchive.wavePeriod, data.wavePeriod);
|
||||
addPoint(hourlyArchive.waveDirection, data.waveDirection);
|
||||
addPoint(hourlyArchive.humidity, data.humidity);
|
||||
addPoint(hourlyArchive.pressure, data.pressure);
|
||||
|
||||
saveArchive();
|
||||
console.log('[GraphsCore] Dati orari archiviati');
|
||||
}
|
||||
|
||||
/**
|
||||
* Ottiene i dati per un grafico specifico
|
||||
* @param {string} parameter - temperatura, vento, onde, etc.
|
||||
* @param {number} hours - ultimi N ore (default 24)
|
||||
*/
|
||||
function getGraphData(parameter, hours = 24) {
|
||||
const paramMap = {
|
||||
'temperature': hourlyArchive.temperature,
|
||||
'windSpeed': hourlyArchive.windSpeed,
|
||||
'windDirection': hourlyArchive.windDirection,
|
||||
'waveHeight': hourlyArchive.waveHeight,
|
||||
'wavePeriod': hourlyArchive.wavePeriod,
|
||||
'waveDirection': hourlyArchive.waveDirection,
|
||||
'humidity': hourlyArchive.humidity,
|
||||
'pressure': hourlyArchive.pressure
|
||||
};
|
||||
|
||||
const data = paramMap[parameter] || [];
|
||||
const cutoff = Date.now() - (hours * 60 * 60 * 1000);
|
||||
|
||||
return data.filter(point => new Date(point.timestamp).getTime() > cutoff);
|
||||
}
|
||||
|
||||
/**
|
||||
* Genera dati formattati per Chart.js
|
||||
*/
|
||||
function formatForChart(parameter, hours = 24) {
|
||||
const data = getGraphData(parameter, hours);
|
||||
|
||||
return {
|
||||
labels: data.map(p => {
|
||||
const d = new Date(p.timestamp);
|
||||
return `${d.getHours()}:${String(d.getMinutes()).padStart(2, '0')}`;
|
||||
}),
|
||||
datasets: [{
|
||||
label: getParameterLabel(parameter),
|
||||
data: data.map(p => p.value),
|
||||
borderColor: getParameterColor(parameter),
|
||||
backgroundColor: getParameterColor(parameter, 0.2),
|
||||
tension: 0.3,
|
||||
fill: true
|
||||
}]
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Label leggibili per i parametri
|
||||
*/
|
||||
function getParameterLabel(param) {
|
||||
const labels = {
|
||||
'temperature': 'Temperatura (°C)',
|
||||
'windSpeed': 'Velocità Vento (km/h)',
|
||||
'windDirection': 'Direzione Vento (°)',
|
||||
'waveHeight': 'Altezza Onde (m)',
|
||||
'wavePeriod': 'Periodo Onde (s)',
|
||||
'waveDirection': 'Direzione Onde (°)',
|
||||
'humidity': 'Umidità (%)',
|
||||
'pressure': 'Pressione (hPa)'
|
||||
};
|
||||
return labels[param] || param;
|
||||
}
|
||||
|
||||
/**
|
||||
* Colori per i grafici
|
||||
*/
|
||||
function getParameterColor(param, alpha = 1) {
|
||||
const colors = {
|
||||
'temperature': `rgba(255, 99, 132, ${alpha})`,
|
||||
'windSpeed': `rgba(54, 162, 235, ${alpha})`,
|
||||
'windDirection': `rgba(75, 192, 192, ${alpha})`,
|
||||
'waveHeight': `rgba(153, 102, 255, ${alpha})`,
|
||||
'wavePeriod': `rgba(255, 159, 64, ${alpha})`,
|
||||
'waveDirection': `rgba(255, 205, 86, ${alpha})`,
|
||||
'humidity': `rgba(201, 203, 207, ${alpha})`,
|
||||
'pressure': `rgba(100, 149, 237, ${alpha})`
|
||||
};
|
||||
return colors[param] || `rgba(128, 128, 128, ${alpha})`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ottiene tutti i dati disponibili per dashboard
|
||||
*/
|
||||
function getAllGraphsData(hours = 24) {
|
||||
return {
|
||||
temperature: formatForChart('temperature', hours),
|
||||
windSpeed: formatForChart('windSpeed', hours),
|
||||
waveHeight: formatForChart('waveHeight', hours),
|
||||
humidity: formatForChart('humidity', hours)
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Statistiche sull'archivio
|
||||
*/
|
||||
function getArchiveStats() {
|
||||
return {
|
||||
temperature: hourlyArchive.temperature.length,
|
||||
windSpeed: hourlyArchive.windSpeed.length,
|
||||
waveHeight: hourlyArchive.waveHeight.length,
|
||||
oldestData: getOldestTimestamp(),
|
||||
newestData: getNewestTimestamp()
|
||||
};
|
||||
}
|
||||
|
||||
function getOldestTimestamp() {
|
||||
const all = [
|
||||
...hourlyArchive.temperature,
|
||||
...hourlyArchive.windSpeed,
|
||||
...hourlyArchive.waveHeight
|
||||
];
|
||||
if (all.length === 0) return null;
|
||||
return all.reduce((oldest, p) =>
|
||||
new Date(p.timestamp) < new Date(oldest.timestamp) ? p : oldest
|
||||
).timestamp;
|
||||
}
|
||||
|
||||
function getNewestTimestamp() {
|
||||
const all = [
|
||||
...hourlyArchive.temperature,
|
||||
...hourlyArchive.windSpeed,
|
||||
...hourlyArchive.waveHeight
|
||||
];
|
||||
if (all.length === 0) return null;
|
||||
return all.reduce((newest, p) =>
|
||||
new Date(p.timestamp) > new Date(newest.timestamp) ? p : newest
|
||||
).timestamp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pulisce l'archivio
|
||||
*/
|
||||
function clearArchive() {
|
||||
hourlyArchive = {
|
||||
temperature: [],
|
||||
windSpeed: [],
|
||||
windDirection: [],
|
||||
waveHeight: [],
|
||||
wavePeriod: [],
|
||||
waveDirection: [],
|
||||
humidity: [],
|
||||
pressure: []
|
||||
};
|
||||
saveArchive();
|
||||
console.log('[GraphsCore] Archivio pulito');
|
||||
}
|
||||
|
||||
// Carica archivio all'avvio
|
||||
loadArchive();
|
||||
|
||||
module.exports = {
|
||||
// Gestione dati condivisi
|
||||
updateSharedWeatherData,
|
||||
getSharedWeatherData,
|
||||
isWeatherDataValid,
|
||||
|
||||
// Unità di misura
|
||||
getUnits,
|
||||
formatValue,
|
||||
|
||||
// Archivio orario
|
||||
archiveHourlyData,
|
||||
getGraphData,
|
||||
formatForChart,
|
||||
getAllGraphsData,
|
||||
getArchiveStats,
|
||||
clearArchive,
|
||||
|
||||
// Utility
|
||||
getParameterLabel,
|
||||
getParameterColor
|
||||
};
|
||||
Reference in New Issue
Block a user