Skip to content

Build a live MQTT sensor dashboard

Publish fictional readings through a public MQTT broker, validate the callbacks, and render the latest three values per sensor as a text dashboard.

Broker Bex: I want you to follow each reading from publish to callback, validation, history, and alert before trusting the dashboard., your practice guide

Broker Bex: I want you to follow each reading from publish to callback, validation, history, and alert before trusting the dashboard.
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 connect a subscriber to the one-level sensor wildcard on a unique topic tree.
    You will see
    The terminal names test.mosquitto.org:1883, the run-specific publish root, the /+ subscription, and the rule that + matches exactly one sensor name.
    Why it matters
    A bounded wildcard lets one dashboard consume several sensors without accidentally subscribing to the whole public broker.
    Step 1 terminal capture. A blue ring marks the unique one-level wildcard subscription.
    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 publish seven fictional readings and inspect them in the subscriber callback.
    You will see
    A seven-row table shows sensor, sequence, temperature, QoS, and observation time, followed by Every row above came back through the public broker callback.
    Why it matters
    The received callback rows prove a broker round trip; printing only the publisher's inputs would not prove subscription behavior.
    Step 2 terminal capture. A blue ring marks the statement that the displayed readings came through broker callbacks.
    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 compare valid JSON readings with one deliberately malformed payload.
    You will see
    The validation ledger reports seven accepted messages and one rejected freezer-b payload, not-json, beside the required numeric-field rule.
    Why it matters
    Transport receipt and application acceptance are separate decisions; invalid payloads must not enter the dashboard history.
    Step 3 terminal capture. A blue ring marks the rejected malformed payload.
    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 render the latest accepted value for every sensor.
    You will see
    The dashboard table shows three sensors with latest temperature, sequence, timestamp, and state, followed by the total valid-message count.
    Why it matters
    Keeping ingestion history separate from presentation makes the callback small and lets the view be rebuilt from accepted state.
    Step 4 terminal capture. A blue ring marks the packing sensor's latest dashboard row.
    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 display each sensor's last three accepted readings.
    You will see
    Three compact history rows show seq:value, while the explanation identifies a three-value FIFO window and the next eviction direction.
    Why it matters
    A fixed-length deque bounds memory while preserving enough recent context to see movement rather than one isolated number.
    Step 5 terminal capture. A blue ring marks the three retained freezer-a readings.
    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 evaluate role-specific alert thresholds against the latest values.
    You will see
    The table places each latest value beside either the freezer rule value > -17.0 or the packing rule value > 22.0; all three decisions are ALERT.
    Why it matters
    A temperature number has meaning only with its sensor role and rule, so one universal threshold would be misleading.
    Step 6 terminal capture. A blue ring marks the explanation that thresholds depend on sensor role.
    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 reconcile callback, QoS, validation, and shutdown counts.
    You will see
    The summary accounts for eight callbacks, their QoS levels, seven valid rows, one malformed row, and a clean disconnect, then warns that receipt does not approve a public broker for production commands.
    Why it matters
    Count reconciliation detects silent gaps, while the scope warning keeps a successful teaching round trip separate from production security approval.
    Step 7 terminal capture. A blue ring marks the public-broker scope warning.
    Step 7 · 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 developer prototypes a smart lock system on the unauthenticated port 1883 listener at `test.mosquitto.org` and publishes lock/unlock commands to the topic `smartlock/device123/command`. They plan to ship this to customers. Which statement best explains why this is a critical security risk?

    Return to the chapter’s knowledge check
  2. A temperature sensor in a smart building should only be able to publish its own readings. Which ACL rule best enforces this least-privilege requirement?

    Return to the chapter’s knowledge check

Caution

The public broker is shared: publish only fictional data on the generated topic, never credentials, personal data, actuator commands, or production telemetry. Broker receipt does not prove durable storage or exactly-once application processing.

Return to MQTT Python: Reliable Client Patterns · Browse Labs