Files
intercept/static/css/modes/aprs.css
Smittix cd168da760 Add graphical signal meter for APRS decoding
Backend changes (routes/aprs.py):
- Remove -q h flag from direwolf to enable audio level output
- Add parse_audio_level() to extract levels from direwolf output
- Add rate-limiting (max 10 updates/sec, min 2-level change)
- Push meter events to SSE queue as type='meter'

Frontend changes:
- Add signal meter widget to APRS sidebar
- Horizontal bar gauge with gradient (green->cyan->yellow->red)
- Numeric level display (0-100)
- "BURST" indicator for levels >70
- Status text (weak/moderate/strong signal)
- "No RF activity" state after 5 seconds of silence
- CSS styles in static/css/modes/aprs.css

Also added UK region to dropdown (same freq as Europe: 144.800)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-15 22:03:08 +00:00

132 lines
3.1 KiB
CSS

/* APRS Status Bar Styles */
.aprs-status-bar {
margin-top: 12px;
padding: 10px;
background: rgba(0,0,0,0.3);
border: 1px solid var(--border-color);
border-radius: 4px;
}
.aprs-status-indicator {
display: flex;
align-items: center;
gap: 8px;
margin-bottom: 8px;
}
.aprs-status-dot {
width: 10px;
height: 10px;
border-radius: 50%;
background: var(--text-muted);
}
.aprs-status-dot.standby { background: var(--text-muted); }
.aprs-status-dot.listening {
background: var(--accent-cyan);
animation: aprs-pulse 1.5s ease-in-out infinite;
}
.aprs-status-dot.tracking { background: var(--accent-green); }
.aprs-status-dot.error { background: var(--accent-red); }
@keyframes aprs-pulse {
0%, 100% { opacity: 1; box-shadow: 0 0 0 0 rgba(74, 158, 255, 0.7); }
50% { opacity: 0.6; box-shadow: 0 0 8px 4px rgba(74, 158, 255, 0.3); }
}
.aprs-status-text {
font-size: 10px;
font-weight: bold;
letter-spacing: 1px;
}
.aprs-status-stats {
display: flex;
flex-wrap: wrap;
gap: 8px;
font-size: 9px;
}
.aprs-stat {
color: var(--text-secondary);
}
.aprs-stat-label {
color: var(--text-muted);
}
/* Signal Meter Styles */
.aprs-signal-meter {
margin-top: 12px;
padding: 10px;
background: rgba(0,0,0,0.3);
border: 1px solid var(--border-color);
border-radius: 4px;
}
.aprs-meter-header {
display: flex;
align-items: center;
gap: 8px;
margin-bottom: 8px;
}
.aprs-meter-label {
font-size: 10px;
font-weight: bold;
letter-spacing: 1px;
color: var(--text-secondary);
}
.aprs-meter-value {
font-size: 12px;
font-weight: bold;
font-family: monospace;
color: var(--accent-cyan);
min-width: 24px;
}
.aprs-meter-burst {
font-size: 9px;
font-weight: bold;
color: var(--accent-yellow);
background: rgba(255, 193, 7, 0.2);
padding: 2px 6px;
border-radius: 3px;
animation: burst-flash 0.3s ease-out;
}
@keyframes burst-flash {
0% { opacity: 1; transform: scale(1.1); }
100% { opacity: 1; transform: scale(1); }
}
.aprs-meter-bar-container {
position: relative;
height: 16px;
background: rgba(0,0,0,0.4);
border-radius: 3px;
overflow: hidden;
margin-bottom: 4px;
}
.aprs-meter-bar {
height: 100%;
width: 0%;
background: linear-gradient(90deg,
var(--accent-green) 0%,
var(--accent-cyan) 50%,
var(--accent-yellow) 75%,
var(--accent-red) 100%
);
border-radius: 3px;
transition: width 0.1s ease-out;
}
.aprs-meter-bar.no-signal {
opacity: 0.3;
}
.aprs-meter-ticks {
display: flex;
justify-content: space-between;
font-size: 8px;
color: var(--text-muted);
padding: 0 2px;
}
.aprs-meter-status {
font-size: 9px;
color: var(--text-muted);
text-align: center;
margin-top: 6px;
}
.aprs-meter-status.active {
color: var(--accent-green);
}
.aprs-meter-status.no-signal {
color: var(--accent-yellow);
}