Aggiunta stili CSS per Kiosk, struttura HTML per la Mappa e Riferimenti ai Sensori
• Creato un nuovo file CSS per gli stili del chiosco (kiosk) con variabili, stili per le schede (card) e animazioni. • Aggiunto un file HTML per l'interfaccia della mappa utilizzando Mapbox, inclusi gli stili e il JavaScript per le funzionalità della mappa. • Introdotto un file JSON per i riferimenti ai sensori, definendo percorsi ed elementi per i dati di temperatura, vento, onde, posizione, batteria, motore e sistema. Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
@@ -1,141 +1,104 @@
|
||||
// Mappa globale per salvare gli interval id anche dopo un "hot-reload"
|
||||
if (!global.__meb_live_trackers) {
|
||||
global.__meb_live_trackers = new Map();
|
||||
}
|
||||
const skFlow = require('../../config/skFlow');
|
||||
const { startSession } = require('../utility/live');
|
||||
|
||||
module.exports = [
|
||||
{
|
||||
id: 'live-refresh',
|
||||
execute: async ({ bot, chatId, msg }) => {
|
||||
const liveCmd = require('../commands/live.js');
|
||||
const newText = liveCmd.formatLiveData();
|
||||
|
||||
try {
|
||||
await bot.editMessageText(newText, {
|
||||
chat_id: chatId,
|
||||
message_id: msg.message_id,
|
||||
parse_mode: 'Markdown',
|
||||
reply_markup: {
|
||||
inline_keyboard: [
|
||||
[{ text: 'Avvia Live (2s)', callback_data: 'live-start' }],
|
||||
[{ text: 'Aggiorna', callback_data: 'live-refresh' }]
|
||||
]
|
||||
}
|
||||
});
|
||||
} catch (e) {
|
||||
if (!e.message.includes('message is not modified')) {
|
||||
console.error('[Telegram Live] Errore refresh:', e.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 'live-start',
|
||||
execute: async ({ bot, chatId, msg }) => {
|
||||
const liveCmd = require('../commands/live.js');
|
||||
|
||||
const messageId = msg.message_id;
|
||||
const liveKey = `${chatId}_${messageId}`;
|
||||
|
||||
// Se gia' attivo per questo messaggio, ignora
|
||||
if (global.__meb_live_trackers.has(liveKey)) return;
|
||||
|
||||
const stopMarkup = {
|
||||
inline_keyboard: [
|
||||
[{ text: 'Ferma Live', callback_data: 'live-stop' }]
|
||||
]
|
||||
};
|
||||
|
||||
await bot.editMessageReplyMarkup(stopMarkup, {
|
||||
chat_id: chatId,
|
||||
message_id: messageId
|
||||
});
|
||||
|
||||
// 30 tick da 2 secondi = 60 secondi, poi auto-stop
|
||||
let count = 30;
|
||||
const intervalTimer = setInterval(async () => {
|
||||
count--;
|
||||
const baseText = liveCmd.formatLiveData();
|
||||
|
||||
// Auto-stop quando il tempo scade
|
||||
if (count <= 0) {
|
||||
if (global.__meb_live_trackers.has(liveKey)) {
|
||||
clearInterval(global.__meb_live_trackers.get(liveKey));
|
||||
global.__meb_live_trackers.delete(liveKey);
|
||||
}
|
||||
try {
|
||||
await bot.editMessageText(
|
||||
baseText + `\n_Live terminato automaticamente (60s)._`,
|
||||
{
|
||||
chat_id: chatId,
|
||||
message_id: messageId,
|
||||
parse_mode: 'Markdown',
|
||||
reply_markup: {
|
||||
inline_keyboard: [
|
||||
[{ text: 'Avvia Live (2s)', callback_data: 'live-start' }],
|
||||
[{ text: 'Aggiorna', callback_data: 'live-refresh' }]
|
||||
]
|
||||
}
|
||||
}
|
||||
);
|
||||
} catch (e) { /* ignore */ }
|
||||
return;
|
||||
}
|
||||
|
||||
// Aggiornamento live con countdown
|
||||
const newText = baseText + `\n_Live attivo: arresto tra *${count * 2}s*_`;
|
||||
|
||||
try {
|
||||
await bot.editMessageText(newText, {
|
||||
chat_id: chatId,
|
||||
message_id: messageId,
|
||||
parse_mode: 'Markdown',
|
||||
reply_markup: stopMarkup
|
||||
});
|
||||
} catch (e) {
|
||||
if (e.response && e.response.statusCode === 429) {
|
||||
console.warn('[Telegram Live] Rate limit raggiunto');
|
||||
} else if (e.message && e.message.includes('message to edit not found')) {
|
||||
// Messaggio cancellato dall'utente
|
||||
clearInterval(intervalTimer);
|
||||
global.__meb_live_trackers.delete(liveKey);
|
||||
}
|
||||
// Ignora "message is not modified"
|
||||
}
|
||||
}, 2000);
|
||||
|
||||
global.__meb_live_trackers.set(liveKey, intervalTimer);
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 'live-stop',
|
||||
execute: async ({ bot, chatId, msg }) => {
|
||||
const liveCmd = require('../commands/live.js');
|
||||
|
||||
const messageId = msg.message_id;
|
||||
const liveKey = `${chatId}_${messageId}`;
|
||||
|
||||
// Pulisci l'interval se esiste
|
||||
if (global.__meb_live_trackers.has(liveKey)) {
|
||||
clearInterval(global.__meb_live_trackers.get(liveKey));
|
||||
global.__meb_live_trackers.delete(liveKey);
|
||||
}
|
||||
|
||||
const newText = liveCmd.formatLiveData();
|
||||
|
||||
try {
|
||||
await bot.editMessageText(newText + '\n_Live fermato._', {
|
||||
chat_id: chatId,
|
||||
message_id: messageId,
|
||||
parse_mode: 'Markdown',
|
||||
reply_markup: {
|
||||
inline_keyboard: [
|
||||
[{ text: 'Avvia Live (2s)', callback_data: 'live-start' }],
|
||||
[{ text: 'Aggiorna', callback_data: 'live-refresh' }]
|
||||
]
|
||||
}
|
||||
});
|
||||
} catch (e) { /* ignore */ }
|
||||
}
|
||||
}
|
||||
const logsPaths = [
|
||||
"navigation.position",
|
||||
"navigation.headingTrue",
|
||||
"navigation.speedOverGround",
|
||||
"propulsion.p1.temperature"
|
||||
];
|
||||
|
||||
// Funzioni per generare il testo aggiornato per ogni tipo di dato
|
||||
const textGenerators = {
|
||||
logs: () => {
|
||||
const data = skFlow.getFrom(logsPaths);
|
||||
if (!data || Object.keys(data).length === 0) return 'Nessun log disponibile.';
|
||||
let text = '*Telemetria di Bordo*\n\n';
|
||||
for (const [path, value] of Object.entries(data)) {
|
||||
const displayValue = typeof value === 'object' ? JSON.stringify(value) : value;
|
||||
text += `*${path}*: ${displayValue}\n`;
|
||||
}
|
||||
return text;
|
||||
},
|
||||
weather: () => {
|
||||
const data = skFlow.getWithFilter('meb.forecast');
|
||||
if (!data || Object.keys(data).length === 0) return 'Nessun dato meteo disponibile.';
|
||||
let text = '*Dati Meteo*\n\n';
|
||||
for (const [path, value] of Object.entries(data)) {
|
||||
const displayValue = typeof value === 'object' ? JSON.stringify(value) : value;
|
||||
text += `*${path}*: ${displayValue}\n`;
|
||||
}
|
||||
return text;
|
||||
},
|
||||
marine: () => {
|
||||
const data = skFlow.getWithFilter('meb.marine');
|
||||
if (!data || Object.keys(data).length === 0) return 'Nessun dato sul mare disponibile.';
|
||||
let text = '*Dati Meteo del mare*\n\n';
|
||||
for (const [path, value] of Object.entries(data)) {
|
||||
const displayValue = typeof value === 'object' ? JSON.stringify(value) : value;
|
||||
text += `*${path}*: ${displayValue}\n`;
|
||||
}
|
||||
return text;
|
||||
},
|
||||
data: () => {
|
||||
let text = '';
|
||||
|
||||
const logs = skFlow.getFrom(logsPaths);
|
||||
text += '*Telemetria di Bordo*\n\n';
|
||||
if (logs && Object.keys(logs).length > 0) {
|
||||
for (const [path, value] of Object.entries(logs)) {
|
||||
const displayValue = typeof value === 'object' ? JSON.stringify(value) : value;
|
||||
text += `*${path}*: ${displayValue}\n`;
|
||||
}
|
||||
} else {
|
||||
text += 'Nessun dato disponibile.\n';
|
||||
}
|
||||
|
||||
const weather = skFlow.getWithFilter('meb.forecast');
|
||||
text += '\n*Dati Meteo*\n\n';
|
||||
if (weather && Object.keys(weather).length > 0) {
|
||||
for (const [path, value] of Object.entries(weather)) {
|
||||
const displayValue = typeof value === 'object' ? JSON.stringify(value) : value;
|
||||
text += `*${path}*: ${displayValue}\n`;
|
||||
}
|
||||
} else {
|
||||
text += 'Nessun dato disponibile.\n';
|
||||
}
|
||||
|
||||
const marine = skFlow.getWithFilter('meb.marine');
|
||||
text += '\n*Dati Meteo del mare*\n\n';
|
||||
if (marine && Object.keys(marine).length > 0) {
|
||||
for (const [path, value] of Object.entries(marine)) {
|
||||
const displayValue = typeof value === 'object' ? JSON.stringify(value) : value;
|
||||
text += `*${path}*: ${displayValue}\n`;
|
||||
}
|
||||
} else {
|
||||
text += 'Nessun dato disponibile.\n';
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
prefix: 'live:',
|
||||
handler: async (bot, query) => {
|
||||
const chatId = query.message.chat.id;
|
||||
const botMessageId = query.message.message_id;
|
||||
|
||||
// callback_data = live:<dataType>:<userMessageId>
|
||||
const parts = query.data.split(':');
|
||||
const dataType = parts[1];
|
||||
const userMessageId = parts[2];
|
||||
|
||||
const getTextFn = textGenerators[dataType];
|
||||
if (!getTextFn) {
|
||||
bot.answerCallbackQuery(query.id, { text: 'Tipo non supportato' });
|
||||
return;
|
||||
}
|
||||
|
||||
startSession(bot, chatId, botMessageId, userMessageId, getTextFn);
|
||||
bot.answerCallbackQuery(query.id, { text: 'Live avviato' });
|
||||
},
|
||||
textGenerators
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user