Trace machine-to-machine device exchange
Verify registry admission, request and response, public MQTT fan-out, delayed replay and command refusal.

Blueprint Bina: I want you to inspect the failed case and the record that explains the next decision.
Predict the reading, then compare it with the measurement.
Python 3 in your browser (JupyterLite)
Python · no installVerify registry admission, request and response, public MQTT fan-out, delayed replay and command refusal.
Open the notebook in your browser and run each Python cell; no install or account is needed.
Three ways to run: use JupyterLite here with no install; run main.py locally from the downloadable lab folder; or open the same notebook in Google Colab.
Steps
Step 1
- Do
- Run python main.py and inspect step 1: register devices before routing.
- You will see
- pump-controller-1 ACCEPT; temperature-1 ACCEPT. STEP 1 registry admitted=2 quarantined=1
- Why it matters
- Admission needs a trusted identity, allowed capabilities and an explicit schema. Unknown devices remain quarantined before normal routing.

Step 1 · Python 3 in your browser (JupyterLite); numbered callout added to a real capture. Enlarge screenshot (new tab) Step 2
- Do
- Run python main.py and inspect step 2: trace the legacy rr-001 request and response.
- You will see
- trace=rr-001 gateway=site-gateway-1 device=pump-controller-1; request read_state sent=2026-01-01T00:00:03Z deadline=00:00:05Z. STEP 2 request response matched
- Why it matters
- The host separates device state from platform acceptance. Correlation, age and target state explain why this specific response may be used.

Step 2 · Python 3 in your browser (JupyterLite); numbered callout added to a real capture. Enlarge screenshot (new tab) Step 3
- Do
- Run python main.py and inspect step 3: separate timeout, bounded retry and authorization refusal.
- You will see
- Logical clock; no sleeping or real actuator commands.; t=6 attempt=1 deadline=8 -> TIMEOUT no response within 2 s. STEP 3 retry succeeded; unauthorized control refused
- Why it matters
- A timeout says no timely answer arrived; a refusal records a policy decision. A bounded retry can recover the first without bypassing the second.

Step 3 · Python 3 in your browser (JupyterLite); numbered callout added to a real capture. Enlarge screenshot (new tab) Step 4
- Do
- Run python main.py and inspect step 4: publish through the real public mqtt broker.
- You will see
- broker=test.mosquitto.org:1883; MQTT 3.1.1 QoS=0 clean-session; topic=iotclass/labs/m2m/<unique-run>/telemetry/temperature. STEP 4 public-broker fanout and late join PASS
- Why it matters
- Decoupled consumers receive the same real broker event. A late subscriber gets last-known state, whose age must still be checked before use.

Step 4 · Python 3 in your browser (JupyterLite); numbered callout added to a real capture. Enlarge screenshot (new tab) Step 5
- Do
- Run python main.py and inspect step 5: disconnect upstream and persist three events.
- You will see
- Local outage simulation: gateway cannot send during t=10..19.; sequence event_time_s persisted_depth. STEP 5 outage queue persisted=3
- Why it matters
- The legacy outage exercise requires three accepted events in durable storage. Closing and reopening SQLite proves the queue is not just a Python list.

Step 5 · Python 3 in your browser (JupyterLite); numbered callout added to a real capture. Enlarge screenshot (new tab) Step 6
- Do
- Run python main.py and inspect step 6: replay in sequence and suppress the duplicate.
- You will see
- sequence original_time received_time decision; 44 10 20 ACCEPT delayed. STEP 6 replay delayed=3 duplicate=1 remaining=0
- Why it matters
- Original event times distinguish delayed telemetry from current readings. A durable unique key prevents repeat delivery from creating duplicate platform records.

Step 6 · Python 3 in your browser (JupyterLite); numbered callout added to a real capture. Enlarge screenshot (new tab) Step 7
- Do
- Run python main.py and inspect step 7: reject stale commands and invalid translations.
- You will see
- cmd-004 expires=15 reconnect=20 -> REFUSE expired command; source=fieldbus-adapter address=register_40011 canonical=tank_level. STEP 7 expiry and translation gates PASS
- Why it matters
- Commands can expire while telemetry remains worth replaying. Translation needs explicit units, scaling and quarantine reasons so bad source values are not hidden.

Step 7 · Python 3 in your browser (JupyterLite); numbered callout added to a real capture. Enlarge screenshot (new tab) Step 8
- Do
- Run python main.py and inspect step 8: keep a diagnostic snapshot and decision record.
- You will see
- gateway=site-gateway-1 signal=simulated-good power=simulated-on; firmware=lab-v1 reboot_count=0 last_error=upstream-outage last_contact=20. STEP 8 validation PASS
- Why it matters
- The diagnostic record binds device identity, gateway health and platform results. It separates what was locally simulated from the public MQTT delivery that actually ran.

Step 8 · Python 3 in your browser (JupyterLite); numbered callout added to a real capture. Enlarge screenshot (new tab)
Chapter checks
These questions refer to the chapter’s examples. Use the return links to review their answers.
A campus platform will onboard ventilation controllers, lighting gateways, energy meters, and maintenance apps. Which first platform boundary record keeps the design traceable?
Return to the chapter’s knowledge checkA gateway translates field-bus readings into platform events. Which records best show the platform boundary is well designed?
Return to the chapter’s knowledge check