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:
29
plugin/telegram/callbacks/backupback.js
Normal file
29
plugin/telegram/callbacks/backupback.js
Normal file
@@ -0,0 +1,29 @@
|
||||
const { listDataFiles, buildPage } = require('../commands/backuplogs');
|
||||
|
||||
module.exports = {
|
||||
prefix: 'bkback:',
|
||||
handler: async (bot, query) => {
|
||||
const chatId = query.message.chat.id;
|
||||
const botMessageId = query.message.message_id;
|
||||
|
||||
const parts = query.data.split(':');
|
||||
const page = parseInt(parts[1]);
|
||||
const userMessageId = parts[2];
|
||||
|
||||
const files = await listDataFiles();
|
||||
const keyboard = buildPage(files, page, userMessageId);
|
||||
|
||||
const text = `*Backup & Logs*\n\n${files.length} file disponibili nella cartella data.\n_Seleziona un file per info e download._`;
|
||||
|
||||
try {
|
||||
await bot.editMessageText(text, {
|
||||
chat_id: chatId,
|
||||
message_id: botMessageId,
|
||||
parse_mode: 'Markdown',
|
||||
reply_markup: { inline_keyboard: keyboard }
|
||||
});
|
||||
} catch (e) {}
|
||||
|
||||
bot.answerCallbackQuery(query.id);
|
||||
}
|
||||
};
|
||||
33
plugin/telegram/callbacks/backupdownload.js
Normal file
33
plugin/telegram/callbacks/backupdownload.js
Normal file
@@ -0,0 +1,33 @@
|
||||
const fs = require('fs');
|
||||
const { listDataFiles } = require('../commands/backuplogs');
|
||||
|
||||
module.exports = {
|
||||
prefix: 'bkdl:',
|
||||
handler: async (bot, query) => {
|
||||
const chatId = query.message.chat.id;
|
||||
|
||||
const parts = query.data.split(':');
|
||||
const fileIdx = parseInt(parts[1]);
|
||||
const userMessageId = parts[2];
|
||||
|
||||
const files = await listDataFiles();
|
||||
const file = files[fileIdx];
|
||||
|
||||
if (!file || !fs.existsSync(file.path)) {
|
||||
bot.answerCallbackQuery(query.id, { text: 'File non trovato', show_alert: true });
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await bot.sendDocument(chatId, file.path, {
|
||||
caption: `\`${file.name}\``,
|
||||
parse_mode: 'Markdown'
|
||||
});
|
||||
} catch (e) {
|
||||
bot.answerCallbackQuery(query.id, { text: 'Errore invio file', show_alert: true });
|
||||
return;
|
||||
}
|
||||
|
||||
bot.answerCallbackQuery(query.id, { text: 'File inviato' });
|
||||
}
|
||||
};
|
||||
73
plugin/telegram/callbacks/backupfile.js
Normal file
73
plugin/telegram/callbacks/backupfile.js
Normal file
@@ -0,0 +1,73 @@
|
||||
const fs = require('fs');
|
||||
const fsPromises = require('fs').promises;
|
||||
const readline = require('readline');
|
||||
const { listDataFiles, formatSize, buildPage } = require('../commands/backuplogs');
|
||||
|
||||
/**
|
||||
* Conta le righe di un file in modo efficiente (stream)
|
||||
*/
|
||||
function countLines(filePath) {
|
||||
return new Promise((resolve) => {
|
||||
let count = 0;
|
||||
const stream = fs.createReadStream(filePath);
|
||||
const rl = readline.createInterface({ input: stream, crlfDelay: Infinity });
|
||||
rl.on('line', () => count++);
|
||||
rl.on('close', () => resolve(count));
|
||||
rl.on('error', () => resolve(-1));
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
prefix: 'bkfile:',
|
||||
handler: async (bot, query) => {
|
||||
const chatId = query.message.chat.id;
|
||||
const botMessageId = query.message.message_id;
|
||||
|
||||
const parts = query.data.split(':');
|
||||
const fileIdx = parseInt(parts[1]);
|
||||
const userMessageId = parts[2];
|
||||
|
||||
const files = await listDataFiles();
|
||||
const file = files[fileIdx];
|
||||
|
||||
if (!file || !fs.existsSync(file.path)) {
|
||||
bot.answerCallbackQuery(query.id, { text: 'File non trovato', show_alert: true });
|
||||
return;
|
||||
}
|
||||
|
||||
// Conta righe
|
||||
let lineCount = '—';
|
||||
try {
|
||||
const ext = file.name.split('.').pop().toLowerCase();
|
||||
if (['csv', 'txt', 'log', 'json'].includes(ext)) {
|
||||
lineCount = await countLines(file.path);
|
||||
}
|
||||
} catch (e) {}
|
||||
|
||||
const modified = new Date(file.modified).toLocaleDateString('it-IT', {
|
||||
day: '2-digit', month: 'long', year: 'numeric',
|
||||
hour: '2-digit', minute: '2-digit'
|
||||
});
|
||||
|
||||
const text = `*File:* \`${file.name}\`\n\n` +
|
||||
`*Dimensione:* ${formatSize(file.size)}\n` +
|
||||
`*Ultima modifica:* ${modified}\n` +
|
||||
`*Righe:* ${lineCount}\n`;
|
||||
|
||||
const keyboard = [
|
||||
[{ text: 'Scarica file', callback_data: `bkdl:${fileIdx}:${userMessageId}` }],
|
||||
[{ text: '<- Torna alla lista', callback_data: `bkback:0:${userMessageId}` }]
|
||||
];
|
||||
|
||||
try {
|
||||
await bot.editMessageText(text, {
|
||||
chat_id: chatId,
|
||||
message_id: botMessageId,
|
||||
parse_mode: 'Markdown',
|
||||
reply_markup: { inline_keyboard: keyboard }
|
||||
});
|
||||
} catch (e) {}
|
||||
|
||||
bot.answerCallbackQuery(query.id);
|
||||
}
|
||||
};
|
||||
6
plugin/telegram/callbacks/backupnoop.js
Normal file
6
plugin/telegram/callbacks/backupnoop.js
Normal file
@@ -0,0 +1,6 @@
|
||||
module.exports = {
|
||||
prefix: 'bknoop:',
|
||||
handler: async (bot, query) => {
|
||||
bot.answerCallbackQuery(query.id);
|
||||
}
|
||||
};
|
||||
29
plugin/telegram/callbacks/backuppage.js
Normal file
29
plugin/telegram/callbacks/backuppage.js
Normal file
@@ -0,0 +1,29 @@
|
||||
const { listDataFiles, buildPage } = require('../commands/backuplogs');
|
||||
|
||||
module.exports = {
|
||||
prefix: 'bkpage:',
|
||||
handler: async (bot, query) => {
|
||||
const chatId = query.message.chat.id;
|
||||
const botMessageId = query.message.message_id;
|
||||
|
||||
const parts = query.data.split(':');
|
||||
const page = parseInt(parts[1]);
|
||||
const userMessageId = parts[2];
|
||||
|
||||
const files = await listDataFiles();
|
||||
const keyboard = buildPage(files, page, userMessageId);
|
||||
|
||||
const text = `*Backup & Logs*\n\n${files.length} file disponibili nella cartella data.\n_Seleziona un file per info e download._`;
|
||||
|
||||
try {
|
||||
await bot.editMessageText(text, {
|
||||
chat_id: chatId,
|
||||
message_id: botMessageId,
|
||||
parse_mode: 'Markdown',
|
||||
reply_markup: { inline_keyboard: keyboard }
|
||||
});
|
||||
} catch (e) {}
|
||||
|
||||
bot.answerCallbackQuery(query.id);
|
||||
}
|
||||
};
|
||||
25
plugin/telegram/callbacks/close.js
Normal file
25
plugin/telegram/callbacks/close.js
Normal file
@@ -0,0 +1,25 @@
|
||||
module.exports = {
|
||||
prefix: 'close',
|
||||
handler: async (bot, query) => {
|
||||
const chatId = query.message.chat.id;
|
||||
const botMessageId = query.message.message_id;
|
||||
|
||||
// L'ID del messaggio dell'utente è passato nel callback_data (close:<userMsgId>)
|
||||
const userMessageId = query.data.split(':')[1];
|
||||
|
||||
try {
|
||||
// Elimina il messaggio del bot
|
||||
await bot.deleteMessage(chatId, botMessageId);
|
||||
|
||||
// Elimina il messaggio dell'utente (il comando /data)
|
||||
if (userMessageId) {
|
||||
await bot.deleteMessage(chatId, parseInt(userMessageId));
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('[TELEGRAM] Errore eliminazione messaggi:', error.message);
|
||||
}
|
||||
|
||||
// Rispondi alla callback per togliere il "loading" dal bottone
|
||||
bot.answerCallbackQuery(query.id);
|
||||
}
|
||||
};
|
||||
@@ -1,152 +0,0 @@
|
||||
// Mappa globale per salvare gli interval id anche dopo un "hot-reload"
|
||||
if (!global.__meb_live_dashboards) {
|
||||
global.__meb_live_dashboards = new Map();
|
||||
}
|
||||
|
||||
module.exports = [
|
||||
{
|
||||
id: 'dashboard-refresh',
|
||||
execute: async ({ bot, chatId, msg }) => {
|
||||
const dash = require('../commands/dashboard.js');
|
||||
const newText = dash.formatSensorData();
|
||||
|
||||
try {
|
||||
await bot.editMessageText(newText, {
|
||||
chat_id: chatId,
|
||||
message_id: msg.message_id,
|
||||
parse_mode: 'Markdown',
|
||||
reply_markup: {
|
||||
inline_keyboard: [
|
||||
[
|
||||
{ text: "⚡️ Avvia Live Tracker (2s)", callback_data: 'dashboard-live-start' }
|
||||
],
|
||||
[
|
||||
{ text: "🔄 Ricarica Dati", callback_data: 'dashboard-refresh' }
|
||||
]
|
||||
]
|
||||
}
|
||||
});
|
||||
} catch (e) {
|
||||
if (!e.message.includes('message is not modified')) {
|
||||
console.error("Errore nel refresh dashboard:", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 'dashboard-live-start',
|
||||
execute: async ({ bot, chatId, msg }) => {
|
||||
const dash = require('../commands/dashboard.js');
|
||||
|
||||
const messageId = msg.message_id;
|
||||
const liveKey = `${chatId}_${messageId}`;
|
||||
|
||||
// Se è già attivo un live per questo messaggio, non fare nulla
|
||||
if (global.__meb_live_dashboards.has(liveKey)) return;
|
||||
|
||||
// Avvisa che sta partendo
|
||||
const startMarkup = {
|
||||
inline_keyboard: [
|
||||
[
|
||||
{ text: "🛑 Ferma Live Tracker", callback_data: 'dashboard-live-stop' }
|
||||
]
|
||||
]
|
||||
};
|
||||
|
||||
await bot.editMessageReplyMarkup(startMarkup, { chat_id: chatId, message_id: messageId });
|
||||
|
||||
// Inizializza l'interval a 2 secondi. Autodistruzione dopo 30s
|
||||
let count = 15; // 15 tick da 2 secondi = 30 secondi
|
||||
const intervalTimer = setInterval(async () => {
|
||||
count--;
|
||||
const baseText = dash.formatSensorData();
|
||||
|
||||
// Se il tempo scade, disattiva il live e ripristina i tasti normali
|
||||
if (count <= 0) {
|
||||
if (global.__meb_live_dashboards.has(liveKey)) {
|
||||
clearInterval(global.__meb_live_dashboards.get(liveKey));
|
||||
global.__meb_live_dashboards.delete(liveKey);
|
||||
}
|
||||
try {
|
||||
await bot.editMessageText(baseText + `\n🛑 _Live tracker terminato automaticamente (30s) per risparmiare risorse._`, {
|
||||
chat_id: chatId,
|
||||
message_id: messageId,
|
||||
parse_mode: 'Markdown',
|
||||
reply_markup: {
|
||||
inline_keyboard: [
|
||||
[{ text: "⚡️ Avvia Live Tracker (2s)", callback_data: 'dashboard-live-start' }],
|
||||
[{ text: "🔄 Ricarica Dati", callback_data: 'dashboard-refresh' }]
|
||||
]
|
||||
}
|
||||
});
|
||||
} catch (e) { }
|
||||
return;
|
||||
}
|
||||
|
||||
// Altrimenti prosegui con l'aggiornamento e la stringa del countdown
|
||||
const newText = baseText + `\n⏳ _Live attivo: arresto automatico tra *${count * 2}s*_`;
|
||||
|
||||
try {
|
||||
await bot.editMessageText(newText, {
|
||||
chat_id: chatId,
|
||||
message_id: messageId,
|
||||
parse_mode: 'Markdown',
|
||||
reply_markup: startMarkup
|
||||
});
|
||||
} catch (e) {
|
||||
// API limits o the message was not modified
|
||||
if (e.response && e.response.statusCode === 400 && e.message.includes("message is not modified")) {
|
||||
// ignore
|
||||
} else if (e.response && e.response.statusCode === 429) {
|
||||
// Troppe richieste Telegram
|
||||
console.warn("[Telegram Dashboard] Rate Limit raggionto. Riprovo più tardi...");
|
||||
} else if (e.response && e.response.statusCode === 400 && e.message.includes("message to edit not found")) {
|
||||
// Il messaggio è stato cancellato dall'utente
|
||||
clearInterval(intervalTimer);
|
||||
global.__meb_live_dashboards.delete(liveKey);
|
||||
} else {
|
||||
console.error("[Telegram Dashboard] Errore update live:", e);
|
||||
}
|
||||
}
|
||||
}, 2000);
|
||||
|
||||
global.__meb_live_dashboards.set(liveKey, intervalTimer);
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 'dashboard-live-stop',
|
||||
execute: async ({ bot, chatId, msg }) => {
|
||||
const dash = require('../commands/dashboard.js');
|
||||
|
||||
const messageId = msg.message_id;
|
||||
const liveKey = `${chatId}_${messageId}`;
|
||||
|
||||
// Pulisci l'interval se esiste
|
||||
if (global.__meb_live_dashboards.has(liveKey)) {
|
||||
clearInterval(global.__meb_live_dashboards.get(liveKey));
|
||||
global.__meb_live_dashboards.delete(liveKey);
|
||||
}
|
||||
|
||||
// Ripristina la formattazione iniziale
|
||||
const newText = dash.formatSensorData();
|
||||
|
||||
try {
|
||||
await bot.editMessageText(newText, {
|
||||
chat_id: chatId,
|
||||
message_id: messageId,
|
||||
parse_mode: 'Markdown',
|
||||
reply_markup: {
|
||||
inline_keyboard: [
|
||||
[
|
||||
{ text: "⚡️ Avvia Live Tracker (2s)", callback_data: 'dashboard-live-start' }
|
||||
],
|
||||
[
|
||||
{ text: "🔄 Ricarica Dati", callback_data: 'dashboard-refresh' }
|
||||
]
|
||||
]
|
||||
}
|
||||
});
|
||||
} catch (e) { }
|
||||
}
|
||||
}
|
||||
];
|
||||
@@ -1,26 +0,0 @@
|
||||
module.exports = [
|
||||
{
|
||||
id: 'data-refresh',
|
||||
execute: async ({ bot, chatId, msg }) => {
|
||||
const dataCmd = require('../commands/data.js');
|
||||
const newText = dataCmd.formatSensorData();
|
||||
|
||||
try {
|
||||
await bot.editMessageText(newText, {
|
||||
chat_id: chatId,
|
||||
message_id: msg.message_id,
|
||||
parse_mode: 'Markdown',
|
||||
reply_markup: {
|
||||
inline_keyboard: [
|
||||
[{ text: 'Aggiorna', callback_data: 'data-refresh' }]
|
||||
]
|
||||
}
|
||||
});
|
||||
} catch (e) {
|
||||
if (!e.message.includes('message is not modified')) {
|
||||
console.error('[Telegram Data] Errore refresh:', e.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
];
|
||||
@@ -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
|
||||
};
|
||||
|
||||
15
plugin/telegram/callbacks/livestop.js
Normal file
15
plugin/telegram/callbacks/livestop.js
Normal file
@@ -0,0 +1,15 @@
|
||||
const { stopSession, getSession } = require('../utility/live');
|
||||
|
||||
module.exports = {
|
||||
prefix: 'livestop',
|
||||
handler: async (bot, query) => {
|
||||
const chatId = query.message.chat.id;
|
||||
const botMessageId = query.message.message_id;
|
||||
|
||||
// callback_data = livestop:<userMessageId>
|
||||
const userMessageId = query.data.split(':')[1];
|
||||
|
||||
await stopSession(bot, chatId, botMessageId, userMessageId);
|
||||
bot.answerCallbackQuery(query.id);
|
||||
}
|
||||
};
|
||||
12
plugin/telegram/callbacks/logbusy.js
Normal file
12
plugin/telegram/callbacks/logbusy.js
Normal file
@@ -0,0 +1,12 @@
|
||||
module.exports = {
|
||||
prefix: 'logbusy:',
|
||||
handler: async (bot, query) => {
|
||||
const logName = query.data.split(':')[1];
|
||||
|
||||
// Mostra un alert all'utente che il file non si puo scaricare
|
||||
bot.answerCallbackQuery(query.id, {
|
||||
text: `La registrazione "${logName}" è in corso. Fermala per scaricare il file.`,
|
||||
show_alert: true
|
||||
});
|
||||
}
|
||||
};
|
||||
69
plugin/telegram/callbacks/logfile.js
Normal file
69
plugin/telegram/callbacks/logfile.js
Normal file
@@ -0,0 +1,69 @@
|
||||
const recorder = require('../../cores/logs.local');
|
||||
|
||||
module.exports = {
|
||||
prefix: 'logfile:',
|
||||
handler: async (bot, query) => {
|
||||
const chatId = query.message.chat.id;
|
||||
const listMessageId = query.message.message_id;
|
||||
|
||||
// callback_data = logfile:<name>:<userMessageId>
|
||||
const parts = query.data.split(':');
|
||||
const logName = parts[1];
|
||||
const userMessageId = parts[2];
|
||||
|
||||
// Elimina il messaggio con la lista dei file
|
||||
try {
|
||||
await bot.deleteMessage(chatId, listMessageId);
|
||||
} catch (e) {}
|
||||
|
||||
// Ottieni il file e le sue informazioni
|
||||
const filePath = recorder.getLogFile(logName);
|
||||
if (!filePath) {
|
||||
bot.answerCallbackQuery(query.id, { text: 'File non trovato' });
|
||||
return;
|
||||
}
|
||||
|
||||
// Controllo aggiuntivo: se il file è quello in registrazione attiva
|
||||
const session = recorder.getSession();
|
||||
if (session && session.name === logName) {
|
||||
bot.answerCallbackQuery(query.id, {
|
||||
text: `Il file "${logName}" è attualmente in uso per la registrazione attiva. Fermala per scaricarlo.`,
|
||||
show_alert: true
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Ottieni info del file
|
||||
const fs = require('fs');
|
||||
const stat = fs.statSync(filePath);
|
||||
const sizeMB = (stat.size / (1024 * 1024)).toFixed(2);
|
||||
const created = new Date(stat.birthtime).toLocaleDateString('it-IT', {
|
||||
day: '2-digit', month: '2-digit', year: 'numeric',
|
||||
hour: '2-digit', minute: '2-digit'
|
||||
});
|
||||
|
||||
const caption = `*CSV\nCreato: ${created}\ ${sizeMB} MB`;
|
||||
|
||||
// Invia il file
|
||||
const docMessage = await bot.sendDocument(chatId, filePath, {
|
||||
caption: caption,
|
||||
parse_mode: 'Markdown'
|
||||
});
|
||||
|
||||
// Elimina il messaggio dell'utente (il comando /logs)
|
||||
try {
|
||||
if (userMessageId) {
|
||||
await bot.deleteMessage(chatId, parseInt(userMessageId));
|
||||
}
|
||||
} catch (e) {}
|
||||
|
||||
// Dopo 5 secondi, elimina il messaggio con il documento
|
||||
setTimeout(async () => {
|
||||
try {
|
||||
await bot.deleteMessage(chatId, docMessage.message_id);
|
||||
} catch (e) {}
|
||||
}, 10000); //dopo 10 secondi
|
||||
|
||||
bot.answerCallbackQuery(query.id);
|
||||
}
|
||||
};
|
||||
@@ -1,51 +0,0 @@
|
||||
const realtime = require('../../realtime/core.js');
|
||||
const { config } = require('../../config.js');
|
||||
|
||||
module.exports = [
|
||||
{
|
||||
id: 'logs-refresh',
|
||||
execute: async ({ bot, chatId, msg }) => {
|
||||
const stats = realtime.getStats();
|
||||
const consoleUrl = config.cloudUrl || 'https://console.mebboat.it';
|
||||
|
||||
let statusIcon = '🔴';
|
||||
if (stats.status === 'connected') statusIcon = '🟢';
|
||||
else if (stats.status === 'error') statusIcon = '🟡';
|
||||
|
||||
const now = new Date().toLocaleTimeString('it-IT');
|
||||
let text = `📊 *Registrazione Dati Realtime*\n\n`;
|
||||
text += `Stato: ${statusIcon} *${stats.status}*\n`;
|
||||
text += `Sensore: \`${stats.sensorID}\`\n`;
|
||||
text += `Messaggi inviati: *${stats.sent}*\n`;
|
||||
text += `Frequenza: ogni *${stats.sentEveryMLS / 1000}s*\n`;
|
||||
|
||||
if (stats.buffered > 0) {
|
||||
text += `⚠️ Messaggi in buffer: *${stats.buffered}*\n`;
|
||||
}
|
||||
|
||||
if (stats.reconnections > 0) {
|
||||
text += `Riconnessioni: ${stats.reconnections}\n`;
|
||||
}
|
||||
|
||||
text += `\n_(Aggiornato: ${now})_`;
|
||||
|
||||
try {
|
||||
await bot.editMessageText(text, {
|
||||
chat_id: chatId,
|
||||
message_id: msg.message_id,
|
||||
parse_mode: 'Markdown',
|
||||
reply_markup: {
|
||||
inline_keyboard: [
|
||||
[{ text: '📈 Apri Console Log', url: `${consoleUrl}/logs` }],
|
||||
[{ text: '🔄 Aggiorna Stato', callback_data: 'logs-refresh' }]
|
||||
]
|
||||
}
|
||||
});
|
||||
} catch (e) {
|
||||
if (!e.message.includes('message is not modified')) {
|
||||
console.error("[Telegram] Errore refresh logs:", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
];
|
||||
@@ -1,80 +0,0 @@
|
||||
module.exports = [
|
||||
{
|
||||
id: 'set-meteo',
|
||||
execute: async ({ bot, chatId, app }) => {
|
||||
const config = app.mebConfig;
|
||||
const currentFreqMin = config.forecast_current_frequency / 60000;
|
||||
const hourlyFreqMin = config.forecast_hourly_frequency / 60000;
|
||||
|
||||
const msg = `*Configura Aggiornamenti Meteo*\n\n` +
|
||||
`Aggiorno il meteo (attuale) ogni *${currentFreqMin} minuti*\n` +
|
||||
`Registro le previsioni future (prossimi 7 giorni) ogni *${hourlyFreqMin} minuti*`;
|
||||
|
||||
await bot.sendMessage(chatId, msg, {
|
||||
parse_mode: 'Markdown',
|
||||
reply_markup: {
|
||||
inline_keyboard: [
|
||||
[
|
||||
{ text: "1 sec", callback_data: 'set-meteo-curr-1' },
|
||||
{ text: "10 sec", callback_data: 'set-meteo-curr-10' },
|
||||
],
|
||||
[
|
||||
{ text: "1 min", callback_data: 'set-meteo-curr-60' },
|
||||
{ text: "10 min", callback_data: 'set-meteo-curr-600' }
|
||||
],
|
||||
[
|
||||
{ text: "30m", callback_data: 'set-meteo-hour-1800' }
|
||||
],
|
||||
[
|
||||
{ text: "⬅️ Indietro", callback_data: 'session-refresh' }
|
||||
]
|
||||
]
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
{
|
||||
match: (data) => data.startsWith('set-meteo-curr-'),
|
||||
execute: async ({ bot, chatId, app, data, msg }) => {
|
||||
const val = parseInt(data.replace('set-meteo-curr-', ''), 10);
|
||||
if (app.mebPlugin && app.mebPlugin.setConfig) {
|
||||
app.mebPlugin.setConfig('forecast_current_frequency', val);
|
||||
await bot.editMessageText(`✅ Frequenza Aggiornamenti meteo aggiornata a *${val / 60} minuti*.\n_Ritorno al menu..._`, {
|
||||
chat_id: chatId,
|
||||
message_id: msg.message_id,
|
||||
parse_mode: 'Markdown'
|
||||
});
|
||||
setTimeout(() => {
|
||||
const sessionCmd = require('../commands/status.js');
|
||||
bot.editMessageText("*Servizi*\n\n", {
|
||||
chat_id: chatId, message_id: msg.message_id, parse_mode: 'Markdown', reply_markup: sessionCmd.createSessionMenu(app).reply_markup
|
||||
}).catch(() => { });
|
||||
}, 3000);
|
||||
} else {
|
||||
await bot.sendMessage(chatId, "Errore: il plugin non è accessibile per salvare la configurazione.");
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
match: (data) => data.startsWith('set-meteo-hour-'),
|
||||
execute: async ({ bot, chatId, app, data, msg }) => {
|
||||
const val = parseInt(data.replace('set-meteo-hour-', ''), 10);
|
||||
if (app.mebPlugin && app.mebPlugin.setConfig) {
|
||||
app.mebPlugin.setConfig('forecast_hourly_frequency', val);
|
||||
await bot.editMessageText(`✅ Frequenza previsioni future aggiornata a *${val / 60} minuti*.\n_Ritorno al menu..._`, {
|
||||
chat_id: chatId,
|
||||
message_id: msg.message_id,
|
||||
parse_mode: 'Markdown'
|
||||
});
|
||||
setTimeout(() => {
|
||||
const sessionCmd = require('../commands/status.js');
|
||||
bot.editMessageText("*Servizi*\n\n", {
|
||||
chat_id: chatId, message_id: msg.message_id, parse_mode: 'Markdown', reply_markup: sessionCmd.createSessionMenu(app).reply_markup
|
||||
}).catch(() => { });
|
||||
}, 3000);
|
||||
} else {
|
||||
await bot.sendMessage(chatId, "Errore: il plugin non è accessibile per salvare la configurazione.");
|
||||
}
|
||||
}
|
||||
}
|
||||
];
|
||||
@@ -1,67 +0,0 @@
|
||||
const realtime = require('../../realtime/core.js');
|
||||
|
||||
module.exports = [
|
||||
{
|
||||
id: 'session-weather-toggle',
|
||||
execute: async ({ bot, chatId, app, msg }) => {
|
||||
if (!app.mebPlugin) {
|
||||
return bot.answerCallbackQuery(msg.id, { text: "Errore: Plugin Meteo non caricato" });
|
||||
}
|
||||
|
||||
let isActive = app.mebPlugin.isPollingActive();
|
||||
|
||||
if (isActive) {
|
||||
app.mebPlugin.stopPolling();
|
||||
} else {
|
||||
app.mebPlugin.startPolling();
|
||||
}
|
||||
|
||||
const sessionCmd = require('../commands/status.js');
|
||||
const newMarkup = sessionCmd.createSessionMenu(app);
|
||||
|
||||
await bot.editMessageReplyMarkup(newMarkup.reply_markup, {
|
||||
chat_id: chatId,
|
||||
message_id: msg.message_id
|
||||
});
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 'session-realtime-info',
|
||||
execute: async ({ bot, chatId, msg }) => {
|
||||
const stats = realtime.getStats();
|
||||
|
||||
let text = `📡 *Stato Realtime*\n\n`;
|
||||
text += `Stato: *${stats.status}*\n`;
|
||||
text += `Sensore: \`${stats.sensorID}\`\n`;
|
||||
text += `Messaggi inviati: *${stats.sent}*\n`;
|
||||
text += `Buffer: ${stats.buffered} msg\n`;
|
||||
text += `Riconnessioni: ${stats.reconnections}\n`;
|
||||
text += `\n_I dati vengono inviati automaticamente ogni ${stats.sentEveryMLS / 1000}s_`;
|
||||
|
||||
await bot.answerCallbackQuery(msg.id, { text: `Realtime: ${stats.status} | ${stats.sent} msg inviati` });
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 'session-refresh',
|
||||
execute: async ({ bot, chatId, app, msg }) => {
|
||||
const sessionCmd = require('../commands/status.js');
|
||||
const newMarkup = sessionCmd.createSessionMenu(app);
|
||||
|
||||
const now = new Date().toLocaleTimeString('it-IT');
|
||||
const newText = `*Servizi*\n\n_(Ultimo aggiornamento: ${now})_`;
|
||||
|
||||
try {
|
||||
await bot.editMessageText(newText, {
|
||||
chat_id: chatId,
|
||||
message_id: msg.message_id,
|
||||
parse_mode: 'Markdown',
|
||||
reply_markup: newMarkup.reply_markup
|
||||
});
|
||||
} catch (e) {
|
||||
if (!e.message.includes('message is not modified')) {
|
||||
console.error("Errore nel refresh session:", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
];
|
||||
@@ -1,26 +0,0 @@
|
||||
module.exports = [
|
||||
{
|
||||
id: 'weather-refresh',
|
||||
execute: async ({ bot, chatId, msg }) => {
|
||||
const weather = require('../commands/weather.js');
|
||||
const newText = weather.formatWeatherData();
|
||||
|
||||
try {
|
||||
await bot.editMessageText(newText, {
|
||||
chat_id: chatId,
|
||||
message_id: msg.message_id,
|
||||
parse_mode: 'Markdown',
|
||||
reply_markup: {
|
||||
inline_keyboard: [
|
||||
[{ text: 'Aggiorna', callback_data: 'weather-refresh' }]
|
||||
]
|
||||
}
|
||||
});
|
||||
} catch (e) {
|
||||
if (!e.message.includes('message is not modified')) {
|
||||
console.error('[Telegram Weather] Errore refresh:', e.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
];
|
||||
Reference in New Issue
Block a user