@sailingrotevista/rotevista-dash 6.0.6 → 6.0.8

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.
Files changed (3) hide show
  1. package/app.js +49 -33
  2. package/index.js +12 -7
  3. package/package.json +1 -1
package/app.js CHANGED
@@ -885,10 +885,14 @@ function manageHistory(type, value) {
885
885
  const samples = Math.max(2, CONFIG.graphs.samples || 60);
886
886
  const bucketIntervalMs = (historyMinutes * 60000) / samples;
887
887
 
888
- // --- 2. INIT SICURO (Strict Check) ---
888
+ // --- 2. INIT SICURO (Sintonizzato all'epoca assoluta UTC) ---
889
889
  if (!store.graphTempBuf[type]) store.graphTempBuf[type] = [];
890
890
  if (!store.histories[type]) store.histories[type] = [];
891
- if (store.lastUpdates[type] === undefined) store.lastUpdates[type] = 0;
891
+
892
+ // SINTONIZZAZIONE DI FASE: Agganciamo il timer iniziale al multiplo UTC più vicino
893
+ if (store.lastUpdates[type] === undefined || store.lastUpdates[type] === 0) {
894
+ store.lastUpdates[type] = Math.floor(now / bucketIntervalMs) * bucketIntervalMs;
895
+ }
892
896
 
893
897
  const tempBuf = store.graphTempBuf[type];
894
898
 
@@ -956,7 +960,8 @@ function manageHistory(type, value) {
956
960
 
957
961
  // Reset per il prossimo bucket
958
962
  store.graphTempBuf[type] = [];
959
- store.lastUpdates[type] = now;
963
+ // Spostiamo il timer esattamente al confine del secchiello assoluto appena concluso
964
+ store.lastUpdates[type] = Math.floor(now / bucketIntervalMs) * bucketIntervalMs;
960
965
  }
961
966
 
962
967
  /**
@@ -1317,13 +1322,26 @@ function connect() {
1317
1322
  let addr = window.location.host || CONFIG.server.fallbackIp;
1318
1323
  try {
1319
1324
  socket = new WebSocket(`ws://${addr}/signalk/v1/stream?subscribe=self`);
1320
- socket.onopen = () => { ui.status.className = "online"; ui.status.innerText = "ONLINE"; reconnectDelay = 1000; };
1325
+
1326
+ socket.onopen = async () => {
1327
+ ui.status.className = "online";
1328
+ ui.status.innerText = "ONLINE";
1329
+ reconnectDelay = 1000;
1330
+
1331
+ // SINCRONIZZAZIONE AUTOMATICA: Ogni volta che la connessione si apre o si riapre,
1332
+ // scarichiamo lo storico fresco dal server e ridisegnamo i grafici
1333
+ try {
1334
+ await fetchServerHistory();
1335
+ ['stw', 'sog', 'depth', 'tws'].forEach(refreshGraph);
1336
+ } catch (err) {
1337
+ console.warn("⚠️ Sincronizzazione storico fallita alla connessione:", err);
1338
+ }
1339
+ };
1321
1340
 
1322
1341
  socket.onmessage = (e) => {
1323
1342
  const d = JSON.parse(e.data);
1324
1343
  if (d.updates) {
1325
1344
  d.updates.forEach(u => {
1326
- // ESTRAZIONE AVANZATA DELLA SORGENTE (Gestisce $source e stringhe native)
1327
1345
  let sourceLabel = "Unknown";
1328
1346
  if (u.$source) {
1329
1347
  sourceLabel = u.$source;
@@ -1342,8 +1360,17 @@ function connect() {
1342
1360
  }
1343
1361
  };
1344
1362
 
1345
- socket.onclose = () => { if (!simulationMode) { ui.status.className = "offline"; ui.status.innerText = "RECONNECTING..."; setTimeout(connect, reconnectDelay); reconnectDelay = Math.min(reconnectDelay * 1.5, 10000); } };
1346
- } catch (e) { setTimeout(connect, reconnectDelay); }
1363
+ socket.onclose = () => {
1364
+ if (!simulationMode) {
1365
+ ui.status.className = "offline";
1366
+ ui.status.innerText = "RECONNECTING...";
1367
+ setTimeout(connect, reconnectDelay);
1368
+ reconnectDelay = Math.min(reconnectDelay * 1.5, 10000);
1369
+ }
1370
+ };
1371
+ } catch (e) {
1372
+ setTimeout(connect, reconnectDelay);
1373
+ }
1347
1374
  }
1348
1375
 
1349
1376
  // ==========================================================================
@@ -1366,46 +1393,35 @@ window.addEventListener('contextmenu', e => e.preventDefault(), true);
1366
1393
  async function init() {
1367
1394
  loadDashboardState();
1368
1395
 
1369
- // Prova a caricare lo storico reale dal Cerbo GX tramite l'API deviata
1370
- try {
1371
- await fetchServerHistory();
1372
- } catch (err) {
1373
- console.warn("⚠️ Impossibile caricare lo storico dal server.");
1374
- }
1375
-
1396
+ // Proviamo un primo caricamento configurazioni
1376
1397
  await fetchServerConfig();
1377
1398
  startDisplayLoop();
1378
- connect(); // Si collegherà in tempo reale al WebSocket del Cerbo (usando l'IP di fallback se sei su Mac)
1399
+ connect();
1379
1400
 
1380
1401
  setInterval(watchConfigChanges, 10000);
1381
1402
 
1382
1403
  // ==========================================================================
1383
- // WATCHDOG DI RISVEGLIO (SLEEP/WAKE DETECTOR)
1404
+ // RICONNESSIONE RAPIDA AL RISVEGLIO (VISIBILITY WATCHDOG)
1384
1405
  // ==========================================================================
1385
1406
 
1386
- // Rileva quando la scheda del browser torna in primo piano (es. sblocco iPad o Mac aperto)
1407
+ // Quando sblocchi l'iPad o riapri il browser, forziamo la chiusura del vecchio
1408
+ // WebSocket orfano. Questo farà scattare immediatamente connect() e la sincronizzazione.
1387
1409
  document.addEventListener('visibilitychange', () => {
1388
1410
  if (document.visibilityState === 'visible') {
1389
- handleWakeUp();
1411
+ console.log("⏰ Schermo sbloccato: forzatura riconnessione rapida.");
1412
+ if (socket) {
1413
+ try {
1414
+ socket.close(); // Fa scattare onclose -> connect() -> onopen -> fetchServerHistory()
1415
+ } catch (e) {
1416
+ connect();
1417
+ }
1418
+ } else {
1419
+ connect();
1420
+ }
1390
1421
  }
1391
1422
  });
1392
-
1393
- // Rileva se il computer è andato in sospensione misurando il ritardo dei secondi
1394
- let lastHeartbeat = Date.now();
1395
- setInterval(() => {
1396
- const now = Date.now();
1397
- const diff = now - lastHeartbeat;
1398
- lastHeartbeat = now;
1399
-
1400
- // Se passano più di 6 secondi tra un ciclo e l'altro (invece di 1 secondo),
1401
- // significa che il PC era in sospensione. Avviamo il risveglio.
1402
- if (diff > 6000) {
1403
- handleWakeUp();
1404
- }
1405
- }, 1000);
1406
1423
  }
1407
1424
 
1408
1425
 
1409
-
1410
1426
  window.addEventListener('load', init);
1411
1427
  window.addEventListener('pagehide', saveDashboardState);
package/index.js CHANGED
@@ -153,11 +153,15 @@ module.exports = function (app) {
153
153
  const samples = 60;
154
154
  const bucketIntervalMs = (historyMinutes * 60000) / samples;
155
155
 
156
- if (!graphTempBuf[type]) graphTempBuf[type] = [];
157
- if (!histories[type]) histories[type] = [];
158
- if (lastUpdates[type] === undefined) lastUpdates[type] = 0;
156
+ if (!graphTempBuf[type]) graphTempBuf[type] = [];
157
+ if (!histories[type]) histories[type] = [];
158
+
159
+ // SINTONIZZAZIONE DI FASE LATO SERVER (UTC Snap)
160
+ if (lastUpdates[type] === undefined || lastUpdates[type] === 0) {
161
+ lastUpdates[type] = Math.floor(now / bucketIntervalMs) * bucketIntervalMs;
162
+ }
159
163
 
160
- const tempBuf = graphTempBuf[type];
164
+ const tempBuf = graphTempBuf[type];
161
165
 
162
166
  // Anti-dropout dinamico sul vento forte
163
167
  if ((type === 'tws' || type === 'aws') && value < 0.05 && tempBuf.length > 0) {
@@ -219,9 +223,10 @@ module.exports = function (app) {
219
223
  histories[type].shift();
220
224
  }
221
225
 
222
- graphTempBuf[type] = [];
223
- lastUpdates[type] = now;
224
- }
226
+ graphTempBuf[type] = [];
227
+ // Spostiamo il timer esattamente al confine del secchiello assoluto appena concluso
228
+ lastUpdates[type] = Math.floor(now / bucketIntervalMs) * bucketIntervalMs;
229
+ }
225
230
 
226
231
  /**
227
232
  * plugin.schema: Definisce l'interfaccia grafica in Signal K Admin.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sailingrotevista/rotevista-dash",
3
- "version": "6.0.6",
3
+ "version": "6.0.8",
4
4
  "description": "Wind Dashboard with navigation and course aids",
5
5
  "main": "index.js",
6
6
  "publishConfig": {