Skip to content

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., your practice guide

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 install

Verify registry admission, request and response, public MQTT fan-out, delayed replay and command refusal.

Tier 2 · Web · paste-in setup · No account

Version tested: Python 3.12.7 / Pyodide 0.27.6 in JupyterLite 0.6.4; Chromium 148.0.7778.96; captured against a local Mosquitto-compatible WebSocket broker because the capture host cannot reach the public broker; the notebook targets test.mosquitto.org; captureSource playwright:jupyterlite. Date: 2026-09-10.

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.

Open in your browser (new tab)

Steps

Screens captured against Python 3 in your browser (JupyterLite) Python 3.12.7 / Pyodide 0.27.6 in JupyterLite 0.6.4; Chromium 148.0.7778.96; captured against a local Mosquitto-compatible WebSocket broker because the capture host cannot reach the public broker; the notebook targets test.mosquitto.org; captureSource playwright:jupyterlite on 2026-09-10; the tool may have moved on — the text steps are the contract.

  1. 1 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.
    JupyterLite step 1 showing the executed Python and its observed result.
    Step 1 · Python 3 in your browser (JupyterLite); numbered callout added to a real capture. Enlarge screenshot (new tab)
  2. 2 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.
    JupyterLite step 2 showing the executed Python and its observed result.
    Step 2 · Python 3 in your browser (JupyterLite); numbered callout added to a real capture. Enlarge screenshot (new tab)
  3. 3 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.
    JupyterLite step 3 showing the executed Python and its observed result.
    Step 3 · Python 3 in your browser (JupyterLite); numbered callout added to a real capture. Enlarge screenshot (new tab)
  4. 4 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.
    JupyterLite step 4 showing the executed Python and its observed result.
    Step 4 · Python 3 in your browser (JupyterLite); numbered callout added to a real capture. Enlarge screenshot (new tab)
  5. 5 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.
    JupyterLite step 5 showing the executed Python and its observed result.
    Step 5 · Python 3 in your browser (JupyterLite); numbered callout added to a real capture. Enlarge screenshot (new tab)
  6. 6 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.
    JupyterLite step 6 showing the executed Python and its observed result.
    Step 6 · Python 3 in your browser (JupyterLite); numbered callout added to a real capture. Enlarge screenshot (new tab)
  7. 7 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.
    JupyterLite step 7 showing the executed Python and its observed result.
    Step 7 · Python 3 in your browser (JupyterLite); numbered callout added to a real capture. Enlarge screenshot (new tab)
  8. 8 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.
    JupyterLite step 8 showing the executed Python and its observed result.
    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.

  1. 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 check
  2. A 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

Caution

Use only fictional data on this public, unencrypted broker. The local allowlist is a teaching policy, not broker access control. QoS 0 has no delivery guarantee; this run verifies exact receipt. If the broker is unavailable, the program exits clearly; rerun later. Retained messages use a unique topic and are deleted after receipt.

Return to M2M Service Platforms · Browse Labs