diff --git a/examples/simple_repeater/MyMesh.cpp b/examples/simple_repeater/MyMesh.cpp index 1e3201d1..1a1940c2 100644 --- a/examples/simple_repeater/MyMesh.cpp +++ b/examples/simple_repeater/MyMesh.cpp @@ -1851,6 +1851,37 @@ static bool neighborPublishEntryComesBefore( return strcmp(lhs.pubkey_hex, rhs.pubkey_hex) < 0; } +#if defined(ESP_PLATFORM) +// ArduinoJson v7 JsonDocument has no real capacity cap (DynamicJsonDocument(N) +// is a no-op shim). Keep the pool off internal DRAM and soft-cap peak growth to +// the publish buffer size. used only rises on allocate — conservative for this +// single-shot doc (overflow path removes+breaks, so no further growth after free). +struct NeighborsDocAllocator : ArduinoJson::Allocator { + size_t used = 0; + static const size_t kBudget = MQTTBridge::NEIGHBORS_JSON_BUFFER_SIZE; + + void* allocate(size_t size) override { + if (used >= kBudget || size > kBudget - used) return nullptr; + void* p = heap_caps_malloc(size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT); + if (p) used += size; + return p; + } + + void deallocate(void* ptr) override { + heap_caps_free(ptr); + } + + void* reallocate(void* ptr, size_t new_size) override { + size_t old_size = ptr ? heap_caps_get_allocated_size(ptr) : 0; + size_t next_used = (used >= old_size) ? (used - old_size) : 0; + if (next_used >= kBudget || new_size > kBudget - next_used) return nullptr; + void* p = heap_caps_realloc(ptr, new_size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT); + if (p) used = next_used + new_size; + return p; + } +}; +#endif + // Build the neighbors-table JSON and hand it to the bridge, then reschedule. void MyMesh::finishNeighborDiscover() { getLocalScopes(self_scopes_buf, sizeof(self_scopes_buf)); @@ -1908,7 +1939,12 @@ void MyMesh::finishNeighborDiscover() { return; } +#if defined(ESP_PLATFORM) + NeighborsDocAllocator doc_alloc; + JsonDocument doc(&doc_alloc); +#else JsonDocument doc; +#endif int json_len = MQTTMessageBuilder::buildNeighborsMessage( doc, origin, self_pubkey_hex, timestamp, self_scopes_buf, entries, neighbor_discover_count, diff --git a/src/helpers/CommonCLI.cpp b/src/helpers/CommonCLI.cpp index b430374b..50b27c3e 100644 --- a/src/helpers/CommonCLI.cpp +++ b/src/helpers/CommonCLI.cpp @@ -814,6 +814,11 @@ void CommonCLI::loadMQTTPrefs( if (_mqtt_prefs.mqtt_neighbors_interval < MQTT_NEIGHBORS_MIN_INTERVAL_MS || _mqtt_prefs.mqtt_neighbors_interval > MQTT_NEIGHBORS_MAX_INTERVAL_MS) { _mqtt_prefs.mqtt_neighbors_interval = MQTT_NEIGHBORS_DEFAULT_INTERVAL_MS; + // Persist the repair so a corrupt flash value is not re-clamped every boot. + // Skip when hold is set so we never overwrite a deliberately preserved file. + if (!_mqtt_prefs_hold) { + mqtt_rewrite_pending = true; + } MESH_DEBUG_PRINTLN("MQTT: invalid neighbors interval reset to %u hours", (unsigned)MQTT_NEIGHBORS_DEFAULT_INTERVAL_HOURS); }