Skip to content

Conversation

@krisclarkdev
Copy link

@krisclarkdev krisclarkdev commented Jan 5, 2026

Summary

Fixes #9187

This PR adds ACK batching to reduce airtime consumption in busy meshes. Instead of sending individual ACK packets for each received message, ACKs are queued and sent as a single combined packet.

Problem

In busy meshes, ACK traffic can consume significant airtime. Each ACK requires a separate transmission with full packet overhead, even though ACKs are small.

Solution

Queue ACKs per-destination and flush them as a single batched packet after:

  • 200ms timeout (configurable via DEFAULT_BATCH_WINDOW_MS)
  • 8 ACKs accumulated for the same destination

Each batched ACK uses only 5 bytes (4-byte packet ID + 1-byte error code), significantly reducing overhead compared to individual ACK packets.

Features

  • Disabled by default for backwards compatibility
  • Two ways to enable:

Build-time Enable

Add to platformio.ini:

build_flags = 
  -DACK_BATCHING_ENABLED=1

Runtime Enable

Send a direct message to yourself with one of these commands:

  • !ackbatch on - Enable ACK batching
  • !ackbatch off - Disable ACK batching
  • !ackbatch - Show current status

The response appears in the serial log.

Testing

  • ✅ Builds clean for heltec-v3 and heltec-v4
  • ✅ Tested on Linux (native build)
  • ✅ Tested on Heltec V4 hardware
  • ✅ Unit tests included (test/test_ackbatcher/)

Backwards Compatibility

  • Disabled by default - no behavior change unless explicitly enabled
  • Nodes without this feature will ignore batched ACK packets (unrecognized payload format)
  • Batched ACKs use the existing ROUTING_APP portnum with a magic byte prefix (0xBA) for identification

Files Changed

  • src/mesh/AckBatcher.h / .cpp - Core batching logic
  • src/mesh/NextHopRouter.h - Periodic flush timer
  • src/mesh/ReliableRouter.cpp - Batched ACK detection and processing
  • src/modules/RoutingModule.cpp - Queue ACKs instead of immediate send
  • src/modules/Modules.cpp - AckBatcher initialization
  • src/modules/TextMessageModule.cpp - Runtime toggle command
  • test/test_ackbatcher/test_main.cpp - Unit tests

Encode multiple ACKs into a single packet to reduce channel congestion
in busy meshes. ACKs are queued per-destination and flushed after 200ms
or when 8 ACKs accumulate.

Features:
- Runtime toggle via text message command
- Compile-time enable option
- Disabled by default for backwards compatibility
- Unit tests included
@thebentern thebentern requested a review from GUVWAF January 5, 2026 21:37
@GUVWAF
Copy link
Member

GUVWAF commented Jan 5, 2026

Thanks for the PR.

Have you done analysis on how often this will actually be used? 200ms for the default flush timeout sounds very short. A single LoRa packet on LongFast preset is already quite some longer than that.

Besides, it would be better to use protbuf encoding for the block ACK.

@krisclarkdev
Copy link
Author

@GUVWAF the time was just an arbitrary number, I figured with some testing and user feedback that we could find a good default. I also think that this feature if implemented should probably be left option as an admin command since it would only be beneficial in large meshes so it'd be good to have the option.

@GUVWAF
Copy link
Member

GUVWAF commented Jan 6, 2026

With which LoRa preset have you been testing this?

For this to be effective, for LongFast we will be talking about seconds of delay. I'm not sure that's worth it, as multiple packets to the same node quickly after each other is not common, and you'll have to wait longer until you get an acknowledgment.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature Request]: Batch ACK responses to reduce LoRa transmission overhead

2 participants