feat: Implement rulesets and layout management for kiosk plugin

- 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.
This commit is contained in:
Giuseppe Raffa
2026-05-12 10:17:54 +02:00
parent bb8d267cd4
commit c2c1598226
27 changed files with 1061 additions and 326 deletions

View File

@@ -6,6 +6,8 @@ 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) {
@@ -17,6 +19,10 @@ module.exports = function(app) {
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
@@ -43,12 +49,22 @@ module.exports = function(app) {
// 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
// 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 {
@@ -83,8 +99,9 @@ module.exports = function(app) {
// Intervalli: current ogni 5 min, hourly ogni 1 ora
const startWeatherIntervals = () => {
setInterval(fetchWeather, 5 * 60 * 1000);
setInterval(fetchForecasts, 60 * 60 * 1000);
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
@@ -93,10 +110,11 @@ module.exports = function(app) {
await openmeteo.fetchAll(position);
startWeatherIntervals();
} else {
const waitForPosition = setInterval(async () => {
positionWaitIntervalId = setInterval(async () => {
const pos = skFlow.get('navigation.position');
if (pos) {
clearInterval(waitForPosition);
clearInterval(positionWaitIntervalId);
positionWaitIntervalId = null;
await openmeteo.fetchAll(pos);
startWeatherIntervals();
}
@@ -106,6 +124,9 @@ module.exports = function(app) {
}
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');