Add weather satellite auto-scheduler, polar plot, ground track map, and rtlamr Docker support

- Fix SDR device stuck claimed on capture failure via on_complete callback
- Improve SatDump output parsing to emit all lines (throttled 2s) for real-time feedback
- Extract shared pass prediction into utils/weather_sat_predict.py with trajectory/ground track support
- Add auto-scheduler (utils/weather_sat_scheduler.py) using threading.Timer for unattended captures
- Add scheduler API endpoints (enable/disable/status/passes/skip) with SSE event notifications
- Add countdown timer (D/H/M/S) with imminent/active glow states
- Add 24h timeline bar with colored pass markers and current-time cursor
- Add canvas polar plot showing az/el trajectory arc with cardinal directions
- Add Leaflet ground track map with satellite path and observer marker
- Restructure to 3-column layout (passes | polar+map | gallery) with responsive stacking
- Add auto-schedule toggle in strip bar and sidebar
- Add rtlamr (Go utility meter decoder) to Dockerfile

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Mitch Ross
2026-02-05 19:32:12 -05:00
parent c910612f9e
commit a37d91900d
10 changed files with 1653 additions and 144 deletions
+53 -3
View File
@@ -1925,6 +1925,36 @@
</button>
</div>
</div>
<div class="wxsat-strip-divider"></div>
<div class="wxsat-strip-group">
<label class="wxsat-schedule-toggle" title="Auto-capture passes">
<input type="checkbox" id="wxsatAutoSchedule" onchange="WeatherSat.toggleScheduler()">
<span class="wxsat-toggle-label">AUTO</span>
</label>
</div>
</div>
<!-- Countdown + Timeline -->
<div class="wxsat-countdown-bar">
<div class="wxsat-countdown-next">
<div class="wxsat-countdown-boxes" id="wxsatCountdownBoxes">
<div class="wxsat-countdown-box"><span class="wxsat-cd-value" id="wxsatCdDays">--</span><span class="wxsat-cd-unit">DAYS</span></div>
<div class="wxsat-countdown-box"><span class="wxsat-cd-value" id="wxsatCdHours">--</span><span class="wxsat-cd-unit">HRS</span></div>
<div class="wxsat-countdown-box"><span class="wxsat-cd-value" id="wxsatCdMins">--</span><span class="wxsat-cd-unit">MIN</span></div>
<div class="wxsat-countdown-box"><span class="wxsat-cd-value" id="wxsatCdSecs">--</span><span class="wxsat-cd-unit">SEC</span></div>
</div>
<div class="wxsat-countdown-info" id="wxsatCountdownInfo">
<span class="wxsat-countdown-sat" id="wxsatCountdownSat">--</span>
<span class="wxsat-countdown-detail" id="wxsatCountdownDetail">No passes predicted</span>
</div>
</div>
<div class="wxsat-timeline" id="wxsatTimeline">
<div class="wxsat-timeline-track" id="wxsatTimelineTrack"></div>
<div class="wxsat-timeline-cursor" id="wxsatTimelineCursor"></div>
<div class="wxsat-timeline-labels">
<span>00:00</span><span>06:00</span><span>12:00</span><span>18:00</span><span>24:00</span>
</div>
</div>
</div>
<!-- Capture progress -->
@@ -1938,9 +1968,9 @@
</div>
</div>
<!-- Main content: passes + gallery -->
<!-- Main content: 3-column layout -->
<div class="wxsat-content">
<!-- Pass predictions -->
<!-- Left: Pass predictions -->
<div class="wxsat-passes-panel">
<div class="wxsat-passes-header">
<span class="wxsat-passes-title">Upcoming Passes</span>
@@ -1953,7 +1983,24 @@
</div>
</div>
<!-- Image gallery -->
<!-- Center: Polar plot + Ground track map -->
<div class="wxsat-center-panel">
<div class="wxsat-polar-container">
<div class="wxsat-panel-header">
<span class="wxsat-panel-title">Polar Plot</span>
<span class="wxsat-panel-subtitle" id="wxsatPolarSat">--</span>
</div>
<canvas id="wxsatPolarCanvas" width="300" height="300"></canvas>
</div>
<div class="wxsat-map-container">
<div class="wxsat-panel-header">
<span class="wxsat-panel-title">Ground Track</span>
</div>
<div id="wxsatGroundMap" class="wxsat-ground-map"></div>
</div>
</div>
<!-- Right: Image gallery -->
<div class="wxsat-gallery-panel">
<div class="wxsat-gallery-header">
<span class="wxsat-gallery-title">Decoded Images</span>
@@ -2899,6 +2946,9 @@
SSTV.init();
} else if (mode === 'weathersat') {
WeatherSat.init();
setTimeout(() => {
WeatherSat.invalidateMap();
}, 100);
}
}
@@ -174,6 +174,23 @@
</div>
</div>
<div class="section">
<h3>Auto-Scheduler</h3>
<p class="info-text" style="font-size: 11px; color: var(--text-dim); margin-bottom: 8px;">
Automatically capture satellite passes based on predictions.
Set your location above and toggle AUTO in the strip bar.
</p>
<div class="form-group">
<label style="display: flex; align-items: center; gap: 6px;">
<input type="checkbox" id="wxsatSidebarAutoSchedule" onchange="WeatherSat.toggleScheduler()" style="width: auto;">
Enable Auto-Capture
</label>
</div>
<div id="wxsatSchedulerStatus" style="font-size: 11px; color: var(--text-dim); font-family: 'JetBrains Mono', monospace; margin-top: 4px;">
Disabled
</div>
</div>
<div class="section">
<h3>Resources</h3>
<div style="display: flex; flex-direction: column; gap: 6px;">