Aggiunto collegamento al server

This commit is contained in:
Giuseppe Raffa
2026-03-11 15:25:03 +01:00
parent c37f30e4ea
commit 41f33ce181
51 changed files with 3088 additions and 4414 deletions

56
plugin/routes/dataset.js Normal file
View File

@@ -0,0 +1,56 @@
/**
* Registers dataset recording control routes.
* @param {Object} router - Route wrapper with get/post methods
* @param {Object} app - SignalK app instance
*/
function registerDatasetRoutes(router, app) {
router.post("/dataset/start", (req, res) => {
try {
if (!app.datasetControl) {
return res.status(503).json({ error: "Dataset control not available" });
}
const result = app.datasetControl.start();
res.json({ success: result, message: result ? "Recording started" : "Already recording" });
} catch (e) {
res.status(500).json({ error: e.message });
}
});
router.post("/dataset/stop", (req, res) => {
try {
if (!app.datasetControl) {
return res.status(503).json({ error: "Dataset control not available" });
}
const result = app.datasetControl.stop();
res.json({ success: result, message: result ? "Recording stopped" : "No active recording" });
} catch (e) {
res.status(500).json({ error: e.message });
}
});
router.post("/dataset/restart", (req, res) => {
try {
if (!app.datasetControl) {
return res.status(503).json({ error: "Dataset control not available" });
}
const result = app.datasetControl.restart();
res.json({ success: result, message: "Recording restarted" });
} catch (e) {
res.status(500).json({ error: e.message });
}
});
router.get("/dataset/status", (req, res) => {
try {
if (!app.datasetControl) {
return res.status(503).json({ error: "Dataset control not available" });
}
const status = app.datasetControl.getStatus();
res.json(status);
} catch (e) {
res.status(500).json({ error: e.message });
}
});
}
module.exports = registerDatasetRoutes;

View File

@@ -0,0 +1,63 @@
const { getForecast, getSeaConditions } = require("../api_models/openmeteo.js");
/**
* Registers forecast-related routes.
* @param {Object} router - Route wrapper with get/post methods
* @param {Object} app - SignalK app instance
*/
function registerForecastRoutes(router, app) {
// Get current forecast data directly from OpenMeteo
router.get("/forecasts/data", async (req, res) => {
try {
const position = app.getSelfPath('navigation.position')?.value;
if (!position?.latitude || !position?.longitude) {
return res.status(503).json({ error: "Position not available" });
}
const mode = req.query.mode || 'both';
const [forecastData, wavesData] = await Promise.all([
getForecast(position, { mode }),
getSeaConditions(position, { mode })
]);
res.status(200).json({
forecast: forecastData,
sea: wavesData
});
} catch (error) {
console.error('[MEB] Error in /meb/forecasts/data:', error);
res.status(500).json({ error: error.message });
}
});
// Force update: fetch fresh hourly data from OpenMeteo
router.post("/forecasts/update", async (req, res) => {
try {
const position = app.getSelfPath('navigation.position')?.value;
if (!position?.latitude || !position?.longitude) {
return res.status(503).json({ error: "Position not available" });
}
const [forecastData, wavesData] = await Promise.all([
getForecast(position, { mode: 'both' }),
getSeaConditions(position, { mode: 'both' })
]);
if (!forecastData?.hourly || !wavesData?.hourly) {
return res.status(500).json({ error: "Hourly data not available from API" });
}
res.status(200).json({
forecast: forecastData,
sea: wavesData
});
} catch (error) {
console.error('[MEB] Error in /meb/forecasts/update:', error);
res.status(500).json({ error: error.message });
}
});
}
module.exports = registerForecastRoutes;

30
plugin/routes/helm.js Normal file
View File

@@ -0,0 +1,30 @@
const path = require("path");
const websPath = path.join(__dirname, "..", "public");
/**
* Registers helm/steering support routes.
* @param {Object} router - Route wrapper with get/post methods
*/
function registerHelmRoutes(router) {
router.get("/helm", (req, res) => {
try {
const side = req.query.side || "destra";
const helmPath = path.join(websPath, "steering_support", `helm_steering_${side}.html`);
res.status(200).sendFile(helmPath);
} catch (e) {
res.status(500).json({ error: e.message });
}
});
router.get("/helm/support", (req, res) => {
try {
const indexPath = path.join(websPath, "steering_support", "steering_support.html");
res.status(200).sendFile(indexPath);
} catch (error) {
res.status(500).json({ error: error.message });
}
});
}
module.exports = registerHelmRoutes;

34
plugin/routes/index.js Normal file
View File

@@ -0,0 +1,34 @@
const registerMapRoutes = require("./map");
const registerHelmRoutes = require("./helm");
const registerDatasetRoutes = require("./dataset");
const registerForecastRoutes = require("./forecasts");
const registerTelegramRoutes = require("./telegram");
/**
* Registers all plugin routes under the /meb prefix.
* @param {Object} app - SignalK app instance
* @param {Object} settings - Plugin settings
*/
module.exports = function (app, settings) {
const router = {
get: (subPath, handler) => {
const fullPath = '/meb' + (subPath.startsWith('/') ? subPath : `/${subPath}`);
app.get(fullPath, handler);
},
post: (subPath, handler) => {
const fullPath = '/meb' + (subPath.startsWith('/') ? subPath : `/${subPath}`);
app.post(fullPath, handler);
}
};
// Health check
router.get("/ping", (req, res) => {
res.status(200).send("Ping is active!");
});
registerMapRoutes(router, app, settings);
registerHelmRoutes(router);
registerDatasetRoutes(router, app);
registerForecastRoutes(router, app);
registerTelegramRoutes(router);
};

43
plugin/routes/map.js Normal file
View File

@@ -0,0 +1,43 @@
const fs = require("fs");
const path = require("path");
const websPath = path.join(__dirname, "..", "public");
/**
* Registers map-related routes.
* @param {Object} router - Route wrapper with get/post methods
* @param {Object} app - SignalK app instance
* @param {Object} settings - Plugin settings
*/
function registerMapRoutes(router, app, settings) {
// Serve interactive map with Mapbox token injected
router.get('/map', (req, res) => {
const filePath = path.join(websPath, "map.html");
fs.readFile(filePath, "utf8", (err, html) => {
if (err) {
res.status(500).send("Error loading map");
return;
}
const token = settings?.mapboxKey ?? "";
const finalHtml = html.replace("{{MAPBOX_KEY}}", token);
res.setHeader("Content-Type", "text/html; charset=utf-8");
res.send(finalHtml);
});
});
// Stream boat position and serve latest via API
let lastPosition = null;
app.streambundle.getSelfStream("navigation.position").onValue(pos => {
lastPosition = pos;
});
router.get('/map/boat', (req, res) => {
if (!lastPosition) {
return res.json({ error: "No position data available" });
}
res.json(lastPosition);
});
}
module.exports = registerMapRoutes;

13
plugin/routes/telegram.js Normal file
View File

@@ -0,0 +1,13 @@
const { reloadBot } = require("../telegram/telegram.core.js");
module.exports = function (router) {
router.post("/telegram/reload", (req, res) => {
try {
reloadBot();
res.status(200).json({ status: "success", message: "Bot ricaricato." });
} catch (error) {
console.error("[MEB] Errore nel ricaricamento del bot da API:", error);
res.status(500).json({ status: "error", message: "Errore durante il reload del bot." });
}
});
};