Siddhant Kumar
Project 065 · Industrial

OEE Productivity Tracker.

Automatically logs a machine's uptime, speed and quality and computes OEE — turning a factory's vague sense of "how are we doing?" into the exact numbers that show where output is lost.

Intermediate 12–18 hours 30 min read OEEAnalyticsIndustry
Jump to source Bill of materials
OEE Productivity Tracker — reference build illustration MCU VCC · GND · SIG · NC
Difficulty
Intermediate
Build time
12–18 hours
Indicative cost
₹2,500 – ₹4,500
Platform
ESP32 DevKit V1 (ESP-WROOM-32)
Category
Industrial
Last updated
28 July 2026
Contents — 26 sections

Project Overview

Automatically logs a machine's uptime, speed and quality and computes OEE — turning a factory's vague sense of "how are we doing?" into the exact numbers that show where output is lost.

Every factory wants to make more with what it has, but most cannot say where their output is being lost — to stoppages, to running slow, or to scrap. OEE (Overall Equipment Effectiveness) is the standard metric that answers this, and it does so by decomposing productivity into three factors: Availability (was the machine running when it should have been?), Performance (did it run at its rated speed?), and Quality (were the parts good?). Multiply them and you get one number, 0-100%, that captures the true productive fraction of a machine — and, more usefully, three numbers that pinpoint which kind of loss is hurting you. This project measures the inputs automatically and computes OEE live, replacing gut feel and manual logs with the real figures.

The tracker senses the three inputs from the machine. Availability comes from a run/stop signal (a machine-on input, a cycle sensor, or motor current) that logs exactly when the machine was running versus down, and for how long each stoppage lasted. Performance comes from counting output (a cycle/item counter) and comparing the actual rate to the machine's ideal rate. Quality comes from a good/reject signal (a reject-station input, or manual entry) giving the good-part fraction. From these it computes each factor and the overall OEE, live, per shift and per batch — and because it logs why the machine stopped (downtime reasons) it exposes the "six big losses" that OEE is designed to attack.

The value is that OEE is actionable: a low Availability points at breakdowns and changeovers, a low Performance at minor stops and slow running, a low Quality at scrap and rework — so improvement effort goes where the loss actually is, and the same numbers verify whether a fix worked. The tracker reports to a dashboard, ranks losses, and gives operators a live OEE they can respond to. It is honest that OEE is only as good as its inputs (a correct ideal cycle time, an honest definition of planned production time, accurate good/reject counts) and that it measures effectiveness, not the whole business. But as an automatic, always-on OEE tracker, it converts a machine's activity into the industry-standard productivity numbers that show, precisely, where output is being lost and whether it is being recovered.

Automated machinery on a factory production line
OEE turns a vague sense of productivity into three precise factors that show where output is lost. Photograph sourced from Wikimedia Commons — Factory automation.jpg. Reused under the licence stated on that page; please check it before republishing.

What this project does

  • Logs machine run/stop (Availability) with per-stoppage duration and reason
  • Counts output and compares to ideal rate (Performance)
  • Captures good/reject counts (Quality)
  • Computes Availability × Performance × Quality = OEE, live
  • Reports OEE per shift/batch and ranks the losses
  • Exposes the "six big losses" for targeted improvement
  • Verifies whether improvements actually raised OEE

Real-World Applications

SettingHow it is used
Machine / line productivityLive OEE per machine to find and reduce the biggest output losses.
Continuous improvement / leanData-driven targeting of the six big losses and verification of kaizen results.
Shift / management reportingObjective per-shift/batch productivity figures instead of manual logs.
Capacity / bottleneck analysisUnderstanding true available capacity across machines.

Deployment contexts where a build of this kind earns its keep.

Features & Capabilities

  • Automatic three-factor OEE (Availability/Performance/Quality)
  • Downtime logging with reasons (six big losses)
  • Live and per-shift/batch OEE
  • Loss ranking to target improvement
  • Before/after verification of fixes
  • Dashboard and operator display
  • Honest about input quality and OEE's scope

Difficulty, Time & Required Skills

AttributeValue
Difficulty levelIntermediate
Estimated completion time12–18 hours
Indicative build cost₹2,500 – ₹4,500
Primary disciplineIndustrial
Reference platformESP32 DevKit V1 (ESP-WROOM-32)

Skills you should have (or will pick up)

  • Sensing run/stop, output count and good/reject
  • Computing Availability, Performance, Quality and OEE
  • Downtime-reason capture and loss classification
  • Live/shift aggregation and dashboards
  • Defining ideal cycle time and planned production time correctly

Bill of Materials

Every part below is commonly available from Indian and international hobby-electronics suppliers. Prices are indicative 2026 retail figures in Indian rupees and will drift — treat them as a budgeting guide, not a quotation.

ComponentKey specificationQtyApprox. cost
ESP32 DevKit V1 (ESP-WROOM-32)
Wi-Fi transmit bursts peak near 500 mA — size the regulator accordingly.
Dual-core Xtensa LX6 @ 240 MHz, 520 KB SRAM, 4 MB flash, Wi-Fi 802.11 b/g/n + BLE 4.2, 34 GPIO, 18× 12-bit ADC, 2× 8-bit DAC1₹450
Reed switch + magnet pair (door contact)
Wire it normally-closed so a cut cable reads the same as an open door — fail-safe by construction.
NO contact, 10–15 mm operating gap, 100 V / 0.5 A, > 10⁷ operations1₹55
TCRT5000 IR reflectance sensor module
Ambient sunlight saturates it — shroud the sensor on outdoor robots.
1–8 mm optimum sensing gap, 950 nm emitter, analogue + digital out1₹45
ACS712 hall-effect current sensor (20 A)
Zero-offset drifts with temperature — re-zero at boot with no load.
±20 A, 100 mV/A, 80 kHz bandwidth, 1.2 mΩ internal resistance, 2.1 kV isolation1₹180
0.96″ SSD1306 OLED display
Static images burn in — invert or scroll the screen periodically.
128 × 64 monochrome, 1.3–3.3 V logic, 100 kHz–400 kHz I²C1₹250
4×4 matrix membrane keypad
Debounce in software — 20 ms is enough for membrane keys.
16 keys, 8-wire matrix, 35 × 76 mm adhesive-backed1₹70
5 V 3 A regulated SMPS adapter
Measure the real output — many "3 A" adapters sag below 4.7 V at 2 A.
100–240 VAC in, 5 V ±5 % out, 3 A, short-circuit and over-voltage protection1₹350
Machine-state inputs
Tap a clean signal for Availability
Run/stop signal (machine-on / cycle sensor / motor current)1₹400
Output counter sensorCycle/item sensor for Performance (count vs ideal rate)1₹300
Reject/good input + reason selectorReject-station signal or operator buttons for Quality and downtime reasons1₹350
Andon displayOperator display/stack-light showing live OEE and state1₹800

Estimated total: ₹3,250, excluding tools, shipping and consumables.

Tools and consumables

  • Soldering iron (temperature controlled, 350 °C) with 0.8 mm 60/40 or lead-free solder
  • Digital multimeter — continuity, DC volts and current ranges
  • Wire strippers, flush cutters and a small set of precision screwdrivers
  • Heat-shrink tubing and a heat gun (or a lighter, carefully)
  • A laptop with a USB port and the toolchain listed above

Hardware Specifications

PartSpecificationSupplyInterfaceReference
ESP32 DevKit V1 (ESP-WROOM-32)Dual-core Xtensa LX6 @ 240 MHz, 520 KB SRAM, 4 MB flash, Wi-Fi 802.11 b/g/n + BLE 4.2, 34 GPIO, 18× 12-bit ADC, 2× 8-bit DAC3.3 V logic / 5 V USBUART, SPI, I²C, I²S, CAN, PWMDatasheet
Reed switch + magnet pair (door contact)NO contact, 10–15 mm operating gap, 100 V / 0.5 A, > 10⁷ operationspassiveDigital with pull-upDatasheet
TCRT5000 IR reflectance sensor module1–8 mm optimum sensing gap, 950 nm emitter, analogue + digital out3.3–5 VAnalogue + digitalDatasheet
ACS712 hall-effect current sensor (20 A)±20 A, 100 mV/A, 80 kHz bandwidth, 1.2 mΩ internal resistance, 2.1 kV isolation5 VAnalogueDatasheet
0.96″ SSD1306 OLED display128 × 64 monochrome, 1.3–3.3 V logic, 100 kHz–400 kHz I²C3.3–5 VI²C (0x3C)Datasheet
4×4 matrix membrane keypad16 keys, 8-wire matrix, 35 × 76 mm adhesive-backedlogic level8 GPIO matrix scanDatasheet
5 V 3 A regulated SMPS adapter100–240 VAC in, 5 V ±5 % out, 3 A, short-circuit and over-voltage protection5 VDC barrel / USBDatasheet

Consolidated electrical and interface specifications for every active part in the build.

Power Budget & Supply Sizing

Add up the typical active current of every part, then size the supply with at least 50 % headroom so transmit bursts and motor inrush never brown out the controller.

LoadSupply railTypical current (mA)Notes
ESP32 DevKit V1 (ESP-WROOM-32)3.3 V logic / 5 V USB160Wi-Fi transmit bursts peak near 500 mA — size the regulator accordingly.
TCRT5000 IR reflectance sensor module3.3–5 V20Ambient sunlight saturates it — shroud the sensor on outdoor robots.
ACS712 hall-effect current sensor (20 A)5 V10Zero-offset drifts with temperature — re-zero at boot with no load.
0.96″ SSD1306 OLED display3.3–5 V20Static images burn in — invert or scroll the screen periodically.
4×4 matrix membrane keypadlogic level1Debounce in software — 20 ms is enough for membrane keys.
5 V 3 A regulated SMPS adapter5 V3000Measure the real output — many "3 A" adapters sag below 4.7 V at 2 A.

Summed typical draw is 3211 mA. With a 1.5× design margin the supply should deliver at least 4900 mA continuously at the stated rail voltage.

Software Requirements & Development Environment

Reference toolchain: Arduino IDE 2.3.x with the ESP32 board package 3.x (or PlatformIO on VS Code). Anything newer normally works; anything older may lack the board definitions used here.

  • Install the Arduino IDE 2.3.x (or PlatformIO if you prefer a real editor and dependency locking).
  • Add https://espressif.github.io/arduino-esp32/package_esp32_index.json under File → Preferences → Additional Board Manager URLs, then install esp32 from the Boards Manager.
  • Set the correct port under Tools → Port. On Linux add yourself to the dialout group: sudo usermod -aG dialout $USER and log out and back in.
  • Open the Serial Monitor at 115200 baud — every sketch here logs its state there.
  • Keep File → Preferences → Show verbose output during: compilation switched on while you are debugging build errors.

Required libraries

LibraryWhy it is neededInstall
WiFi (ESP32 core) bundledStation/AP connection management for the ESP32.Bundled with the ESP32 Arduino core
PubSubClient 2.8Lightweight MQTT 3.1.1 client for constrained devices.Library Manager → "PubSubClient" by Nick O'Leary
Adafruit SSD1306 + GFX 2.5.xFramebuffer and text/graphics primitives for the OLED.Library Manager → "Adafruit SSD1306"
NTPClient / configTime bundledWall-clock time from an NTP server for timestamping.Bundled (`configTime()` on ESP32)
ArduinoJson 7.xZero-allocation JSON serialisation and parsing.Library Manager → "ArduinoJson" by Benoit Blanchon
Preferences (NVS) bundledWear-levelled key/value storage in ESP32 flash for settings.Bundled with the ESP32 core

Block Diagram

The block diagram shows the functional decomposition of the system — what senses, what decides, what acts, and where the data ends up.

OEE Productivity Tracker — system block diagramFunctional block diagram of the OEE Productivity Tracker system. SenseRun/stopAvailabilityCountPerformanceGood/rejectQualityReasondowntimeComputeESP32A×P×Q = OEELossessix big lossesShowAndonlive OEEDashboardshift/batchImproveTarget lossrankVerifybefore/afterrightrightnone
OEE Productivity Tracker — system block diagram

Circuit Diagram & Wiring

Every signal line in the build is shown below, followed by a pin-by-pin connection table you can work through with a multimeter in hand.

OEE Productivity Tracker — wiring schematicConnection schematic showing which controller pin drives each peripheral. Sensors / InputsControllerActuators / OutputsESP32 DevKit V1(ESP-WROOM-32)3.3 V logic / 5 V USBRun/stop signalGPIO 34Machine runningstateOutput sensorGPIO 27Cycle/item countReject/goodGPIO 26Quality countReason selectorGPIO matrixDowntime reasonOLED/AndonGPIO 21/22Live OEE + stateWi-FiDashboardRTCGPIO 21/22Shift timing5V supply3V3 regPower
OEE Productivity Tracker — wiring schematic
PeripheralPeripheral pinController pinSignal
Run/stop signalinGPIO 34Machine running state
Output sensorPULSEGPIO 27Cycle/item count
Reject/goodinGPIO 26Quality count
Reason selectorkeypadGPIO matrixDowntime reason
OLED/AndonSDA/SCLGPIO 21/22Live OEE + state
Wi-Fion-chipDashboard
RTCSDA/SCLGPIO 21/22Shift timing
5V supply+/–3V3 regPower

Wire one row at a time and tick it off — most "it does not work" reports trace back to a single swapped pair.

Wiring explanation

  • Tap a clean, unambiguous run/stop signal for Availability — a machine-on contact, a cycle sensor, or a motor-current threshold.
  • Use a reliable output sensor for counting cycles/items; debounce it like a counter.
  • Provide a good/reject input (reject-station signal or operator confirmation) for Quality.
  • Give operators an easy way to select the downtime reason so losses are classified (the six big losses).
  • Show live OEE/state on an operator display/stack-light so the floor can respond.
An ESP32 development board with the ESP-WROOM-32 module and USB connector
ESP32 module logging run/stop, output and good/reject to compute OEE live. Photograph sourced from Wikimedia Commons — ESP32 Espressif ESP-WROOM-32 Dev Board.jpg. Reused under the licence stated on that page; please check it before republishing.

System Architecture

Read the stack from the bottom up: physical hardware, the firmware that drives it, the transport that moves data off the device, and the software a human actually looks at.

OEE Productivity Tracker — architecture stackLayered architecture from hardware to user interface. Hardware layerESP32 DevKit V1 (ESP-WROOM-32) · TCRT5000 IR reflectance sensor module ·ACS712 hall-effect current sensor (20 A)Driver layerwifi · pubsub · ssd1306 · ntpApplication logicsampling loop · filtering · thresholds · state machineTransport layerWi-Fi + MQTT → OEE dashboard/MES · TLS · retry and backoffPresentation layerdashboard · mobile notifications · historical charts
OEE Productivity Tracker — architecture stack

Working Principle

OEE is powerful because it decomposes a single fuzzy question — "how productive is this machine?" — into three precise, multiplicative factors, each capturing a distinct family of loss. Availability = running time / planned production time, hurt by breakdowns and changeovers (down time). Performance = actual output / output at ideal speed, hurt by minor stops and slow running (speed loss). Quality = good parts / total parts, hurt by scrap and rework (quality loss). Their product, OEE = A × P × Q, is the fraction of planned time that produced good product at full speed — a brutally honest number (a "typical" machine often scores far lower than its operators assume). The decomposition is the point: a single OEE tells you how much you are losing; A, P and Q together tell you which kind, which is what you can act on.

Measuring the three factors means sensing three things automatically. Availability needs a truthful run/stop signal and a truthful definition of planned production time (the time the machine was scheduled to run, excluding planned breaks) — from a machine-on input, a cycle sensor, or motor current, logging every stoppage and its duration. Performance needs the output count and the machine's ideal cycle time (the fastest it is designed to make one part): actual rate versus ideal rate gives the speed factor, and getting the ideal cycle time right is critical because it anchors the whole Performance number. Quality needs the good/reject split, from a reject-station signal or operator entry. Each is a modest sensing task, but all three are required — OEE with a factor missing or guessed is not OEE.

The classification of loss is where OEE guides action, through the six big losses it is designed to expose: breakdowns and setup/changeover (Availability); minor stops and reduced speed (Performance); startup rejects and production rejects (Quality). By capturing the reason each time the machine stops — a quick operator selection — the tracker attributes downtime to specific causes and ranks them, so improvement effort targets the biggest real loss rather than the loudest complaint. This is the crucial link from measurement to improvement: OEE does not just score you, it tells you which of the six losses to attack first, and the same live numbers then verify whether the fix actually moved the needle.

Finally, the tracker is honest about OEE's dependencies and scope. Its accuracy rests entirely on the honesty of its inputs: a wrong ideal cycle time inflates or deflates Performance, a loose definition of planned production time distorts Availability, and inaccurate good/reject counts corrupt Quality — so agreeing and getting these right is as important as the electronics. And OEE measures equipment effectiveness, not the whole business — it does not, by itself, capture demand, cost or whether you should be running the machine at all — so it is a targeting tool within a wider improvement effort, not the sole metric. Built with correct inputs and reason capture, though, an automatic OEE tracker converts a machine's raw activity into the standard, decomposable, actionable productivity numbers that show a factory exactly where its output is going and whether it is winning it back.

The maths behind it

The three factors

plainThe three factors
Availability = Run Time / Planned Production Time
Performance  = (Ideal Cycle Time × Total Count) / Run Time
             = Actual Rate / Ideal Rate
Quality      = Good Count / Total Count

Each is a fraction 0–1 capturing one loss family.

OEE

plainOEE
OEE = Availability × Performance × Quality

The fraction of planned time producing GOOD parts at
FULL speed. Multiplicative → each factor gates the result.
World-class ~85%; many machines score far lower than assumed.

Six big losses (what to attack)

plainSix big losses (what to attack)
Availability: breakdowns, setup/changeover
Performance : minor stops, reduced speed
Quality     : startup rejects, production rejects

Capture the downtime REASON to attribute and rank losses,
then fix the biggest and verify OEE improves.

Program Flowchart

The firmware is a single cooperative loop. Nothing blocks for long, so networking, sensing and the user interface all stay responsive.

OEE Productivity Tracker — firmware flowchartControl flow through the main program loop. Track run/stop, count,good/rejectOn stop: capture reasonCompute A, P, QOEE = A × P × QA/P/Q low → which loss?Rank + flag lossUpdate dashboardRank + flag lossUpdate dashboardShift/batch rollups
OEE Productivity Tracker — firmware flowchart

Assembly Instructions

Build on a breadboard first and only commit to solder once the whole system has run for an hour without a fault.

  1. Wire the three inputs and a reason selector

    Connect a clean run/stop signal (Availability), an output counter (Performance), and a good/reject input (Quality), plus operator buttons/keypad to select downtime reasons.

    Add an operator display/stack-light for live OEE and state.

  2. Configure the anchors

    Set the ideal cycle time and the planned-production-time definition (shift schedule, planned breaks) — agreed with the team, since these anchor the numbers.

  3. Set up computation and reporting

    Compute A/P/Q and OEE live, roll up per shift/batch, rank losses, and report to a dashboard.

Step-by-Step Implementation Guide

Work through these in order. Each step ends in something you can observe, so a failure is always localised to the step you just finished.

  1. Compute the three factors and OEE

    Accumulate run time, total and good counts, and stoppage reasons; compute Availability, Performance and Quality and multiply for OEE.

    cppoee.ino
    struct OEE {
      uint32_t plannedS, runS;        // seconds
      uint32_t totalCount, goodCount;
      float idealCycleS;              // ideal seconds per part
    };
    
    float availability(const OEE &o){
      return o.plannedS ? (float)o.runS / o.plannedS : 0;
    }
    float performance(const OEE &o){
      if (!o.runS) return 0;
      float ideal = o.idealCycleS * o.totalCount;   // ideal run time for the count
      return ideal / o.runS;                         // capped at 1 in practice
    }
    float quality(const OEE &o){
      return o.totalCount ? (float)o.goodCount / o.totalCount : 0;
    }
    float oee(const OEE &o){
      return availability(o) * performance(o) * quality(o);
    }
    
    // Which factor is the biggest loss right now?
    const char* biggestLoss(const OEE &o){
      float a=availability(o), p=performance(o), q=quality(o);
      if (a <= p && a <= q) return "Availability (downtime/changeover)";
      if (p <= a && p <= q) return "Performance (slow/minor stops)";
      return "Quality (scrap/rework)";
    }
    return o.plannedS ? (float)o.runS / o.plannedS : 0Availability is run time over planned production time — the down-time factor, anchored on a correct definition of planned time.
    float ideal = o.idealCycleS * o.totalCountPerformance compares the ideal run time for the parts made against the actual run time, capturing speed loss — and depends on a correct ideal cycle time.
    return o.totalCount ? (float)o.goodCount / o.totalCount : 0Quality is the good-part fraction, the scrap/rework factor.
    return availability(o) * performance(o) * quality(o)OEE multiplies the three, so a weakness in any one factor gates the whole result — which is exactly why the decomposition is so informative.
    const char* biggestLoss(const OEE &o)Identifying which factor is lowest points improvement effort at the family of loss that is actually costing the most output.
  2. Capture reasons, rank losses, report

    On each stop, capture the reason; aggregate downtime by cause into the six big losses, rank them, show live OEE on the andon, and report per shift/batch — using before/after to verify fixes.

Complete Source Code

The listing below is complete and compiles as written — there are no elided sections. Read the annotations under each block before you upload it.

cppoee-tracker.ino
/* ═══════════════════════════════════════════════════════════════
   OEE Productivity Tracker — ESP32

   Logs run/stop (Availability), output vs ideal (Performance), and
   good/reject (Quality) to compute OEE live, captures downtime reasons
   (six big losses), and reports per shift/batch to a dashboard.
   OEE = Availability x Performance x Quality.
   ══════════════════════════════════════════════════════════════════ */

#include <WiFi.h>
#include <PubSubClient.h>
#include <Wire.h>
#include <Adafruit_SSD1306.h>
#include <Preferences.h>

#define PIN_RUN   34      // machine running (HIGH = running)
#define PIN_COUNT 27      // output pulse
#define PIN_GOOD  26      // good part (else counted as reject)
#define IDEAL_CYCLE_S 3.0f
#define SHIFT_S  (8*3600)

Adafruit_SSD1306 oled(128,64,&Wire);
Preferences prefs; WiFiClient net; PubSubClient mqtt(net);

uint32_t runS=0, downS=0, total=0, good=0, shiftStart=0, lastTick=0;
bool running=false; uint32_t stopStart=0;
volatile bool countFlag=false;
void IRAM_ATTR onCount(){ countFlag=true; }

float availability(){ uint32_t planned=runS+downS; return planned? (float)runS/planned:0; }
float performance(){ return runS? (IDEAL_CYCLE_S*total)/runS : 0; }
float quality(){ return total? (float)good/total : 0; }

void setup(){
  Serial.begin(115200);
  pinMode(PIN_RUN,INPUT); pinMode(PIN_COUNT,INPUT_PULLUP); pinMode(PIN_GOOD,INPUT);
  attachInterrupt(PIN_COUNT,onCount,FALLING);
  Wire.begin(21,22); oled.begin(SSD1306_SWITCHCAPVCC,0x3C);
  WiFi.begin(WIFI_SSID,WIFI_PASS); mqtt.setServer(MQTT_HOST,1883);
  shiftStart=millis(); lastTick=millis();
}

void loop(){
  if(!mqtt.connected()&&WiFi.status()==WL_CONNECTED) mqtt.connect("oee-1");
  mqtt.loop();
  uint32_t now=millis();
  uint32_t dt=(now-lastTick)/1000; if(dt){ lastTick+=dt*1000; }

  bool isRunning = digitalRead(PIN_RUN)==HIGH;
  if (isRunning) runS+=dt; else downS+=dt;

  // state transition -> capture stop / reason
  if (running && !isRunning){ stopStart=now; }        // just stopped
  if (!running && isRunning && stopStart){            // just restarted
    uint32_t dur=(now-stopStart)/1000;
    const char* reason = getSelectedReason();         // operator selection
    logDowntime(dur, reason);                          // attribute the loss
    stopStart=0;
  }
  running=isRunning;

  if (countFlag){                                     // an output part
    countFlag=false; total++;
    if (digitalRead(PIN_GOOD)==HIGH) good++;          // else it's a reject
  }

  float a=availability(), p=performance(), q=quality();
  float oee=a*p*q;

  oled.clearDisplay(); oled.setCursor(0,0);
  oled.printf("OEE %.0f%%\nA %.0f P %.0f Q %.0f\n%s",
    oee*100, a*100, p*100, q*100, isRunning?"RUN":"DOWN");
  oled.display();

  char m[220];
  snprintf(m,sizeof m,
    "{\"oee\":%.3f,\"a\":%.3f,\"p\":%.3f,\"q\":%.3f,"
    "\"total\":%u,\"good\":%u,\"run\":%s}",
    oee,a,p,q,total,good, isRunning?"true":"false");
  mqtt.publish("oee/machine1/live", m);

  // shift rollup
  if (now-shiftStart >= SHIFT_S*1000UL){
    mqtt.publish("oee/machine1/shift", m);
    runS=downS=total=good=0; shiftStart=now;          // reset for next shift
  }
  delay(1000);
}
if (isRunning) runS+=dt; else downS+=dtEvery second is attributed to run or down time, building the Availability numerator/denominator from a truthful run/stop signal.
logDowntime(dur, reason)When the machine restarts, the stoppage duration and the operator-selected reason are logged, attributing the loss to one of the six big losses.
if (digitalRead(PIN_GOOD)==HIGH) good++;Each output part is counted as good or reject, feeding the Quality factor.
float oee=a*p*qOEE is the product of the three factors, computed live so the andon and dashboard always show the current effectiveness.
runS=downS=total=good=0; shiftStart=nowAt shift end the totals roll up and reset, giving clean per-shift OEE for reporting and comparison.

Configuration & Calibration

Configuration steps

  • Set the ideal cycle time and the planned-production-time/shift definition (agreed with the team).
  • Configure the run/stop, output and good/reject inputs and the downtime-reason list (six big losses).
  • Set shift/batch boundaries and the andon/dashboard reporting.
  • Decide how good/reject is determined (reject station vs operator entry).

Calibration procedure

An uncalibrated sensor produces confident, precise, wrong numbers. Do this once per physical unit and record the constants.

  1. Ideal cycle time

    Confirm the machine's true ideal cycle time (fastest sustainable per-part time); it anchors Performance.

  2. Planned time

    Agree what counts as planned production time (schedule minus planned breaks) so Availability is meaningful.

  3. Counts

    Verify output and good/reject counts against a manual check so Performance and Quality are accurate.

Network Architecture & Connectivity

OEE Productivity Tracker — network topologyPath taken by telemetry from field node to end user. Edge nodesGatewayCloudClientsOEE trackerESP32Other machinesper-machineWi-Fi 2.4 GHzRouterto MQTTMQTT 1883OEE dashboard/MESA/P/Q + lossesDashboardOEE trendsAndonlive OEE
OEE Productivity Tracker — network topology

Communication protocol

Live OEE and A/P/Q publish continuously; shift/batch rollups and downtime-with-reason publish at boundaries and on events, feeding loss ranking.

Topic / endpointDirectionPayload
oee/machine1/livenode → dashboardOEE, A, P, Q, counts, run state
oee/machine1/downtimenode → dashboardstoppage duration + reason
oee/machine1/shiftnode → MESper-shift/batch OEE rollup

Message contract between the device and the broker.

Cloud platform configuration

A dashboard/MES trends OEE and its factors per machine/shift/batch, ranks the six big losses, and supports before/after verification of improvements.

Dashboard setup

Live OEE and A/P/Q per machine, a Pareto of downtime reasons, shift/batch trends, and improvement comparisons.

Mobile app integration

Alerts on prolonged downtime or a significant OEE drop; shift summaries.

Security considerations

  • Authenticate nodes so productivity data is trustworthy.
  • Agree input definitions (ideal cycle time, planned time) so numbers are comparable.
  • Alert on tracker silence so a machine goes not-unmonitored.

Testing Procedure & Expected Output

Test from the bottom up. Confirm power, then each sensor in isolation, then the integrated loop — the first failing step tells you exactly where to look.

TestWhat you should see
Run at ideal speed, all goodA, P, Q and OEE near 100%
Introduce a stoppageAvailability drops; downtime logged with reason
Run slow / minor stopsPerformance drops
Produce rejectsQuality drops
End a shiftPer-shift OEE rolled up and reset
Apply a fix and compareOEE change verifies whether the fix worked

Bench-test checklist. If a row fails, stop and fix it before moving on.

Expected output

The andon shows live OEE and A/P/Q; the dashboard trends OEE per shift/batch, ranks downtime reasons (six big losses), and compares before/after.

jsonoee.json
{
  "oee": 0.62,
  "a": 0.82,
  "p": 0.86,
  "q": 0.88,
  "total": 1240,
  "good": 1091,
  "run": true
}

An OEE of 62% with A/P/Q of 82/86/88 shows Availability is the biggest loss here — so the ranked downtime reasons point straight at the breakdowns/changeovers to attack first.

A Grafana time-series dashboard
A dashboard ranks the six big losses and verifies whether improvements raised OEE. Photograph sourced from Wikimedia Commons — Grafana dashboard.png. Reused under the licence stated on that page; please check it before republishing.

Troubleshooting: Common Errors & Fixes

OEE looks implausible

Likely cause. Wrong ideal cycle time or planned time

Fix. Agree and set the correct ideal cycle time and planned-production-time definition

Losses not attributable

Likely cause. Downtime reasons not captured

Fix. Make reason selection one-touch; require a reason on restart

Performance > 100%

Likely cause. Ideal cycle time set too slow

Fix. Correct the ideal cycle time to the true fastest rate

Quality wrong

Likely cause. Good/reject miscounted

Fix. Verify the good/reject input against a manual count

Availability distorted

Likely cause. Planned time includes/excludes wrong periods

Fix. Define planned production time consistently (exclude planned breaks)

The sketch will not upload — "Failed to connect" or "avrdude: stk500_recv()"

Likely cause. The bootloader is not being reached: wrong port, wrong board, a serial monitor holding the port open, or a USB cable that only carries power.

Fix. Close every serial monitor, confirm Tools → Board and Port, and swap to a known data-capable USB cable. On an ESP32 hold BOOT while the IDE prints "Connecting…", then release. If a peripheral is wired to the UART pins (GPIO 1/3 on ESP32, D0/D1 on Uno) unplug it — it fights the programmer.

The board resets in a loop, or the serial monitor prints "Brownout detector was triggered"

Likely cause. The supply cannot deliver peak current. Wi-Fi transmit bursts, relay coils and servos all pull far more than their average draw.

Fix. Power peripherals from a separate regulated supply with a common ground rather than from the board 5 V pin. Add a 470–1000 µF electrolytic capacitor across the supply near the load, and use a real power adapter rather than a laptop USB port.

Serial monitor shows garbage characters

Likely cause. Baud rate mismatch between Serial.begin() and the monitor, or a floating/shared UART line.

Fix. Set the monitor to 115200 to match the sketch. If it still garbles, the crystal or the USB bridge is being confused by noise — shorten the cable and keep motor wiring away from the USB lead.

An I²C device is not detected

Likely cause. Wrong address, missing pull-ups, swapped SDA/SCL, or a bus too long for the pull-up value.

Fix. Run an I²C scanner sketch first — it should print the device address. Most breakout boards include 4.7 kΩ pull-ups, but if you have chained four of them the parallel resistance is too low; remove the pull-ups from all but one board. Keep the bus under 30 cm at 100 kHz.

Wi-Fi connects but MQTT never does (state -2)

Likely cause. Wrong broker address or port, a firewall in the way, or the broker requiring credentials the sketch is not sending.

Fix. Test from a laptop on the same network first: mosquitto_sub -h <broker> -t "#" -v. If that works, the problem is on the device — check the IP literal, port 1883 (or 8883 for TLS), and that client.setServer() runs before connect(). PubSubClient state codes are documented in its header.

Readings arrive for a while and then stop

Likely cause. The Wi-Fi or MQTT session dropped and the sketch never reconnects, or the broker dropped the client on keep-alive timeout.

Fix. Never assume the link stays up. Check WiFi.status() and client.connected() at the top of every loop and reconnect with exponential backoff. Add a watchdog so a wedged network stack reboots the device instead of going silent.

Performance Optimisation

  • Accumulate time and counts at 1 Hz; OEE does not need high-rate sampling.
  • Debounce the output counter and use interrupts for accurate counts.
  • Roll up per shift/batch and report live plus on events.
  • Keep reason capture one-touch so it actually happens.
  • Replace every delay() with a millis() comparison — blocking delays are the single most common cause of dropped readings.
  • Sample sensors on a fixed cadence and publish on a slower one; you almost never need to transmit at the sampling rate.
  • Move networking into its own FreeRTOS task so a slow DNS lookup cannot stall the control loop.
  • Use uint8_t / uint16_t where the range allows; on an 8-bit AVR a 32-bit add costs four times as much.
  • Batch several samples into one MQTT publish. Radio time, not CPU time, dominates the energy budget.
  • Set the MQTT keep-alive to a value that matches your reporting interval so the broker does not churn reconnections.
  • For battery builds use deep sleep between samples: an ESP32 drops from ~160 mA awake to about 10 µA asleep, which is the difference between days and months of runtime.

Safety Precautions

  • Sense machine signals safely and without interfering with machine control.
  • OEE is only as good as its inputs — agree the ideal cycle time and planned-time definition, and keep counts accurate.
  • Use OEE to target losses, not to blame operators; capture reasons constructively.
  • OEE measures effectiveness, not the whole business — keep it in context.
  • Wear eye protection when soldering or cutting, and solder in a ventilated space — rosin flux fumes are a respiratory irritant.
  • Power the circuit through a bench supply with a current limit while you are testing. A 300 mA limit turns a wiring mistake into a beep instead of a dead board.
  • Disconnect power before changing any wiring. Hot-plugging a sensor onto a live bus is the fastest way to lose a controller.

Maintenance

  • Re-verify ideal cycle time and planned-time definitions after process changes.
  • Check count/quality inputs against manual counts periodically.
  • Keep the downtime-reason list meaningful and current.
  • Review loss rankings and confirm improvements with before/after OEE.
  • Re-check every screw terminal and header after the first week — thermal cycling loosens connections that felt tight on day one.
  • Keep the broker and dashboard containers patched, and rotate device credentials at least once a year.
  • Recalibrate at the interval given in the calibration section, and keep the constants in a text file next to the firmware — not only in flash.
  • Keep a short logbook of firmware versions and what changed. Six months later you will not remember why that constant is 1.083.

Future Improvements & Upgrades

A working v1 is a platform, not a finish line. These are the upgrades that add the most capability for the least rework.

  • Auto-classify downtime causes from signals to reduce manual reason entry.
  • Integrate with MES/ERP for scheduling-aware OEE and TEEP.
  • Add micro-stop detection for finer Performance analysis.
  • Benchmark OEE across machines/lines and shifts.
  • Design a proper PCB. Once the breadboard version has run for a month, moving to a two-layer board removes the intermittent-contact failures that dominate prototype faults.
  • Add over-the-air firmware updates so you never have to physically reach a deployed node again.
  • Add persistent local storage (microSD or the on-chip flash) so a network outage does not create a hole in your data.
  • Move configuration out of the source: a captive-portal setup page or a JSON config file makes the build reusable without a recompile.
  • Add a battery and solar option so the unit survives a power cut and can be sited away from a socket.
  • Write a small test harness that feeds synthetic sensor values through the decision logic, so you can validate thresholds without physically triggering the event.

Frequently Asked Questions

What exactly is OEE?

Overall Equipment Effectiveness = Availability × Performance × Quality — the fraction of planned time that produced good parts at full speed. One number for how productive a machine is, and three factors for which kind of loss is hurting it.

Why decompose into three factors?

Because the fix differs by factor: low Availability means downtime/changeovers, low Performance means slow running/minor stops, low Quality means scrap. The decomposition tells you which loss to attack.

What are the "six big losses"?

Breakdowns and setup/changeover (Availability), minor stops and reduced speed (Performance), and startup and production rejects (Quality). Capturing downtime reasons attributes losses to these so you target the biggest.

Why must the ideal cycle time be right?

It anchors Performance. If it is wrong, Performance (and OEE) is meaningless — too slow an ideal makes Performance exceed 100%, too fast under-reports it. Agree the true fastest rate.

Is OEE the only metric I need?

No — it measures equipment effectiveness, not demand, cost or whether you should run the machine at all. It is a powerful targeting tool within a wider improvement effort, not the whole picture.

References & Learning Resources

These are the primary sources worth reading in full. Manufacturer datasheets always outrank forum posts when the two disagree.

  1. Overall Equipment Effectiveness (OEE)Reference
  2. The six big lossesReference
  3. Total Productive Maintenance (TPM)Reference
  4. Lean manufacturing and continuous improvementReference
  5. Andon (visual management)Reference