Skip to content

[feature] Add HLTH antenna health sidebar applet#3133

Closed
jensenpat wants to merge 2 commits into
aethersdr:mainfrom
jensenpat:aether/hlth-sidebar-applet
Closed

[feature] Add HLTH antenna health sidebar applet#3133
jensenpat wants to merge 2 commits into
aethersdr:mainfrom
jensenpat:aether/hlth-sidebar-applet

Conversation

@jensenpat

@jensenpat jensenpat commented May 25, 2026

Copy link
Copy Markdown
Collaborator
image

Summary

Adds a new HLTH sidebar applet focused on antenna health while transmitting. The applet gives operators a compact, always-available view of SWR, return loss, and output power, with adaptive graphing and incident markers designed for spotting broad variance patterns that can indicate counterpoise, grounding, feedline, or matching issues.

Features

  • Adds the HLTH applet to the default sidebar applet order near the transmit-related controls.
  • Streams live SWR and forward power from the freshest active meter source, preferring amplifier telemetry, then TGXL tuner telemetry, then radio TX telemetry.
  • Adds a smooth scrolling three-lane graph for SWR, return loss in dB, and forward output power.
  • Centers each graph lane around moving averages instead of raw absolute scale so small but meaningful changes remain visible in the sidebar applet footprint.
  • Highlights suspicious health regions when SWR, return loss, SWR variance, or coupled power sag indicate possible trouble.
  • Adds incident markers directly into the scrolling graph for notable SWR, RL, VAR, and WATCH transitions.
  • Adds an antenna health score from 0 to 100 and compact status states: IDLE, OK, WATCH, GROUND?, and PAUSED.
  • Adds click-to-pause/click-to-resume behavior across the applet so operators can freeze the graph for screenshots or comparison while live meter data continues updating behind the scenes.
  • Adds explanatory tooltips for the status, source, score, graph, SWR, return loss, power, and variance labels.

Use Cases

  • Spot a grounding or counterpoise problem during transmit when SWR is not simply high, but wandering broadly under RF load.
  • Catch a feedline or antenna issue where return loss degrades before the SWR number alone feels alarming.
  • Compare output power sag against SWR movement to distinguish antenna/load problems from normal modulation changes.
  • Freeze the graph during an event and take a screenshot for later diagnosis or support without stopping the operator workflow.
  • Keep a compact health readout visible in the sidebar without opening a larger diagnostics view.
  • Make amplifier/tuner/radio meter source differences visible by labeling the active source used for the graph.

Implementation Notes

  • Introduces HealthApplet, a compact Qt widget with its own custom graph renderer.
  • Connects HLTH to MeterModel::txMetersChanged, MeterModel::tgxlMetersChanged, and MeterModel::ampMetersChanged.
  • Uses MeterModel amp telemetry as the single amplifier data path, matching the existing meter applet flow and avoiding duplicate PGXL writes.
  • Resolves label styles, graph paint colors, severity bands, and incident markers through ThemeManager tokens so the applet follows Default Dark, Default Light, and live theme changes.
  • Starts the 20 Hz sampling timer only while HLTH is visible and unpaused, stopping it while hidden or paused.
  • Uses short recent-window statistics plus slower EWMA baselines to separate real variance from normal meter jitter.
  • Uses a cooldown on incident markers so repeated warnings do not flood the small graph.

Review Feedback Addressed

  • Replaced hardcoded HLTH colors with theme tokens and re-applies/repaints on ThemeManager::themeChanged.
  • Stopped hidden applet work by moving the timer to showEvent/hideEvent, with an additional visibility guard in appendFrame().
  • Removed the duplicate direct PGXL amplifier update path; HLTH now consumes amplifier telemetry through MeterModel::ampMetersChanged.

Validation

  • Built successfully with env -u CPLUS_INCLUDE_PATH cmake --build build -j22.
  • Deployed the resulting app bundle with the AetherSDR test deploy workflow.
  • The remote Mac refused replacing the existing /Users/patj/Desktop/AetherSDR.app due Desktop/app bundle permissions, so the uploaded review-fix build was preserved as /Users/patj/Desktop/AetherSDR-HLTH-REVIEW-20260525-083550.app with quarantine cleared.

👨🏼‍💻 Generated with OpenAI Codex (GPT-5.5 Pro 4/23) and tested by @jensenpat

Add a compact antenna health applet that tracks live SWR, return loss, and output power from the freshest active meter source. The applet includes adaptive graph scaling, variance highlighting, incident markers, click-to-pause behavior for screenshots, and explanatory label tooltips.

Co-authored-by: Codex <noreply@openai.com>
@jensenpat jensenpat changed the title Add HLTH antenna health sidebar applet [feature] Add HLTH antenna health sidebar applet May 25, 2026
@jensenpat jensenpat marked this pull request as ready for review May 25, 2026 14:35
@jensenpat jensenpat requested review from a team as code owners May 25, 2026 14:35

@aethersdr-agent aethersdr-agent Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the thoughtful applet, @jensenpat — the moving-average-centered lanes, incident markers, and source-priority cascade (AMP → TUN → RAD) all read as deliberate choices for spotting broad-variance counterpoise/ground problems, which is a real gap. Scope of the six touched files matches the stated feature. A few items worth addressing before merge:

1. Theme bypass — all colours are hardcoded. Every visible colour in HealthApplet.cpp is a literal hex (#56d8a3, #ffd066, #0x08,0x0d,0x14, severity bands, pill backgrounds, trace glows). The file #includes core/ThemeManager.h but never uses it. With Default Light theme just shipped (#3129) and the live Theme Editor in flight (#3130), this applet will look wrong under Light and won't respond to themeChanged. Sibling applets call ThemeManager::instance().resolve("... {{color.text.primary}} ...") — see TxApplet.cpp:128-166 for the pattern. For the painter-side colours (traces, severity bands, lane backgrounds), please pull from existing tokens (color.meter.bar.fill, color.accent.danger, color.background.0/1/2, etc.) and re-resolve on ThemeManager::themeChanged. If you need new tokens for the three-lane series colours and the WATCH/GROUND severity tints, that's a reasonable follow-up — but the current hardcoded path will land already-broken under Light.

2. 20 Hz timer runs unconditionally — even when the applet is hidden. The constructor calls hide() then m_tickTimer->start() at 50 ms, and appendFrame() keeps doing EWMA/stddev/severity math + a QWidget::update() on the graph every tick regardless of isVisible(). Two cheap options: gate appendFrame() on isVisible() (early-return when hidden, keep the timer cheap), or start/stop the timer in showEvent/hideEvent. The work-per-tick is small, but it runs 20×/sec forever in every session whether HLTH is active or not.

3. Duplicate amplifier path. MainWindow.cpp now calls m_appletPanel->healthApplet()->updateAmplifierMeters(watts, swr) from the PGXL connection lambda and the applet subscribes to MeterModel::ampMetersChanged in setMeterModel(). If PGXL telemetry feeds into MeterModel::ampMetersChanged (which it appears to, since MeterApplet uses the model signal), every amp update is being cached twice. Functionally last-write-wins so it isn't a bug, but pick one path. The model signal alone is cleaner and consistent with how MeterApplet consumes amp data.

4. Minor — unused <limits> include is fine, but the unused ThemeManager.h include should go (or, better, actually use it per item 1).

Nothing structurally wrong with the meter cascade, stats, or pause UX — those look solid. The theme item is the one that genuinely needs to land before merge so this doesn't become a regression on Light themes.

73


🤖 aethersdr-agent · cost: $7.2036 · model: claude-opus-4-7

Resolve the PR review concerns by moving HLTH paint and label colors to ThemeManager tokens with live theme refresh, stopping the 20 Hz applet timer while hidden or paused, and relying on MeterModel amp telemetry instead of the duplicate direct PGXL path.

Co-authored-by: Codex <noreply@openai.com>
@ten9876

ten9876 commented May 25, 2026

Copy link
Copy Markdown
Collaborator

Claude here.

The HLTH applet itself is well-built — the meter-source-priority (amp → tuner → radio TX), the EWMA-against-recent-window variance detection, the centered moving-average graphs instead of fixed scales, and the visibility-gated 20 Hz timer all read as production-ready. Particularly appreciate the theme-token migration in the latest iteration and the timer-on-show / off-hide pattern; that's exactly the right shape for a sidebar applet.

There's a mechanical conflict, though, that I want to give you a head start on rather than blocking review: PR #3150 (currently open) restructures the button bar into a 5-button favorites row + push-down drawer model, and both PRs touch kDefaultOrder, the m_appletOrder.append(makeEntry(...)) block, and the surrounding btnRow1 / btnRow2 plumbing. Whichever lands first will leave the other with a rebase to do.

To avoid making you re-do work that's already correct, I've rebased your PR onto PR #3150's branch (fix/button-bar) and pushed it as auto/hlth-on-buttonbar. Diff vs your branch is small — just the AppletPanel integration touchpoints, no changes to HealthApplet.{h,cpp}. You should see your name on the commit; the cherry-pickable changes are:

  1. makeEntry callsite routes through m_drawer / m_drawerLayout (the new drawer layout), matching every other drawer-resident applet:

    m_healthApplet = new HealthApplet;
    m_appletOrder.append(makeEntry("HLTH", "Antenna Health",
        m_healthApplet, false, m_drawer, m_drawerLayout));

    Bar-button registration is automatic via PR feat(bar): customizable button bar — favorites + push-down drawer #3150's registerBarButton() inside makeEntry() — no manual btnRow2 routing required.

  2. Default position moved from index 4 (between TX and PHNE) to after MTR in the drawer:

    "RX", "TUN", "AMP", "TX", "PHNE", "P/CW", "EQ", "WAVE", "TXDSP",
    "CAT", "DAX", "TCI", "IQ", "MTR", "HLTH", "AG", "SS"

    Reasoning: with the new model, positions 0–4 are the always-visible 5-button favorites row. Putting HLTH there by default would push PHNE out of favorites, which would surprise shipping users. Operators who want HLTH in favorites can right-click any bar button → drag HLTH up via the Favorites picker — that's the new UI.

HealthApplet.{h,cpp} are unchanged. Build is clean on Linux (CachyOS x86_64).

A couple of paths forward, your call:

Either way the HLTH applet ships — this is purely about which side absorbs the merge.

Thanks for the careful work on this, especially the EWMA/recent-window variance detection. That's the kind of diagnostics that actually catches grounding issues operators would otherwise blame on the radio.

73, Jeremy KK7GWY & Claude (AI dev partner)

@ten9876

ten9876 commented May 25, 2026

Copy link
Copy Markdown
Collaborator

Claude here.

Quick follow-up — Jeremy asked me to go ahead with option A from my earlier comment. Pushed #3153 as the rebased version targeting PR #3150's branch. Your HealthApplet.{h,cpp} are preserved verbatim with you as the commit author; the only delta is the AppletPanel integration (3 lines across CMakeLists/AppletPanel.h/AppletPanel.cpp).

This is purely so the HLTH work doesn't have to wait on you doing a manual rebase after #3150 lands. Your PR (#3133) stays open as the canonical reference — happy to close ours and you do the rebase yourself if you'd prefer, or close #3133 once #3153 lands. Whichever shape you'd like the merge to take.

Either path, credit stays with you on the HealthApplet commit.

73, Jeremy KK7GWY & Claude (AI dev partner)

ten9876 pushed a commit that referenced this pull request May 25, 2026
…n-bar refactor)

Rebases @jensenpat's PR #3133 onto the customisable button-bar
architecture introduced in PR #3150.  HealthApplet.{h,cpp} are
preserved verbatim from PR #3133; the integration changes are the
delta that lets the new BarButton registry + favorites/drawer model
own placement.

Changes vs PR #3133 originally targeted at main:

* Default placement moved from position 4 (between TX and PHNE,
  inside the new favorites zone) to after MTR in the drawer.
  Reasoning: HLTH is a diagnostic, not an every-tune control —
  putting it in favorites by default would push PHNE out of the
  5-button favorites row and surprise shipping users.  Operators
  who want HLTH in favorites can right-click any bar button →
  Favorites picker → drag HLTH up.
* makeEntry() call uses m_drawer / m_drawerLayout (the new drawer
  layout from PR #3150), matching the convention every other
  drawer-resident applet now uses.
* Bar-button registration is automatic via PR #3150's
  registerBarButton() inside makeEntry() — no manual btnRow1/2
  routing needed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@ten9876

ten9876 commented May 25, 2026

Copy link
Copy Markdown
Collaborator

Claude here.

Closing this in favour of #3153 — same HealthApplet.{h,cpp} verbatim with you as the commit author, just rebased onto post-#3150 main since the button-bar refactor reshaped the AppletPanel integration touchpoints that #3133 was targeting.

If you'd rather take #3153 over yourself (push commits to its branch, or open a fresh PR from your fork that supersedes #3153), entirely welcome — happy to close #3153 in that case so you stay in control of your own work. Otherwise we'll merge #3153 once review wraps up and your commit attribution carries through.

Either way, thanks again for the HLTH applet — the EWMA variance detection is a really nice touch.

73, Jeremy KK7GWY & Claude (AI dev partner)

@ten9876 ten9876 closed this May 25, 2026
ten9876 added a commit that referenced this pull request May 25, 2026
…on-bar refactor (#3153)

## Summary

Rebased version of @jensenpat's #3133 onto PR #3150's customisable
button-bar architecture. Same `HealthApplet.{h,cpp}` source verbatim
from #3133 (zero changes to applet code) — this PR is purely the
AppletPanel integration delta that adapts to PR #3150's new `BarButton`
registry + favorites/drawer model.

**Depends on #3150** — currently targets `fix/button-bar`. Once #3150
merges to main, this PR's base will be retargeted to main and the diff
will collapse to just the HLTH integration touchpoints.

## What changed vs #3133

Three integration touchpoints adjusted; HealthApplet itself untouched:

1. **`makeEntry()` callsite** routes through `m_drawer` /
`m_drawerLayout` (the new drawer layout from #3150), matching every
other drawer-resident applet's pattern. PR #3150's `registerBarButton()`
inside `makeEntry()` handles bar-button registration automatically — no
manual `btnRow2` plumbing required.

2. **Default position** moved from index 4 (between TX and PHNE) to
after MTR in the drawer:
   ```cpp
   "RX", "TUN", "AMP", "TX", "PHNE", "P/CW", "EQ", "WAVE", "TXDSP",
   "CAT", "DAX", "TCI", "IQ", "MTR", "HLTH", "AG", "SS"
   ```
With the new 5-button favorites row, putting HLTH at index 4 would push
PHNE out of favorites and surprise shipping users. Operators who want
HLTH up top can drag it via the right-click Favorites picker.

3. **CMakeLists.txt** — `src/gui/HealthApplet.cpp` added to
`GUI_SOURCES`.

## Credit

Commit attribution stays with @jensenpat as the HealthApplet author.
This PR exists only so the HLTH work doesn't have to wait on the
contributor doing a manual rebase after #3150 lands — they're welcome to
keep #3133 open if they'd prefer to do the rebase themselves.

## Review of HLTH itself

The applet code is well-built — appreciated zero hardcoded colours
(every paint and stylesheet call reads from `ThemeManager`), clean
paint-method separation, visibility-gated 20 Hz timer, three-tier meter
source priority (amp → TGXL tuner → radio TX), and EWMA + recent-window
variance detection.

One small consistency note for a follow-up: HLTH uses
`widget->setStyleSheet(theme.resolve(...))` (~8 sites) instead of
`theme.applyStyleSheet(widget, ...)`. That's the pattern PR #3144 swept
across the rest of the codebase to make widgets inspector-discoverable.
A two-line conversion would let the Phase 5 inspector find HLTH labels.
Tiny follow-up — not blocking this PR.

## Test plan

- [x] Linux (x86_64) — builds clean against `fix/button-bar` (`cmake
--build --target all`)
- [ ] Live smoke: HLTH appears in the drawer after MTR; right-click bar
→ Favorites picker shows HLTH in Active column
- [ ] Once #3150 merges, retarget base to main, confirm no further diff
change

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Pat Jensen <jensenpat@users.noreply.github.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants