Packaging Hall
A soft drink packaging hall with three identical 500 mL PET lines at 400 bottles a minute, all running from one syrup room, one compressor set and one CIP skid. 18 devices and 293 tags over Modbus TCP.
Operator view | port 4021 |
|---|---|
Protocol server | port 5031 |
Devices and tags | 18 devices, 293 tags |
Litmus Edge driver | Modbus TCP |
Image | food-beverage-multiline-demo |
Overview
A single line cannot show what goes wrong when three lines share one set of utilities. Each line here is filler, capper, labeler, checkweigher and case packer, and every line runs the same SKU at the same nominal rate. The three shared assets are their own ISA-95 area, separate from the lines:
Shared asset | What it serves |
|---|---|
Syrup room and product ring main | one transfer pump feeding all three fillers |
Compressed air plant | three compressors and one receiver, shared by all three lines and the CIP skid |
CIP skid | one skid, three lines, each due for a clean on its own clock |
Three of the five scenarios start in a shared asset, so they arrive on every line at once and cannot be traced from any single line's data. The other two are confined to one line, with two healthy lines beside it for comparison.
Scenarios
Shared-utility contention. The product header pressure depends on how many lines are drawing, and no line publishes it. The fillers need 2.60 bar. With a worn pump impeller the header holds 2.80 bar at two lines and falls to about 2.18 bar at three, so the fault costs nothing until the third line starts. In six minutes that is 166 rejected bottles against 17 on a healthy pump. Each filler then lengthens its fill time to hold its mean, and when the sag clears, or a line is simply stopped, that trim is left standing: giveaway rises on every line, including the two that were never affected, a minute after the cause has gone.
Loose caps on every line at once. The compressed air plant carries three lines and the CIP skid with a small margin. Trip one compressor and two lines still fit. Run three and the header falls below 6.20 barg, every pneumatic capping head delivers under its setpoint, and 37 percent of caps go out below the 1.35 Nm seal minimum on all three lines, with 7 rejects. A loose cap weighs the same as a good one, so it passes the checkweigher. The only tag that reports it is the capper's LowTorqueCount, and the cause is on a different device.
CIP scheduling and verification. One skid serves three lines, so a clean is a resource a line waits for, and a wait past the clean window is a compliance event rather than a rate loss. When the caustic wash runs cold, the cycle completes normally and fails verification, and the line rejoins the queue behind whoever is already waiting. The overdue time grows with each failed cycle until the line misses its window, without any schedule causing it.
Which line to walk to first. With one SKU and one nominal rate, the difference between the three lines is the plant rather than the product. The operator view ranks them worst first by OEE and names the dominant loss. Labeler wear on line 3 widens the OEE spread from about 1.5 to about 10.3 points, and the ranking says "line 3, availability" rather than only "line 3".
Tag names
Every device carries the same PackML block: UnitMode, State, StopReasonCode, EquipmentBlocked, EquipmentStarved, ProdProcessedCount, ProdDefectiveCount, CurMachSpeed, DesMachSpeed and AccStoppedTime. Each machine adds its own tags, for example FillPressure and FillTimeMs on the filler, TorqueApplied and AirPressure on the capper, MeanNetWeight and RejectCount on the checkweigher.
Device names are the line and the machine: PL2_Capper is the capper on line 2, and PU1_SyrupRoom, PU1_AirHeader and PU1_CipSkid are the shared assets. The shared assets carry the plant numbers no line publishes, such as LinesDrawing and HeaderPressure on the syrup room, TotalDemand and CompressorsRunning on the air plant, and ServingLine and QueueDepth on the CIP skid.
What it creates on Litmus Edge
Component | Created |
|---|---|
DeviceHub | 18 devices on the Modbus TCP driver, 293 tags |
Digital Twin | 9 models, 21 instances |
Analytics | 5 groups, 23 processors |
Five machine models are instantiated once per line, the three shared assets have one model each, and a PackagingLine model has one instance per line whose attributes come from five different devices. A fourth line would add six instances and no new models.
Analytics group | Computes |
|---|---|
Utility Contention | product header margin against lines drawing, and air header margin against demand and running capacity |
Cap Integrity | applied cap torque against the seal minimum, per line |
Plant Giveaway | mean net weight over the declared weight, per line |
CIP Verification | caustic wash temperature against its limit, and which line the skid was cleaning |
Line Availability | filler downtime by line |
Cap Integrity, Plant Giveaway and Line Availability each run one processor chain across all three lines, scoped by the tag name, so they do not grow when a line is added.
Requirements
- Litmus Edge 4.0.x, reachable over HTTPS from the host running the solution
- An API token for that Edge, or a username and password, or a client id and secret
- Docker, and Docker Compose for the compose deployment
- A network path in both directions: the solution reaches the Edge's API, and the Edge reaches this host on port 5031
Deploy
The solution ships two ways. Use the registry if the host can reach Google Artifact Registry, and the downloaded archive if it cannot.
Option 1: pull from the registry
Requires a read-only registry credential, supplied by Litmus separately.
cat key.json | docker login -u _json_key --password-stdin https://us-docker.pkg.devSave this as docker-compose.yml:
services:
packaging-hall:
image: us-docker.pkg.dev/litmus-customer-facing/litmus-solutions/food-beverage-multiline-demo:0.5.0
container_name: food-beverage-multiline-demo
restart: unless-stopped
ports:
- target: 4021
published: 4021
protocol: tcp
- target: 5031
published: 5031
protocol: tcp
environment:
# Fill these in.
EDGE_URL: "${EDGE_URL:-}"
EDGE_API_TOKEN: "${EDGE_API_TOKEN:-}"
SIM_HOST: "${SIM_HOST:-auto}"
APPLY_ON_START: "${APPLY_ON_START:-1}"
EDGE_VERIFY_TLS: "${EDGE_VERIFY_TLS:-0}"
HTTP_PORT: "4021"
MODBUS_PORT: "5031"
AUTOSTART: "1"
TICK_SECONDS: "0.2"
SEED: "7"
LOG_LEVEL: "INFO"Put the three values in a .env file beside it:
EDGE_URL=https://10.0.0.5
EDGE_API_TOKEN=your-token
SIM_HOST=10.0.0.9docker compose up -dOption 2: load the downloaded archive
Download food-beverage-multiline-demo-0.5.0-amd64.tar.gz from the solution's page on portal.litmus.io. The archive is the container image, not a source bundle, and needs no registry access.
docker load -i food-beverage-multiline-demo-0.5.0-amd64.tar.gzdocker load prints the image it added:
Loaded image: us-docker.pkg.dev/litmus-customer-facing/litmus-solutions/food-beverage-multiline-demo:0.5.0That reference is the one the compose file above already names, so the same docker-compose.yml and .env now work offline with no docker login:
docker compose up -dOpen http://localhost:4021. Within about a minute the Edge is configured and the page fills in.
The page stays on its waiting panel until the Edge carries this solution's devices. That is deliberate: the simulation does not tick and no value is shown until Litmus Edge is verified to hold the devices and poll them, so nothing on screen can be mistaken for data that never made the trip. With APPLY_ON_START at its default of 1 the solution configures the Edge itself on startup, which takes 30 to 60 seconds. If you set it to 0, or the apply failed, press Apply to Edge in the page header.
Configuration
Variable | Default | Purpose |
|---|---|---|
EDGE_URL | the Docker host | Litmus Edge to configure |
EDGE_API_TOKEN | unset | token for that Edge. Alternatively EDGE_USERNAME and EDGE_PASSWORD, or EDGE_CLIENT_ID and EDGE_CLIENT_SECRET |
SIM_HOST | auto | address the Edge polls to reach this solution |
APPLY_ON_START | 1 | configure the Edge on startup |
EDGE_VERIFY_TLS | 0 | 1 verifies the Edge's certificate |
AUTOSTART | 1 | start the lines running |
TICK_SECONDS | 0.2 | simulation step |
SEED | 7 | makes a run repeatable |
An incorrect SIM_HOST fails quietly: the devices are created, they report as online, and no tag ever reads a value, because the address written into the template is one the Edge cannot reach. The solution refuses to apply a template whose address is obviously unreachable and reports why.
Operator view
The header shows the worst line with its dominant loss, the product ring main pressure against its specification, the compressed air header against demand and running capacity, giveaway per day, the share of caps under torque, and what the CIP skid is doing and how many lines are waiting for it.
Below that are the three lines and the shared utilities, with the product and air mains drawn from the utilities to every line. Below them, the lines are ranked worst first. Each line can be started and stopped on its own, because how many lines run changes what each line sees.
Below the lines are the faults. Three are marked as shared utilities, affecting all three lines:
- product pump impeller worn (all three lines)
- one air compressor trips (all three lines)
- caustic wash runs cold (all three lines)
- PL3 labeler micro-stops (one line)
- PL2 capper jams (one line)
Each fault has a guide naming the DataHub topics, the Analytics group and the Digital Twin topic to watch while it runs.
Apply and remove
The header carries both controls. Apply to Edge pushes the devices, twins and analytics, and greys out once the solution is on the Edge. Remove from Edge previews first, listing what would be removed and from which Edge, then offers to remove it.
The solution removes only what it created, and records which Edge its apply landed on, so repointing at a different Edge cannot leave a solution stranded on the first one.
Reports
Preview report and Export report produce one self-contained HTML file that opens offline, emails and prints. It carries a summary, the lines ranked by OEE with the dominant loss for each, the shared utilities with header pressure, giveaway by line and the weight distribution, a downtime Pareto, every CIP cycle with its result and how far past its clean window it ran, the faults injected, and the Litmus Edge configuration that produced it.