Skip to content

Broadcast rate limiting and staged send API#54

Draft
puddly wants to merge 19 commits into
devfrom
puddly/broadcast-limiting
Draft

Broadcast rate limiting and staged send API#54
puddly wants to merge 19 commits into
devfrom
puddly/broadcast-limiting

Conversation

@puddly

@puddly puddly commented Jul 25, 2026

Copy link
Copy Markdown
Contributor

See #43 for a much more in-depth discussion. This PR implements broadcast rate limiting for Ziggurat and changes the send API and updates the wire format, hopefully bringing it into its final state for a long while.

The broadcast budget is effectively a token bucket implementation with a capacity of 15 tokens, draining at a rate of 0.55/sec (just under the steady-state SiLabs router rate). Three token slots are reserved for internal stack operations. Two are reserved just for relaying new frames. The rest are available to the application to consume. I think this minimizes broadcast storms while also avoiding the 5s timer issue SiLabs coordinators end up exposing to the user.

When rate limited, broadcasts are instantly rejected by the stack but the error status now carries information about when you can retry again.

The wire format has been updated and send_aps has been split into three separate commands, one for each send type.


This PR also rolls in a rather large send API refactor. Instead of having all-or-nothing sends (and an async API that treats sends as atomic!), we now have a multi-stage API. It allows for:

  • Synchronous fire and forget requests, where they are queued up without waiting for any confirmation yet still driven to completion/error by the stack in the background.
  • Waiting for a request to be handed off to its next-hop destination.
  • Waiting for a request to be "delivered", having separate semantics for APS ACKs, broadcast neighbor quorum, etc.

I'd like to explore something similar for zigpy, since it represents enqueue failures (i.e. rate limiting or concurrency limits), send failures (i.e. CCA), and delivery failures (i.e. no route, no ACK) separately but allows a consumer to opt into the send guarantee that is appropriate.

@puddly

puddly commented Jul 25, 2026

Copy link
Copy Markdown
Contributor Author

@burmistrzak You asked about a stable wire API. This branch's wire.rs is I think the final state? Let me know if you spot any issues or run into any missing APIs.

@burmistrzak burmistrzak left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking quite good!

From an implementer's perspective, most things can be figured out from wire.rs but stuff like endianness or reserved namespaces/IDs aren't always super obvious.
If not a formal specification, I'd appreciate a few more clarifying comments. 😅

@puddly

puddly commented Jul 25, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for the review. I'm writing up some more documentation and doing one final streamlining pass for the framing, to simplify implementations.

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.

2 participants