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

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
    In the JupyterLite notebook, run the Step 1 cell to register devices before routing.
    You will see
    Input: Run python main.py and inspect step 1: register devices before routing. Observed heading: "Register devices before routing" Observed intermediate: "pump-controller-1 site-operations plant-1 v1 0" Observed rule or check: "Also required: sequence message_type quality payload; identity lists are lab policy." Observed result: "STEP 1 registry admitted=2 quarantined=1" Expected from the existing capture: 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. Intermediate evidence: "pump-controller-1 site-operations plant-1 v1 0" gives a value or state to inspect. Comparison cue: "Also required: sequence message_type quality payload; identity lists are lab policy." supplies the rule or adjacent evidence for that check. Result: "STEP 1 registry admitted=2 quarantined=1" records how this input was classified.
    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
    In the JupyterLite notebook, run the Step 2 cell to trace the legacy rr-001 request and response.
    You will see
    Input: Run python main.py and inspect step 2: trace the legacy rr-001 request and response. Observed heading: "Trace the legacy rr-001 request and response" Observed intermediate: "result=ACK running/local_auto sequence=42" Observed rule or check: "Response age=1 s <= freshness rule 2 s; request correlation=rr-001" Observed result: "STEP 2 request response matched" Expected from the existing capture: 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. Intermediate evidence: "result=ACK running/local_auto sequence=42" gives a value or state to inspect. Comparison cue: "Response age=1 s <= freshness rule 2 s; request correlation=rr-001" supplies the rule or adjacent evidence for that check. Result: "STEP 2 request response matched" records how this input was classified.
    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
    In the JupyterLite notebook, run the Step 3 cell to separate timeout, bounded retry and authorization refusal.
    You will see
    Input: Run python main.py and inspect step 3: separate timeout, bounded retry and authorization refusal. Observed heading: "Separate timeout, bounded retry and authorization refusal" Observed intermediate: "t=10 viewer requests stop -> REFUSE authorization: viewer cannot control" Observed rule or check: "The public broker transports telemetry; authorization is local lab policy." Observed result: "STEP 3 retry succeeded; unauthorized control refused" Expected from the existing capture: 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. Intermediate evidence: "t=10 viewer requests stop -> REFUSE authorization: viewer cannot control" gives a value or state to inspect. Comparison cue: "The public broker transports telemetry; authorization is local lab policy." supplies the rule or adjacent evidence for that check. Result: "STEP 3 retry succeeded; unauthorized control refused" records how this input was classified.
    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
    In the JupyterLite notebook, run the Step 4 cell to 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
    In the JupyterLite notebook, run the Step 5 cell to disconnect upstream and persist three events.
    You will see
    Input: Run python main.py and inspect step 5: disconnect upstream and persist three events. Observed heading: "Disconnect upstream and persist three events" Observed intermediate: "45 11 2" Observed rule or check: "Durable queue uses SQLite commit; close/reopen proves records survive connection loss." Observed result: "STEP 5 outage queue persisted=3" Expected from the existing capture: 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. Intermediate evidence: "45 11 2" gives a value or state to inspect. Comparison cue: "Durable queue uses SQLite commit; close/reopen proves records survive connection loss." supplies the rule or adjacent evidence for that check. Result: "STEP 5 outage queue persisted=3" records how this input was classified.
    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
    In the JupyterLite notebook, run the Step 6 cell to replay in sequence and suppress the duplicate.
    You will see
    Input: Run python main.py and inspect step 6: replay in sequence and suppress the duplicate. Observed heading: "Replay in sequence and suppress the duplicate" Observed intermediate: "44 10 20 SUPPRESS duplicate" Observed rule or check: "Advance the queue only in the same transaction as platform acceptance." Observed result: "STEP 6 replay delayed=3 duplicate=1 remaining=0" Expected from the existing capture: 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. Intermediate evidence: "44 10 20 SUPPRESS duplicate" gives a value or state to inspect. Comparison cue: "Advance the queue only in the same transaction as platform acceptance." supplies the rule or adjacent evidence for that check. Result: "STEP 6 replay delayed=3 duplicate=1 remaining=0" records how this input was classified.
    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
    In the JupyterLite notebook, run the Step 7 cell to reject stale commands and invalid translations.
    You will see
    Input: Run python main.py and inspect step 7: reject stale commands and invalid translations. Observed heading: "Reject stale commands and invalid translations" Observed intermediate: "735 /10 73.5 percent ACCEPT" Observed rule or check: "Rule: retain provenance and quarantine out-of-range values; do not clamp." Observed result: "STEP 7 expiry and translation gates PASS" Expected from the existing capture: 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. Intermediate evidence: "735 /10 73.5 percent ACCEPT" gives a value or state to inspect. Comparison cue: "Rule: retain provenance and quarantine out-of-range values; do not clamp." supplies the rule or adjacent evidence for that check. Result: "STEP 7 expiry and translation gates PASS" records how this input was classified.
    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
    In the JupyterLite notebook, run the Step 8 cell to 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 identity decision belongs first in its platform boundary record?

    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