Rttningar

This commit is contained in:
root
2026-05-03 06:39:58 +00:00
parent b5d65c4a52
commit 3a066ea589
3 changed files with 33 additions and 13 deletions

View File

@@ -28,6 +28,21 @@ from maidenhead import latlon_to_subsquare, subsquare_bounds
import re as _re import re as _re
def _valid_position(lat, lon) -> bool:
"""Filter out corrupt or irrelevant positions."""
if lat is None or lon is None:
return False
if lat != lat or lon != lon: # NaN check
return False
if abs(lat) < 0.01 and abs(lon) < 0.01: # 0,0 = no GPS fix
return False
if lat < 54 or lat > 72: # outside Scandinavia
return False
if lon < 4 or lon > 32: # outside Scandinavia
return False
return True
def _extract_digis(path: str) -> str: def _extract_digis(path: str) -> str:
""" """
Reduce a raw APRS path to the actual physical digipeaters that handled it. Reduce a raw APRS path to the actual physical digipeaters that handled it.
@@ -187,6 +202,10 @@ async def ingest_rf(frame: RFFrameIn) -> None:
lat, lon, _ = _parse_position(tnc2) lat, lon, _ = _parse_position(tnc2)
# Nullify invalid positions so they are stored as NULL rather than corrupt data
if not _valid_position(lat, lon):
lat, lon = None, None
logger.info( logger.info(
"RF %-6s %-9s [%s] lat=%s lon=%s", "RF %-6s %-9s [%s] lat=%s lon=%s",
"DIRECT" if frame.heard_direct else "VIA", "DIRECT" if frame.heard_direct else "VIA",

View File

@@ -3,7 +3,7 @@
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>heardlog ??? APRS RF Coverage</title> <title>heardlog APRS RF Coverage</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/leaflet.min.css"> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/leaflet.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/leaflet.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/leaflet.min.js"></script>
<style> <style>
@@ -115,10 +115,10 @@
<header> <header>
<div class="logo">heard<span>log</span> &mdash; <em>APRS RF COVERAGE</em></div> <div class="logo">heard<span>log</span> &mdash; <em>APRS RF COVERAGE</em></div>
<div class="controls"> <div class="controls">
<div class="stat">SQUARES <strong id="sq-count" onclick="toggleSquaresPanel()">???</strong></div> <div class="stat">SQUARES <strong id="sq-count" onclick="toggleSquaresPanel()"></strong></div>
<div class="stat">POSITIONS <strong id="pt-count">???</strong></div> <div class="stat">POSITIONS <strong id="pt-count"></strong></div>
<div class="stat">RX <strong>SA6ANW-1</strong></div> <div class="stat">RX <strong>SA6ANW-1</strong></div>
<button class="btn" onclick="refresh()">??? REFRESH</button> <button class="btn" onclick="refresh()">&#8635; REFRESH</button>
</div> </div>
</header> </header>
<div id="map"></div> <div id="map"></div>
@@ -167,7 +167,7 @@ async function fetchAll() {
} }
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Popup HTML ??? square view + station view both in DOM, toggled with CSS // Popup HTML square view + station view both in DOM, toggled with CSS
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
function makePopupHTML(sq) { function makePopupHTML(sq) {
const pathRows = sq.paths.map(p => { const pathRows = sq.paths.map(p => {
@@ -242,7 +242,7 @@ async function showStation(sqId, callsign) {
try { try {
const res = await fetch(`${API}/api/coverage/station/${encodeURIComponent(callsign)}`); const res = await fetch(`${API}/api/coverage/station/${encodeURIComponent(callsign)}`);
const d = await res.json(); const d = await res.json();
const fmt = iso => iso ? new Date(iso).toLocaleString('sv-SE',{dateStyle:'short',timeStyle:'short'}) : '???'; const fmt = iso => iso ? new Date(iso).toLocaleString('sv-SE',{dateStyle:'short',timeStyle:'short'}) : '';
const topPaths = (d.top_paths||[]).map(p => const topPaths = (d.top_paths||[]).map(p =>
`<div class="detail-row"><span class="detail-label">${p.path}</span><span class="detail-value">${p.count}</span></div>` `<div class="detail-row"><span class="detail-label">${p.path}</span><span class="detail-value">${p.count}</span></div>`
).join(''); ).join('');
@@ -253,16 +253,16 @@ async function showStation(sqId, callsign) {
<div class="detail-row"><span class="detail-label">Unique positions</span><span class="detail-value">${d.unique_positions}</span></div> <div class="detail-row"><span class="detail-label">Unique positions</span><span class="detail-value">${d.unique_positions}</span></div>
<div class="detail-row"><span class="detail-label">Unique paths</span><span class="detail-value">${d.unique_paths}</span></div> <div class="detail-row"><span class="detail-label">Unique paths</span><span class="detail-value">${d.unique_paths}</span></div>
<div class="detail-section">DISTANCE (LINE OF SIGHT)</div> <div class="detail-section">DISTANCE (LINE OF SIGHT)</div>
<div class="detail-row"><span class="detail-label">Closest</span><span class="detail-value">${d.distance_min_km??'???'} km</span></div> <div class="detail-row"><span class="detail-label">Closest</span><span class="detail-value">${d.distance_min_km??''} km</span></div>
<div class="detail-row"><span class="detail-label">Farthest</span><span class="detail-value">${d.distance_max_km??'???'} km</span></div> <div class="detail-row"><span class="detail-label">Farthest</span><span class="detail-value">${d.distance_max_km??''} km</span></div>
<div class="detail-row"><span class="detail-label">Average</span><span class="detail-value">${d.distance_avg_km??'???'} km</span></div> <div class="detail-row"><span class="detail-label">Average</span><span class="detail-value">${d.distance_avg_km??''} km</span></div>
<div class="detail-section">TIMESTAMPS</div> <div class="detail-section">TIMESTAMPS</div>
<div class="detail-row"><span class="detail-label">First heard</span><span class="detail-value">${fmt(d.first_heard)}</span></div> <div class="detail-row"><span class="detail-label">First heard</span><span class="detail-value">${fmt(d.first_heard)}</span></div>
<div class="detail-row"><span class="detail-label">Last heard</span><span class="detail-value">${fmt(d.last_heard)}</span></div> <div class="detail-row"><span class="detail-label">Last heard</span><span class="detail-value">${fmt(d.last_heard)}</span></div>
<div class="detail-section">TOP PATHS</div> <div class="detail-section">TOP PATHS</div>
${topPaths} ${topPaths}
<div class="detail-section">SQUARES</div> <div class="detail-section">SQUARES</div>
<div class="squares-list">${(d.squares||[]).join(' &nbsp;') || '???'}</div>`; <div class="squares-list">${(d.squares||[]).join(' &nbsp;') || ''}</div>`;
} catch(e) { } catch(e) {
body.innerHTML = '<div class="loading-msg">Failed to load data.</div>'; body.innerHTML = '<div class="loading-msg">Failed to load data.</div>';
} }
@@ -509,7 +509,7 @@ function clearPathLines() {
function drawPath(rawPath, stationLat, stationLon) { function drawPath(rawPath, stationLat, stationLon) {
clearPathLines(); clearPathLines();
// Build waypoints: station ??? each digi ??? RX // Build waypoints: station each digi RX
const waypoints = [{ lat: stationLat, lon: stationLon, label: 'Station' }]; const waypoints = [{ lat: stationLat, lon: stationLon, label: 'Station' }];
if (rawPath && rawPath !== 'DIRECT') { if (rawPath && rawPath !== 'DIRECT') {
@@ -613,8 +613,8 @@ map.on('popupopen', e => {
map.on('zoomend', renderLayers); map.on('zoomend', renderLayers);
async function refresh() { async function refresh() {
document.getElementById('sq-count').textContent = '???'; document.getElementById('sq-count').textContent = '';
document.getElementById('pt-count').textContent = '???'; document.getElementById('pt-count').textContent = '';
await fetchAll(); await fetchAll();
} }

View File

@@ -1,6 +1,7 @@
server { server {
listen 80; listen 80;
charset utf-8; charset utf-8;
source_charset utf-8;
location / { location / {
root /usr/share/nginx/html; root /usr/share/nginx/html;