OEE Connector
Overview
Section titled “Overview”The OEE (Overall Equipment Effectiveness) connector computes the canonical SEMI E10 manufacturing KPI from cumulative production counters arriving on the input stream. It emits per-block OEE plus the three component metrics (Availability, Performance, Quality) so they can be rendered as gauges, charts, or stored in a time-series database.
Connector Types:
OEE- Stateful processor that computes OEE on a sliding window or per-shift basis
OEE is computed as:
OEE = Availability × Performance × QualityWhere:
- Availability =
runTime / plannedProductionTime - Performance =
(idealCycleTime × totalCount) / runTime - Quality =
goodCount / totalCount
All three are clamped to [0, 1].
Features
Section titled “Features”- ✅ Two window modes: sliding (time-based) and shift (HH:MM bracketed)
- ✅ Automatic accumulation when
RunTime/PlannedProductionTimeare not provided by the device - ✅ Accepts
runningas a boolean-ish status field (true/false, 1/0, on/off, yes/no, etc.) - ✅ Configurable thresholds (
red,yellow) andtargetfor gauge styling - ✅ Emits N/A payload (
oee.*omitted) when a window has insufficient data - ✅ Per-block ID namespacing so multiple OEE instances can write to the same payload
- ✅ Lenient numeric parsing — strings parsed as floats automatically
Basic Configuration
Section titled “Basic Configuration”Sliding Window with Device-Reported Counters
Section titled “Sliding Window with Device-Reported Counters”{ "type": "OEE", "config": { "fields": { "plannedProductionTime": "planned_time_s", "runTime": "run_time_s", "idealCycleTime": "ideal_cycle_s", "totalCount": "parts_total", "goodCount": "parts_good" }, "windowMode": "sliding", "windowSeconds": 3600, "thresholds": { "red": 0.6, "yellow": 0.8 }, "target": 0.85 }}Shift Window with Status Flag and Literal Cycle Time
Section titled “Shift Window with Status Flag and Literal Cycle Time”{ "type": "OEE", "config": { "fields": { "running": "machine_running", "totalCount": "parts_total", "goodCount": "parts_good" }, "idealCycleTimeSeconds": 4.5, "windowMode": "shift", "shiftStart": "06:00", "shiftEnd": "14:00", "timezone": "Europe/Rome", "thresholds": { "red": 0.6, "yellow": 0.8 }, "target": 0.85 }}Configuration Parameters
Section titled “Configuration Parameters”Fields
Section titled “Fields”The fields object names the payload keys the connector reads from each incoming sample.
{ "fields": { "plannedProductionTime": "planned_time_s", "runTime": "run_time_s", "running": "machine_running", "idealCycleTime": "ideal_cycle_s", "totalCount": "parts_total", "goodCount": "parts_good" }}| Field | Required? | Notes |
|---|---|---|
plannedProductionTime | Optional | Cumulative seconds. If omitted, the connector accumulates wall-clock seconds since the first sample |
runTime | One of runTime / running is required | Cumulative seconds the machine was running |
running | One of runTime / running is required | Boolean-ish status; integrated internally |
idealCycleTime | One of idealCycleTime / idealCycleTimeSeconds is required | Seconds per part at ideal speed |
totalCount | Required | Cumulative count of parts attempted |
goodCount | Required | Cumulative count of good parts |
Ideal Cycle Time (Literal)
Section titled “Ideal Cycle Time (Literal)”When the device does not publish ideal cycle time, you can declare it as a constant:
{ "idealCycleTimeSeconds": 4.5}This is mutually exclusive with fields.idealCycleTime.
Window Mode
Section titled “Window Mode”{ "windowMode": "sliding"}sliding- Computes deltas over a rolling time window of lengthwindowSecondsshift- Computes deltas since the beginning of the current shift, defined byshiftStart,shiftEnd, and optionaltimezone
Window Seconds (Sliding Mode)
Section titled “Window Seconds (Sliding Mode)”{ "windowSeconds": 3600}Required for windowMode: sliding. Must be > 0.
Recommended values:
- Realtime gauge: 300-900 (5-15 minutes)
- Hour-by-hour trend: 3600 (1 hour)
- Long-term smoothing: 28800 (8 hours)
Shift Configuration (Shift Mode)
Section titled “Shift Configuration (Shift Mode)”Required for windowMode: shift:
{ "shiftStart": "06:00", "shiftEnd": "14:00", "timezone": "Europe/Rome"}shiftStart/shiftEnd-HH:MM24-hour formattimezone- IANA timezone identifier (e.g.Europe/Rome,America/New_York,Asia/Tokyo). Defaults to UTC if omitted- Overnight shifts are supported (e.g.
22:00→06:00)
Thresholds and Target
Section titled “Thresholds and Target”Styling hints emitted alongside the OEE values so dashboards can color gauges consistently:
{ "thresholds": { "red": 0.6, "yellow": 0.8 }, "target": 0.85}Constraints:
red < yellow(strictly)0 ≤ red, yellow ≤ 10 ≤ target ≤ 1
Output Payload
Section titled “Output Payload”Each output is namespaced by the block ID of the OEE connector instance (auto-injected by Meddle):
{ "oee.<blockId>": 0.78, "availability.<blockId>": 0.92, "performance.<blockId>": 0.95, "quality.<blockId>": 0.89, "red.<blockId>": 0.6, "yellow.<blockId>": 0.8, "target.<blockId>": 0.85}When the window does not yet have enough data (e.g. fewer than two snapshots in sliding mode, or the shift just started), the oee/availability/performance/quality keys are omitted and only the gauge styling keys are emitted. This is the N/A payload.
Data Flow
Section titled “Data Flow”DataPayload (cumulative counters) → OEE → DataPayload (oee.<blockId>, etc.)Example (sliding window, 60s):
Input stream:
{ "planned_time_s": 0, "run_time_s": 0, "parts_total": 0, "parts_good": 0 }{ "planned_time_s": 60, "run_time_s": 55, "parts_total": 12, "parts_good": 11 }{ "planned_time_s": 120, "run_time_s": 110, "parts_total": 24, "parts_good": 22 }With idealCycleTimeSeconds: 4.5, windowSeconds: 60:
After the third sample:
- ΔPlanned = 60s, ΔRun = 55s, ΔTotal = 12, ΔGood = 11
- A = 55/60 = 0.917
- P = (4.5 × 12) / 55 = 0.982
- Q = 11/12 = 0.917
- OEE = 0.917 × 0.982 × 0.917 = 0.826
Output:
{ "oee.<blockId>": 0.826, "availability.<blockId>": 0.917, "performance.<blockId>": 0.982, "quality.<blockId>": 0.917, "red.<blockId>": 0.6, "yellow.<blockId>": 0.8, "target.<blockId>": 0.85}Common Use Cases
Section titled “Common Use Cases”1. Rolling 15-Minute OEE Gauge
Section titled “1. Rolling 15-Minute OEE Gauge”Best for live operator dashboards where the gauge responds to recent activity:
{ "type": "OEE", "config": { "fields": { "running": "is_running", "totalCount": "cumulative_parts", "goodCount": "cumulative_good" }, "idealCycleTimeSeconds": 6.0, "windowMode": "sliding", "windowSeconds": 900, "thresholds": { "red": 0.55, "yellow": 0.75 }, "target": 0.85 }}2. Per-Shift OEE for Reporting
Section titled “2. Per-Shift OEE for Reporting”{ "type": "OEE", "config": { "fields": { "plannedProductionTime": "shift_planned_s", "runTime": "shift_run_s", "idealCycleTime": "ideal_cycle_s", "totalCount": "shift_parts_total", "goodCount": "shift_parts_good" }, "windowMode": "shift", "shiftStart": "06:00", "shiftEnd": "14:00", "timezone": "Europe/Rome", "thresholds": { "red": 0.6, "yellow": 0.8 }, "target": 0.85 }}3. Night Shift (Overnight Boundary)
Section titled “3. Night Shift (Overnight Boundary)”{ "type": "OEE", "config": { "fields": { "running": "running_flag", "totalCount": "ct_total", "goodCount": "ct_good" }, "idealCycleTimeSeconds": 3.2, "windowMode": "shift", "shiftStart": "22:00", "shiftEnd": "06:00", "timezone": "America/New_York", "thresholds": { "red": 0.5, "yellow": 0.75 }, "target": 0.8 }}Troubleshooting
Section titled “Troubleshooting”Output Has Only Gauge Styling Fields (No oee.*)
Section titled “Output Has Only Gauge Styling Fields (No oee.*)”Problem: The N/A payload is being emitted
Solutions:
- Sliding mode: requires at least 2 snapshots in the window. Wait for a second sample
- Shift mode: returns N/A when the current time is outside
[shiftStart, shiftEnd] - Shift mode startup: the first sample inside the shift establishes the baseline; OEE will appear from the second sample onward
non-positive window deltas
Section titled “non-positive window deltas”Problem: An error is reported with deltas reported as 0 or negative
Solutions:
- The counters must be monotonically increasing. If the device resets them (e.g. on shift change), wrap the input in a
Transformto convert to deltas first, or split the OEE instance per shift - Confirm the field names map to non-zero values
- If the window is very short (
windowSeconds: 10) and the line is idle, deltas can be exactly zero; widen the window
Invalid Value Errors
Section titled “Invalid Value Errors”Problem: invalid value for "..." errors
Solutions:
- Values must be non-negative finite numbers. NaN, infinity, and negatives are rejected
- Strings are tolerated only if they parse to a non-negative finite float
- If your source emits booleans for “running”, ensure the
runningfield — notrunTime— is configured
OEE Pegged at 1.0
Section titled “OEE Pegged at 1.0”Problem: Suspiciously perfect OEE
Solutions:
- Check that
idealCycleTimeis realistic. An overly slow ideal makes Performance ≥ 1, which clamps to 1 - Verify that
runTime<plannedProductionTime. If they’re identical, Availability is 1.0
Wrong Timezone for Shift Boundaries
Section titled “Wrong Timezone for Shift Boundaries”Problem: Shift starts/ends are off by N hours
Solutions:
- Always set
timezoneto a valid IANA name - Do not use offset notations like
+02:00— they’re rejected
Best Practices
Section titled “Best Practices”1. Prefer Device-Reported Counters When Available
Section titled “1. Prefer Device-Reported Counters When Available”If the PLC publishes runTime and plannedProductionTime as cumulative seconds, use them directly. The internal accumulator is a fallback for devices that only publish a running flag.
2. Match Window to Audience
Section titled “2. Match Window to Audience”- Operators: 5-15 minute sliding window
- Supervisors: per-shift window
- Executives: per-day or per-week aggregation (downstream)
3. Calibrate idealCycleTime Honestly
Section titled “3. Calibrate idealCycleTime Honestly”The ISO definition is “fastest sustainable cycle time”, not “marketing brochure”. An optimistic value depresses Performance and undersells real OEE.
4. Pair with a Filter or Transform Upstream
Section titled “4. Pair with a Filter or Transform Upstream”If your raw stream contains unrelated payloads, use Filter to keep only counter updates before the OEE block.
5. Use Separate OEE Blocks per Machine
Section titled “5. Use Separate OEE Blocks per Machine”Each OEE connector instance is namespaced by blockId, so multi-machine dashboards can coexist in a single Meddle flow.
Example Workflows
Section titled “Example Workflows”Full Production Dashboard Pipeline
Section titled “Full Production Dashboard Pipeline”ModbusReader (machine 1) ──┐ModbusReader (machine 2) ──┼─→ Merge → Reshape → OEE → Chart (gauge)ModbusReader (machine 3) ──┘ └→ InfluxDb2Writer- ModbusReader (×N): Pulls counters from each machine
- Merge: Combines payloads keyed by machine ID
- Reshape: Normalizes field names to match the OEE config
- OEE: Computes OEE per machine instance
- Chart: Renders the gauge with
red,yellow,targetstyling - InfluxDb2Writer: Persists OEE for historical trending
OEE + Alarm Combo
Section titled “OEE + Alarm Combo”OpcuaReader → OEE → Isa182 (alarm on OEE < 0.5) → Alert (email)Triggers a notification when sustained OEE drops below 50% — useful for chronic underperformance detection.
Related Connectors
Section titled “Related Connectors”- Chart - Render the gauge from OEE output
- ISA-18.2 - Trigger alarms on low OEE
- Reshape - Normalize counter field names
- InfluxDB v2 - Persist OEE for trending
- Transform - Compute deltas from non-monotonic counters
Additional Resources
Section titled “Additional Resources”- OEE Foundation
- SEMI E10 - Specification for Definition and Measurement of Equipment Reliability, Availability, and Maintainability
- ISO 22400 - Key performance indicators (KPIs) for manufacturing operations management
- IANA Time Zone Database