feat(mqtt): add support for custom base topic in MQTT configuration UI

This commit is contained in:
Rightup committed 2026-08-18 22:33:47 +01:00
1 parent 4633520149
commit 653733a8b5
3 files changed
+53 -1

No files matched your search

+7
View File
@@ -2822,6 +2822,13 @@ class APIEndpoints:
"host": str(b["host"]).strip(),
"port": port,
"format": str(b["format"]).strip(),
# Custom base topic for legacy `mqtt` format. Persist
# None when blank so the handler can apply defaults.
"base_topic": (
(str(b["base_topic"]).strip() or None)
if "base_topic" in b and b.get("base_topic") is not None
else None
),
"disallowed_packet_types": list(b.get("disallowed_packet_types", [])),
"retain_status": bool(b.get("retain_status", False)),
# Opt-in per broker; brokers that do not expect the
+10 -1
View File
@@ -2593,13 +2593,22 @@ def test_update_mqtt_config_validation_and_success(cherrypy_ctx):
"status_interval": 20,
"brokers": [
{"preset": "waev"},
{"name": "a", "host": "h", "port": 443, "format": "json", "enabled": True},
{
"name": "a",
"host": "h",
"port": 443,
"format": "mqtt",
"enabled": True,
"base_topic": "meshcore/custom/base",
},
],
}
api.config_manager.update_and_save.return_value = {"success": True, "saved": True}
out = api.update_mqtt_config()
assert out["success"] is True
assert out["data"]["restart_required"] is True
updates = api.config_manager.update_and_save.call_args.kwargs["updates"]["mqtt_brokers"]
assert updates["brokers"][1]["base_topic"] == "meshcore/custom/base"
api.config_manager.update_and_save.return_value = {"success": False, "error": "save failed"}
out2 = api.update_mqtt_config()
+36
View File
@@ -236,3 +236,39 @@ def test_mqtt_published_packet_legacy_mqtt_format_uses_singular_packet_topic():
payload_dict = json.loads(captured[0]["payload"])
# Duration still flows through correctly even on the legacy topic
assert int(payload_dict["duration"]) > 0
def test_mqtt_published_packet_legacy_mqtt_format_uses_supplied_base_topic():
"""When a broker supplies ``base_topic``, downstream publishing must use
that value instead of the legacy default prefix.
"""
config = _make_config(format_value="mqtt", iata_code="LAX")
config["mqtt_brokers"]["brokers"][0]["base_topic"] = "site/edge/gw1"
public_key_hex = "12" * 32
identity = _FakeIdentity(public_key_hex)
pusher = MeshCoreToMqttPusher(local_identity=identity, config=config)
captured = _attach_capturing_client(pusher.connections[0])
raw_bytes = bytes(range(16))
airtime_mgr = AirtimeManager(config)
packet_record = {
"timestamp": 1700000000.0,
"type": 1,
"route": 1,
"rssi": -70,
"snr": 6.0,
"score": 0.2,
"payload_length": 10,
"packet_hash": "C0FFEE00" + "00" * 4,
"raw_packet": raw_bytes.hex(),
"airtime_ms": airtime_mgr.calculate_airtime(len(raw_bytes)),
}
record = PacketRecord.from_packet_record(
packet_record, origin="test-node", origin_id=public_key_hex.upper()
)
pusher.publish_packet(record.to_dict())
assert len(captured) == 1
# Legacy `mqtt` format still uses singular subtopic, but custom base prefix.
assert captured[0]["topic"] == "site/edge/gw1/packet"