Mesh And Zenoh¶
truST uses a Zenoh-backed mesh surface for explicit multi-runtime sharing.
Use this when¶
- you want publish/subscribe-style data sharing between runtimes
- you need explicit control over what a runtime publishes or subscribes to
- discovery alone is not enough because you need live data exchange
Core config surface¶
Mesh is configured in [runtime.mesh] in runtime.toml.
Typical keys:
enabledrolelistenconnecttlsauth_tokenzenohd_versionpublish[runtime.mesh.subscribe]
Example:
[runtime.mesh]
enabled = true
role = "peer"
listen = "127.0.0.1:5212"
connect = []
tls = false
auth_token = ""
zenohd_version = "1.7.2"
publish = ["Status.PLCState"]
[runtime.mesh.subscribe]
"LineB:Status.PLCState" = "Local.Status.RemoteState"
How to think about it¶
- discovery finds peers
- pairing establishes trust/access workflow
- mesh moves selected runtime values between trusted peers
If you need same-host deterministic transport, use Realtime T0 instead. Mesh is not the HardRT path.
Worked tutorial¶
Tutorial 15: Multi-PLC Discovery, Pairing, and Mesh Sharing¶
This tutorial runs two runtimes and walks through:
- network discovery,
- optional pairing,
- mesh data sharing.
Why this tutorial exists¶
Single-PLC workflows are only the start. Real plants often split logic across multiple runtimes. You need a repeatable method to discover peers, trust peers, and exchange selected data safely.
What you will learn¶
- how to configure two runtimes so they can be discovered
- why service names and unique ports matter
- how to enable mesh publish/subscribe with explicit mappings
Prerequisites¶
- complete Tutorial 13 first
- one machine is enough (we will run two runtimes with different ports)
Step 1: Create PLC-A and PLC-B project copies¶
Why: separate project folders simulate real independent PLC nodes.
rm -rf /tmp/trust-plc-a /tmp/trust-plc-b
cp -R /tmp/trust-tutorial-13 /tmp/trust-plc-a
cp -R /tmp/trust-tutorial-13 /tmp/trust-plc-b
Expected result: - two independent project trees
Step 2: Configure unique runtime endpoints¶
Why: each runtime needs unique control/web/mesh endpoints on one host.
Set PLC-A runtime config:
cat > /tmp/trust-plc-a/runtime.toml <<'TOML'
[bundle]
version = 1
[resource]
name = "PlcA"
cycle_interval_ms = 100
[runtime.control]
endpoint = "unix:///tmp/trust-runtime-plc-a.sock"
mode = "production"
debug_enabled = false
[runtime.web]
enabled = true
listen = "127.0.0.1:18101"
auth = "local"
[runtime.discovery]
enabled = true
service_name = "LineA"
advertise = true
interfaces = []
[runtime.mesh]
enabled = true
listen = "127.0.0.1:5211"
auth_token = ""
publish = []
subscribe = {}
[runtime.log]
level = "info"
[runtime.retain]
mode = "none"
save_interval_ms = 1000
[runtime.watchdog]
enabled = false
timeout_ms = 5000
action = "halt"
[runtime.fault]
policy = "halt"
TOML
Set PLC-B runtime config:
cat > /tmp/trust-plc-b/runtime.toml <<'TOML'
[bundle]
version = 1
[resource]
name = "PlcB"
cycle_interval_ms = 100
[runtime.control]
endpoint = "unix:///tmp/trust-runtime-plc-b.sock"
mode = "production"
debug_enabled = false
[runtime.web]
enabled = true
listen = "127.0.0.1:18102"
auth = "local"
[runtime.discovery]
enabled = true
service_name = "LineB"
advertise = true
interfaces = []
[runtime.mesh]
enabled = true
listen = "127.0.0.1:5212"
auth_token = ""
publish = ["Status.PLCState"]
subscribe = {}
[runtime.log]
level = "info"
[runtime.retain]
mode = "none"
save_interval_ms = 1000
[runtime.watchdog]
enabled = false
timeout_ms = 5000
action = "halt"
[runtime.fault]
policy = "halt"
TOML
Expected result:
- both runtimes are discoverable
- PLC-B publishes one mesh point (Status.PLCState)
Step 3: Build both projects¶
Why: each node still needs valid bytecode before it can run.
trust-runtime build --project /tmp/trust-plc-a --sources /tmp/trust-plc-a/src
trust-runtime build --project /tmp/trust-plc-b --sources /tmp/trust-plc-b/src
Expected result:
- program.stbc exists in both folders
Step 4: Start both runtimes¶
Why: discovery and mesh only work when both nodes are online.
Terminal A:
trust-runtime run --project /tmp/trust-plc-a
Terminal B:
trust-runtime run --project /tmp/trust-plc-b
Expected result:
- PLC-A Web UI on http://127.0.0.1:18101
- PLC-B Web UI on http://127.0.0.1:18102
Step 5: Verify discovery from Web UI¶
Why: discovery is the first proof that nodes can see each other on the network.
- Open PLC-A Web UI (
http://127.0.0.1:18101). - Go to
Network -> Discovery. - Confirm
LineBappears.
Expected result: - PLC-B is listed with reachable link
If discovery fails:
- verify both runtimes are running
- verify runtime.discovery.enabled = true
- use manual add with PLC-B URL (127.0.0.1:18102)
Step 6: Pair nodes (optional but recommended)¶
Why: pairing is a safer trust workflow than sharing static credentials manually.
- In PLC-B, open
Network -> Pairingand generate a code. - In PLC-A, claim PLC-B using that code.
Expected result: - PLC-A can access PLC-B without repeated token prompts
Step 7: Configure mesh subscription on PLC-A¶
Why: publish/subscribe must be explicit so only intended data flows between runtimes.
Edit /tmp/trust-plc-a/runtime.toml and replace subscribe = {} with:
[runtime.mesh.subscribe]
"LineB:Status.PLCState" = "Local.Status.RemoteState"
Restart PLC-A after edit.
Expected result: - PLC-A subscribes to PLC-B status
Step 8: Verify mesh connection¶
Why: operational confidence requires observing active mesh links, not just configuration files.
- Open PLC-A Web UI.
- Go to
Network -> Mesh connections. - Confirm connection to
LineBis present.
Expected result: - mesh link appears as connected/healthy
Common mistakes¶
- same web or mesh ports for both PLCs
- service name mismatch (
LineBin config vs actual runtime name) - editing
runtime.tomlwithout restarting runtime
Completion checklist¶
- [ ] PLC-A and PLC-B both running
- [ ] discovery shows peer runtime
- [ ] optional pairing completed
- [ ] mesh publish/subscription configured
- [ ] mesh connection observed in UI