feat(052): runtime-neutral MQTT connector - #253
Merged
Merged
Conversation
… Embedded backends
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
`Self::tls` is `embassy-tls`-gated, but `make doc` builds this crate with `embassy-runtime` only, so the link failed the docs gate in CI. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…hance documentation
- Implemented a new `manager` module to handle per-session broker state, event handling, and message pumping. - Updated `MqttConnector` to support `Delay` and `StreamDialer` traits for embedded systems. - Refactored `MqttSink` and `MqttSource` to use action and event channels directly, removing unnecessary wrappers. - Introduced `ClientDelay` to bridge core's `Delay` with the MQTT client's requirements. - Enhanced the `run_sessions` function to manage MQTT sessions more effectively, ensuring reconnections and resubscriptions. - Updated tests to ensure proper session reconnection and resubscription behavior. - Adjusted Tokio adapter to implement `Delay` for seamless integration with the connector.
…ial support - Consolidated the MqttConnector structure to allow seamless switching between Native and Embedded backends without separate builders. - Introduced credential handling in the Native backend, allowing credentials to be set via the MqttConnector interface. - Updated the Embassy client to streamline the transport setup and improve TLS handling. - Enhanced tests to verify credential transmission for both backends, ensuring consistent behavior across different configurations. - Removed deprecated builder patterns and unnecessary complexity in the connector implementation.
- Implement SNTP codec for encoding and parsing SNTP packets, including request and reply handling. - Introduce TLS transport for the Embassy MQTT client, supporting secure connections with certificate verification. - Refactor the library structure to separate native and embedded implementations, enhancing modularity. - Update the MQTT connector to support both plain and secure MQTT connections, with appropriate error handling and logging.
- Introduced a new feature `_test-tls-broker` for testing MQTT over TLS with a pinned self-signed root CA. - Updated the Makefile to include new test commands for the MQTT connector with TLS. - Modified `Cargo.toml` to add dependencies for embedded TLS and SNTP. - Refactored the `EmbeddedTls` struct to use a caller-supplied transport instead of owning the network stack. - Implemented a new `WallClock` for certificate validity checks in the absence of an RTC. - Created a new test `tls_broker.rs` to validate the MQTT handshake over TLS. - Updated the example to demonstrate the use of MQTT over TLS with SNTP for time synchronization.
…ges and enhanced features for std and no_std runtimes
…ated docs `make doc` runs `cargo doc` per feature leg with `-D warnings`, so an intra-doc link that resolves on one leg and not another fails the build. Five such links had crept in: - `[Embedded]` in the ungated backend table, which only exists with the embedded backend - `[build]` and `[WallClock]`, both private - `[SntpClock]`, deleted when the TLS clock became the runtime's - `[sntp]`, now `embassy-tls`-gated while `tls.rs` is `embedded-tls` The `doc` target only covered `std` and `embassy-runtime`, which is why only the first two reached CI; add the `embedded`, `embedded-tls` and `embassy-tls` legs so the rest cannot recur silently. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Brings in the runtime-neutral TCP, serial and KNX connectors (#250, #251, #252) alongside this branch's runtime-neutral MQTT work. Conflicts resolved: - Makefile (`doc` target): kept this branch's MQTT doc legs (`std`, `embassy-tls`) and took main's KNX legs, which move off the deprecated `tokio-runtime`/`embassy-runtime` aliases to `std`/`connector`, plus its new serial and TCP embedded legs. - aimdb-embassy-adapter/CHANGELOG.md: both Unreleased entries kept - the `Delay for EmbassyTcpDialer` addition and main's `EmbassyUdpBinder::bind` `TransportError::Busy` fix are independent. - aimdb-embassy-adapter/src/net.rs: took main's `EmbassyTcpDialer` doc paragraph on `Clone` sharing the socket (docs only, no code change). Verified: make doc, make fmt-check, make clippy, the three thumbv8m example builds, and the core/embassy-adapter/MQTT/KNX/serial/TCP test legs of `make test` all pass. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016YAJUWDFEi3TeBgVEYA5Bs
- Updated `StreamDialer::connect` to accept hostnames and IP literals, enabling DNS resolution in `EmbassyTcpDialer`. - Modified `EmbassyTcpDialer` to include a DNS query mechanism for hostname resolution. - Updated changelog to reflect breaking changes and required adjustments for users. - Added tests to ensure hostname resolution works correctly across both embedded and native backends. - Adjusted resource allocation in examples and other components to accommodate the new DNS feature.
- Updated Clippy commands in the Makefile to reflect changes in the MQTT connector's features and targets. - Changed descriptions for Clippy runs to better represent the current configurations. --- Update CHANGELOG.md for aimdb-mqtt-connector - Documented significant changes including protocol backend updates, removal of deprecated features, and improvements in error handling. - Added details about the new `MqttConnectorBuilder` API and adjustments in the session management. --- Modify README.md for aimdb-mqtt-connector - Updated example usage to reflect the new API structure for the MQTT connector. - Adjusted import statements to align with the latest changes in the library. --- Update lib.rs documentation for aimdb-mqtt-connector - Revised documentation to clarify the usage of the embedded and TLS features. - Enhanced descriptions of the API and its components. --- Revise CHANGELOG.md for aimdb-tokio-adapter - Clarified the addition of `Delay` for `TokioTcpDialer` and its implications for the embedded MQTT backend. --- Revise README.md for embassy-mqtt-connector-demo - Updated the demo example to reflect the new connector API and usage patterns. - Clarified hardware requirements and resource links. --- Update main.rs for embassy-mqtt-connector-demo - Adjusted import statements to align with the latest changes in the MQTT connector library.
…bassy and Tokio adapters
- Introduced a new session loop in `session_loop.rs` that operates on an event-driven model, replacing the previous polling mechanism. - The new loop efficiently manages reading and writing operations without contention, ensuring that no partially-read packets are discarded. - Added support for handling multiple futures concurrently using `select3`, allowing for improved responsiveness to incoming data and actions. - Implemented a structured approach to manage MQTT packets, including connection, subscription, and publish actions, with appropriate error handling. - Created a comprehensive test suite in `session_loop.rs` to validate the behavior of the new session loop against various scenarios, ensuring it meets the specified design criteria. - The tests cover idle session behavior, handling of partial packets, QoS 1 publish acknowledgments, and the interaction between inbound and outbound traffic under load.
- Added a scripted broker implementation in `common/mod.rs` to simulate various broker behaviors during tests. - Introduced `CountingDialer` to track sleep calls made by the session. - Refactored session loop tests in `session_loop.rs` to utilize the new scripted broker. - Created a new test file `tls_session.rs` to validate MQTT over TLS, ensuring session behavior aligns with design criteria. - Implemented tests for idle session wake-up, handling partial packets, and ensuring pings are sent during slow PUBACKs over TLS.
…d-hal-async dependencies; enhance session handling and add ByteStream::split support
- Updated comments in `sntp.rs` to clarify the purpose of SNTP for Unix time synchronization. - Simplified and clarified documentation in `tls.rs`, focusing on the TLS transport and its interaction with the MQTT client. - Enhanced clarity in `native.rs` regarding the broker connection setup and the role of the `MqttConnectorImpl`. - Improved comments in `backend_parity.rs` and `common/mod.rs` to better explain the purpose of tests and the behavior of the fake broker. - Streamlined documentation in `embassy_broker.rs` to focus on the interaction between `embassy-net` stacks and the fake broker. - Clarified the behavior of the session loop in `session_loop.rs` and `tokio_broker.rs`, emphasizing reconnect and subscription logic. - Updated `net.rs` to improve the explanation of stream splitting and its implications for locking and deadlock prevention.
…larity on packet handling and limits
… pushes are acknowledged
…thentication details
…s-webpki, and spin
…re consistency across backends
…meters for MQTT connections
…idation in build process
…s for property handling
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Wave C of design 052, plus the event-driven session rewrite that came out of it.
The split is now std vs
no_std, not Tokio vs Embassy: the embedded backend runs on any target whose adapter supplies aStreamDialer, so a FreeRTOS port costs one adapter crate and no change here.Why MQTT keeps two protocol clients
Unifying on
mountain-mqttwas considered and rejected: it does not support QoS 2 (Qos2NotSupported; the codec haspubrec/pubrel/pubcomp, the state machine does not use them).rumqttccannot ride the neutral layer either — itsTransportis a closed enum, so no stream can be injected.So one
MqttConnector<B>over two backends, which keeps unification a later, small change: if QoS 2 lands in the fork, deletingNativeis a deletion, not a rewrite.Native(no transport supplied)rumqttc(std)Embedded<D>(.transport(..))mountain-mqtt(no_std)embedded-tlsThe session is event-driven — nothing polls
The old loop woke every 10 ms to ask three sources whether they had work, which on a battery node is the only state that normally runs. Worse, the "non-blocking peek" it polled with could block indefinitely, parking the loop and with it the pings, the liveness check and every queued publish.
The stream is now split into halves driven by three futures in one
select: a reader lifting bytes off the socket, a writer draining encoded packets, and the session itself on two channels and one timer.tests/session_loop.rsasserts an idle session wakes fewer than 30 times in 3 s where the poll cost ~300, and that a QoS 1 publish no longer spins waiting inline for its PUBACK.TLS runs that same loop.
mqtts://used to need a loop of its own because the client wanted a readiness peek a TLS session cannot answer honestly — bytes on the wire may decrypt to no application data at all. Nothing peeks any more, so the bespokeConnection, the readiness probe onto the raw socket beneath the TLS session, and theRefCellwrapping the whole socket so both could reach it are gone. What replaces them is one lock per direction behind a cloneable handle.mountain-mqttis now the codec alone —default-features = false, no features, onaimdb-mountain-mqtt0.5.1 (upstreammain, zero-line source delta). The driver half lives here. A Makefilecargo treeguard asserts the subtree stays codec-only and that no executor, network stack, adapter or logger reaches theembeddedgraph.Breaking
Features rename.
stdcarriesrumqttc(tokio-runtimeis a deprecated alias, still works);embeddedcarriesmountain-mqttwithalloconly;embedded-tlsis runtime-neutral TLS;embassy-runtimeandembassy-tlsare convenience bundles over those.critical-section-std-impllinks acritical-sectionimpl for std binaries.Modules rename with no compatibility re-export:
tokio_client→native,embassy_client→embedded. A shim would have been theatre — the builders those modules held are gone too, so the old import fails either way.The Tokio path is otherwise unchanged —
MqttConnector::new(&url)still. Embedded callers supply the transport:.tls(dialer, options)replaces.tls(stack, options). The certificate-validity clock comes fromRuntimeOps::unix_time(); SNTP is opt-in viaTlsOptions::with_sntpfor a runtime with no wall clock of its own.MqttConnectorBuilderand theTokio*/Embassy*aliases are gone;with_client_id/with_credentialsnow work on either backend.The largest MQTT packet the session can receive is 3328 bytes (was 4096). Reassembly, read scratch and the inbound slot are carved out of one
BUFFER_SIZErather than added to it, with one read chunk held in reserve so a chunk completing one packet can still carry the head of the next. Outbound packets are encoded to exactly their own size on the heap, so they gain no fixed cap.Core and adapters
ByteStream::split, withByteRead/ByteWrite(aimdb-core) — borrows a stream into independently pollable halves, which a single&mutstream cannot express. Both adapters implement it. The cancellation contract is written down with it:readis cancel-safe on both adapters AimDB ships,write_allis cancel-safe nowhere and must never sit in aselectarm.EmbassyTcpDialerresolves hostnames, so the adapter'snetfeature now enablesembassy-net/dns.embassy_net::newadds the resolver socket itself, so every application usingnetmust grow itsStackResources<N>by one; too small anNpanics at stack construction. Previously a connector handing through a hostname dialed fine on Tokio and failed forever on Embassy.aimdb-tokio-adaptergains anembedded-iofeature — theembedded-io-asynctrio on thenetstreams, including a non-destructiveReadReadyviapoll_peek. That is what lets the embedded backend andembedded-tlsrun on a host, so both are covered by real tests rather than a cross-compile alone.Both dialers also implement
Delay, so a connector generic over one needs no separate clock handle.Fixed during review
try_send-and-forget, so a coalesced burst lost every response past the fourth — measured at 19 of 40 acknowledged. Unrecoverable: the client state had already retired the message, and pings kept the liveness watchdog satisfied, so the node went deaf on inbound QoS 1 with no error and no reconnect. Protocol obligations now wait for a slot; only pings are still dropped, since a ping arms no response deadline.every_qos1_push_is_acknowledgedis the regression test.qos=2diverged silently between backends —Nativehonours it,Embeddeddowngrades to QoS 1. The build now names each such route in a warning.?qos=query on the link URL, whichLinkAddress::parsestrips, so every test ran at the default regardless. Both now use.with_qos(..).embedded-hal-asyncwas a dead manifest entry; the TLS locking comment pointed at a test file that did not exist.Not addressed
with_config("qos", "two")) falls to the default on both backends identically. Consistent, so not a divergence — worth its own pass if route-URL typos bite.Verification
Locally: all connector tests across six binaries, the
aimdb-coresession suite, clippy-D warningson thestd,embedded,embedded,tracingandembassy-runtime,embassy-tls,defmtlegs (thumbv7em where applicable), rustdoc-D warningsper feature leg, andcargo fmt --check. The full matrix is CI's.🤖 Generated with Claude Code