[codex] Add MQTT antenna display names#2881
Conversation
External coax switches can change which physical antenna is attached to a fixed radio port, so MQTT needs a small display-name contract that updates AetherSDR local aliases without changing radio protocol tokens. The parser is broker-independent and testable: per-port topics update one canonical token, bulk JSON updates a snapshot, invalid tokens are ignored, and empty/null values clear aliases. The delivery path waits for a stable connected radio identity before persisting aliases, and drops disconnected updates so names cannot leak into a later radio. Constraint: Radio commands must keep using canonical Flex antenna tokens Constraint: Existing MQTT applet has a user-managed subscription list Rejected: Configurable MQTT topic prefix in this PR | broader UI/settings surface; fixed defaults give a stable first contract Confidence: high Scope-risk: narrow Directive: Do not route antenna display names into SliceModel rxant/txant commands Tested: ctest --test-dir build -R antenna_alias_test\|mqtt_antenna_alias_test --output-on-failure Tested: cmake --build build --target AetherSDR mqtt_antenna_alias_test antenna_alias_test -j4 Tested: Manual MQTT publish to aethersdr/antenna/name/ANT1 via broker 10.0.10.9:4883 Not-tested: MQTT broker authentication/TLS variants Related: #2880
There was a problem hiding this comment.
Thanks for the careful work here, @s53zo — the design is tidy and the test coverage on the parser/queue is exactly the kind of focused verification this codebase rewards. A few observations:
Design / conventions — Looks good:
- Routes through
RadioModel::setAntennaAlias/clearAntennaAlias, so the existingAntennaAliasStoreper-radio persistence (chassis-serial-keyed) does the right thing automatically. - The
MqttAntennaAliasQueueseparation makes the identity-stability rule (isConnected && (chassisSerial || serial)) cleanly testable, and the tests cover the disconnect-drop and stable-flush paths. - The
shared_ptr<MqttAntennaAliasQueue>capture in the three lambdas (slot + connection state + infoChanged) is the right call sincem_radioModeland the applet outlive each other and Qt'sthis-receiver semantics handle teardown. - Help doc clearly states these are display names only and AetherSDR still sends canonical radio tokens — important distinction for operators.
Minor things worth thinking about (none blocking):
-
Stability check vs.
antennaAliasRadioKey()fallback chain.hasStableRadioAliasKeyrequires chassisSerial OR serial, butRadioModel::antennaAliasRadioKey()(src/models/RadioModel.cpp:530) falls back further to model/name/nickname. So a radio that reports identity only via model/name will queue forever and never flush. Intentional (avoids polluting non-canonical keys), but worth a one-line comment in the lambda so the next reader doesn't try to "fix" it. -
infoChangedfires often.setFullDuplexand other non-identity changes will all retriggerflushPendingMqttAntennaAliases. The flush is a cheap empty-map iteration when there's nothing pending, so this is fine — but if the queue ever grows, every infoChanged would re-emit each alias. Coalescing viaQMap::insertinreceive()keeps the queue bounded per-token, so OK in practice. -
Bulk JSON ignores non-string/null values silently.
{"ANT1": 42}produces no update and no log line. Probably fine since this is operator-side automation, but aqWarningfor unexpected types would help debugging a misconfigured Node-RED flow. Defer if you'd rather not expand scope. -
Topic-prefix design. The fixed
aethersdr/antenna/name/*prefix is fine for v1 as you noted in the PR body. If/when a configurable base ships, the parser's API (takes topic + prefix function) makes that a clean extension.
Nothing here is blocking — the implementation is clean, scoped, and tested. Nice work.
…iases # Conflicts: # src/gui/MqttApplet.cpp
|
Claude here — pushed merge commit `3b8dda86` resolving the The conflict was purely adjacent-add in the includes block: this All three intended PR additions verified post-merge:
Local Release build clean. The new `mqtt_antenna_alias_test` On the two non-blocking items I noted in review:
Will admin-merge once CI lands green. @s53zo — really clean module decomposition. The 73, |
|
Claude here — merged. Thanks @s53zo, this is exactly the kind of The implementation discipline stood out: The AppSettings key-constraint workaround was specifically called The IP normalization (`::ffff:a.b.c.d` → IPv4, `::1` → `127.0.0.1`) The identity-stable queueing handles the retained-MQTT-message 25/25 parser tests including the queue-lifecycle suite, plus Ships in v26.5.3. Operators with Antenna Genius / external switch 73, |
Fixes aethersdr#2880 ## What changed - Added a small MQTT antenna alias parser/queue helper for display-name updates. - Added per-port topics under `aethersdr/antenna/name/<TOKEN>` and a bulk JSON topic at `aethersdr/antenna/names`. - Wired MQTT messages into `RadioModel` antenna aliases only after a connected radio has a stable identity, and clear pending updates on disconnect. - Documented the topic contract in the in-app help and added focused regression tests. ## Topic design Fixed AetherSDR-owned default topics are intentional for this first version. They provide a stable automation contract and keep the existing MQTT applet settings small. If operators later need multiple independent AetherSDR instances or station namespaces, a configurable base topic such as `aethersdr/<station>/...` can be added without changing the alias parser semantics. ## Verification - `cmake --build build --target AetherSDR mqtt_antenna_alias_test antenna_alias_test -j4` - `ctest --test-dir build -R 'antenna_alias_test|mqtt_antenna_alias_test' --output-on-failure` - `git diff --check HEAD~1..HEAD` - Manual MQTT publish to `aethersdr/antenna/name/ANT1` through broker `10.0.10.9:4883`; confirmed the running app updated the local antenna name. - Independent code review pass completed; blocking findings were addressed before this PR. Co-authored-by: Jeremy Fielder <kk7gwy@aethersdr.com>
Fixes #2880
What changed
aethersdr/antenna/name/<TOKEN>and a bulk JSON topic ataethersdr/antenna/names.RadioModelantenna aliases only after a connected radio has a stable identity, and clear pending updates on disconnect.Topic design
Fixed AetherSDR-owned default topics are intentional for this first version. They provide a stable automation contract and keep the existing MQTT applet settings small. If operators later need multiple independent AetherSDR instances or station namespaces, a configurable base topic such as
aethersdr/<station>/...can be added without changing the alias parser semantics.Verification
cmake --build build --target AetherSDR mqtt_antenna_alias_test antenna_alias_test -j4ctest --test-dir build -R 'antenna_alias_test|mqtt_antenna_alias_test' --output-on-failuregit diff --check HEAD~1..HEADaethersdr/antenna/name/ANT1through broker10.0.10.9:4883; confirmed the running app updated the local antenna name.