@sailingrotevista/rotevista-dash 7.0.37 → 7.0.38
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/app.js +43 -18
- package/index.js +24 -15
- package/package.json +1 -1
package/app.js
CHANGED
|
@@ -53,6 +53,7 @@ let rotationTrend = 0, meteoTrend = 0;
|
|
|
53
53
|
let lastShortAvgVal = null, lastInstantTwa = null;
|
|
54
54
|
let lastTrendTime = Date.now(), lastGybeAlarmTime = 0, lastTWCompute = 0;
|
|
55
55
|
let twDirty = false, isNavigating = false, reconnectDelay = 1000;
|
|
56
|
+
let lastMessageReceivedTime = Date.now(); // Watchdog anti-zombie per monitorare il flusso dati reale
|
|
56
57
|
|
|
57
58
|
let pressTimer, isFocusActive = false;
|
|
58
59
|
|
|
@@ -665,10 +666,17 @@ function startDisplayLoop() {
|
|
|
665
666
|
// --- CALCOLO TREND VENTO & ALLARME STRAMBATA ---
|
|
666
667
|
updateWindTrend();
|
|
667
668
|
|
|
668
|
-
// --- AGGIORNAMENTO STATUS CON
|
|
669
|
+
// --- AGGIORNAMENTO STATUS CON WATCHDOG ANTI-ZOMBIE ---
|
|
669
670
|
const isSocketOpen = socket && socket.readyState === WebSocket.OPEN;
|
|
671
|
+
const isDataFlowing = (now - lastMessageReceivedTime) < 6000; // Flusso dati attivo negli ultimi 6s
|
|
670
672
|
|
|
671
|
-
|
|
673
|
+
// Se il socket risulta aperto ma non riceve pacchetti da > 6s (connessione zombie congelata da Android)
|
|
674
|
+
if (isSocketOpen && !isDataFlowing && !document.hidden && !simulationMode) {
|
|
675
|
+
console.warn("🔌 [Watchdog] Rilevato socket zombie (0 byte ricevuti da 6s). Forzo riconnessione...");
|
|
676
|
+
connect();
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
if (isSocketOpen && isDataFlowing) {
|
|
672
680
|
ui.status.className = "online"; // Colore Verde
|
|
673
681
|
const viewportMinutes = CONFIG.graphs.historyMinutes * (isNavigating ? 1 : 2);
|
|
674
682
|
const requiredMs = viewportMinutes * 60000;
|
|
@@ -687,7 +695,7 @@ function startDisplayLoop() {
|
|
|
687
695
|
}
|
|
688
696
|
} else {
|
|
689
697
|
ui.status.className = "offline"; // Colore Rosso
|
|
690
|
-
ui.status.innerText = "
|
|
698
|
+
ui.status.innerText = isSocketOpen ? "STALL (RECONNECTING...)" : "OFFLINE";
|
|
691
699
|
}
|
|
692
700
|
|
|
693
701
|
// --- WATCHDOG: CONTROLLO TIMEOUT ---
|
|
@@ -1266,6 +1274,17 @@ function startDynamicSimulation() {
|
|
|
1266
1274
|
|
|
1267
1275
|
function connect() {
|
|
1268
1276
|
if (simulationMode) return;
|
|
1277
|
+
|
|
1278
|
+
// Pulizia preventiva del vecchio socket orfano (elimina memory leak ed eventi doppi)
|
|
1279
|
+
if (socket) {
|
|
1280
|
+
socket.onopen = null;
|
|
1281
|
+
socket.onmessage = null;
|
|
1282
|
+
socket.onerror = null;
|
|
1283
|
+
socket.onclose = null;
|
|
1284
|
+
try { socket.close(); } catch(e) {}
|
|
1285
|
+
socket = null;
|
|
1286
|
+
}
|
|
1287
|
+
|
|
1269
1288
|
let addr = window.location.host || CONFIG.server.fallbackIp;
|
|
1270
1289
|
try {
|
|
1271
1290
|
// Connessione con subscribe=none per impedire a Signal K l'invio automatico di tutto lo stream di bordo
|
|
@@ -1275,6 +1294,7 @@ function connect() {
|
|
|
1275
1294
|
ui.status.className = "online";
|
|
1276
1295
|
ui.status.innerText = "ONLINE";
|
|
1277
1296
|
reconnectDelay = 1000;
|
|
1297
|
+
lastMessageReceivedTime = Date.now(); // Reset timestamp dati
|
|
1278
1298
|
|
|
1279
1299
|
// Sottoscrizione selettiva bilanciata: applichiamo un filtro a 3 Hz (333ms) per i dati rapidi,
|
|
1280
1300
|
// garantendo fluidità matematica senza ritardi e ottimizzando profondità (1s) e GPS (10s)
|
|
@@ -1316,11 +1336,12 @@ function connect() {
|
|
|
1316
1336
|
};
|
|
1317
1337
|
|
|
1318
1338
|
socket.onmessage = (e) => {
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1339
|
+
lastMessageReceivedTime = Date.now(); // Aggiorna il battito cardiaco del flusso dati
|
|
1340
|
+
const d = JSON.parse(e.data);
|
|
1341
|
+
if (d.updates) {
|
|
1342
|
+
d.updates.forEach(u => {
|
|
1343
|
+
// Sincronizzazione dell'orologio sul tempo reale del server (NMEA/GPS)
|
|
1344
|
+
const timeMs = u.timestamp ? new Date(u.timestamp).getTime() : Date.now();
|
|
1324
1345
|
let sourceLabel = "Unknown";
|
|
1325
1346
|
if (u.$source) {
|
|
1326
1347
|
sourceLabel = u.$source;
|
|
@@ -1467,20 +1488,24 @@ async function init() {
|
|
|
1467
1488
|
}
|
|
1468
1489
|
}
|
|
1469
1490
|
|
|
1470
|
-
//
|
|
1471
|
-
|
|
1472
|
-
if (document.
|
|
1473
|
-
console.log("🔌 [Watchdog]
|
|
1474
|
-
|
|
1491
|
+
// Gestore unificato di riattivazione su Android / iOS (Visibility, Focus, Pageshow, Online)
|
|
1492
|
+
const handleWakeUp = () => {
|
|
1493
|
+
if (!document.hidden) {
|
|
1494
|
+
console.log("🔌 [Watchdog] Risveglio dispositivo / Tab attiva. Riconnessione immediata...");
|
|
1495
|
+
reconnectDelay = 1000;
|
|
1475
1496
|
connect();
|
|
1476
|
-
} else
|
|
1477
|
-
console.log("🔌 [Watchdog] Schermo bloccato / Tab in background. Chiusura
|
|
1478
|
-
// Tagliamo attivamente la connessione per congelare all'istante l'attività di rete ed i consumi del browser
|
|
1497
|
+
} else {
|
|
1498
|
+
console.log("🔌 [Watchdog] Schermo bloccato / Tab in background. Chiusura preventiva WebSocket.");
|
|
1479
1499
|
if (socket) {
|
|
1480
|
-
socket.close();
|
|
1500
|
+
try { socket.close(); } catch(e) {}
|
|
1481
1501
|
}
|
|
1482
1502
|
}
|
|
1483
|
-
}
|
|
1503
|
+
};
|
|
1504
|
+
|
|
1505
|
+
document.addEventListener('visibilitychange', handleWakeUp);
|
|
1506
|
+
window.addEventListener('pageshow', handleWakeUp);
|
|
1507
|
+
window.addEventListener('focus', handleWakeUp);
|
|
1508
|
+
window.addEventListener('online', handleWakeUp);
|
|
1484
1509
|
|
|
1485
1510
|
window.addEventListener('load', init);
|
|
1486
1511
|
window.addEventListener('pagehide', saveDashboardState);
|
package/index.js
CHANGED
|
@@ -762,13 +762,13 @@ module.exports = function (app) {
|
|
|
762
762
|
|
|
763
763
|
lastForecast30mSlot = current30mSlot; // Aggiorna preventivamente lo slot per evitare chiamate simultanee in caso di rallentamento di rete
|
|
764
764
|
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
765
|
+
const req = https.get(url, (res) => {
|
|
766
|
+
if (res.statusCode !== 200) {
|
|
767
|
+
app.error(`[Open-Meteo] HTTP Error: ${res.statusCode}`);
|
|
768
|
+
res.resume();
|
|
769
|
+
lastForecast30mSlot = 0; // Reset in caso di errore per permettere un tentativo al prossimo pacchetto GPS
|
|
770
|
+
return;
|
|
771
|
+
}
|
|
772
772
|
|
|
773
773
|
let data = '';
|
|
774
774
|
res.on('data', (chunk) => { data += chunk; });
|
|
@@ -808,15 +808,24 @@ module.exports = function (app) {
|
|
|
808
808
|
calculateInterpolatedFuture(forecastList);
|
|
809
809
|
|
|
810
810
|
} catch (err) {
|
|
811
|
-
|
|
812
|
-
|
|
811
|
+
app.error(`[Open-Meteo] Error parsing JSON: ${err.message}`);
|
|
812
|
+
lastForecast30mSlot = 0;
|
|
813
|
+
}
|
|
814
|
+
});
|
|
815
|
+
});
|
|
816
|
+
|
|
817
|
+
// Timeout di sicurezza a 8 secondi contro cadute di linea 4G/Satellite
|
|
818
|
+
req.setTimeout(8000, () => {
|
|
819
|
+
app.error('[Open-Meteo] Request Timeout (8s)');
|
|
820
|
+
req.abort();
|
|
821
|
+
lastForecast30mSlot = 0;
|
|
822
|
+
});
|
|
823
|
+
|
|
824
|
+
req.on('error', (err) => {
|
|
825
|
+
app.error(`[Open-Meteo] Network Error: ${err.message}`);
|
|
826
|
+
lastForecast30mSlot = 0;
|
|
827
|
+
});
|
|
813
828
|
}
|
|
814
|
-
});
|
|
815
|
-
}).on('error', (err) => {
|
|
816
|
-
app.error(`[Open-Meteo] Network Error: ${err.message}`);
|
|
817
|
-
lastForecast30mSlot = 0;
|
|
818
|
-
});
|
|
819
|
-
}
|
|
820
829
|
|
|
821
830
|
/**
|
|
822
831
|
* calculateInterpolatedFuture: Esegue l'interpolazione lineare e vettoriale circolare
|