feat+fix batch: Station Control dashboard (fixed-width panels, grip-handle drag reorder, amp meters from the Flex stream, compact relays), Ultrabeam element list capped to 3 (READ_BANDS over-read), spot-click on Flex panadapter now sets mode, DAX TX toggle, DVK panel state persists across relaunch, duplicate amp meters cleared on power-cycle, QSO audio recording snapshot taken synchronously at log time (was racing the form-clear cancel), Flex COMP meter max -20->-25 and MIC scale to 0; changelog 0.20.10

This commit is contained in:
2026-07-23 01:08:47 +02:00
parent 13de53772b
commit 1070637c40
7 changed files with 142 additions and 62 deletions
+32
View File
@@ -649,6 +649,18 @@ func (f *Flex) handleStatus(payload string) {
}
if removed {
f.amp = flexAmp{}
// The amp's meters (FWD / ID / TEMP …) don't always get an individual
// "meter removed" push, so power-cycling the amp left the OLD meter
// ids in the maps while the re-registered amp added NEW ones — the
// panel then showed every amp meter twice. Drop every AMP-sourced
// meter here so only the fresh set survives.
for id, mi := range f.meterMeta {
if strings.Contains(strings.ToUpper(mi.src), "AMP") {
delete(f.meterMeta, id)
delete(f.meterVal, id)
delete(f.meterSub, id)
}
}
}
f.mu.Unlock()
}
@@ -660,6 +672,26 @@ func (f *Flex) handleStatus(payload string) {
f.meterRawLogged = true
debugLog.Printf("Flex: meter status raw: %s", payload)
}
// Meter removal — "meter <id> removed": drop it so a stale value can't
// linger (e.g. after an amp/slice is torn down).
removedMeter := false
for _, tok := range fields[1:] {
if tok == "removed" || tok == "in_use=0" {
removedMeter = true
}
}
if removedMeter {
f.mu.Lock()
for _, tok := range fields[1:] {
if n, err := strconv.Atoi(strings.TrimSpace(tok)); err == nil {
delete(f.meterMeta, n)
delete(f.meterVal, n)
delete(f.meterSub, n)
}
}
f.mu.Unlock()
return
}
var newIDs []int
f.mu.Lock()
for _, tok := range fields[1:] {