Files

69 lines
3.5 KiB
Python

"""Discovered sources (sdr-discover) and the queue of frequencies promoted into the scan table."""
import re
import threading
import time
from radio.channels import channels
from radio.config import ADSB_FILE, MAX_PROMOTED, PROMOTED_FILE, SOURCES_FILE
from radio.util import read_json, write_json_atomic
_promo_lock = threading.Lock()
def adsb_latest():
return read_json(ADSB_FILE, {})
def sources():
db = read_json(SOURCES_FILE, {})
promo = read_json(PROMOTED_FILE, [])
promo_f = {int(p.get("freq_hz", 0)) for p in promo if isinstance(p, dict)}
scan = channels().get("channels", {})
scan_f = {int(k) for k in scan}
out = []
for e in (db.get("sources") or {}).values():
f = int(e.get("f", 0))
in_scan = any(abs(f - k) < 3000 for k in scan_f)
out.append({
"f": f, "label": e.get("label"), "mod": e.get("mod"), "kind": e.get("kind"),
"bw_khz": e.get("bw_khz"), "max_db": e.get("max_db"), "last_db": e.get("last_db"),
"act": e.get("act"), "std": e.get("std"), "runs": e.get("runs"), "hits": e.get("hits"),
"seen_frac": e.get("seen_frac"), "first": e.get("first"), "last": e.get("last"),
"in_scan": in_scan, "promoted": f in promo_f and not in_scan,
})
out.sort(key=lambda x: (-(x["last"] or 0), -(x["hits"] or 0)))
scan_channels = sorted(({"f": int(k), "label": (v or {}).get("label"), "group": (v or {}).get("group")}
for k, v in scan.items()), key=lambda c: c["f"])
promo = [p for p in promo if isinstance(p, dict)]
# promoted.json is the persistent table of channels added from discovery (gen_config reads it on every scanner
# start); only entries not yet present in the scan table are really "queued"
queued = [{"f": int(p.get("freq_hz", 0)), "label": p.get("label"), "mod": p.get("mod"), "ts": p.get("ts")}
for p in promo if not any(abs(int(p.get("freq_hz", 0)) - k) < 3000 for k in scan_f)]
return {"runs": db.get("runs", 0), "last_run": db.get("last_run"), "last_sweeps": db.get("last_sweeps"),
"floor_dbfs": db.get("floor_dbfs"), "sources": out,
"promoted": promo, "scan_channels": scan_channels, "queued": queued}
def promote(freq):
"""Queue a discovered frequency for the scan table (picked up by gen_config on scanner restart)."""
src = (read_json(SOURCES_FILE, {}).get("sources") or {}).get(str(freq))
if not src:
return 404, "частота не найдена среди обнаруженных"
f = int(src["f"])
if not (108_000_000 <= f <= 175_000_000 or 400_000_000 <= f <= 470_000_000):
return 400, "вне поддерживаемых диапазонов"
mod = src.get("mod") if src.get("mod") in ("am", "nfm") else "nfm"
label = re.sub(r"[^\w .,()/+-]", "", str(src.get("label") or ""), flags=re.U)[:40]
label = f"{f / 1e6:.4f} {label}".strip()
with _promo_lock:
promo = read_json(PROMOTED_FILE, [])
if not isinstance(promo, list):
promo = []
if any(isinstance(p, dict) and p.get("freq_hz") == f for p in promo):
return 200, "уже в очереди"
if len(promo) >= MAX_PROMOTED:
return 409, f"очередь заполнена ({MAX_PROMOTED})"
promo.append({"freq_hz": f, "mod": mod, "label": label, "ts": int(time.time())})
write_json_atomic(PROMOTED_FILE, promo, ensure_ascii=False, indent=1)
return 200, "добавлено: сканер подхватит после следующего обзора (до 1 ч)"