Smart Manufacturing

Packaging Line Monitoring: Finding Micro-Stops and Speed Losses with MQTT

Packaging lines lose most of their time in short stops nobody records. This use case shows how to capture every stop and speed change over MQTT and turn them into a micro-stop Pareto.

Packaging line monitoring illustration showing filler, capper, labeler and case packer with micro-stops highlighted on an MQTT-fed timeline
Run this on your own MQTT brokerGet a private, managed MQTT broker on the Free plan and start from ready-made code samples.
Try it free Code samples No card required

Packaging line monitoring is about the stops nobody writes down: a jammed label, a fallen bottle, a case erector waiting for blanks. This use case shows how to capture every stop and speed change on a packaging line over MQTT, classify micro-stops automatically and find the machine that really limits output. You will end up with a simple event model, a working micro-stop detector and a list of what to do with the results.

Why Packaging Lines Hide Their Losses

Packaging lines are chains of fast machines linked by conveyors and accumulation tables. When one machine stops for 20 seconds, the buffer absorbs it and the line keeps going, so nobody logs it. When the same thing happens forty times a shift, the buffer drains, the upstream machine blocks and the line slows down. Manual logs capture the long breakdowns, but the short, frequent stops and the machines running below rated speed are usually invisible on paper.

Those hidden losses are often larger than the breakdowns that get all the attention. Packaging lines are therefore one of the places where automatic data collection pays off fastest: the signals already exist in the machine PLCs, and the pattern only emerges when every event is recorded.

Stop Categories You Need to Separate

Not every stop is the machine's fault. A useful packaging line monitoring system distinguishes:

Category Definition Typical cause
Micro-stop Machine stopped for less than a threshold (often under 2 to 5 minutes), cleared without maintenance Jams, misfeeds, sensor false trips
Breakdown Stop above the threshold or requiring maintenance Mechanical or electrical failure
Starved Machine ready but no product arriving Upstream stop or empty buffer
Blocked Machine ready but output backed up Downstream stop or full buffer
Speed loss Running, but below rated speed Operator reduced speed, unstable infeed
Planned stop Changeover, cleaning, break Scheduled activity

Starved and blocked are the key. A capper that is starved is not a capper problem; it points upstream. Without separating them, every machine looks bad and the real constraint is hidden.

Signals and Message Design

Each machine's PLC usually exposes running, faulted, starved and blocked bits, a speed value and counters. Publish a state event on every change and a periodic counter message:

connectmq/demo/<your-id>/plant2/pack3/<machine>/state
connectmq/demo/<your-id>/plant2/pack3/<machine>/counts
{"state": "STOPPED", "cause": "FAULT", "code": 214, "speed": 0, "ts": 1792140125.42}
{"infeed": 120544, "outfeed": 120391, "reject": 153, "speed": 312, "rated_speed": 400, "ts": 1792140130.0}

Use cause values FAULT, STARVED, BLOCKED and PLANNED when stopped. The fault code comes from the machine's own alarm list, which gives you a reason for many stops without asking operators. Timestamps should be set at the edge with sub-second precision, because micro-stops are short and ordering matters.

A Micro-Stop Detector in Python

This subscriber listens to every machine's state topic, measures each stop duration when the machine restarts, classifies it and publishes a summary event. It also maintains a per-machine tally you could push to a dashboard every minute.

import json
import time
from collections import defaultdict

import paho.mqtt.client as mqtt

PREFIX = "connectmq/demo/p9x2c6/plant2/pack3"
MICRO_STOP_SECONDS = 120

stopped_since = {}  # machine -> (start_ts, cause, code)
tally = defaultdict(lambda: defaultdict(lambda: {"count": 0, "seconds": 0.0}))


def on_connect(client, userdata, flags, reason_code, properties):
    client.subscribe(f"{PREFIX}/+/state", qos=1)


def on_message(client, userdata, msg):
    machine = msg.topic.split("/")[-2]
    event = json.loads(msg.payload)
    ts = event.get("ts", time.time())

    if event["state"] == "STOPPED" and machine not in stopped_since:
        stopped_since[machine] = (ts, event.get("cause", "UNKNOWN"), event.get("code"))
        return

    if event["state"] == "RUNNING" and machine in stopped_since:
        start, cause, code = stopped_since.pop(machine)
        duration = ts - start
        if cause == "FAULT":
            category = "MICRO_STOP" if duration < MICRO_STOP_SECONDS else "BREAKDOWN"
        else:
            category = cause  # STARVED, BLOCKED, PLANNED
        bucket = tally[machine][category]
        bucket["count"] += 1
        bucket["seconds"] += duration
        summary = {
            "machine": machine,
            "category": category,
            "code": code,
            "duration": round(duration, 1),
            "ended": ts,
        }
        client.publish(f"{PREFIX}/{machine}/stop", json.dumps(summary), qos=1)
        print(summary)


client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id="microstop-p9x2c6")
client.on_connect = on_connect
client.on_message = on_message
client.connect("broker.connectmq.com", 1883, keepalive=30)
client.loop_forever()

Test it without a real line by publishing events by hand:

mosquitto_pub -h broker.connectmq.com -p 1883 -i tester-p9x2c6 -t "connectmq/demo/p9x2c6/plant2/pack3/labeler/state" -m '{"state":"STOPPED","cause":"FAULT","code":214,"speed":0,"ts":1792140125.4}'
mosquitto_pub -h broker.connectmq.com -p 1883 -i tester-p9x2c6 -t "connectmq/demo/p9x2c6/plant2/pack3/labeler/state" -m '{"state":"RUNNING","speed":380,"ts":1792140143.9}'

The detector prints an 18.5 second MICRO_STOP for the labeler with fault code 214. Every stop event is now a record you can store, chart and sum by code.

Finding Speed Losses

Stops are half of the story. A line rated at 400 units per minute that runs at 330 to keep a temperamental labeler happy loses capacity every minute it runs, and no stop log shows it. Compare speed against rated_speed in the counts message and accumulate the gap only while the machine is running. A simple daily report of "minutes equivalent lost to speed" per machine is often a surprise: operators reduce speed for good reasons, but those reasons can be fixed once they are visible.

Speed loss and micro-stops together form the performance component of OEE. The OEE calculation guide shows how they combine with availability and quality.

Analysis Checklist: From Data to Action

Once a week of data is collected, work through this list:

  1. Find the constraint. The machine with the least starved and blocked time is usually the bottleneck. Improvements elsewhere do not raise line output.
  2. Pareto micro-stops by machine and fault code. Often a small number of codes cause most of the stops on the bottleneck.
  3. Check the time pattern. Stops clustered after changeovers or at specific times point to setup or material issues.
  4. Look at buffer behaviour. If the bottleneck is frequently starved, the upstream buffer may be too small or the upstream machine too unreliable.
  5. Review speed settings. Compare actual and rated speed for each machine and ask why the gap exists.
  6. Attach reasons to long stops. Micro-stops are explained by fault codes, but breakdowns need a human reason. A structured list of downtime reason codes keeps those entries usable.

Displaying It on the Line

A large screen beside the line with each machine's state, the current micro-stop count for the shift and the top three fault codes changes behaviour quickly, because operators can see the effect of fixing a guide rail or adjusting a sensor within the same shift. The production line monitoring dashboard tutorial shows how to build one from these topics.

Sizing the Data Flow

Packaging lines generate more events than most people expect, so it is worth estimating the message rate before going live. A typical line has five to eight machines. Each publishes a state message on every change and a counts message every few seconds. On a bad shift, a single labeler can stop dozens of times an hour, but even then the total stays modest: a few messages per second for the whole line, each well under a kilobyte.

A few design choices keep it that way:

  1. Publish states on change only. Never poll and republish an unchanged state every 100 ms.
  2. Send counts at a fixed, slow interval. Every five or ten seconds is enough because counts are cumulative.
  3. Keep fault code text out of the payload. Send the numeric code and keep the description table in the analysis service.
  4. Use one client per gateway. A single gateway reading several PLCs can publish all machine topics over one connection, which saves connections on your broker plan.

With that pattern, one ConnectMQ Serverless broker comfortably carries a packaging line, the detector, a historian and a couple of displays, and you can add further lines by extending the topic tree rather than rebuilding anything.

Moving to a Private Broker

Use the public MQTT test broker for the prototype, then move the real line to a private broker so production data is not readable by others. ConnectMQ provides a managed MQTT broker where each PLC gateway, the detector and the dashboard connect with issued credentials over TLS. The free Serverless plan's 25 connections are enough for one packaging line, and the paid plans scale with QoS 2, larger messages and shared subscriptions when you run several detector instances side by side. The broader roadmap is covered in the smart manufacturing guide.

Get Started with ConnectMQ

Sign up at app.connectmq.com, create a free Serverless broker with no credit card, connect your first packaging machine and start counting the micro-stops your line has been hiding.

Frequently Asked Questions

What counts as a micro-stop on a packaging line?

A short stop cleared by the operator without maintenance, typically under a threshold of a few minutes. Pick one threshold for the plant and keep it fixed so trends stay comparable.

Do I need operators to enter reasons for micro-stops?

No. Micro-stops are too frequent for manual entry; use the machine fault codes instead. Reserve operator input for longer stops.

Why separate starved and blocked from faults?

Because a starved or blocked machine is reacting to a neighbour. Counting those as its own downtime hides the real constraint.

How fast must the data be?

State changes should be published immediately with edge timestamps. Sub-second precision is useful because many micro-stops last only seconds.

Related articles

OEE vs TEEP vs OOE: Which Metric Should You Use?

OEE, OOE and TEEP share the same performance and quality factors but measure against different time bases. This comparison works through one example and lists the MQTT signals each metric needs.

7 min read

All articles →

Your private MQTT broker is a few clicks away

Create an account, get your broker credentials and connect your first device — no servers to install, patch or scale.