@sailingrotevista/rotevista-dash 7.0.38 → 7.0.40

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 CHANGED
@@ -77,6 +77,7 @@ const sourceLocks = {};
77
77
  const store = {
78
78
  raw: {},
79
79
  timestamps: {},
80
+ isNavigating: false, // Stato unificato di navigazione barca in movimento
80
81
  depthProtectedActive: false, // Memoria per lo stato della protezione profondità
81
82
  herculesScales: {}, // Memoria per i limiti attivi della modalità Hercules
82
83
  smoothBuf: { hdg: [], cog: [], awa: [], twa: [], twd: [] },
@@ -662,6 +663,7 @@ function startDisplayLoop() {
662
663
  const sogKts = msToKts(store.raw["navigation.speedOverGround"] || 0);
663
664
 
664
665
  isNavigating = stwKts > CONFIG.averaging.minSpeed || sogKts > CONFIG.averaging.minSpeed;
666
+ store.isNavigating = isNavigating; // Sincronizzazione stato nello store condiviso
665
667
 
666
668
  // --- CALCOLO TREND VENTO & ALLARME STRAMBATA ---
667
669
  updateWindTrend();
@@ -703,11 +705,14 @@ function startDisplayLoop() {
703
705
  "navigation.speedThroughWater": ui.stw, "navigation.speedOverGround": ui.sog,
704
706
  "navigation.headingTrue": ui.hdg, "navigation.courseOverGroundTrue": ui.cog,
705
707
  "environment.wind.speedApparent": ui.awsSvg, "environment.depth.belowTransducer": ui.depth,
706
- "environment.wind.speedTrue": ui.tws
708
+ "environment.wind.speedTrue": ui.tws,
709
+ "environment.wind.angleApparent": ui.awaAvg,
710
+ "environment.wind.angleTrueWater": ui.twaAvg,
711
+ "environment.wind.directionTrue": ui.twdAvg
707
712
  };
708
713
  for (let p in watch) {
709
714
  if (!store.timestamps[p] || (now - store.timestamps[p] > TIMEOUT_MS)) {
710
- safeSetText(watch[p], "---"); // Sostituito innerText con la funzione protetta!
715
+ if (watch[p]) safeSetText(watch[p], "---");
711
716
  delete store.raw[p];
712
717
 
713
718
  // Forza lo scorrimento dei dati fuori dallo schermo per i sensori in timeout
@@ -1032,18 +1037,7 @@ async function fetchServerHistory() {
1032
1037
  timestamp: data.futureForecast.timestamp + timeDelta
1033
1038
  };
1034
1039
  }
1035
- if (data.twd) {
1036
- store.twdMinuteBuffer = data.twd.map(p => ({
1037
- ...p,
1038
- time: p.time + timeDelta
1039
- }));
1040
- }
1041
- if (data.tws) {
1042
- store.twsMinuteBuffer = data.tws.map(p => ({
1043
- ...p,
1044
- time: p.time + timeDelta
1045
- }));
1046
- }
1040
+ // data.twd e data.tws sono già mappati direttamente in store.histories.twd e store.histories.tws
1047
1041
 
1048
1042
  // Sincronizziamo lo storico dei minuti per il radar, ma lasciamo che il buffer rapido 'store.longBuf.twd'
1049
1043
  // parta pulito all'avvio. Si popolerà istantaneamente a 3Hz con i soli dati in tempo reale,
package/charts.js CHANGED
@@ -90,29 +90,13 @@ function calculateScale(type, data, mode) {
90
90
 
91
91
  if (mode === 'hercules') {
92
92
  const roundStep = s.hercSpan;
93
+ // Finestra di calcolo ad alta risoluzione: ancorata rigorosamente all'ultimo terzo dei dati
93
94
  const oneThirdCount = Math.max(1, Math.floor(data.length / 3));
94
95
  const recentThirdData = data.slice(-oneThirdCount);
95
96
 
96
97
  let localMin = Math.min(...recentThirdData);
97
98
  let localMax = Math.max(...recentThirdData);
98
99
 
99
- // SMART MOTORING DETECTION (Specifica per i grafici di velocità: STW, SOG, VMG)
100
- const isSpeedType = (type === 'stw' || type === 'sog' || type === 'vmg');
101
- if (isSpeedType && data.length > oneThirdCount) {
102
- const olderData = data.slice(0, data.length - oneThirdCount);
103
- const olderMin = Math.min(...olderData);
104
- const olderMax = Math.max(...olderData);
105
- const olderRange = olderMax - olderMin; // Variazione nello storico passato
106
-
107
- // Se lo storico passato non era piatto (range > 0.2 nodi) oppure eravamo fermi/all'ancora (< 1.5 nodi),
108
- // significa che il passato è rilevante per il trend. Includiamo il passato nel calcolo della scala Y.
109
- // Se invece era piatto (motore), lo ignoriamo per zoomare subito sulla vela attuale.
110
- if (olderRange > 0.2 || olderMin < 0.77) {
111
- localMin = Math.min(localMin, olderMin);
112
- localMax = Math.max(localMax, olderMax);
113
- }
114
- }
115
-
116
100
  let targetMin = Math.max(0, Math.floor(localMin / roundStep) * roundStep);
117
101
  let targetMax = Math.ceil(localMax / roundStep) * roundStep;
118
102
 
package/gauge.js CHANGED
@@ -4,7 +4,7 @@
4
4
  * ==========================================================================
5
5
  * Gestisce l'aggiornamento grafico dei puntatori analogici (AWA, TWA),
6
6
  * dello scarroccio (Leeway), della rotta (Track) e dei trend della bussola.
7
- * file gauge,js
7
+ * file gauge.js
8
8
  */
9
9
 
10
10
  // 1. VARIABILI DI STATO DELLE ROTAZIONI (Estratte da app.js)
@@ -54,26 +54,26 @@ function updateCentralGauge(store, ui, now, isNavigating, sogKts, stwKts, rawAws
54
54
  }
55
55
  }
56
56
 
57
- // B. Rotazione dei puntatori analogici di AWA (Apparent) e TWA (True)
58
- const smAwa = getCircularAverageFromBuffer(store.smoothBuf.awa, 2000, true);
59
- const smTwa = getCircularAverageFromBuffer(store.smoothBuf.twa, 2000, true);
60
- if (smAwa) ui.awa.setAttribute('transform', `rotate(${curAwaRot = getShortestRotation(curAwaRot, radToDeg(smAwa.val))}, 200, 200)`);
61
- if (smTwa) ui.twa.setAttribute('transform', `rotate(${curTwaRot = getShortestRotation(curTwaRot, radToDeg(smTwa.val))}, 200, 200)`);
57
+ // B. Rotazione dei puntatori analogici di AWA (Apparent) e TWA (True) con passaggio di timestamp "now"
58
+ const smAwa = getCircularAverageFromBuffer(store.smoothBuf.awa, 2000, true, now);
59
+ const smTwa = getCircularAverageFromBuffer(store.smoothBuf.twa, 2000, true, now);
60
+ if (smAwa) ui.awa.setAttribute('transform', `rotate(${curAwaRot = getShortestRotation(curAwaRot, radToDeg(smAwa.val))}, 200, 200)`);
61
+ if (smTwa) ui.twa.setAttribute('transform', `rotate(${curTwaRot = getShortestRotation(curTwaRot, radToDeg(smTwa.val))}, 200, 200)`);
62
62
 
63
- // C. Calcolo dello Scarroccio (Leeway) e orientamento del vettore Track
64
- if (store.raw["navigation.courseOverGroundTrue"] !== undefined && store.raw["navigation.headingTrue"] !== undefined) {
65
- let driftDeg = radToDeg((store.raw["navigation.courseOverGroundTrue"] - store.raw["navigation.headingTrue"] + Math.PI * 3) % (2 * Math.PI) - Math.PI);
66
- smoothedLeeway = (sogKts < CONFIG.averaging.minSpeed) ? 0 : (smoothedLeeway * 0.9) + (driftDeg * 0.1);
67
- curTrackRot = getShortestRotation(curTrackRot, smoothedLeeway);
68
- ui.track.setAttribute('transform', `rotate(${curTrackRot}, 200, 200)`);
69
- ui.leewayVal.style.color = (Math.abs(sogKts - stwKts) > 0.5 && Math.abs(smoothedLeeway) > 7) ? "#ff9800" : "";
70
- updateLeewayDisplay(Math.max(-20, Math.min(20, smoothedLeeway)));
71
- }
63
+ // C. Calcolo dello Scarroccio (Leeway) e orientamento del vettore Track
64
+ if (store.raw["navigation.courseOverGroundTrue"] !== undefined && store.raw["navigation.headingTrue"] !== undefined) {
65
+ let driftDeg = radToDeg((store.raw["navigation.courseOverGroundTrue"] - store.raw["navigation.headingTrue"] + Math.PI * 3) % (2 * Math.PI) - Math.PI);
66
+ smoothedLeeway = (sogKts < CONFIG.averaging.minSpeed) ? 0 : (smoothedLeeway * 0.9) + (driftDeg * 0.1);
67
+ curTrackRot = getShortestRotation(curTrackRot, smoothedLeeway);
68
+ ui.track.setAttribute('transform', `rotate(${curTrackRot}, 200, 200)`);
69
+ ui.leewayVal.style.color = (Math.abs(sogKts - stwKts) > 0.5 && Math.abs(smoothedLeeway) > 7) ? "#ff9800" : "";
70
+ updateLeewayDisplay(Math.max(-20, Math.min(20, smoothedLeeway)));
71
+ }
72
72
 
73
- // D. Orientamento delle icone della barca e del vento nel Mini-Compass (TWD)
74
- const smHdgIcons = getCircularAverageFromBuffer(store.smoothBuf.hdg, 2000, false);
75
- const smTwdIcons = getCircularAverageFromBuffer(store.smoothBuf.twd, 2000, false);
76
- if (smHdgIcons && smTwdIcons) {
73
+ // D. Orientamento delle icone della barca e del vento nel Mini-Compass (TWD) con passaggio di timestamp "now"
74
+ const smHdgIcons = getCircularAverageFromBuffer(store.smoothBuf.hdg, 2000, false, now);
75
+ const smTwdIcons = getCircularAverageFromBuffer(store.smoothBuf.twd, 2000, false, now);
76
+ if (smHdgIcons && smTwdIcons) {
77
77
  curWindCompassRot = getShortestRotation(curWindCompassRot, radToDeg(smTwdIcons.val));
78
78
  ui.twdArrow.setAttribute('transform', `rotate(${curWindCompassRot}, 20, 20)`);
79
79
  curBoatCompassRot = getShortestRotation(curBoatCompassRot, radToDeg(smHdgIcons.val));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sailingrotevista/rotevista-dash",
3
- "version": "7.0.38",
3
+ "version": "7.0.40",
4
4
  "description": "Wind Dashboard with navigation and course aids",
5
5
  "main": "index.js",
6
6
  "publishConfig": {
package/utils.js CHANGED
@@ -36,8 +36,11 @@ function getCircularAverageFromBuffer(bufferArray, windowMs, signed = false, now
36
36
  const len = bufferArray.length;
37
37
  if (len === 0) return null;
38
38
 
39
- // RIFERIMENTO TEMPORALE IMMUNE DA DESINCRONIZZAZIONE (Usa l'ultimo dato del buffer)
40
- const referenceTime = bufferArray[len - 1].time;
39
+ const currentTime = now || Date.now();
40
+ const newestSampleTime = bufferArray[len - 1].time;
41
+
42
+ // Se l'ultimo pacchetto registrato nel buffer ha più di 15 secondi di silenzio, il sensore è offline
43
+ if ((currentTime - newestSampleTime) > 15000) return null;
41
44
 
42
45
  let sSin = 0, sCos = 0, count = 0;
43
46
  let newestTime = 0, oldestTime = 0;
@@ -53,7 +56,8 @@ function getCircularAverageFromBuffer(bufferArray, windowMs, signed = false, now
53
56
 
54
57
  for (let i = len - 1; i >= 0; i--) {
55
58
  const item = bufferArray[i];
56
- if ((referenceTime - item.time) > windowMs) break;
59
+ // Decadimento temporale reale ancorato sull'orologio corrente
60
+ if ((currentTime - item.time) > windowMs) break;
57
61
 
58
62
  let diffRad = Math.atan2(Math.sin(item.val - pilotRad), Math.cos(item.val - pilotRad));
59
63
  let finalSin, finalCos;
package/weather-radar.js CHANGED
@@ -59,8 +59,9 @@ function calculateActive30mRing() {
59
59
  const now = Date.now();
60
60
  const start30m = now - 1800000;
61
61
 
62
- const twdRecent = (store.twdMinuteBuffer || []).filter(p => p.time >= start30m);
63
- const twsRecent = (store.twsMinuteBuffer || []).filter(p => p.time >= start30m);
62
+ // Lettura unificata dai buffer storici dello store
63
+ const twdRecent = (store.histories.twd || []).filter(p => p.time >= start30m);
64
+ const twsRecent = (store.histories.tws || []).filter(p => p.time >= start30m);
64
65
 
65
66
  if (twdRecent.length === 0) return null;
66
67
 
@@ -264,7 +265,8 @@ function renderRadar() {
264
265
  // Disegno del LED lampeggiante del meteo-trend
265
266
  if (activeRing && !activeRing.isCalm) {
266
267
  const twdNow = getCircularAverageFromBuffer(store.longBuf.twd, 60000, false);
267
- const strategicWindowMs = (isNavigating ? 15 : 60) * 60000;
268
+ const isNav = (typeof store !== 'undefined' && store.isNavigating);
269
+ const strategicWindowMs = (isNav ? 15 : 60) * 60000;
268
270
  const twdRef = getCircularAverageFromBuffer(store.longBuf.twd, strategicWindowMs, false);
269
271
 
270
272
  if (twdNow && twdRef) {