Compare commits
6
Commits
v2.0.0
..
d56d3d6b5b
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d56d3d6b5b | ||
|
|
cd2960d00b | ||
|
|
95b5dd4cbc | ||
|
|
74d7c41b93 | ||
|
|
cf4dd93c06 | ||
|
|
9fb0b01f30 |
@@ -96,6 +96,10 @@ def init_db():
|
|||||||
c.execute("ALTER TABLE radio_logs ADD COLUMN source_ext TEXT DEFAULT ''")
|
c.execute("ALTER TABLE radio_logs ADD COLUMN source_ext TEXT DEFAULT ''")
|
||||||
except sqlite3.OperationalError: pass
|
except sqlite3.OperationalError: pass
|
||||||
|
|
||||||
|
try:
|
||||||
|
c.execute("ALTER TABLE radio_logs ADD COLUMN rssi REAL DEFAULT 0")
|
||||||
|
except sqlite3.OperationalError: pass
|
||||||
|
|
||||||
c.execute('''CREATE TABLE IF NOT EXISTS users
|
c.execute('''CREATE TABLE IF NOT EXISTS users
|
||||||
(id INTEGER PRIMARY KEY AUTOINCREMENT, username TEXT UNIQUE, password_hash TEXT,
|
(id INTEGER PRIMARY KEY AUTOINCREMENT, username TEXT UNIQUE, password_hash TEXT,
|
||||||
role TEXT, allowed_nodes TEXT)''')
|
role TEXT, allowed_nodes TEXT)''')
|
||||||
@@ -185,8 +189,15 @@ def save_cache(data):
|
|||||||
def save_to_sqlite(client_id, data, protocol="DMR"):
|
def save_to_sqlite(client_id, data, protocol="DMR"):
|
||||||
conn = sqlite3.connect(DB_PATH, timeout=10)
|
conn = sqlite3.connect(DB_PATH, timeout=10)
|
||||||
c = conn.cursor()
|
c = conn.cursor()
|
||||||
c.execute("INSERT INTO radio_logs (timestamp, client_id, protocol, source_id, target, slot, duration, ber, source_ext) VALUES (datetime('now', 'localtime'), ?, ?, ?, ?, ?, ?, ?, ?)",
|
|
||||||
(client_id, protocol, str(data.get('src_id', '---')), str(data.get('dst_id', '---')), data.get('slot', 0), round(data.get('duration', 0), 1), round(data.get('ber', 0), 2), str(data.get('src_ext', ''))))
|
rssi_val = 0
|
||||||
|
if 'rssi' in data and isinstance(data['rssi'], dict):
|
||||||
|
rssi_val = data['rssi'].get('ave', 0)
|
||||||
|
elif 'rssi' in data:
|
||||||
|
rssi_val = data['rssi']
|
||||||
|
|
||||||
|
c.execute("INSERT INTO radio_logs (timestamp, client_id, protocol, source_id, target, slot, duration, ber, source_ext, rssi) VALUES (datetime('now', 'localtime'), ?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
||||||
|
(client_id, protocol, str(data.get('src_id', '---')), str(data.get('dst_id', '---')), data.get('slot', 0), round(data.get('duration', 0), 1), round(data.get('ber', 0), 2), str(data.get('src_ext', '')), rssi_val))
|
||||||
conn.commit()
|
conn.commit()
|
||||||
conn.close()
|
conn.close()
|
||||||
notify_update('log_aggiornato')
|
notify_update('log_aggiornato')
|
||||||
@@ -631,7 +642,7 @@ def get_clients():
|
|||||||
def get_logs():
|
def get_logs():
|
||||||
conn = sqlite3.connect(DB_PATH, timeout=10)
|
conn = sqlite3.connect(DB_PATH, timeout=10)
|
||||||
c = conn.cursor()
|
c = conn.cursor()
|
||||||
c.execute("SELECT timestamp, client_id, protocol, source_id, target, slot, duration, ber, source_ext FROM radio_logs ORDER BY id DESC LIMIT 60")
|
c.execute("SELECT timestamp, client_id, protocol, source_id, target, slot, duration, ber, source_ext, rssi FROM radio_logs ORDER BY id DESC LIMIT 60")
|
||||||
logs = c.fetchall()
|
logs = c.fetchall()
|
||||||
conn.close()
|
conn.close()
|
||||||
return jsonify(logs)
|
return jsonify(logs)
|
||||||
|
|||||||
+27
-3
@@ -213,6 +213,7 @@
|
|||||||
<th>Target / TG</th>
|
<th>Target / TG</th>
|
||||||
<th data-i18n="thDur">Duration</th>
|
<th data-i18n="thDur">Duration</th>
|
||||||
<th>BER</th>
|
<th>BER</th>
|
||||||
|
<th>RSSI</th> <!-- NUOVA COLONNA -->
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody id="log-body"></tbody>
|
<tbody id="log-body"></tbody>
|
||||||
@@ -970,17 +971,40 @@
|
|||||||
const time = row[0] ? row[0].split(' ')[1] : "--:--";
|
const time = row[0] ? row[0].split(' ')[1] : "--:--";
|
||||||
const clientId = row[1]; const protocol = row[2] || "DMR"; let source = row[3] || "---"; const target = row[4] || "---";
|
const clientId = row[1]; const protocol = row[2] || "DMR"; let source = row[3] || "---"; const target = row[4] || "---";
|
||||||
const rawSlot = row[5]; const source_ext = row[8];
|
const rawSlot = row[5]; const source_ext = row[8];
|
||||||
|
const rawRssi = row[9]; // Estrai il nuovo valore
|
||||||
|
|
||||||
let sourceHtml = esc(source);
|
let sourceHtml = esc(source);
|
||||||
if (source_ext && source_ext.trim() !== "") { sourceHtml += ` <span style="font-size:0.8em; color:#94a3b8; font-family:'JetBrains Mono', monospace;">/${esc(source_ext)}</span>`; }
|
if (source_ext && source_ext.trim() !== "") { sourceHtml += ` <span style="font-size:0.8em; color:#94a3b8; font-family:'JetBrains Mono', monospace;">/${esc(source_ext)}</span>`; }
|
||||||
|
|
||||||
const slotDisplay = protocol === "DMR" ? `TS${rawSlot}` : "--";
|
const slotDisplay = protocol === "DMR" ? `TS${rawSlot}` : "--";
|
||||||
let protoColor = "#3b82f6"; if (protocol === "NXDN") protoColor = "#10b981"; else if (protocol === "YSF") protoColor = "#8b5cf6"; else if (protocol === "D-STAR") protoColor = "#06b6d4"; else if (protocol === "P25") protoColor = "#f59e0b";
|
let protoColor = "#3b82f6"; if (protocol === "NXDN") protoColor = "#10b981"; else if (protocol === "YSF") protoColor = "#8b5cf6"; else if (protocol === "D-STAR") protoColor = "#06b6d4"; else if (protocol === "P25") protoColor = "#f59e0b";
|
||||||
|
|
||||||
|
// Formatta l'RSSI con S-Meter grafico (nascondilo se è 0)
|
||||||
|
let rssiDisplay = '---';
|
||||||
|
if (rawRssi && rawRssi !== 0) {
|
||||||
|
// Calcola la percentuale su un range utile di 80 dB (da -130 a -50 dBm)
|
||||||
|
const pct = Math.max(0, Math.min(100, ((rawRssi + 130) / 80) * 100));
|
||||||
|
|
||||||
|
// Assegna il colore in stile S-Meter amatoriale
|
||||||
|
let barColor = "var(--success)"; // Verde (fino a S9 / -93 dBm)
|
||||||
|
if (rawRssi > -93) barColor = "#f59e0b"; // Giallo (S9+)
|
||||||
|
if (rawRssi > -73) barColor = "var(--danger)"; // Rosso (S9+20 o superiore)
|
||||||
|
|
||||||
|
rssiDisplay = `
|
||||||
|
<div style="display: flex; align-items: center; gap: 8px;" title="${esc(rawRssi)} dBm">
|
||||||
|
<div style="width: 50px; height: 6px; background: rgba(255,255,255,0.1); border-radius: 3px; overflow: hidden; box-shadow: inset 0 1px 2px rgba(0,0,0,0.5);">
|
||||||
|
<div style="width: ${pct}%; height: 100%; background: ${barColor}; transition: width 0.3s ease;"></div>
|
||||||
|
</div>
|
||||||
|
<span style="font-size: 0.85em; color: var(--text-muted); min-width: 3ch;">${esc(rawRssi)}</span>
|
||||||
|
</div>`;
|
||||||
|
}
|
||||||
|
|
||||||
if (source.includes("🌐")) {
|
if (source.includes("🌐")) {
|
||||||
if (!networkLogs[clientId]) networkLogs[clientId] = "";
|
if (!networkLogs[clientId]) networkLogs[clientId] = "";
|
||||||
networkLogs[clientId] += `<div style="border-bottom:1px solid rgba(255,255,255,0.1); padding:4px 0;"><span style="color:#64748b;">[${esc(time)}]</span> <span style="color:${protoColor}; font-weight:bold;">[${esc(protocol)}]</span> <span style="color:#cbd5e1;">${esc(source.replace("🌐", "").trim())}</span></div>`;
|
networkLogs[clientId] += `<div style="border-bottom:1px solid rgba(255,255,255,0.1); padding:4px 0;"><span style="color:#64748b;">[${esc(time)}]</span> <span style="color:${protoColor}; font-weight:bold;">[${esc(protocol)}]</span> <span style="color:#cbd5e1;">${esc(source.replace("🌐", "").trim())}</span></div>`;
|
||||||
} else {
|
} else {
|
||||||
tableHTML += `<tr><td>${esc(time)}</td><td><b style="color:var(--text-main);">${esc(String(clientId).toUpperCase())}</b></td><td><span style="background:${protoColor}; color:white; padding:3px 8px; border-radius:8px; font-size:0.7rem; font-weight:800;">${esc(protocol)}</span></td><td style="font-family:'JetBrains Mono', monospace; font-weight:bold; text-align:center;">${esc(slotDisplay)}</td><td style="color:var(--accent); font-weight:800;">${sourceHtml}</td><td style="font-family:'JetBrains Mono', monospace;">${esc(target.trim())}</td><td>${esc(row[6])}s</td><td>${esc(row[7])}%</td></tr>`;
|
// Aggiunto il TD per l'RSSI alla fine
|
||||||
|
tableHTML += `<tr><td>${esc(time)}</td><td><b style="color:var(--text-main);">${esc(String(clientId).toUpperCase())}</b></td><td><span style="background:${protoColor}; color:white; padding:3px 8px; border-radius:8px; font-size:0.7rem; font-weight:800;">${esc(protocol)}</span></td><td style="font-family:'JetBrains Mono', monospace; font-weight:bold; text-align:center;">${esc(slotDisplay)}</td><td style="color:var(--accent); font-weight:800;">${sourceHtml}</td><td style="font-family:'JetBrains Mono', monospace;">${esc(target.trim())}</td><td>${esc(row[6])}s</td><td>${esc(row[7])}%</td><td style="font-family:'JetBrains Mono', monospace;">${rssiDisplay}</td></tr>`;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
tbody.innerHTML = tableHTML;
|
tbody.innerHTML = tableHTML;
|
||||||
@@ -1121,10 +1145,10 @@
|
|||||||
html += `<div style="display:flex; justify-content:space-between; align-items:center; padding:15px; border-bottom:1px solid var(--border-color); background:rgba(128,128,128,0.05); border-radius:12px; margin-bottom:8px; border-left: 5px solid ${statusColor};">
|
html += `<div style="display:flex; justify-content:space-between; align-items:center; padding:15px; border-bottom:1px solid var(--border-color); background:rgba(128,128,128,0.05); border-radius:12px; margin-bottom:8px; border-left: 5px solid ${statusColor};">
|
||||||
<div><strong style="font-size:1.1rem; display:block; font-family:'JetBrains Mono',monospace;">${esc(name)}</strong><span class="${isOnline?'':'blink'}" style="color:${statusColor}; font-size:0.8rem; font-weight:800;">${esc(String(status).toUpperCase())}</span></div>
|
<div><strong style="font-size:1.1rem; display:block; font-family:'JetBrains Mono',monospace;">${esc(name)}</strong><span class="${isOnline?'':'blink'}" style="color:${statusColor}; font-size:0.8rem; font-weight:800;">${esc(String(status).toUpperCase())}</span></div>
|
||||||
<div style="display:flex; gap:8px;">
|
<div style="display:flex; gap:8px;">
|
||||||
${!isOnline ? `<button onclick="controlService(${q(clientId)}, ${q(name)}, 'start')" class="btn-cmd" style="background:var(--success);">▶</button>` : ''}
|
${!isOnline ? `<button onclick="controlService(${q(clientId)},${q(name)}, 'start')" class="btn-cmd" style="background:var(--success);">▶</button>` : ''}
|
||||||
<button onclick="controlService(${q(clientId)}, ${q(name)}, 'restart')" class="btn-cmd" style="background:#f59e0b;">🔄</button>
|
<button onclick="controlService(${q(clientId)}, ${q(name)}, 'restart')" class="btn-cmd" style="background:#f59e0b;">🔄</button>
|
||||||
<button onclick="openEditorModal(${q(clientId)}, ${q(name)})" class="btn-cmd" style="background:#8e44ad;">📝</button>
|
<button onclick="openEditorModal(${q(clientId)}, ${q(name)})" class="btn-cmd" style="background:#8e44ad;">📝</button>
|
||||||
${isOnline ? `<button onclick="controlService(${q(clientId)}, ${q(name)}, 'stop')" class="btn-cmd" style="background:var(--danger);">🛑</button>` : ''}
|
${isOnline ? `<button onclick="controlService(${q(clientId)},${q(name)}, 'stop')" class="btn-cmd" style="background:var(--danger);">🛑</button>` : ''}
|
||||||
</div>
|
</div>
|
||||||
</div>`;
|
</div>`;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user