Skip to content

umqtt.simple: Encode subscribe Remaining Length as VBI.#1142

Open
pablogventura wants to merge 4 commits into
micropython:masterfrom
pablogventura:umqtt-subscribe-remaining-length
Open

umqtt.simple: Encode subscribe Remaining Length as VBI.#1142
pablogventura wants to merge 4 commits into
micropython:masterfrom
pablogventura:umqtt-subscribe-remaining-length

Conversation

@pablogventura

@pablogventura pablogventura commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes #969. subscribe (and unsubscribe) packed Remaining Length with
struct.pack_into("!BH", ...), so values above 127 overflow a single byte
and long topics fail on the wire.

MQTT 3.1.1 section 2.2.3 requires a Variable Byte Integer. This PR encodes
Remaining Length that way for subscribe/unsubscribe, sharing a small
_encode_len helper with connect and publish.

Testing

  • Unix port: micropython micropython/umqtt.simple/test_umqtt_simple.py
    (mock socket, no broker):
    • short topic (single-byte Remaining Length)
    • subscribe with topic length 123 (Remaining Length 128 -> 82 80 01)
    • unsubscribe with topic length 124 (Remaining Length 128 -> a2 80 01)
  • simple.mpy via mpy-cross vs upstream/master: 2512 -> 2515 bytes (+3).

Trade-offs and Alternatives

  • Subscribe and unsubscribe share _send_subunsub; Remaining Length encoding
    is factored into _encode_len and reused by connect/publish to keep .mpy
    size close to master.
  • unsubscribe is included because it had the same one-byte Remaining Length
    bug.

Generative AI

I used generative AI tools when creating this PR, but a human has checked the
code and is responsible for the code and the description above.

Use the same variable-byte Remaining Length encoding as publish for
subscribe and unsubscribe so long topics no longer overflow a single
length byte. Fixes micropython#969.

Signed-off-by: Pablo Ventura <pablogventura@gmail.com>
@dpgeorge

Copy link
Copy Markdown
Member

Thanks for the fix.

Can you try and reduce compiled .mpy code size here? Eg by creating a helper function, or even combining subscribe and unsubscribe into one helper function.

Factor Remaining Length VBI and ACK wait into _send_subunsub to reduce
.mpy size after the long-topic fix.

Signed-off-by: Pablo Ventura <pablogventura@gmail.com>
@pablogventura

pablogventura commented Jul 20, 2026

Copy link
Copy Markdown
Contributor Author

Thanks. I combined the shared path into _send_subunsub() in 51bbbaa (subscribe/unsubscribe now just set type, ACK opcode, and optional QoS).

simple.mpy sizes with mpy-cross vs upstream/master:

Version bytes vs master vs previous commit
master 2512 - -
first fix (duplicated VBI) 2658 +146 -
_send_subunsub helper 2568 +56 -90

Unix mock tests still pass.

Factor the Variable Byte Integer encoder into a module helper and reuse it
from connect, publish, and the subscribe/unsubscribe path to cut .mpy size.

Signed-off-by: Pablo Ventura <pablogventura@gmail.com>
@pablogventura

Copy link
Copy Markdown
Contributor Author

Thanks again. Further size pass in the latest commit: shared _encode_len() used by connect, publish, and _send_subunsub.

simple.mpy sizes with mpy-cross (compiled as simple.py in umqtt/):

Version bytes vs master vs previous
master 2512 - -
first fix (duplicated VBI) 2658 +146 -
_send_subunsub 2568 +56 -90
shared _encode_len 2515 +3 -53

Unix mock tests still pass.

Use ack_n to decide whether to include the QoS byte so ruff E711 passes
without growing the compiled .mpy size.

Signed-off-by: Pablo Ventura <pablogventura@gmail.com>
@pablogventura

Copy link
Copy Markdown
Contributor Author

Fixed the ruff E711 failure: _send_subunsub now uses ack_n > 3 instead of comparing qos to None (subscribe ACK is 4 bytes, unsubscribe is 3).

.mpy size unchanged: 2515 bytes (+3 vs master).

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.

MQTT subscribe Remaining Length encoding is incorrect

2 participants