Tutorial — From zero to a live site bus
By the end you’ll have a bridge relaying a device’s Unified-Namespace traffic onto a second broker
that stands in for the site UNS bus, and you’ll have watched telemetry go up, a command come down,
and a request/reply round-trip cross the bridge intact. No cloud, no hardware — two local MQTT brokers and
cargo.
The whole point of the bridge only becomes visible when there are two brokers: a device bus that a component publishes to, and a site bus that a consumer subscribes to. So the first thing we do is stand up both.
1. Prerequisites
Section titled “1. Prerequisites”- Rust (stable) and
cargo. - Docker, for two throwaway EMQX brokers.
- An MQTT CLI such as
mosquitto_subor MQTTX is useful for watching topics. Normal edgecommons payloads are protobuf bytes, so a plain MQTT CLI cannot handcraft or inspect them as JSON. - This repo checked out, buildable against the sibling
edgecommonslibrary (the gitignored.cargo/config.toml[patch]override — see the repoREADME.md).
2. Start two brokers
Section titled “2. Start two brokers”The device bus on :1883 and the site bus on :1884 — the layout the bundled
test-configs/config.json expects:
docker run -d --name uns-device-broker -p 1883:1883 emqx/emqxdocker run -d --name uns-site-broker -p 1884:1883 emqx/emqxThink of :1883 as “the broker on this one device” and :1884 as “the plant-wide bus every device
bridges onto.”
3. Run the bridge
Section titled “3. Run the bridge”cargo run -- --platform HOST --transport MQTT ./test-configs/config.json \ -c FILE ./test-configs/config.json --thing gw-01You should see it (in order): initialize the edgecommons runtime against the device bus, share the
runtime’s device-bus provider for the relay, derive the private site Last-Will from the bridge’s state
topic, connect to the site broker, subscribe its uplink filters, and log relay running. The device
identity is gw-01 (from --thing); the bundled config places it at dallas/gw-01 via hierarchy/identity.
Leave it running. It is now doing three things at once: mirroring its own health onto both buses, pumping device traffic up to the site broker, and listening for commands to bring down.
4. Watch the bridge announce itself (uplink, the easy case)
Section titled “4. Watch the bridge announce itself (uplink, the easy case)”The bridge is a edgecommons component, so it emits its own heartbeat state keepalive — which matches its
own uplink filter and therefore rides its own relay to the site bus. Subscribe the whole UNS state
class on the site broker (:1884):
mosquitto_sub -p 1884 -t 'ecv1/+/+/state' -t 'ecv1/+/+/+/state' -vWithin ~5 s you’ll see ecv1/gw-01/uns-bridge/state arrive on the site broker even though the
bridge published it on the device broker. The payload is a protobuf EdgeCommonsMessage, so the CLI may show
binary output rather than readable JSON. After decode, the diagnostic projection includes
tags._relay: ["gw-01/uns-bridge"] — the hop tag the bridge stamped as it forwarded. That tag is the bridge’s
loop protection and its “which path did this take” breadcrumb.
5. Send telemetry up with a real EdgeCommons producer
Section titled “5. Send telemetry up with a real EdgeCommons producer”Normal UNS messages are protobuf EdgeCommonsMessage bytes on the wire. Do not use
mosquitto_pub -m '{"header":...}' as a shortcut: that sends JSON text, not protobuf, and the bridge correctly
drops it as MalformedEnvelope.
Use any EdgeCommons component/client to publish a data message on the device bus (:1883) to a topic
such as ecv1/gw-01/opcua-adapter/kep1/data/Temperature. If the application payload is opaque bytes, put them
in the message’s opaque body with a content type; the bridge will preserve those body bytes while it appends
the hop tag to envelope metadata.
Your state subscriber won’t see it (wrong class), so open a second subscriber on the site broker for
the data class:
mosquitto_sub -p 1884 -t 'ecv1/+/+/+/data/#' -vPublish the reading from the EdgeCommons producer. It appears on the site broker on the identical topic — that’s what “topic-verbatim” means — with the hop tag appended after protobuf decode/re-encode. Foreign payloads that are not protobuf EdgeCommons messages do not relay on these normal UNS paths.
6. Watch commands on the device bus
Section titled “6. Watch commands on the device bus”Watch both topic scopes on the device broker in another terminal:
mosquitto_sub -p 1883 -t 'ecv1/gw-01/+/cmd/#' -t 'ecv1/gw-01/+/+/cmd/#' -vThe payloads are protobuf bytes. Both downlink filters are pinned to gw-01; commands for another
device do not reach this device bus.
7. Verify a request/reply round trip
Section titled “7. Verify a request/reply round trip”Install ec-uns-cmd and put it on PATH. Run this
command against the site broker. The bridge’s own runtime on the device bus answers ping;
the relay proxies its reply back to the site-side caller:
ec-uns-cmd --broker localhost:1884 --device gw-01 --component uns-bridge ping --timeout 10The tool subscribes before publishing and prints the successful reply’s result as JSON. The device
watcher sees the downlink cmd; its decoded reply_to names a bridge-minted device-bus topic.
The bridge forwards the first reply to the original site reply topic and removes that temporary
subscription. A timeout is a failed check, not evidence of success.
cargo test covers the pure relay rules without brokers. The dual-broker harness in tests/e2e/
is a separate live gate; consult DESIGN.md for its validation record before relying
on old results. This documentation review did not rerun it.
8. See the disconnect story
Section titled “8. See the disconnect story”Stop the site broker (docker stop uns-site-broker) and publish a couple of protobuf evt messages and a
couple of protobuf data messages on the device bus. The bridge logs that the site link is down: the data
messages are
dropped, but the evt messages are buffered in a bounded memory-only queue. Overflow evicts
the oldest event, and process exit loses the queue. Start the site broker again (docker start uns-site-broker); on the
reconnect rising edge the bridge publishes its two rehydration broadcasts on the device bus and then
replays the buffered evt, in order, to the site broker. Watch your site-side evt subscriber
(ecv1/+/+/evt/# and ecv1/+/+/+/evt/#) to see them arrive after the reconnect.
9. Shut down cleanly
Section titled “9. Shut down cleanly”Ctrl-C the bridge. It aborts its pumps and unsubscribes every filter on both brokers before exiting
(the unsubscribe-before-exit rule), then logs a one-line tally: uplinked, downlinked, loop-dropped,
replies relayed/expired, per-reason drops, evt replayed. Tear the brokers down with
docker rm -f uns-device-broker uns-site-broker.
Next: the how-to guides for the real tasks (site TLS, per-class policy, the reply paired-knob, multi-bridge topologies, deployment); the reference for every option, topic, and metric; the explanation for the model behind all of it.