@sailingrotevista/rotevista-dash 6.0.13 → 6.1.1
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 +39 -54
- package/debug.html +131 -48
- package/index.js +5 -5
- package/package.json +1 -1
package/app.js
CHANGED
|
@@ -22,12 +22,12 @@ let CONFIG = {
|
|
|
22
22
|
minSpeed: 0.5,
|
|
23
23
|
stabilityBreakout: 15
|
|
24
24
|
},
|
|
25
|
-
graphs: { reef1:
|
|
25
|
+
graphs: { reef1: 5, reef2: 10, historyMinutes: 10, samples: 60 },
|
|
26
26
|
scales: {
|
|
27
27
|
stw: { stdMax: 4, hercSpan: 2, step: 1 },
|
|
28
28
|
sog: { stdMax: 4, hercSpan: 2, step: 1 },
|
|
29
29
|
tws: { stdMax: 15, hercSpan: 2, step: 1 },
|
|
30
|
-
depth: { stdMax:
|
|
30
|
+
depth: { stdMax: 5, hercSpan: 2, step: 1 }
|
|
31
31
|
},
|
|
32
32
|
server: { fallbackIp: "192.168.111.240:3000" }
|
|
33
33
|
};
|
|
@@ -328,7 +328,8 @@ function computeTrueWind() {
|
|
|
328
328
|
const tw_ground_x = aws * Math.cos(awa) - sog * Math.cos(drift), tw_ground_y = aws * Math.sin(awa) - sog * Math.sin(drift);
|
|
329
329
|
const tws_ground = Math.sqrt(tw_ground_x * tw_ground_x + tw_ground_y * tw_ground_y);
|
|
330
330
|
|
|
331
|
-
|
|
331
|
+
// Usiamo il tempo esatto di arrivo del pacchetto del vento per la coerenza dei buffer
|
|
332
|
+
const now = store.timestamps["environment.wind.speedApparent"] || Date.now();
|
|
332
333
|
store.raw["environment.wind.speedTrue"] = tws_water;
|
|
333
334
|
if (tws_water > 0.05) {
|
|
334
335
|
const twa = Math.atan2(tw_water_y, tw_water_x);
|
|
@@ -372,8 +373,9 @@ function getSourcePriorityScore(sourceName) {
|
|
|
372
373
|
return 30; // Punteggio standard per sorgenti sconosciute
|
|
373
374
|
}
|
|
374
375
|
|
|
375
|
-
function processIncomingData(path, val, source) {
|
|
376
|
-
|
|
376
|
+
function processIncomingData(path, val, source, timeMs) {
|
|
377
|
+
// Usiamo il tempo reale del pacchetto del server per eliminare lo sfasamento
|
|
378
|
+
const now = timeMs || Date.now();
|
|
377
379
|
const score = getSourcePriorityScore(source);
|
|
378
380
|
|
|
379
381
|
// Gestione dello Smart Lock
|
|
@@ -891,6 +893,12 @@ async function fetchServerHistory() {
|
|
|
891
893
|
store.histories[key] = data[key];
|
|
892
894
|
}
|
|
893
895
|
}
|
|
896
|
+
// --- SILLABAZIONE STRATEGICA DELLA BUSSOLA METEO (TWD) ---
|
|
897
|
+
// Se il server ci invia lo storico del TWD, lo inseriamo direttamente nella memoria a lungo termine
|
|
898
|
+
if (data.twd && data.twd.length > 0) {
|
|
899
|
+
store.longBuf.twd = data.twd;
|
|
900
|
+
console.log(`📈 Memoria strategica TWD sincronizzata dal server (${data.twd.length} punti).`);
|
|
901
|
+
}
|
|
894
902
|
console.log("📈 Storico dei grafici pre-popolato caricato dal server.");
|
|
895
903
|
}
|
|
896
904
|
} catch (err) {
|
|
@@ -1440,6 +1448,8 @@ function connect() {
|
|
|
1440
1448
|
const d = JSON.parse(e.data);
|
|
1441
1449
|
if (d.updates) {
|
|
1442
1450
|
d.updates.forEach(u => {
|
|
1451
|
+
// Sincronizzazione dell'orologio sul tempo reale del server (NMEA/GPS)
|
|
1452
|
+
const timeMs = u.timestamp ? new Date(u.timestamp).getTime() : Date.now();
|
|
1443
1453
|
let sourceLabel = "Unknown";
|
|
1444
1454
|
if (u.$source) {
|
|
1445
1455
|
sourceLabel = u.$source;
|
|
@@ -1452,7 +1462,7 @@ function connect() {
|
|
|
1452
1462
|
}
|
|
1453
1463
|
|
|
1454
1464
|
if (u.values) {
|
|
1455
|
-
u.values.forEach(v => processIncomingData(v.path, v.value, sourceLabel));
|
|
1465
|
+
u.values.forEach(v => processIncomingData(v.path, v.value, sourceLabel, timeMs));
|
|
1456
1466
|
}
|
|
1457
1467
|
});
|
|
1458
1468
|
}
|
|
@@ -1491,56 +1501,31 @@ window.addEventListener('contextmenu', e => e.preventDefault(), true);
|
|
|
1491
1501
|
async function init() {
|
|
1492
1502
|
loadDashboardState();
|
|
1493
1503
|
|
|
1494
|
-
//
|
|
1495
|
-
|
|
1496
|
-
startDisplayLoop();
|
|
1497
|
-
connect();
|
|
1498
|
-
|
|
1499
|
-
setInterval(watchConfigChanges, 10000);
|
|
1504
|
+
// Rileviamo se siamo sul Mac tramite file:// (Ambiente di sviluppo locale)
|
|
1505
|
+
const isLocalFile = (window.location.protocol === 'file:');
|
|
1500
1506
|
|
|
1501
|
-
//
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
if (document.visibilityState === 'visible') {
|
|
1508
|
-
// 1. Se la connessione è già attiva e sana, scarichiamo solo lo storico senza disconnetterci
|
|
1509
|
-
if (socket && socket.readyState === WebSocket.OPEN) {
|
|
1510
|
-
console.log("⏰ Schermo sbloccato: connessione attiva, sincronizzazione dello storico.");
|
|
1511
|
-
fetchServerHistory().then(() => {
|
|
1512
|
-
['stw', 'sog', 'depth', 'tws'].forEach(refreshGraph);
|
|
1513
|
-
}).catch(err => {});
|
|
1514
|
-
}
|
|
1515
|
-
// 2. Se la connessione è persa o morta, forzatura riconnessione rapida
|
|
1516
|
-
else {
|
|
1517
|
-
console.log("⏰ Schermo sbloccato: connessione assente, forzatura riconnessione rapida.");
|
|
1518
|
-
if (socket) {
|
|
1519
|
-
try {
|
|
1520
|
-
socket.close();
|
|
1521
|
-
} catch (e) {
|
|
1522
|
-
connect();
|
|
1523
|
-
}
|
|
1524
|
-
} else {
|
|
1525
|
-
connect();
|
|
1526
|
-
}
|
|
1527
|
-
}
|
|
1528
|
-
}
|
|
1529
|
-
});
|
|
1507
|
+
// 1. CARICAMENTO STORICO GRAFICI REALI DAL CERBO GX
|
|
1508
|
+
try {
|
|
1509
|
+
await fetchServerHistory();
|
|
1510
|
+
} catch (err) {
|
|
1511
|
+
console.warn("⚠️ Impossibile caricare lo storico reale dal server.");
|
|
1512
|
+
}
|
|
1530
1513
|
|
|
1531
|
-
//
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1514
|
+
// 2. CARICAMENTO CONFIGURAZIONI REALI (Bypassato su Mac per preservare i tuoi test!)
|
|
1515
|
+
if (!isLocalFile) {
|
|
1516
|
+
await fetchServerConfig();
|
|
1517
|
+
} else {
|
|
1518
|
+
// Mantiene la CONFIG locale di app.js per farti fare le prove delle scale sul Mac
|
|
1519
|
+
console.log("🎮 Esecuzione locale file://: utilizzo delle calibrazioni di CONFIG locali di debug.");
|
|
1520
|
+
}
|
|
1521
|
+
|
|
1522
|
+
startDisplayLoop();
|
|
1523
|
+
connect(); // Si collegherà in tempo reale al WebSocket reale della barca
|
|
1524
|
+
|
|
1525
|
+
// Controlla le modifiche di configurazione sul Cerbo solo se non siamo sul Mac via file://
|
|
1526
|
+
if (!isLocalFile) {
|
|
1527
|
+
setInterval(watchConfigChanges, 10000);
|
|
1528
|
+
}
|
|
1544
1529
|
}
|
|
1545
1530
|
|
|
1546
1531
|
|
package/debug.html
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="UTF-8">
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
-
<title>SignalK Data Debugger & Logger CSV</title>
|
|
6
|
+
<title>SignalK Data Debugger & Logger CSV (Pro v6.0)</title>
|
|
7
7
|
<style>
|
|
8
8
|
body {
|
|
9
9
|
background-color: #121212;
|
|
@@ -19,9 +19,8 @@
|
|
|
19
19
|
h1 { color: #4CAF50; border-bottom: 1px solid #333; padding-bottom: 10px; margin-top: 0; flex-shrink: 0; }
|
|
20
20
|
|
|
21
21
|
/* Controlli in alto */
|
|
22
|
-
.controls { margin-bottom:
|
|
23
|
-
input[type="text"]
|
|
24
|
-
input[type="text"] { width: 200px; }
|
|
22
|
+
.controls { margin-bottom: 15px; display: flex; gap: 10px; align-items: center; flex-shrink: 0; flex-wrap: wrap; }
|
|
23
|
+
input[type="text"] { padding: 8px; background: #222; color: #fff; border: 1px solid #444; width: 200px; }
|
|
25
24
|
button { padding: 8px 15px; background: #4CAF50; color: white; border: none; cursor: pointer; font-weight: bold; border-radius: 4px; }
|
|
26
25
|
button:hover { opacity: 0.8; }
|
|
27
26
|
button.stop { background: #f44336; }
|
|
@@ -30,6 +29,41 @@
|
|
|
30
29
|
#status { font-weight: bold; color: #f44336; margin-left: auto; }
|
|
31
30
|
#status.online { color: #4CAF50; }
|
|
32
31
|
|
|
32
|
+
/* Pannello dei filtri avanzati */
|
|
33
|
+
.filter-container {
|
|
34
|
+
background: #1a1a1a;
|
|
35
|
+
border: 1px solid #333;
|
|
36
|
+
border-radius: 8px;
|
|
37
|
+
padding: 15px;
|
|
38
|
+
margin-bottom: 20px;
|
|
39
|
+
flex-shrink: 0;
|
|
40
|
+
}
|
|
41
|
+
.presets {
|
|
42
|
+
margin: 10px 0;
|
|
43
|
+
display: flex;
|
|
44
|
+
gap: 10px;
|
|
45
|
+
flex-wrap: wrap;
|
|
46
|
+
}
|
|
47
|
+
.checkbox-grid {
|
|
48
|
+
display: grid;
|
|
49
|
+
grid-template-columns: repeat(auto-fill, minmax(290px, 1fr));
|
|
50
|
+
gap: 8px;
|
|
51
|
+
margin-top: 12px;
|
|
52
|
+
border-top: 1px solid #222;
|
|
53
|
+
padding-top: 10px;
|
|
54
|
+
}
|
|
55
|
+
.checkbox-item {
|
|
56
|
+
display: flex;
|
|
57
|
+
align-items: center;
|
|
58
|
+
gap: 8px;
|
|
59
|
+
font-size: 11px;
|
|
60
|
+
color: #ccc;
|
|
61
|
+
cursor: pointer;
|
|
62
|
+
}
|
|
63
|
+
.checkbox-item input {
|
|
64
|
+
cursor: pointer;
|
|
65
|
+
}
|
|
66
|
+
|
|
33
67
|
/* Layout a due pannelli (Sopra Tabella, Sotto Log) */
|
|
34
68
|
.panels-container {
|
|
35
69
|
display: flex;
|
|
@@ -47,18 +81,31 @@
|
|
|
47
81
|
border-radius: 8px;
|
|
48
82
|
padding: 10px;
|
|
49
83
|
overflow-x: auto;
|
|
84
|
+
max-height: 250px;
|
|
85
|
+
overflow-y: auto;
|
|
50
86
|
}
|
|
51
|
-
table {
|
|
52
|
-
|
|
53
|
-
|
|
87
|
+
table {
|
|
88
|
+
width: 100%;
|
|
89
|
+
border-collapse: collapse;
|
|
90
|
+
font-size: 13px;
|
|
91
|
+
table-layout: fixed; /* BLOCCO RIGIDO DELLE COLONNE (Evita ridimensionamenti continui) */
|
|
92
|
+
}
|
|
93
|
+
th, td {
|
|
94
|
+
border: 1px solid #333;
|
|
95
|
+
padding: 6px 8px;
|
|
96
|
+
text-align: left;
|
|
97
|
+
overflow: hidden;
|
|
98
|
+
word-wrap: break-word; /* Forza l'andamento a capo dei testi lunghi dentro le colonne fisse */
|
|
99
|
+
}
|
|
100
|
+
th { background-color: #222; color: #aaa; text-transform: uppercase; position: sticky; top: 0; z-index: 10; }
|
|
54
101
|
.val-cell { min-width: 120px; }
|
|
55
102
|
|
|
56
103
|
/* Stili Testo Tabella */
|
|
57
|
-
.value { color: #64ffda; font-weight: bold; font-size:
|
|
58
|
-
.unit { color: #888; font-size:
|
|
59
|
-
.source { color: #ffb74d; font-size:
|
|
60
|
-
.time { color: #90caf9; font-size:
|
|
61
|
-
.raw { color: #777; font-size:
|
|
104
|
+
.value { color: #64ffda; font-weight: bold; font-size: 15px; }
|
|
105
|
+
.unit { color: #888; font-size: 11px; margin-left: 5px; }
|
|
106
|
+
.source { color: #ffb74d; font-size: 11px; word-break: break-all; }
|
|
107
|
+
.time { color: #90caf9; font-size: 11px; }
|
|
108
|
+
.raw { color: #777; font-size: 10px; display: block; margin-top: 2px; }
|
|
62
109
|
|
|
63
110
|
/* Pannello Inferiore: Log Sequenziale in Formato Testo (simil-CSV) */
|
|
64
111
|
.log-panel {
|
|
@@ -78,7 +125,7 @@
|
|
|
78
125
|
justify-content: space-between;
|
|
79
126
|
align-items: center;
|
|
80
127
|
border-radius: 8px 8px 0 0;
|
|
81
|
-
font-size:
|
|
128
|
+
font-size: 13px;
|
|
82
129
|
font-weight: bold;
|
|
83
130
|
color: #aaa;
|
|
84
131
|
}
|
|
@@ -112,26 +159,29 @@
|
|
|
112
159
|
</head>
|
|
113
160
|
<body>
|
|
114
161
|
|
|
115
|
-
<h1>SignalK Data Debugger & Logger CSV</h1>
|
|
162
|
+
<h1>SignalK Data Debugger & Logger CSV (Pro v6.0)</h1>
|
|
116
163
|
|
|
117
164
|
<div class="controls">
|
|
118
165
|
<label>Server IP:</label>
|
|
119
166
|
<input type="text" id="server-ip" value="192.168.111.240:3000">
|
|
120
167
|
<button id="btn-connect" onclick="toggleConnection()">Connetti</button>
|
|
121
|
-
|
|
122
|
-
<span style="margin-left: 20px; color:#aaa;">Filtra Log:</span>
|
|
123
|
-
<select id="log-filter">
|
|
124
|
-
<option value="all">Tutti i dati monitorati</option>
|
|
125
|
-
<option value="navigation.position">Solo Posizione (GPS)</option>
|
|
126
|
-
<option value="navigation.speedOverGround">Solo SOG (Velocità sul fondo)</option>
|
|
127
|
-
<option value="navigation.courseOverGroundTrue">Solo COG (Rotta sul fondo)</option>
|
|
128
|
-
<option value="wind">Solo Vento (TWS/TWA/AWS/AWA)</option>
|
|
129
|
-
<option value="depth">Solo Profondità</option>
|
|
130
|
-
</select>
|
|
131
|
-
|
|
132
168
|
<span id="status">DISCONNESSO</span>
|
|
133
169
|
</div>
|
|
134
170
|
|
|
171
|
+
<!-- AREA FILTRI AVANZATA CON CHECKBOX E PRESET -->
|
|
172
|
+
<div class="filter-container">
|
|
173
|
+
<span style="font-weight: bold; color: #4CAF50; font-size: 13px;">Seleziona percorsi da scrivere nel Log CSV:</span>
|
|
174
|
+
<div class="presets">
|
|
175
|
+
<button class="secondary" onclick="applyPreset('all')">Seleziona Tutto</button>
|
|
176
|
+
<button class="secondary" style="background-color: #2c3e50;" onclick="applyPreset('twd')">Analisi Bussola Meteo (TWD/Vento/Rotta)</button>
|
|
177
|
+
<button class="secondary" style="background-color: #0088cc;" onclick="applyPreset('gps')">Solo GPS / Rotte</button>
|
|
178
|
+
<button class="secondary" onclick="applyPreset('none')">Deseleziona Tutto</button>
|
|
179
|
+
</div>
|
|
180
|
+
<div id="path-checkboxes" class="checkbox-grid">
|
|
181
|
+
<!-- Generate via JS -->
|
|
182
|
+
</div>
|
|
183
|
+
</div>
|
|
184
|
+
|
|
135
185
|
<div class="panels-container">
|
|
136
186
|
|
|
137
187
|
<!-- PANNELLO TABELLA RIASSUNTIVA -->
|
|
@@ -139,10 +189,11 @@
|
|
|
139
189
|
<table>
|
|
140
190
|
<thead>
|
|
141
191
|
<tr>
|
|
142
|
-
|
|
143
|
-
<th width="
|
|
144
|
-
<th width="
|
|
145
|
-
<th width="
|
|
192
|
+
<!-- BLOCCO RIGIDO DELLE LARGHEZZE DELLE COLONNE -->
|
|
193
|
+
<th width="25%">Path (Percorso)</th>
|
|
194
|
+
<th width="31.5%">Valore Convertito</th>
|
|
195
|
+
<th width="31.5%">Sorgente (Sensore - Dettagliato)</th>
|
|
196
|
+
<th width="12%">Ultimo Ricevuto</th>
|
|
146
197
|
</tr>
|
|
147
198
|
</thead>
|
|
148
199
|
<tbody id="data-table">
|
|
@@ -180,6 +231,7 @@
|
|
|
180
231
|
"environment.wind.angleApparent",
|
|
181
232
|
"environment.wind.speedTrue",
|
|
182
233
|
"environment.wind.angleTrueWater",
|
|
234
|
+
"environment.wind.directionTrue",
|
|
183
235
|
"environment.depth.belowTransducer"
|
|
184
236
|
];
|
|
185
237
|
|
|
@@ -192,37 +244,69 @@
|
|
|
192
244
|
const radToDeg = (rad) => rad * (180 / Math.PI);
|
|
193
245
|
const msToKts = (ms) => ms * 1.94384;
|
|
194
246
|
|
|
195
|
-
// Inizializza la Tabella Riassuntiva
|
|
247
|
+
// Inizializza la Tabella Riassuntiva e genera le Checkbox
|
|
196
248
|
const tbody = document.getElementById('data-table');
|
|
249
|
+
const checkboxGrid = document.getElementById('path-checkboxes');
|
|
250
|
+
|
|
197
251
|
pathsToWatch.forEach(path => {
|
|
252
|
+
const safeId = path.replace(/\./g, '-');
|
|
253
|
+
|
|
254
|
+
// 1. Creazione righe Tabella
|
|
198
255
|
const tr = document.createElement('tr');
|
|
199
|
-
tr.id = `row-${
|
|
200
|
-
|
|
256
|
+
tr.id = `row-${safeId}`;
|
|
201
257
|
tr.innerHTML = `
|
|
202
258
|
<td><strong>${path}</strong></td>
|
|
203
|
-
<td id="val-${
|
|
204
|
-
<td id="src-${
|
|
205
|
-
<td id="time-${
|
|
259
|
+
<td id="val-${safeId}" class="val-cell"><span class="value">---</span></td>
|
|
260
|
+
<td id="src-${safeId}"><span class="source">---</span></td>
|
|
261
|
+
<td id="time-${safeId}"><span class="time">---</span></td>
|
|
206
262
|
`;
|
|
207
263
|
tbody.appendChild(tr);
|
|
264
|
+
|
|
265
|
+
// 2. Creazione Checkbox
|
|
266
|
+
const label = document.createElement('label');
|
|
267
|
+
label.className = 'checkbox-item';
|
|
268
|
+
label.innerHTML = `
|
|
269
|
+
<input type="checkbox" id="chk-${safeId}" checked>
|
|
270
|
+
<span>${path}</span>
|
|
271
|
+
`;
|
|
272
|
+
checkboxGrid.appendChild(label);
|
|
208
273
|
});
|
|
209
274
|
|
|
210
275
|
const csvHeader = "Timestamp,Path,Value,Unit,Source,IsSpike";
|
|
211
276
|
document.getElementById('log-container').value = csvHeader + "\n";
|
|
212
277
|
|
|
278
|
+
// =========================================================
|
|
279
|
+
// PRESET RAPIDI DI SELEZIONE
|
|
280
|
+
// =========================================================
|
|
281
|
+
function applyPreset(preset) {
|
|
282
|
+
pathsToWatch.forEach(path => {
|
|
283
|
+
const safeId = path.replace(/\./g, '-');
|
|
284
|
+
const chk = document.getElementById(`chk-${safeId}`);
|
|
285
|
+
if (!chk) return;
|
|
286
|
+
|
|
287
|
+
if (preset === 'all') {
|
|
288
|
+
chk.checked = true;
|
|
289
|
+
} else if (preset === 'none') {
|
|
290
|
+
chk.checked = false;
|
|
291
|
+
} else if (preset === 'gps') {
|
|
292
|
+
// Solo GPS, SOG e COG
|
|
293
|
+
const isGps = path.includes('position') || path === 'navigation.speedOverGround' || path === 'navigation.courseOverGroundTrue';
|
|
294
|
+
chk.checked = isGps;
|
|
295
|
+
} else if (preset === 'twd') {
|
|
296
|
+
// Analisi strategica bussola vento ( Heading, COG, AWA, TWA, TWD, TWS, AWS )
|
|
297
|
+
const isTwd = path.includes('wind') || path === 'navigation.headingTrue' || path === 'navigation.courseOverGroundTrue';
|
|
298
|
+
chk.checked = isTwd;
|
|
299
|
+
}
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
|
|
213
303
|
// =========================================================
|
|
214
304
|
// ESTRAZIONE AVANZATA DELLA SORGENTE (GPS / NMEA)
|
|
215
305
|
// =========================================================
|
|
216
306
|
function extractSourceIdentifier(update) {
|
|
217
|
-
|
|
218
|
-
if (update.$source) {
|
|
219
|
-
return update.$source;
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
// 2. Se non presente, analizza l'oggetto o la stringa source tradizionale
|
|
307
|
+
if (update.$source) return update.$source;
|
|
223
308
|
if (update.source) {
|
|
224
309
|
if (typeof update.source === 'object') {
|
|
225
|
-
// Estrae label, nome talker o identificativo bus hardware se disponibili
|
|
226
310
|
return update.source.label ||
|
|
227
311
|
update.source.talker ||
|
|
228
312
|
update.source.src ||
|
|
@@ -230,7 +314,6 @@
|
|
|
230
314
|
}
|
|
231
315
|
return String(update.source);
|
|
232
316
|
}
|
|
233
|
-
|
|
234
317
|
return "Unknown-Source";
|
|
235
318
|
}
|
|
236
319
|
|
|
@@ -272,7 +355,6 @@
|
|
|
272
355
|
|
|
273
356
|
if (data.updates) {
|
|
274
357
|
data.updates.forEach(update => {
|
|
275
|
-
// Cattura l'identificativo sorgente con la nuova logica avanzata
|
|
276
358
|
const sourceName = extractSourceIdentifier(update);
|
|
277
359
|
const timeISO = new Date(update.timestamp).toISOString();
|
|
278
360
|
const timeUI = new Date(update.timestamp).toLocaleTimeString() + '.' + new Date(update.timestamp).getMilliseconds().toString().padStart(3, '0');
|
|
@@ -331,7 +413,7 @@
|
|
|
331
413
|
lastValues[path] = formattedVal;
|
|
332
414
|
}
|
|
333
415
|
|
|
334
|
-
} else if (path.includes("angle") || path.includes("heading") || path.includes("course")) {
|
|
416
|
+
} else if (path.includes("angle") || path.includes("heading") || path.includes("course") || path.includes("direction")) {
|
|
335
417
|
formattedVal = radToDeg(rawValue).toFixed(2);
|
|
336
418
|
unit = "deg";
|
|
337
419
|
|
|
@@ -357,9 +439,10 @@
|
|
|
357
439
|
// 1. Aggiorna la Tabella in alto
|
|
358
440
|
updateTableRow(path, formattedVal, unit, rawValue, source, timeUI);
|
|
359
441
|
|
|
360
|
-
// 2. Aggiungi riga al Log CSV (
|
|
361
|
-
const
|
|
362
|
-
|
|
442
|
+
// 2. Aggiungi riga al Log CSV (Solo ed esclusivamente se la checkbox di questo percorso è spuntata!)
|
|
443
|
+
const safeId = path.replace(/\./g, '-');
|
|
444
|
+
const chk = document.getElementById(`chk-${safeId}`);
|
|
445
|
+
if (chk && chk.checked) {
|
|
363
446
|
addLogEntry(timeISO, path, formattedVal, unit, source, isSpike);
|
|
364
447
|
}
|
|
365
448
|
}
|
package/index.js
CHANGED
|
@@ -31,11 +31,11 @@ module.exports = function (app) {
|
|
|
31
31
|
currentConfig = options;
|
|
32
32
|
app.debug(`${plugin.name} started/updated with new options`);
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
34
|
+
// Reset dello storico al riavvio del plugin per evitare incoerenze (Sintonizzato Pro v6.0)
|
|
35
|
+
histories = { stw: [], sog: [], depth: [], tws: [], vmg: [], aws: [], twd: [] };
|
|
36
|
+
graphTempBuf = { stw: [], sog: [], depth: [], tws: [], vmg: [], aws: [], twd: [] };
|
|
37
|
+
lastUpdates = { stw: 0, sog: 0, depth: 0, tws: 0, vmg: 0, aws: 0, twd: 0 };
|
|
38
|
+
raw = {};
|
|
39
39
|
|
|
40
40
|
// 2. Registra le rotte API solo la prima volta (Abilitate per CORS remoto)
|
|
41
41
|
if (!routeRegistered) {
|