This commit is contained in:
pablorevilla-meshtastic
2026-02-11 07:00:21 -08:00
parent 20e3f9c104
commit 89fbc6aeca
4 changed files with 67 additions and 1 deletions

View File

@@ -218,6 +218,11 @@
"show_qr_code": "Show QR Code",
"toggle_coverage": "Predicted Coverage",
"toggle_observed_coverage": "Observed Coverage",
"observed_settings": "Observed Settings",
"max_hops": "Max Hops",
"bearing_step": "Bearing Step",
"packets_limit": "Packets",
"refresh": "Refresh",
"location_required": "Location required for coverage",
"coverage_help": "Coverage Help",
"share_contact_qr": "Share Contact QR",

View File

@@ -204,6 +204,11 @@
"show_qr_code": "Mostrar código QR",
"toggle_coverage": "Cobertura predicha",
"toggle_observed_coverage": "Cobertura observada",
"observed_settings": "Ajustes observados",
"max_hops": "Máx. saltos",
"bearing_step": "Paso de rumbo",
"packets_limit": "Paquetes",
"refresh": "Actualizar",
"location_required": "Se requiere ubicación para la cobertura",
"coverage_help": "Ayuda de cobertura",
"share_contact_qr": "Compartir contacto QR",

View File

@@ -348,6 +348,24 @@
Coverage Help
</a>
</div>
<div id="observedCoverageControls" class="node-actions" style="display:none;">
<span data-translate-lang="observed_settings">Observed Settings</span>
<label>
<span data-translate-lang="max_hops">Max Hops</span>
<input id="observedMaxHops" type="number" min="0" max="10" value="1" style="width:60px;">
</label>
<label>
<span data-translate-lang="bearing_step">Bearing Step</span>
<input id="observedBearingStep" type="number" min="1" max="90" value="5" style="width:60px;">
</label>
<label>
<span data-translate-lang="packets_limit">Packets</span>
<input id="observedPacketsLimit" type="number" min="1" max="1000" value="50" style="width:80px;">
</label>
<button onclick="refreshObservedCoverage()" id="refreshObservedCoverageBtn">
<span data-translate-lang="refresh">Refresh</span>
</button>
</div>
<!-- Impersonation Warning -->
<div id="impersonationWarning" class="impersonation-warning" style="display:none;">
@@ -647,6 +665,7 @@ let currentPacketRows = [];
let map, markers = {};
let coverageLayer = null;
let observedCoverageLayer = null;
let observedControlsVisible = false;
let chartData = {}, neighborData = { ids:[], names:[], snrs:[] };
let fromNodeId = new URLSearchParams(window.location.search).get("from_node_id");
@@ -743,6 +762,9 @@ async function loadNodeInfo(){
const hasLocation = Boolean(node.last_lat && node.last_long);
coverageHelp.style.display = hasLocation ? "" : "none";
}
if (!(node.last_lat && node.last_long)) {
setObservedControlsVisible(false);
}
let lastSeen = "—";
if (node.last_seen_us) {
@@ -881,6 +903,7 @@ async function toggleObservedCoverage() {
if (observedCoverageLayer) {
map.removeLayer(observedCoverageLayer);
observedCoverageLayer = null;
setObservedControlsVisible(false);
return;
}
if (coverageLayer) {
@@ -892,8 +915,12 @@ async function toggleObservedCoverage() {
if (!nodeId) return;
try {
setObservedControlsVisible(true);
const maxHops = getObservedNumber("observedMaxHops", 1, 0, 10);
const bearingStep = getObservedNumber("observedBearingStep", 5, 1, 90);
const packetsLimit = getObservedNumber("observedPacketsLimit", 50, 1, 1000);
const res = await fetch(
`/api/coverage_observed/${encodeURIComponent(nodeId)}?max_hops=1&bearing_step=10&packets_limit=10`
`/api/coverage_observed/${encodeURIComponent(nodeId)}?max_hops=${maxHops}&bearing_step=${bearingStep}&packets_limit=${packetsLimit}`
);
if (!res.ok) {
console.error("Observed coverage request failed", res.status);
@@ -918,6 +945,30 @@ async function toggleObservedCoverage() {
}
}
function setObservedControlsVisible(show) {
const controls = document.getElementById("observedCoverageControls");
if (!controls) return;
observedControlsVisible = show;
controls.style.display = show ? "" : "none";
}
function getObservedNumber(id, fallback, min, max) {
const el = document.getElementById(id);
if (!el) return fallback;
const num = Number(el.value);
if (Number.isNaN(num)) return fallback;
return Math.max(min, Math.min(max, num));
}
async function refreshObservedCoverage() {
if (!observedCoverageLayer) {
await toggleObservedCoverage();
return;
}
await toggleObservedCoverage();
await toggleObservedCoverage();
}
function hideMap(){
const mapDiv = document.getElementById("map");
if (mapDiv) {

View File

@@ -58,6 +58,9 @@ def _bearing_deg(lat1, lon1, lat2, lon2):
return (bearing + 360.0) % 360.0
OBSERVED_MAX_DISTANCE_KM = 50.0
def init_api_module(packet_class, seq_regex, lang_dir):
"""Initialize API module with dependencies from main web module."""
global Packet, SEQ_REGEX, LANG_DIR
@@ -1240,6 +1243,8 @@ async def api_coverage_observed(request):
gw_lat = gw.last_lat * 1e-7
gw_lon = gw.last_long * 1e-7
dist_km = _haversine_km(src_lat, src_lon, gw_lat, gw_lon)
if dist_km > OBSERVED_MAX_DISTANCE_KM:
continue
bearing = _bearing_deg(src_lat, src_lon, gw_lat, gw_lon)
bucket = int(bearing // bearing_step) * bearing_step