- Added rulesets manager to handle various data types and updates via HTTP and WebSocket. - Introduced layout store for managing kiosk layouts with caching and server synchronization. - Enhanced dashboard and data routes to support new layout and ruleset features. - Updated kiosk HTML and JavaScript to utilize new layout rendering and data binding. - Removed obsolete map route and integrated map functionality into the new tile renderer. - Improved Telegram commands to reflect changes in data structure and logging. - Refactored weather fetching intervals to prevent multiple instances. - Added SSE stream for real-time layout updates in the kiosk.
140 lines
5.1 KiB
JavaScript
140 lines
5.1 KiB
JavaScript
const settingsSchema = require('./config/skSettings.js')
|
|
const configManager = require('./config/configManager.js')
|
|
const routes = require('./routes/main.js')
|
|
const openmeteo = require('./cores/openmeteo.js')
|
|
const skFlow = require('./config/skFlow.js')
|
|
const telegram = require('./telegram/core.js')
|
|
const recorder = require('./cores/logs.local.js')
|
|
const realtime = require('./cores/realtime/core.js')
|
|
const rulesets = require('./cores/rulesets.js')
|
|
const layoutStore = require('./tools/kiosk/server-layout-store.js')
|
|
const { LOG_PATHS } = require('./rules')
|
|
|
|
module.exports = function(app) {
|
|
|
|
const plugin = {};
|
|
|
|
plugin.id = 'meb.plugin';
|
|
plugin.name = 'MEB Plugin';
|
|
plugin.description = 'MEB custom plugin';
|
|
plugin.version = '1.5.0';
|
|
|
|
let weatherIntervalId = null;
|
|
let forecastIntervalId = null;
|
|
let positionWaitIntervalId = null;
|
|
|
|
plugin.start = async function(options) {
|
|
|
|
// Inizializza il gestore della configurazione con le opzioni del plugin
|
|
configManager.init(options);
|
|
|
|
// Setup routing
|
|
if (process.env.NODE_ENV === 'development') {
|
|
app.debug('Running in DEVELOPMENT mode: routes will be reloaded on every request');
|
|
app.use('/meb', (req, res, next) => {
|
|
const path = require('path');
|
|
const routesPath = path.resolve(__dirname, 'routes');
|
|
Object.keys(require.cache).forEach(key => {
|
|
if (key.startsWith(routesPath)) {
|
|
delete require.cache[key];
|
|
}
|
|
});
|
|
require('./routes/main.js')(req, res, next);
|
|
});
|
|
} else {
|
|
app.debug('Running in PRODUCTION mode: routes are cached');
|
|
app.use('/meb', routes);
|
|
}
|
|
|
|
// Inizializza il modulo per la pubblicazione dei dati Signal K
|
|
skFlow.init(app);
|
|
|
|
// Carica i rulesets (cache su disco + defaults), poi avvia consumer
|
|
await rulesets.init();
|
|
|
|
// Layout kiosk (cache su disco)
|
|
await layoutStore.init();
|
|
|
|
// Inizializza il bot Telegram
|
|
telegram.init();
|
|
|
|
// Avvia la connessione realtime al server (ricevera' ruleset_update via WS)
|
|
realtime.init();
|
|
|
|
// In parallelo bootstrap HTTP delle versioni attive (puo' fallire silenzioso se server down)
|
|
rulesets.bootstrapFromServer().catch(err => console.warn('[INDEX] bootstrap rulesets:', err.message));
|
|
layoutStore.bootstrapFromServer().catch(err => console.warn('[INDEX] bootstrap layout:', err.message));
|
|
|
|
// Inizializza e avvia subito la registrazione log (1 riga/secondo)
|
|
recorder.init(LOG_PATHS);
|
|
try {
|
|
await recorder.startRecording();
|
|
} catch (err) {
|
|
console.warn('[INDEX] Errore avvio recording, proseguo:', err.message);
|
|
}
|
|
|
|
// ===== Weather & Forecast =====
|
|
|
|
const fetchWeather = async () => {
|
|
try {
|
|
const position = skFlow.get('navigation.position');
|
|
if (position) {
|
|
await openmeteo.fetchCurrentWeather(position);
|
|
}
|
|
} catch (err) {
|
|
console.error('[INDEX] Errore fetchCurrentWeather:', err.message);
|
|
}
|
|
};
|
|
|
|
const fetchForecasts = async () => {
|
|
try {
|
|
const position = skFlow.get('navigation.position');
|
|
if (position) {
|
|
await openmeteo.fetchHourlyForecasts(position);
|
|
}
|
|
} catch (err) {
|
|
console.error('[INDEX] Errore fetchHourlyForecasts:', err.message);
|
|
}
|
|
};
|
|
|
|
// Intervalli: current ogni 5 min, hourly ogni 1 ora
|
|
const startWeatherIntervals = () => {
|
|
if (weatherIntervalId || forecastIntervalId) return;
|
|
weatherIntervalId = setInterval(fetchWeather, 5 * 60 * 1000);
|
|
forecastIntervalId = setInterval(fetchForecasts, 60 * 60 * 1000);
|
|
};
|
|
|
|
// Aspetta la posizione GPS, poi avvia il fetch meteo
|
|
const position = skFlow.get('navigation.position');
|
|
if (position) {
|
|
await openmeteo.fetchAll(position);
|
|
startWeatherIntervals();
|
|
} else {
|
|
positionWaitIntervalId = setInterval(async () => {
|
|
const pos = skFlow.get('navigation.position');
|
|
if (pos) {
|
|
clearInterval(positionWaitIntervalId);
|
|
positionWaitIntervalId = null;
|
|
await openmeteo.fetchAll(pos);
|
|
startWeatherIntervals();
|
|
}
|
|
}, 2000);
|
|
}
|
|
|
|
}
|
|
|
|
plugin.stop = function() {
|
|
if (weatherIntervalId) { clearInterval(weatherIntervalId); weatherIntervalId = null; }
|
|
if (forecastIntervalId) { clearInterval(forecastIntervalId); forecastIntervalId = null; }
|
|
if (positionWaitIntervalId) { clearInterval(positionWaitIntervalId); positionWaitIntervalId = null; }
|
|
recorder.stopRecording();
|
|
realtime.stop();
|
|
app.debug('Plugin stopped');
|
|
}
|
|
|
|
plugin.schema = settingsSchema
|
|
|
|
return plugin;
|
|
|
|
}
|