diff --git a/examples/simple_repeater/MyMesh.cpp b/examples/simple_repeater/MyMesh.cpp index 34b6c469..ecad3cd6 100644 --- a/examples/simple_repeater/MyMesh.cpp +++ b/examples/simple_repeater/MyMesh.cpp @@ -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); diff --git a/examples/simple_room_server/MyMesh.cpp b/examples/simple_room_server/MyMesh.cpp index b9ac92b2..fe2af053 100644 --- a/examples/simple_room_server/MyMesh.cpp +++ b/examples/simple_room_server/MyMesh.cpp @@ -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); diff --git a/src/helpers/CommonCLI.cpp b/src/helpers/CommonCLI.cpp index d75a3c94..991e1993 100644 --- a/src/helpers/CommonCLI.cpp +++ b/src/helpers/CommonCLI.cpp @@ -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] == ' ')) { diff --git a/src/helpers/bridges/MQTTBridge.cpp b/src/helpers/bridges/MQTTBridge.cpp index 28721176..dae7e053 100644 --- a/src/helpers/bridges/MQTTBridge.cpp +++ b/src/helpers/bridges/MQTTBridge.cpp @@ -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; diff --git a/src/helpers/bridges/MQTTBridge.h b/src/helpers/bridges/MQTTBridge.h index 785812ba..e633e1de 100644 --- a/src/helpers/bridges/MQTTBridge.h +++ b/src/helpers/bridges/MQTTBridge.h @@ -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);