Skip to content

feat(mqtt): per-slot IATA override (mqttN.iata) - #69

Merged
agessaman merged 1 commit into
agessaman:observer-firmware-devfrom
anieto:feat/per-slot-iata
Oct 21, 2026
Merged

agessaman merged 1 commit into
agessaman:observer-firmware-devfrom
anieto:feat/per-slot-iata

Conversation

@anieto

@anieto anieto commented Oct 19, 2026

Copy link
Copy Markdown

Why

mqtt.iata is node-wide, so every slot publishes meshcore/<same code>/…. That breaks down when an observer feeds brokers whose region maps differ. In Texas, for example, MeshMapper has LBB (Lubbock) and MAF (Midland/Odessa) but no CRP (Corpus Christi) or ACT (Waco), while MeshTexas's broker is the reverse, and it rejects codes it doesn't know. Today a Corpus Christi observer can't be correct on both: whichever code it picks is wrong (or refused) on the other network.

What

  • New per-slot setting mqttN.iata <code>. Empty (the default) means "use mqtt.iata", so nothing changes for existing nodes.
    set mqtt.iata SAT     # node-wide default
    set mqtt2.iata CRP    # slot 2 publishes meshcore/CRP/...
    get mqtt2.iata        # > CRP
    set mqtt2.iata        # clear, back to mqtt.iata
    
  • Applies to every MeshCore-style topic the slot publishes (presets and custom slots without a template) and to {iata} in a custom topic template. MeshRank topics carry no region code, so it has no effect there.
  • Same validation as mqtt.iata (exactly 3 alphanumerics, uppercased).
  • mqttSlotIata() in MQTTTopicRouter.h picks the effective code. An empty, XXX, or otherwise invalid override falls back to the global code, so a bad override can't take a working slot offline.
  • Slot readiness (isSlotReady) and the set mqttN.preset hint now check the slot's effective code, so a slot with only an override counts as configured. MQTTBridge::isIATAValid() was replaced by slotIata()/isSlotIATAValid() (it had no other callers).

Persistence

  • Runtime-only field MQTTPrefs::mqtt_slot_iata[6][8], appended at the end like display_timeout_secs. LegacyV1MQTTPrefs and the frozen binary layouts are untouched.
  • JSON: optional iata key inside each slotN group, no format-version bump.
    • Upgrade: files without the key load with an empty override (test: PrefsWrittenBeforeSlotIataStillLoad).
    • Downgrade: older firmware ignores the unknown key, per the existing UnknownKeysInsideAKnownGroupAreDowngradeSafe behavior. The slot falls back to mqtt.iata.
  • On load, a lowercase override is uppercased and an invalid one is cleared (not repaired to a default), with repaired set.

Web config

  • iata added to WC_ALLOWED_SLOT_KEYS and to the /api/config slot objects.
  • Slot cards get an "IATA region code" field (maxlength 3), shown for any non-none slot except token-only (MeshRank) presets. CLI autocomplete table and the mock server updated.

Tests

  • test_mqtt_topic_router: override precedence/fallback; override feeds MeshCore and custom-template topics.
  • test_mqtt_prefs_serializer: round trip; pre-feature file loads; case repair and invalid-override clearing.
  • test_webconfig_keys: mqttN.iata is allowlisted.
  • pio test -e native: all 38 suites pass. Not yet built or tested on hardware.

Notes

  • The MQTT task reads the override from prefs live, the same way it already reads mqtt_slot_token. Setting it calls restartBridgeSlot() like the other slot setters.
  • scripts/webconfig_cli_audit.py reports gps diag missing from the UI command table. That's pre-existing on observer-firmware-dev and unrelated to this change.

mqtt.iata is node-wide, so an observer feeding brokers with different
region maps can't publish the right code to each. mqttN.iata overrides
it for one slot; empty keeps the node-wide code, so existing nodes are
unchanged. Stored as an optional per-slot JSON key, downgrade-safe.
@agessaman
agessaman merged commit 7ec719a into agessaman:observer-firmware-dev Oct 21, 2026
@anieto
anieto deleted the feat/per-slot-iata branch October 22, 2026 17:02
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