Files
HaloKeymind/src/helpers/MQTTTopicRouter.h
T
mikecarper 7605b12cc7 Merge remote-tracking branch 'review/observer-firmware' into keymindCascade
# Conflicts:
#	.github/workflows/build-observer-firmwares.yml
#	.gitignore
#	MQTT_IMPLEMENTATION.md
#	MQTT_INTERNALS.md
#	README.md
#	STABILITY_TESTABILITY_HANDOFF.md
#	docs/cli_commands.md
#	examples/companion_radio/MyMesh.cpp
#	examples/simple_repeater/MyMesh.cpp
#	examples/simple_repeater/UITask.cpp
#	examples/simple_room_server/MyMesh.cpp
#	examples/simple_room_server/UITask.cpp
#	examples/simple_sensor/SensorMesh.cpp
#	platformio.ini
#	scripts/generate_webconfig_html.py
#	scripts/webconfig_mock_server.py
#	src/helpers/CommonCLI.cpp
#	src/helpers/CommonCLI.h
#	src/helpers/JWTHelper.cpp
#	src/helpers/MQTTDefaults.h
#	src/helpers/MQTTMessageBuilder.cpp
#	src/helpers/MQTTPayloadBuilder.h
#	src/helpers/MQTTPresets.h
#	src/helpers/bridges/MQTTBridge.h
#	src/helpers/esp32/WebConfigServer.cpp
#	src/helpers/esp32/WebConfigServer.h
#	src/helpers/ui/SH1106Display.cpp
#	variants/lilygo_tbeam_SX1262/platformio.ini
#	variants/lilygo_tbeam_SX1276/platformio.ini
#	variants/lilygo_tlora_v2_1/platformio.ini
#	variants/thinknode_m7/platformio.ini
#	webui/index.html
2026-08-14 08:53:02 -07:00

90 lines
3.3 KiB
C

#pragma once
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include "MQTTObserverValidation.h"
#include "MQTTTopicTemplate.h"
// Pure MQTT publication-topic policy shared by MQTTBridge and the native tests.
// Keep these values aligned with MQTTBridge::MQTTMessageType; the bridge passes
// its enum value as an int so this helper stays independent of ESP/Arduino types.
enum MQTTPublicationType {
MQTT_PUBLICATION_STATUS = 0,
MQTT_PUBLICATION_PACKETS = 1,
MQTT_PUBLICATION_RAW = 2,
MQTT_PUBLICATION_NEIGHBORS = 3,
};
enum MQTTTopicRouteStyle {
MQTT_ROUTE_MESHCORE,
MQTT_ROUTE_MESHRANK,
MQTT_ROUTE_CUSTOM,
};
static inline bool mqttTopicSlotIndexValid(int index, size_t slot_count) {
return index >= 0 && (size_t)index < slot_count;
}
static inline const char* mqttPublicationTypeName(int type) {
switch (type) {
case MQTT_PUBLICATION_STATUS: return "status";
case MQTT_PUBLICATION_PACKETS: return "packets";
case MQTT_PUBLICATION_RAW: return "raw";
case MQTT_PUBLICATION_NEIGHBORS: return "neighbors";
default: return NULL;
}
}
static inline bool mqttWriteTopic(char* buf, size_t buf_size, const char* format,
const char* first, const char* second,
const char* third) {
if (!buf || buf_size == 0 || !format || !first || !second || !third) return false;
buf[0] = '\0';
int written = snprintf(buf, buf_size, format, first, second, third);
return written > 0 && (size_t)written < buf_size;
}
// Build the complete topic for one publication. MeshRank takes status, packets,
// and neighbors under meshrank/uplink/{token}/{device}/, using the same type
// suffixes as the MeshCore layout, and requires a per-slot token rather than an
// IATA. MeshCore routes require a configured IATA and device id. Custom
// templates may omit either placeholder, so their individual values are allowed
// to be empty.
static inline bool mqttBuildPublicationTopic(MQTTTopicRouteStyle style, int type,
const char* custom_template,
const char* iata, const char* device,
const char* token,
char* buf, size_t buf_size) {
if (!buf || buf_size == 0) return false;
buf[0] = '\0';
const char* type_name = mqttPublicationTypeName(type);
if (!type_name) return false;
switch (style) {
case MQTT_ROUTE_MESHCORE:
if (!mqttIataValid(iata) || strcmp(iata, "XXX") == 0 || !device || device[0] == '\0') {
return false;
}
return mqttWriteTopic(buf, buf_size, "meshcore/%s/%s/%s", iata, device, type_name);
case MQTT_ROUTE_MESHRANK:
// Raw is deliberately withheld: highest-volume topic, and the broker does
// not consume it. observer-firmware still sends it -- keep this on merge.
if (type == MQTT_PUBLICATION_RAW || !token || token[0] == '\0' ||
!device || device[0] == '\0') {
return false;
}
return mqttWriteTopic(buf, buf_size, "meshrank/uplink/%s/%s/%s",
token, device, type_name);
case MQTT_ROUTE_CUSTOM:
return mqttSubstituteTopic(custom_template, iata, device, token, type_name,
buf, buf_size);
default:
return false;
}
}