Commit Graph

332 Commits

Author SHA1 Message Date
thatsatechnique
0c3ccac21c feat(ook): add timing presets, RSSI, bit-order suggest, pattern filter, TSCM link
- Timing presets: five quick-fill buttons (300/600, 300/900, 400/800, 500/1500, 500 MC)
  that populate all six pulse-timing fields at once — maps to CTF flag timing profiles
- RSSI per frame: add -M level to rtl_433 command; parse snr/rssi/level from JSON;
  display dB SNR inline with each frame; include rssi_db column in CSV export
- Auto bit-order suggest: "Suggest" button counts printable chars across all stored
  frames for MSB vs LSB, selects the winner, shows count — no decoder restart needed
- Pattern filter: live hex/ASCII filter input above the frame log; hides non-matching
  frames and highlights matches in green; respects current bit order
- TSCM integration: "Decode (OOK)" button in RF signal device details panel switches
  to OOK mode and pre-fills frequency — frontend-only, no backend changes needed

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 14:28:49 -08:00
thatsatechnique
4c282bb055 feat: add Generic OOK Signal Decoder module
New 'OOK Decoder' mode for capturing and decoding arbitrary OOK/ASK
signals using rtl_433's flex decoder with fully configurable pulse
timing. Covers PWM, PPM, and Manchester encoding schemes.

Backend (utils/ook.py, routes/ook.py):
- Configurable modulation: OOK_PWM, OOK_PPM, OOK_MC_ZEROBIT
- Full rtl_433 flex spec builder with user-supplied pulse timings
- Bit-inversion fallback for transmitters with swapped short/long mapping
- Optional frame deduplication for repeated transmissions
- SSE streaming via /ook/stream

Frontend (static/js/modes/ook.js, templates/partials/modes/ook.html):
- Live MSB/LSB bit-order toggle — re-renders all stored frames instantly
  without restarting the decoder
- Full-detail frame display: timestamp, bit count, hex, dotted ASCII
- Modulation selector buttons with encoding hint text
- Full timing grid: short, long, gap/reset, tolerance, min bits
- CSV export of captured frames
- Global SDR device panel injection (device, SDR type, rtl_tcp, bias-T)

Integration (app.py, routes/__init__.py, templates/):
- Globals: ook_process, ook_queue, ook_lock
- Registered blueprint, nav entries (desktop + mobile), welcome card
- ookOutputPanel in visuals area with bit-order toolbar

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 14:28:49 -08:00
Smittix
fef54e5276 Merge pull request #175 from thatsatechnique/fix/pager-display-classification
fix: improve pager message display and mute visibility
2026-03-04 18:00:33 +00:00
Smittix
8d91c200a5 fix: HackRF users get misleading RTL-SDR error in rtlamr/sstv/weather-sat modes
Several modes didn't pass sdr_type to claim_sdr_device(), defaulting to
'rtlsdr' and triggering an rtl_test USB probe that fails for HackRF with
a confusing "check that the RTL-SDR is connected" message.

- Add sdr_type to frontend start requests for rtlamr, weather-sat, sstv-general
- Read sdr_type in backend routes and pass to claim/release_sdr_device()
- Add early guard returning clear "not yet supported" error for non-RTL-SDR
  hardware in modes that are hardcoded to RTL-SDR tools
- Make probe_rtlsdr_device error message device-type-agnostic

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 07:52:13 +00:00
ribs
ec62cd9083 fix: prevent silent muting from hiding pager messages
The "Mute" button on pager cards persists muted addresses to
localStorage with no visible indicator, making it easy to
accidentally hide an address and forget about it. This caused
flag fragment messages on RIC 1337 to silently disappear.

- Add "X muted source(s) — Unmute All" indicator to sidebar
- Stop persisting hideToneOnly filter across sessions so the
  default (show all) always applies on page load
- Remove default checked state from Tone Only filter checkbox

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 16:05:01 -08:00
Smittix
f07ec23da9 feat: add space weather image prefetch and stable cache-busting
Backend: Add /prefetch-images endpoint that warms the image cache in
parallel using a thread pool, skipping already-cached images.

Frontend: Trigger prefetch on mode init so images load instantly.
Replace per-request Date.now() cache-bust with a 5-minute rotating
key to allow browser caching aligned with backend max-age.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 22:21:55 +00:00
Smittix
6a334c61df fix: resolve meteor WebSocket race condition and setup apt-get failure
Meteor: onopen callback used closure variable _ws instead of `this`,
so a double-click during CONNECTING state sent on the wrong socket.
Also clean up any in-progress connection on re-start, not just running ones.

Setup: make apt-get update non-fatal so third-party repo errors
(e.g. stale PPAs on Debian) don't abort the entire install.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 21:48:56 +00:00
Smittix
845629ea46 feat: enhance Meteor Scatter with sidebar fixes and visual effects
Move SDR Device below mode title, add sidebar Start/Stop buttons,
and add starfield canvas, meteor streak animations, particle bursts,
signal strength meter, and enhanced ping flash effects.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 21:04:35 +00:00
Smittix
7311dd10ab feat: add Meteor Scatter mode for VHF beacon ping detection
Full-stack meteor scatter monitoring mode that captures IQ data from
an RTL-SDR, computes FFT waterfall frames via WebSocket, and runs a
real-time detection engine to identify transient VHF reflections from
meteor ionization trails (e.g. GRAVES radar at 143.050 MHz).

Backend: MeteorDetector with EMA noise floor, SNR threshold state
machine (IDLE/DETECTING/ACTIVE/COOLDOWN), hysteresis, and CSV/JSON
export. WebSocket at /ws/meteor for binary waterfall frames, SSE at
/meteor/stream for detection events and stats.

Frontend: spectrum + waterfall + timeline canvases, event table with
SNR/duration/confidence, stats strip, turbo colour LUT. Uses shared
SDR device selection panel with conflict tracking.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 20:38:15 +00:00
Smittix
e2e92b6b38 fix: cache ISS position/schedule and parallelize SSTV init API calls
SSTV mode was slow to populate next-pass countdown and ISS location map
due to uncached skyfield computation and sequential JS API calls.

- Cache ISS position (10s TTL) and schedule (15min TTL, keyed by rounded lat/lon)
- Cache skyfield timescale object (expensive to create on every request)
- Reduce external API timeouts from 5s to 3s
- Fire checkStatus, loadImages, loadIssSchedule, updateIssPosition in parallel via Promise.all

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 18:05:57 +00:00
Smittix
90b455aa6c feat: add signal activity waveform component for radiosonde mode
Reusable SVG bar waveform (SignalWaveform.Live) that animates in response
to incoming SSE data — idle breathing when stopped, active oscillation
proportional to telemetry update frequency, smooth decay on signal loss.

Integrated into radiosonde Status section with ping() on each balloon
message and stop() on tracking stop. Also hardens the fetch error path
to show a readable message instead of a JSON parse error when the server
returns HTML.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 16:27:09 +00:00
Smittix
910b69594d Merge pull request #145 from mitchross/main
All review issues addressed. Merging with fixup commit for XSS escaping, import cleanup, VDL2 click behavior, frequency defaults, and misc fixes.
2026-03-01 20:42:50 +00:00
Smittix
a154601e86 fix: address PR #145 review issues
- Escape ac.icao, callsign, typeCode with escapeHtml() in aircraft card (XSS)
- Add linking comments between duplicated IATA_TO_ICAO mappings
- VDL2 sidebar: single-click selects aircraft, double-click opens modal
- Remove stale ICAOs from acarsAircraftIcaos in cleanupOldAircraft()
- Add null guard to drawPolarPlot() in weather-satellite.js
- Move deferred imports (translate_message, get_flight_correlator) to module level
- Check all frequency checkboxes by default on initial load
- Remove extra blank lines and uncertain MC/MCO airline code entry
- Add TODO comments linking duplicated renderAcarsCard implementations

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 20:42:14 +00:00
Smittix
bdeb32e723 feat: add rtl_tcp remote SDR support to weather satellite decoder
Extends the rtl_tcp support (added in c1339b6 for APRS, Morse, DSC) to
the weather satellite mode. When a remote SDR host is provided, SatDump
uses --source rtltcp instead of --source rtlsdr, local device claiming
is skipped, and the frontend sends rtl_tcp params via getRemoteSDRConfig().

Closes #166

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 16:55:04 +00:00
Mitch Ross
b5c3d71247 Merge branch 'smittix:main' into main 2026-02-28 16:30:56 -05:00
Smittix
c1339b6c65 feat: add rtl_tcp remote SDR support to aprs, morse, and dsc routes
Closes #164. Only pager and sensor routes supported rtl_tcp connections.
Now aprs, morse, and dsc routes follow the same pattern: extract
rtl_tcp_host/port from the request, skip local device claiming for
remote connections, and use SDRFactory.create_network_device(). DSC also
refactored from manual rtl_fm command building to use SDRFactory's
builder abstraction. Frontend wired up for all three modes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 19:21:28 +00:00
Smittix
10e4804e0a fix: bluetooth no results, audio waveform leak, and mode switch cleanup
- Change 'already_running' to 'already_scanning' status in bluetooth_v2
  so frontend recognizes the response and connects the SSE stream
- Hide pagerScopePanel and sensorScopePanel in switchMode() to prevent
  audio waveform bars leaking into other modes
- Clear devices Map, pendingDeviceIds Set, and UI in BluetoothMode.destroy()
  to prevent memory accumulation on repeated mode switches

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 17:16:55 +00:00
Smittix
c6e8602184 Merge pull request #160 from thatsatechnique/main
feat: add OOK/AM envelope detection mode to Morse decoder
2026-02-27 19:49:10 +00:00
mitchross
29873fb3c0 Merge upstream/main and resolve acars, vdl2, dashboard conflicts
Resolved conflicts:
- routes/acars.py: keep /messages and /clear endpoints for history reload
- routes/vdl2.py: keep /messages and /clear endpoints for history reload
- templates/adsb_dashboard.html: keep removal of hardcoded device-1
  defaults for ACARS/VDL2 selectors (users pick their own device)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 14:47:57 -05:00
Smittix
4f096c6c01 perf: add destroy() lifecycle to all mode modules to prevent resource leaks
Mode modules were leaking EventSource connections, setInterval timers,
and setTimeout timers on every mode switch, causing progressive browser
sluggishness. Added destroy() to 8 modules missing it (meshtastic,
bluetooth, wifi, bt_locate, sstv, sstv-general, websdr, spy-stations)
and centralized all destroy calls in switchMode() via a moduleDestroyMap
that cleanly tears down only the previous mode.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 19:18:13 +00:00
ribs
377519fd95 feat: add OOK/AM envelope detection mode to Morse decoder
Re-implements envelope detection on top of the rewritten Morse decoder.
Addresses PR #160 review feedback:
- Rebase: rebuilt on current upstream/main (lifecycle state machine)
- Gap thresholds: 2.0/5.0 for envelope only; goertzel keeps 2.6/6.0
- Frequency validation: max_mhz=1766 for envelope, 30 for goertzel
- Tests: EnvelopeDetector unit tests + envelope-mode decoder test
- Envelope uses direct magnitude threshold (no SNR/noise ref)
- Goertzel path completely unchanged

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 10:35:56 -08:00
Smittix
f9dc54cc3b fix: globe init using requestAnimationFrame retry like GPS mode
The globe wasn't rendering because initGlobe() used setTimeout(100)
which can race with the display:none removal by switchMode(). Both
GPS and WebSDR modes use requestAnimationFrame to wait for the browser
to compute layout before initializing Globe.gl.

- Replace setTimeout with RAF-based retry loop (up to 8 frames)
- Add try-catch around Globe() init with fallback message
- Match the proven pattern from GPS and WebSDR modes

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 00:04:28 +00:00
Smittix
f679433ac0 fix: globe rendering, CPU sizing, manual location support
- Fix globe destroyed on re-render by preserving canvas DOM node across
  renderLocationCard() calls instead of recreating from scratch
- Reduce globe.gl camera minDistance (180->120) so globe is visible in
  200px container
- Clear stale globeInstance ref when canvas is gone
- Enlarge CPU gauge (90->110px), percentage label (18->22px), core bars
  (24->48px height), and detail text (11->12px)
- JS fetchLocation() now supplements server response with client-side
  ObserverLocation.getShared() from localStorage when server returns
  'default' or 'none', picking up manual coordinates from settings modal
- Location priority: GPS > config env vars > manual (localStorage) > default

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 00:00:51 +00:00
Smittix
4b31474080 fix: location fallback to constants, compact card sizing
- Add third location fallback to utils/constants (London 51.5074/-0.1278)
  so location always resolves even without GPS or env vars configured
- Remove min-height from sys-card to eliminate wasted space
- Switch System Info to vertical key-value layout filling the card
- Clean up OS string (strip glibc suffix), use locale date for boot time
- Bump info grid font size from 11px to 12px for readability

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 23:55:36 +00:00
Smittix
f72b43c6bf fix: use GPS utility for location, compact dashboard layout
Replace broken app.gps_state lookup with utils.gps.get_current_position()
and return GPS metadata (fix quality, satellites, accuracy). Shrink location
card to single-column with 200px globe, move System Info into row 2.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 23:51:26 +00:00
Smittix
0a90010c1f feat: enhance System Health dashboard with rich telemetry and visualizations
Add SVG arc gauge, per-core CPU bars, temperature sparkline, network
interface monitoring with bandwidth deltas, disk I/O rates, 3D globe
with observer location, weather overlay, battery/fan/throttle support,
and process grid layout. New /system/location and /system/weather endpoints.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 23:42:45 +00:00
mitchross
81a8f24e27 Merge upstream/main and resolve weather-satellite.js conflict
Keep allPasses assignment for satellite filtering support.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 18:37:09 -05:00
Smittix
1cfeb193c7 feat: add System Health monitoring mode
Real-time dashboard for host metrics (CPU, memory, disk, temperatures),
active decoder process status, and SDR device enumeration via SSE streaming.
Auto-connects when entering the mode with graceful psutil fallback.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 23:21:52 +00:00
Smittix
deb7e2d15d fix: filter upcoming passes by selected satellite in weather sat mode
The satellite dropdown had no change listener, so selecting a different
satellite never updated the pass list, timeline, countdown, or polar plot.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 22:58:22 +00:00
Smittix
818d9c9f90 morse: fix stop timeout causing restart loop via checkStatus
When the stop POST timed out (5s), lifecycle was set to 'idle' on error,
allowing checkStatus to see running=true and reconnect SSE. Now:
- stop .then() stays in 'stopping' on timeout/error instead of going idle
- checkStatus skips reconnect when lifecycle is 'stopping' post-timeout
  but still transitions to idle when server confirms running=false
- LOCAL_STOP_TIMEOUT_MS raised from 5s to 12s to match server cleanup time

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 22:17:26 +00:00
Smittix
dc0775f7df morse: guard in-flight status polls from overriding stop state
The previous stopPromise guard only prevented new polls from being
dispatched. Polls already in-flight before stop was clicked could still
return with running=true and override the stopping lifecycle, causing
SSE reconnection and an apparent restart loop. Add a second guard in
the .then() handler to check stopPromise/lifecycle before acting.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 22:04:32 +00:00
Smittix
c0fb22124b morse: fix stop restart loop and lower SNR threshold for decoding
Guard checkStatus() against in-flight stop to prevent status poller
from overriding stopping state and reconnecting SSE. Lower SNR floor
from 1.3 to 1.15 to accommodate weaker CW signals. Add SNR/noise_ref
to scope events and metrics for real-time threshold debugging.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 21:57:08 +00:00
Smittix
97b10b3ac9 morse: fix SNR threshold for real CW and stop timeout
Widen noise detector offset from ±100Hz to ±200Hz to reduce spectral
leakage into the noise reference, and scale threshold_multiplier for
SNR space (2.8 → 1.54) so real CW signals reliably trigger tone
detection instead of producing all-E's at 60 WPM.

Fix misleading "decoder startup" timeout message on stop requests and
increase stop timeout from 2.2s to 5s.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 21:30:43 +00:00
Smittix
24d1777e63 morse: add multimon decoder alias fallback and clear stale idle scope 2026-02-26 17:43:23 +00:00
Smittix
d3b737c19b Switch Morse startup to IQ-first and harden timeout handling 2026-02-26 13:44:04 +00:00
Smittix
a50d200af4 Prevent Morse start timeout aborts on slow startup 2026-02-26 12:39:31 +00:00
Smittix
806bc1397a Keep Morse panels visible and persist startup error diagnostics 2026-02-26 11:38:49 +00:00
Smittix
8eb4ff41e2 Improve Morse stream startup compatibility and diagnostics 2026-02-26 11:15:45 +00:00
Smittix
286ab53d26 Fix Morse mode lifecycle stop hangs and rebuild CW decoder 2026-02-26 11:03:00 +00:00
Smittix
bfae73cabf Forward rtl_fm stderr to Morse frontend diagnostic log
rtl_fm prints device info, tuning, and errors to stderr but the morse
route only logged these server-side. Now stderr lines are forwarded to
the morse queue as info events, displayed in a compact diagnostic log
below the scope canvas. After 10s with no audio data, the scope text
escalates to prompt the user to check the SDR log.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 09:43:28 +00:00
Smittix
c0c066904c Fix Morse decoder scope events not reaching frontend
Replace blocking rtl_stdout.read() with select()+os.read() so the
decoder thread emits diagnostic heartbeat scope events when rtl_fm
produces no PCM data (common in direct sampling mode). Add waiting-state
rendering in the scope canvas and hide the generic placeholder/status
bar for morse mode.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 09:30:58 +00:00
Smittix
0bf8341b6c Fix Morse mode HF reception, stop button, and UX guidance
Enable direct sampling (-D 2) for RTL-SDR at HF frequencies below 24 MHz
so rtl_fm can actually receive CW signals. Add startup health check to
detect immediate rtl_fm failures. Push stopped status event from decoder
thread on EOF so the frontend auto-resets. Add frequency placeholder and
help text. Fix stop button silently swallowing errors.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 08:43:51 +00:00
mitchross
5f583e5718 Merge upstream/main and resolve weather-satellite.js conflict
Resolved conflict in static/js/modes/weather-satellite.js:
- Kept allPasses state variable and applyPassFilter() for satellite pass filtering
- Kept satellite select dropdown listener for filter feature
- Adopted upstream's optimistic stop() UI pattern for better responsiveness
- Kept optional chaining (pass?.trajectory) since drawPolarPlot can receive null

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 00:37:02 -05:00
Smittix
dc7c05b03f Fix welcome dashboard jitter and refine Morse mode UI
Fix "What's New" section shifting up/down on smaller screens (#157) by
isolating the logo pulse animation to its own compositing layer, stabilizing
the scrollbar gutter, and pinning the welcome container dimensions.

Morse mode improvements: relocate scope and decoded output panels to the
main content area, use shared SDR device controls, and reduce panel heights
for better layout.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 23:26:47 +00:00
Smittix
a50f77629c Fix Morse mode button styling to match standard UI patterns
Use run-btn/stop-btn classes and bottom placement instead of
btn-primary/btn-danger in a flex section, and preset-btn class
for band presets. Aligns with all other mode panels.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 21:18:35 +00:00
Smittix
ecdc060d81 Add HackRF support to TSCM RF scan and misc improvements
TSCM RF scan now auto-detects HackRF via SDRFactory and uses
hackrf_sweep as an alternative to rtl_power. Also includes
improvements to listening post, rtlamr, weather satellite,
SubGHz, Meshtastic, SSTV, WeFax, and process monitor modules.

Fixes #154

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 20:58:57 +00:00
Smittix
ee9356c358 Add CW/Morse code decoder mode
New signal mode for decoding Morse code (CW) transmissions via SDR.
Includes route blueprint, utility decoder, frontend UI, and tests.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 20:58:48 +00:00
Smittix
7fdf162f1e Fix waterfall retaining invalid span after error (#150)
When an error occurred with an out-of-range span (e.g. 30 MHz on
RTL-SDR), the span input kept the invalid value. Track the last
effective span from successful starts and reset the input on error.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 20:31:30 +00:00
Smittix
dbf76a4e84 Improve waterfall error handling and SDR tool path resolution
- Add pre-flight check for I/Q capture binary before spawning process
- Capture stderr from I/Q process for better error diagnostics
- Sync effective span value back to UI when backend adjusts it
- Use get_tool_path('rx_sdr') in Airspy, HackRF, LimeSDR, and SDRPlay
  command builders to support custom install locations

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 18:32:14 +00:00
Smittix
f3158cbb69 Add multi-SDR support to WeFax decoder (HackRF, LimeSDR, Airspy, SDRPlay)
Replace hardcoded rtl_fm with SDRFactory abstraction layer so WeFax works
with any supported SDR hardware, matching the pattern used by APRS and
other modes. RTL-SDR direct sampling flag preserved for HF reception.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 16:45:07 +00:00