Skip to content

Cookbook: Packaging Line OEE with Shifts and Downtime ​

Last updated

License feature: OEE Tracking

This recipe sets up OEE for one case packer: two shifts, downtime reason codes, counts fed from the PLC by a custom page on the line PC, operators logging stops, and an OEE dashboard.

Note: This line's PLC counters are shift counters — they zero themselves at every shift boundary (06:00 and 14:00), and the line has two shifts a day. The OEE Configuration's Tag Bindings (Good/Reject Count Tag) accumulate counts for the whole UTC day, not per shift, so on a counter that resets more than once a day they would blend both shifts' parts into whichever shift is posted last. This recipe posts the counter's own per-shift value directly with a shiftId instead, from a custom page — see Feeding OEE Counts and Downtime. If your line has one shift a day, or a counter that only resets once a day (or never), Tag Bindings are simpler — bind them on the Configuration tab and skip Step 6. Downtime still always needs Log Downtime (or the API); nothing detects a stop automatically.

The line ​

ItemValue
MachineCase Packer 3, CompactLogix at 10.20.3.15
Rated speed30 cases/min → ideal cycle time 2.0 s
PLC tagsCP3_GoodCount_Shift (DINT), CP3_RejectCount_Shift (DINT), CP3_Running (BOOL)
Counter resetThe PLC zeroes both shift counters at 06:00 and 14:00
ShiftsDay 06:00–14:00, Swing 14:00–22:00, Mon–Fri, 30 min of breaks each

If your counters never reset, see "Counters that don't reset" at the end.

Step 1: Turn the features on ​

  1. As admin: System > Settings → Feature Toggles → Production.
  2. Switch on OEE Tracking and Downtime Tracking and Shift Scheduling.
  3. Refresh the browser. OEE, Downtime and Shifts appear under Monitor.

Step 2: Add the PLC and subscribe the tags ​

  1. Devices → Add Device → CompactLogix. Device Name Case Packer 3, IP Address 10.20.3.15, Port 44818, Polling Rate (ms) 1000 → Create Device. See Allen-Bradley PLCs.
  2. On its page, Browse Tags, tick CP3_GoodCount_Shift, CP3_RejectCount_Shift and CP3_Running, click Subscribe Selected.

The custom page in Step 6 can only receive tags that are subscribed.

Step 3: Create the shifts ​

Monitor > Shifts → New Shift → fill in → Save. Repeat.

NameStartEndActive DaysTotal Break (min)Takt Time (s)Target Parts/Shift
Day Shift06:0014:00Mon–Fri30213500
Swing Shift14:0022:00Mon–Fri30213500

Only Start, End, Active Days and Total Break (min) affect OEE. Takt, target and Break Periods are shown on the Shifts page only. Planned production time per shift is 8 h − 30 min = 450 min.

Step 4: Set up downtime reasons ​

Monitor > Downtime → Reasons → Add Reason. The seeded reasons stay; add the line's own:

NameCategoryColor
Case JamUnplanned#ef4444
Glue Hopper RefillUnplanned#f97316
Carton Magazine EmptyUnplanned#eab308
Size ChangePlanned#3b82f6

How categories count: Planned time is removed from planned production time and does not lower Availability; Unplanned, Changeover and events with no reason all lower it. The seeded Tool Change and Product Changeover reasons are in the Changeover category and therefore count against Availability. That's why this line's size change is a Planned reason.

Don't log Break / Lunch events on this line: the 30 minutes of Total Break (min) are already subtracted, and logging them would subtract the time twice.

Step 5: Configure OEE for the machine ​

  1. Monitor > OEE → Configuration → Add Device.
  2. Device Case Packer 3; Ideal Cycle Time (seconds) 2; Production Time Source From Shift Schedule.
  3. Leave the Tag Bindings empty. They would work for a single continuous counter, but this line's per-shift counters need the shift-aware posting in Step 6 instead (see the note above).
  4. Click Save.

Between shifts, and on any Sunday, the engine uses Planned Production Time (minutes per day) instead (default 480). See OEE: Configuration.

Step 6: Post the counts from a custom page ​

Server scripts can't call the OEE API (it needs a signed-in user), so the counts come from a custom page kept open on the line PC.

  1. Custom Pages → New Page → CP3 OEE Counter → Create.
  2. HTML tab:
html
<div style="padding:24px;font-size:20px">
  <h2>Case Packer 3 — OEE counter</h2>
  <p>Good: <b id="good">—</b> · Reject: <b id="reject">—</b> · Shift: <b id="shift">—</b></p>
  <p id="status">Starting…</p>
</div>
  1. JavaScript tab:
javascript
var DEVICE_NAME = 'Case Packer 3';
var deviceId = null, shiftId = null, good = null, reject = null;

function show(id, text) { document.getElementById(id).textContent = text; }

function keepCount(tagPath, apply) {
  scadaink.subscribe(deviceId, tagPath, function (value, update) {
    if (update && update.quality !== 'good') return;   // ignore bad reads
    if (value === '' || isNaN(Number(value))) return;
    apply(Number(value));
  });
}

function refreshShift() {
  return scadaink.api.get('/shifts/current').then(function (res) {
    shiftId = res.data ? res.data.id : null;
    show('shift', res.data ? res.data.name : 'none');
  });
}

function postCounts() {
  if (good === null || reject === null) { show('status', 'Waiting for counts'); return; }
  if (shiftId === null) { show('status', 'No shift running — nothing posted'); return; }
  scadaink.api.post('/oee/snapshot', {
    deviceId: deviceId, shiftId: shiftId, goodCount: good, rejectCount: reject,
  }).then(function () {
    show('status', 'Posted at ' + new Date().toLocaleTimeString());
  }).catch(function (err) {
    show('status', 'Post failed: ' + err.message);
  });
}

scadaink.devices.find(DEVICE_NAME).then(function (id) {
  if (id === null) { show('status', 'Device not found: ' + DEVICE_NAME); return; }
  deviceId = id;
  keepCount('CP3_GoodCount_Shift', function (n) { good = n; show('good', n); });
  keepCount('CP3_RejectCount_Shift', function (n) { reject = n; show('reject', n); });
  refreshShift();
  setInterval(function () { refreshShift().then(postCounts); }, 60000);   // once a minute
});
  1. Save. On the line PC, sign in as an operator (posting needs operator or higher) and open /view/page/<id> full screen. Leave it open.

What this does: once a minute it asks which shift is running and posts the PLC's shift counters with that shift's id. With a shift id, repeated posts update one history row per machine, shift and day instead of adding a row each minute.

Limits of this approach:

  • It only runs while the page is open. If the PC sleeps or the browser closes, OEE stops getting counts.
  • Open it on one PC only; every open copy posts.
  • The last post of a shift is up to a minute before the PLC resets its counters, so the last minute's cases can be missing from that shift's row. Keep the PLC and appliance clocks in step.
  • If the page reloads (for example when the viewer's session token is renewed), it starts again on its own; counts posted before are kept.

Step 7: Log stops ​

When the packer stops, the operator (on a tablet or the same PC):

  1. Monitor > Downtime → Events → Log Downtime.
  2. Device Case Packer 3, Reason e.g. Case Jam (unplanned), Notes Jammed at flap folder → Start Downtime.
  3. When it runs again, click End in the red Active Downtime banner.

The reason can only be chosen when starting. Nothing detects stops automatically; if a stop isn't logged, Availability stays at 100 %. To start and end events automatically from CP3_Running, extend the page with the downtime pattern in Feeding OEE Counts and Downtime.

Step 8: Build the OEE dashboard ​

Dashboards → New Dashboard → Line 3 OEE:

WidgetConfiguration / binding
OEE GaugeDevice Case Packer 3
OEE TimelineDevice Case Packer 3, Days to Show 10 — this is a number of rows, and with two shift rows a day it covers about five days
Downtime ParetoDevice Case Packer 3, Max Reasons 6 — all-time, closed events with a reason only
Value "Good this shift"value → CP3_GoodCount_Shift
Value "Rejects this shift"value → CP3_RejectCount_Shift
Status "Packer"value → CP3_Running; default rules (true = Running)

The production widgets refresh on their own timers and need a signed-in viewer; on a public or kiosk screen they stay empty. For a TV scoreboard see Andon Displays.

Step 9: Read the numbers at shift end ​

Day shift result:

InputValue
Planned time P450 min = 27,000 s
Unplanned downtime loggedCase Jam 38 min + Glue Hopper Refill 12 min = 3,000 s
Last snapshotgood 11,040, reject 160 → total 11,200
  1. Run time = 27,000 − 3,000 = 24,000 s.
  2. Availability = 24,000 / 27,000 = 0.889.
  3. Performance = 11,200 × 2.0 / 24,000 = 0.933.
  4. Quality = 11,040 / 11,200 = 0.986.
  5. OEE = 0.889 × 0.933 × 0.986 = 0.818 → 82 % (amber: green starts at 85 %).

Monitor > OEE → History shows one row per shift. The A, P, Q and OEE stored in a row are from the post before the latest counts; read the final figures on the Dashboard tab at shift end, or post once more.

What to expect — plainly ​

SurpriseWhy
OEE reads low all morning (about 50 % at 10:00 even with no stops)Planned time is the whole shift from its first minute; the figure is only right at shift end. See OEE formulas
Swing shift Availability includes the day shift's stopsDowntime is totaled for the whole day, not the shift
Totals reset in the early evening (US) or morning (Asia-Pacific)"Today" for downtime and snapshots is the UTC date
Sunday uses 480 minutesSunday shifts never match in the OEE engine
Andon shows a different reject countAndon takes rejects from quality events, not snapshots

Counters that don't reset ​

If the PLC counts forever, change keepCount so the page stores the counter value at the start of each shift and posts the difference. Keep that start value in a local tag (scadaink.write('CP3/GoodAtShiftStart', n)) so a page reload doesn't lose it.

See also ​

Scada.Ink Help Center