Skip to content

Build stable windowed alerts from an MQTT stream

Publish a small sensor stream, expose a tumbling-window blind spot, and produce one stable deduplicated alert from the same evidence.

Data Dora: I want you to trace every alert back to its MQTT event IDs, window rule, and output guard., your practice guide

Data Dora: I want you to trace every alert back to its MQTT event IDs, window rule, and output guard.
Predict the reading, then compare it with the measurement.

Python 3 in your browser (JupyterLite)

Python · no install

Publish a small sensor stream, expose a tumbling-window blind spot, and produce one stable deduplicated alert from the same evidence.

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-09.

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 JupyterLite Python 3.12.7 / Pyodide 0.27.6; Chromium 148.0.7778.96 on 2026-09-10; the tool may have moved on — the text steps are the contract.

  1. 1 Step 1

    Do
    Run `python3 main.py --step 1` and inspect the event contract before processing any reading.
    You will see
    Under `Event contract`, the field table shows `source freezer-7`, `event_second reading time in seconds`, `celsius temperature in Celsius`, and `status valid`.
    Why it matters
    The table makes the source, clock, measurement unit, and status semantics inspectable before any processing decision uses them.
    JupyterLite notebook output for mqtt-windowed-alerts step 1, captured after running the real Python cell.
    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 `python3 main.py --step 2` while connected to the internet; the program publishes six fictional readings to its random MQTT topic.
    You will see
    Under `MQTT messages received`, six `topic payload` lines show r1 through r6 arriving before `Delivery check: every published event ID returned to this subscriber.`
    Why it matters
    Seeing each broker-delivered topic and JSON payload lets the learner verify the source-to-intake handoff behind the final six-of-six count.
    JupyterLite notebook output for mqtt-windowed-alerts step 2, captured after running the real Python cell.
    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 `python3 main.py --step 3` to place all six event IDs into a four-entry recent-history buffer.
    You will see
    The `arrival buffer after arrival` table grows from `r1 r1` to `r6 r3 r4 r5 r6`, followed by the oldest-ID eviction rule.
    Why it matters
    The row-by-row state trace shows exactly when r1 and r2 leave capacity-four state, distinguishing intentional eviction from loss.
    JupyterLite notebook output for mqtt-windowed-alerts step 3, captured after running the real Python cell.
    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 `python3 main.py --step 4` to count the six-event burst in adjacent 60-second tumbling windows.
    You will see
    The window table places `r1@50 r2@52 r3@54` in `[0, 60)` and `r4@60 r5@62 r6@64` in `[60, 120)`, then says the 3-and-3 split hides the burst.
    Why it matters
    Showing boundaries and members proves why neither fixed window reaches six, rather than asking the summary count to explain itself.
    JupyterLite notebook output for mqtt-windowed-alerts step 4, captured after running the real Python cell.
    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 `python3 main.py --step 5` to evaluate a 60-second sliding window beginning at event-second 50.
    You will see
    The `[50, 110)` membership table marks every reading r1 through r6 `YES`, followed by `Rule: alert when the window contains at least 6 readings.`
    Why it matters
    The explicit boundary and six member rows let the learner recompute the alert and compare sliding-window behavior with the split tumbling windows.
    JupyterLite notebook output for mqtt-windowed-alerts step 5, captured after running the real Python cell.
    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 `python3 main.py --step 6` to pass counts 9, 11, 10, 9, 8, and 6 through separate on and clear thresholds.
    You will see
    The state trace reads `9 OFF`, `11 ON`, `10 ON`, `9 ON`, `8 ON`, and `6 OFF`, then names the turn-on and clear rules.
    Why it matters
    Following every input through both thresholds shows how hysteresis holds state through intermediate counts instead of merely reporting two transitions.
    JupyterLite notebook output for mqtt-windowed-alerts step 6, captured after running the real Python cell.
    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 `python3 main.py --step 7` to submit the same warm-run event ID three times to the output guard.
    You will see
    The decision table shows `warm-run-42 EMIT alert` once and `warm-run-42 SUPPRESS duplicate` twice before naming the one-per-ID rule.
    Why it matters
    Showing each candidate and guard decision makes the idempotent side effect auditable across repeated delivery.
    JupyterLite notebook output for mqtt-windowed-alerts step 7, captured after running the real Python cell.
    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. What makes an IoT streaming pipeline reviewable before downstream consumers depend on it?

    Return to the chapter’s knowledge check
  2. After a processor restart, replayed events produce duplicate alerts for the same equipment event. Which part of the pipeline review should be investigated first?

    Return to the chapter’s knowledge check

Caution

The public broker is shared and offers no privacy or availability guarantee. Publish only the fictional readings generated here, never credentials or personal data. Topic randomness reduces accidental cross-talk but is not access control; use an authenticated private broker for real devices.

Return to Building IoT Streaming Pipelines · Browse Labs