-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Add moar nodedb nodes on esp32 w/ psram to 800, stored messages to 200 #8097
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR introduces a hot/cold memory split architecture for ESP32-S3 devices to support tracking up to 800 nodes by moving NodeInfoLite payloads to PSRAM while keeping critical routing data in DRAM.
- Implements custom PSRAM allocator for ESP32-S3 that stores full NodeInfoLite objects (196B each) in external memory
- Creates NodeHotEntry cache in DRAM containing only essential fields (20B per node) for fast access during routing operations
- Widens counter types from uint8_t to uint16_t to handle node counts beyond 255
Reviewed Changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 2 comments.
Show a summary per file
File | Description |
---|---|
src/modules/AdminModule.cpp | Updates favorite node operations to use new NodeDB API instead of direct field access |
src/mesh/mesh-pb-constants.h | Changes MAX_NUM_NODES calculation to prioritize PSRAM size over flash size for ESP32-S3 |
src/mesh/ProtobufModule.h | Widens numOnlineNodes counter from uint8_t to uint16_t |
src/mesh/NodeDB.h | Adds PSRAM allocator, NodeHotEntry structure, and hot/cold cache management methods |
src/mesh/NodeDB.cpp | Implements complete hot/cold split logic with cache synchronization and PSRAM-aware operations |
src/graphics/niche/InkHUD/Applets/Bases/Map/MapApplet.cpp | Changes loop variables from uint8_t to size_t for handling larger node counts |
src/NodeStatus.h | Widens all node counter types from uint8_t to uint16_t |
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
Is this extensible to the extra qspi flash on the xiao NRF52? |
@NomDeTom I'm not sure we want to slow the nrf52 down any more than it is already. |
I was just thinking of things like nodeDB rolling attacks could be resisted more easily by increasing the size. I'm not sure this would slow it down particularly. |
I currently lack the skill required to make this work for nrf52. Placing in draft for now until someone more talented than I am can make this work. |
I currently have a $50 bounty out for anybody better than me who can do this for nrf52 nodes with flash. In the meantime, can we get this in at least for the ESP32s out there? |
Can't rush this in, 200 nodes is already problematic and entirely vibe coded solutions are generally buggy, get some people testing builds for this. |
More testing complete on this MR and changes since the first revision
Comparing to the development branch, even with 3000 nodes, it is saving about 16% heap memory. All memory is allocated ahead of time.
Testing on a production router has proven successful with no reboots and 661 nodes currently. So far this change has been tested successfully on the following platforms: With 2MB of PSRAM this will use 37%. With 8MB of most ESP32-S3 nodes. Next is to move PacketRecord to PSRAM for a savings of about 120KB with NUM_MAX_NODES == 3000, making the ring 6000 entries. For now it fits in DRAM. Moving back to draft for now, but this is looking very good. |
200 nodes is slow over WiFi |
…-sunl into moar_nodes_esp32_s3
@garthvh For me it's very fast with the Lora V4 and Xiao Wio. Bluetooth is a different beast and can take a few minutes to get 400 nodes. It seems like a lazy population might be better for bluetooth nodes if the client side can support that. (multiple queues possibly?) . I guess we can just limit this to wifi enabled nodes, or only send the most recently heard 100 nodes if on bluetooth to the client. |
Needs to be compatible with the 90% of people using Bluetooth, TCP is also pretty slow 800-3000 nodes seems really optimistic in real world use. |
This MR solves the problem of not having a large enough nodedb. I don't see 3000 nodes as being too much of a problem as the memory is all pre-allocated and leaves enough for everything else, but doing the large dump of the DB when connecting over bluetooth is a problem. I'm not sure why you're finding the wifi to be slow, as I can download the DB very quickly, but maybe my wifi is special. In my previous message I'm trying to provide solutions to the large DB problem. We can have the node download the last 100 heard, and then do a fair share queue between node info updates and other incoming updates. Other options include doing a comparison of blocks of node IDs and share the ones that are missing. Any other thoughts? The bay mesh currently cycles through 358 nodes every 3 hours, 500 every day, and currently up to 716 total over the last 8 days. I am guessing this will be towards 900 or 1000 at the end of this year, 2k at the end of next year. Add in some events, and 3k doesn't seem unreasonable as a goal to expand to. I like this change, and I think it is the absolute best way to increase node counts for nodes with PSRAM while decreasing heap utilization. The problem is the communication between phone and mesh device also needs a refresh to support large data dumps. I see this as the beginning of downloading much larger objects over time without needing a phone always attached. This, plus the ability for reliable message delivery, makes for the ability to transfer images, or other binary data, without impacting realtime communications. Large NodeDB just happens to be the first use-case that requires some kind of fair share mechanism. |
@garthvh I thought there were recent optimisations to the app code, to bring the nodeDB over after initial handshake? If this is a way to slow the nodeDB rolling in a big mesh, it seems useful, if not advisable. |
WARNING: This was vibe coded from gpt5-codex-high. It seems to work, and looking at it initially, it isn't bad. (Trust, this is better than most of my other c++ work)
I have tested this over the last day. I have found bugs with counters, but those are squished.
Note, "online" counter updates after it receives time from NTP/GPS, and will initially show a higher number on boot.
There is a bubble sort used for nodedb. It's completing normally within 3-4ms, but sometimes jumps to 11ms. This seems OK, but willing to accept advice here.
Node Hot/Cold Split
ESP32‑S3 builds now keep the 196 B meshtastic_NodeInfoLite payload in PSRAM using a custom allocator that calls heap_caps_malloc(MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT) (src/mesh/NodeDB.h:20, src/mesh/NodeDB.cpp:73).
DRAM carries only the latency-critical fields in a NodeHotEntry cache (~20 B per node: num, last_heard, snr, channel/flags) alongside dirtiness bits for sync-on-demand (src/mesh/NodeDB.h:33, src/mesh/NodeDB.cpp:78).
Sorting, routing, favorite flips, online counts, and next-hop decisions run entirely out of that hot cache, so the usual packet/route/UI fast paths stay in internal RAM.
Memory Footprint per Node (bytes)
Capacity & Secondary Effects:
MAX_NUM_NODES is a max 5000 nodes as long as psram size is > 2, otherwise the old flash-based limits apply (src/mesh/mesh-pb-constants.h:54).
The packet history ring still targets max(MAX_NUM_NODES*2, …) entries (src/mesh/PacketHistory.cpp:11), so doubling the node ceiling means the history structure grows accordingly—keep an eye on overall PSRAM consumption if future caps rise again.
Serialization & Cold Access:
Runtime Behavior:
Large Mesh Readiness:
Also recently added:
PSRAM-aware message/node expansion
has_psram()
so we only scale up when ≥2 MB of PSRAM is available.ESP.getPsramSize()
calls.🤝 Attestations
Station G2
LILYGO Pager