Refactor MQTT origin handling to use effective origin logic

Updated MyMesh implementations in simple_repeater and simple_room_server to set mqtt_origin to an empty string, allowing the effective origin to follow node_name during publishing. Introduced new functions in MQTTBridge to manage effective origin retrieval and refresh from preferences, ensuring consistent behavior across MQTT operations. This change simplifies the origin management and enhances clarity in the codebase.
This commit is contained in:
agessaman
2026-05-09 17:06:00 -07:00
parent b37db66830
commit ff031f48bb
5 changed files with 46 additions and 18 deletions
+2 -6
View File
@@ -965,8 +965,8 @@ MyMesh::MyMesh(mesh::MainBoard &board, mesh::Radio &radio, mesh::MillisecondCloc
_prefs.gps_interval = 0;
_prefs.advert_loc_policy = ADVERT_LOC_PREFS;
// MQTT defaults
StrHelper::strncpy(_prefs.mqtt_origin, "MeshCore-Repeater", sizeof(_prefs.mqtt_origin));
// MQTT defaults (mqtt_origin empty => effective origin follows node_name at publish time)
_prefs.mqtt_origin[0] = '\0';
StrHelper::strncpy(_prefs.mqtt_iata, "SEA", sizeof(_prefs.mqtt_iata));
_prefs.mqtt_status_enabled = 1; // enabled
_prefs.mqtt_packets_enabled = 1; // enabled
@@ -1010,10 +1010,6 @@ void MyMesh::begin(FILESYSTEM *fs) {
// load persisted prefs
_cli.loadPrefs(_fs);
// Set MQTT origin to actual device name (not build-time ADVERT_NAME)
StrHelper::strncpy(_prefs.mqtt_origin, _prefs.node_name, sizeof(_prefs.mqtt_origin));
MESH_DEBUG_PRINTLN("MQTT origin set to device name: %s", _prefs.mqtt_origin);
acl.load(_fs, self_id);
// TODO: key_store.begin();
region_map.load(_fs);
+2 -6
View File
@@ -682,8 +682,8 @@ MyMesh::MyMesh(mesh::MainBoard &board, mesh::Radio &radio, mesh::MillisecondCloc
_prefs.bridge_baud = 115200; // baud rate
_prefs.bridge_channel = 1; // channel 1
// MQTT defaults (same as repeater)
StrHelper::strncpy(_prefs.mqtt_origin, "MeshCore-RoomServer", sizeof(_prefs.mqtt_origin));
// MQTT defaults (same as repeater; empty mqtt_origin follows node_name when publishing)
_prefs.mqtt_origin[0] = '\0';
StrHelper::strncpy(_prefs.mqtt_iata, "SEA", sizeof(_prefs.mqtt_iata));
_prefs.mqtt_status_enabled = 1; // enabled
_prefs.mqtt_packets_enabled = 1; // enabled
@@ -755,10 +755,6 @@ void MyMesh::begin(FILESYSTEM *fs) {
applyGpsPrefs();
#endif
#ifdef WITH_MQTT_BRIDGE
// Set MQTT origin to actual device name (not build-time ADVERT_NAME) - same as repeater
StrHelper::strncpy(_prefs.mqtt_origin, _prefs.node_name, sizeof(_prefs.mqtt_origin));
MESH_DEBUG_PRINTLN("MQTT origin set to device name: %s", _prefs.mqtt_origin);
if (_prefs.bridge_enabled) {
// Defer construction to avoid static init crashes on ESP32 classic
bridge = new MQTTBridge(&_prefs, _mgr, getRTCClock(), &self_id);
+3 -1
View File
@@ -1660,7 +1660,9 @@ void CommonCLI::handleGetCmd(uint32_t sender_timestamp, char* command, char* rep
#endif
#ifdef WITH_MQTT_BRIDGE
} else if (memcmp(config, "mqtt.origin", 11) == 0) {
sprintf(reply, "> %s", _prefs->mqtt_origin);
char effective_origin[32];
MQTTBridge::getEffectiveMqttOrigin(_prefs, effective_origin, sizeof(effective_origin));
sprintf(reply, "> %s", effective_origin);
} else if (memcmp(config, "mqtt.iata", 9) == 0) {
sprintf(reply, "> %s", _prefs->mqtt_iata);
} else if (memcmp(config, "mqtt.presets", 12) == 0 && (config[12] == '\0' || config[12] == ' ')) {
+36 -5
View File
@@ -37,6 +37,32 @@ static void stripQuotes(char* str, size_t max_len) {
}
}
// Effective MQTT origin: empty mqtt_origin follows node_name; otherwise mqtt_origin override (quotes stripped).
static void applyEffectiveOrigin(const NodePrefs* prefs, char* dest, size_t dest_size) {
if (!prefs || !dest || dest_size == 0) return;
if (prefs->mqtt_origin[0] == '\0') {
strncpy(dest, prefs->node_name, dest_size - 1);
} else {
strncpy(dest, prefs->mqtt_origin, dest_size - 1);
}
dest[dest_size - 1] = '\0';
stripQuotes(dest, dest_size);
}
void MQTTBridge::refreshOriginFromPrefs() {
if (!_prefs) return;
applyEffectiveOrigin(_prefs, _origin, sizeof(_origin));
}
void MQTTBridge::getEffectiveMqttOrigin(const NodePrefs* prefs, char* buf, size_t buf_size) {
if (!buf || buf_size == 0) return;
if (!prefs) {
buf[0] = '\0';
return;
}
applyEffectiveOrigin(prefs, buf, buf_size);
}
// Helper function to check if WiFi credentials are valid
static bool isWiFiConfigValid(const NodePrefs* prefs) {
// Check if WiFi SSID is configured (not empty)
@@ -457,14 +483,11 @@ void MQTTBridge::begin() {
return;
}
// Update origin and IATA from preferences
strncpy(_origin, _prefs->mqtt_origin, sizeof(_origin) - 1);
_origin[sizeof(_origin) - 1] = '\0';
refreshOriginFromPrefs();
strncpy(_iata, _prefs->mqtt_iata, sizeof(_iata) - 1);
_iata[sizeof(_iata) - 1] = '\0';
// Strip quotes from origin and IATA if present
stripQuotes(_origin, sizeof(_origin));
stripQuotes(_iata, sizeof(_iata));
// Convert IATA code to uppercase (IATA codes are conventionally uppercase)
@@ -1650,6 +1673,8 @@ void MQTTBridge::publishStatusToSlot(int index) {
MQTTSlot& slot = _slots[index];
if (!slot.client || !slot.connected) return;
refreshOriginFromPrefs();
// Build per-slot topic (handles IATA check for meshcore, token check for meshrank)
char status_topic[128];
if (!buildTopicForSlot(index, MSG_STATUS, status_topic, sizeof(status_topic))) {
@@ -2344,6 +2369,8 @@ bool MQTTBridge::publishStatus() {
return false;
}
refreshOriginFromPrefs();
// Reuse pre-allocated buffer to avoid heap alloc/free churn under memory pressure.
// _status_json_buffer and _last_raw_data are both Core 0-owned; no mutex needed.
char fallback_status_buffer[STATUS_JSON_BUFFER_SIZE];
@@ -2432,6 +2459,8 @@ bool MQTTBridge::publishPacket(mesh::Packet* packet, bool is_tx,
float snr, float rssi) {
if (!packet) return false;
refreshOriginFromPrefs();
// Memory pressure check: Skip publishes when there's not enough contiguous
// heap for the publish itself (JSON buffer + esp-mqtt outbox frame + WiFi TX
// path). Headroom only — NOT an mbedTLS preflight: persistent clients keep
@@ -2537,6 +2566,8 @@ bool MQTTBridge::publishPacket(mesh::Packet* packet, bool is_tx,
bool MQTTBridge::publishRaw(mesh::Packet* packet) {
if (!packet) return false;
refreshOriginFromPrefs();
// Use pre-allocated buffer; fallback to single stack buffer if not available
char json_buffer_stack[PUBLISH_JSON_BUFFER_SIZE];
char* active_buffer;
+3
View File
@@ -333,6 +333,7 @@ private:
void optimizeMqttClientConfig(PsychicMqttClient* client, bool needs_large_buffer = false);
void getClientVersion(char* buffer, size_t buffer_size) const;
void logMemoryStatus();
void refreshOriginFromPrefs();
public:
MQTTBridge(NodePrefs *prefs, mesh::PacketManager *mgr, mesh::RTCClock *rtc, mesh::LocalIdentity *identity);
@@ -380,6 +381,8 @@ public:
bool isReady() const;
static unsigned long getWifiConnectedAtMillis();
/** Resolved origin for MQTT JSON: node_name when mqtt_origin is empty, else mqtt_origin (with quote stripping). */
static void getEffectiveMqttOrigin(const NodePrefs* prefs, char* buf, size_t buf_size);
static void formatMqttStatusReply(char* buf, size_t bufsize, const NodePrefs* prefs);
/** True when WiFi is set and at least one MQTT slot can run (preset + custom host if needed). */
static bool isConfigValid(const NodePrefs* prefs);